Merge "soong: Use the CpExecutable rule for copying libraries" into main
diff --git a/.gitignore b/.gitignore
index 5d2bc0d..89de74e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,5 @@
 *.iml
 *.ipr
 *.iws
-
+*.swp
+/.vscode
diff --git a/Android.bp b/Android.bp
index 63de015..b1db8e9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -130,3 +130,8 @@
     // Currently, only microdroid can refer to buildinfo.prop
     visibility: ["//packages/modules/Virtualization/microdroid"],
 }
+
+// container for apex_contributions selected using build flags
+all_apex_contributions {
+    name: "all_apex_contributions",
+}
diff --git a/OWNERS b/OWNERS
index 9221d3e..01025fb 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,30 +1,17 @@
+# Bug component: 99142
 # This file is included by several other projects as the list of people
 # approving build related projects.
 
 # AMER
-agespino@google.com
 ccross@android.com
 colefaust@google.com
-cparsons@google.com
-dacek@google.com
-delmerico@google.com
 dwillemsen@google.com
-eakammer@google.com
 jihoonkang@google.com
-jobredeaux@google.com
 joeo@google.com
-juu@google.com
 lamontjones@google.com
 mrziwang@google.com
 spandandas@google.com
-tradical@google.com
-usta@google.com
-vinhdaitran@google.com
 weiwli@google.com
 yudiliu@google.com
 
-# APAC
-jingwen@google.com
-
-# EMEA
-lberki@google.com
+per-file build/soong/ui/build/androidmk_denylist.go = joeo@google.com, weiwli@google.com
\ No newline at end of file
diff --git a/README.md b/README.md
index 2d8f0af..140822b 100644
--- a/README.md
+++ b/README.md
@@ -26,8 +26,6 @@
 [bug tracker](https://issuetracker.google.com/issues/new?component=381517) or
 or write us at android-building@googlegroups.com .
 
-For Googlers, see our [internal documentation](http://go/soong).
-
 ## Android.bp file format
 
 By design, Android.bp files are very simple.  There are no conditionals or
@@ -316,6 +314,9 @@
 * `["//visibility:override"]`: Discards any rules inherited from defaults or a
 creating module. Can only be used at the beginning of a list of visibility
 rules.
+* `["//visibility:any_partition"]`: Any modules of type android_filesystem
+or android_system_image can use this module. Intended for modules that no one
+should link against, but should still be included in soong-built partitions.
 * `["//some/package:__pkg__", "//other/package:__pkg__"]`: Only modules in
 `some/package` and `other/package` (defined in `some/package/*.bp` and
 `other/package/*.bp`) have access to this module. Note that sub-packages do not
@@ -448,6 +449,7 @@
     config_namespace: "acme",
     variables: ["board"],
     bool_variables: ["feature"],
+    list_variables: ["impl"],
     value_variables: ["width"],
     properties: ["cflags", "srcs"],
 }
@@ -459,24 +461,40 @@
 ```
 
 This example describes a new `acme_cc_defaults` module type that extends the
-`cc_defaults` module type, with three additional conditionals based on
-variables `board`, `feature` and `width`, which can affect properties `cflags`
-and `srcs`. Additionally, each conditional will contain a `conditions_default`
-property can affect `cflags` and `srcs` in the following conditions:
+`cc_defaults` module type, with four additional conditionals based on variables
+`board`, `feature`, `impl` and `width` which can affect properties `cflags` and
+`srcs`. The four types of soong variables control properties in the following
+ways.
 
-* bool variable (e.g. `feature`): the variable is unspecified or not set to a true value
+* bool variable (e.g. `feature`): Properties are applied if set to `true`.
+* list variable (e.g. `impl`): (lists of strings properties only) Properties are
+  applied for each value in the list, using `%s` substitution. For example, if
+  the property is `["%s.cpp", "%s.h"]` and the list value is `foo bar`,
+  the result is `["foo.cpp", "foo.h", "bar.cpp", "bar.h"]`.
+* value variable (e.g. `width`): (strings or lists of strings) The value are
+  directly substituted into properties using `%s`.
+* string variable (e.g. `board`): Properties are applied only if they match the
+  variable's value.
+
+Additionally, each conditional containing a `conditions_default` property can
+affect `cflags` and `srcs` in the following conditions:
+
+* bool variable (e.g. `feature`): the variable is unspecified or not set to
+  `true`
+* list variable (e.g. `impl`): the variable is unspecified
 * value variable (e.g. `width`): the variable is unspecified
-* string variable (e.g. `board`): the variable is unspecified or the variable is set to a string unused in the
-given module. For example, with `board`, if the `board`
-conditional contains the properties `soc_a` and `conditions_default`, when
-board=soc_b, the `cflags` and `srcs` values under `conditions_default` will be
-used. To specify that no properties should be amended for `soc_b`, you can set
-`soc_b: {},`.
+* string variable (e.g. `board`): the variable is unspecified or the variable is
+  set to a string unused in the given module. For example, with `board`, if the
+  `board` conditional contains the properties `soc_a` and `conditions_default`,
+  when `board` is `soc_b`, the `cflags` and `srcs` values under
+  `conditions_default` is used. To specify that no properties should be amended
+  for `soc_b`, you can set `soc_b: {},`.
 
 The values of the variables can be set from a product's `BoardConfig.mk` file:
 ```
 $(call soong_config_set,acme,board,soc_a)
 $(call soong_config_set,acme,feature,true)
+$(call soong_config_set,acme,impl,foo.cpp bar.cpp)
 $(call soong_config_set,acme,width,200)
 ```
 
@@ -518,6 +536,12 @@
                 cflags: ["-DWIDTH=DEFAULT"],
             },
         },
+        impl: {
+            srcs: ["impl/%s"],
+            conditions_default: {
+                srcs: ["impl/default.cpp"],
+            },
+        },
     },
 }
 
@@ -529,7 +553,8 @@
 ```
 
 With the `BoardConfig.mk` snippet above, `libacme_foo` would build with
-`cflags: "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200"`.
+`cflags: "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200"` and
+`srcs: ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"]`.
 
 Alternatively, with `DefaultBoardConfig.mk`:
 
@@ -538,12 +563,14 @@
 SOONG_CONFIG_acme += \
     board \
     feature \
+    impl \
     width \
 
 SOONG_CONFIG_acme_feature := false
 ```
 
-then `libacme_foo` would build with `cflags: "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT"`.
+then `libacme_foo` would build with `cflags: "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT"`
+and `srcs: ["*.cpp", "impl/default.cpp"]`.
 
 Alternatively, with `DefaultBoardConfig.mk`:
 
@@ -552,13 +579,15 @@
 SOONG_CONFIG_acme += \
     board \
     feature \
+    impl \
     width \
 
 SOONG_CONFIG_acme_board := soc_c
+SOONG_CONFIG_acme_impl := baz
 ```
 
 then `libacme_foo` would build with `cflags: "-DGENERIC -DSOC_DEFAULT
--DFEATURE_DEFAULT -DSIZE=DEFAULT"`.
+-DFEATURE_DEFAULT -DSIZE=DEFAULT"` and `srcs: ["*.cpp", "impl/baz.cpp"]`.
 
 `soong_config_module_type` modules will work best when used to wrap defaults
 modules (`cc_defaults`, `java_defaults`, etc.), which can then be referenced
@@ -605,7 +634,7 @@
 * [Build Performance](docs/perf.md)
 * [Generating CLion Projects](docs/clion.md)
 * [Generating YouCompleteMe/VSCode compile\_commands.json file](docs/compdb.md)
-* Make-specific documentation: [build/make/README.md](https://android.googlesource.com/platform/build/+/master/README.md)
+* Make-specific documentation: [build/make/README.md](https://android.googlesource.com/platform/build/+/main/README.md)
 
 ## Developing for Soong
 
@@ -650,8 +679,8 @@
 SOONG_DELVE=2345 SOONG_DELVE_STEPS='build,modulegraph' m
 ```
 results in only `build` (main build step) and `modulegraph` being run in the debugger.
-The allowed step names are `api_bp2build`, `bp2build_files`, `bp2build_workspace`,
-`build`, `modulegraph`, `queryview`, `soong_docs`.
+The allowed step names are `bp2build_files`, `bp2build_workspace`, `build`,
+`modulegraph`, `queryview`, `soong_docs`.
 
 Note setting or unsetting `SOONG_DELVE` causes a recompilation of `soong_build`. This
 is because in order to debug the binary, it needs to be built with debug
diff --git a/aconfig/Android.bp b/aconfig/Android.bp
index d2ddfdf..402cf16 100644
--- a/aconfig/Android.bp
+++ b/aconfig/Android.bp
@@ -11,27 +11,21 @@
         "sbox_proto",
         "soong",
         "soong-android",
-        "soong-bazel",
-        "soong-android",
-        "soong-java",
-        "soong-rust",
     ],
     srcs: [
         "aconfig_declarations.go",
         "aconfig_values.go",
         "aconfig_value_set.go",
         "all_aconfig_declarations.go",
-        "cc_aconfig_library.go",
+        "exported_java_aconfig_library.go",
         "init.go",
-        "java_aconfig_library.go",
         "testing.go",
-        "rust_aconfig_library.go",
     ],
     testSrcs: [
         "aconfig_declarations_test.go",
         "aconfig_values_test.go",
         "aconfig_value_set_test.go",
-        "java_aconfig_library_test.go",
+        "all_aconfig_declarations_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go
index d1d1578..d29e312 100644
--- a/aconfig/aconfig_declarations.go
+++ b/aconfig/aconfig_declarations.go
@@ -15,10 +15,11 @@
 package aconfig
 
 import (
-	"android/soong/android"
 	"fmt"
 	"strings"
 
+	"android/soong/android"
+
 	"github.com/google/blueprint"
 )
 
@@ -36,6 +37,12 @@
 
 		// Values from TARGET_RELEASE / RELEASE_ACONFIG_VALUE_SETS
 		Values []string `blueprint:"mutated"`
+
+		// Container(system/vendor/apex) that this module belongs to
+		Container string
+
+		// The flags will only be repackaged if this prop is true.
+		Exportable bool
 	}
 
 	intermediatePath android.WritablePath
@@ -47,8 +54,6 @@
 	android.InitAndroidModule(module)
 	android.InitDefaultableModule(module)
 	module.AddProperties(&module.properties)
-	// TODO: bp2build
-	//android.InitBazelModule(module)
 
 	return module
 }
@@ -68,12 +73,16 @@
 	if len(module.properties.Package) == 0 {
 		ctx.PropertyErrorf("package", "missing package property")
 	}
+	// TODO(b/311155208): Add mandatory check for container after all pre-existing
+	// ones are changed.
 
 	// Add a dependency on the aconfig_value_sets defined in
 	// RELEASE_ACONFIG_VALUE_SETS, and add any aconfig_values that
 	// match our package.
 	valuesFromConfig := ctx.Config().ReleaseAconfigValueSets()
-	ctx.AddDependency(ctx.Module(), implicitValuesTag, valuesFromConfig...)
+	if len(valuesFromConfig) > 0 {
+		ctx.AddDependency(ctx.Module(), implicitValuesTag, valuesFromConfig...)
+	}
 }
 
 func (module *DeclarationsModule) OutputFiles(tag string) (android.Paths, error) {
@@ -97,48 +106,69 @@
 	return sb.String()
 }
 
-// Provider published by aconfig_value_set
-type declarationsProviderData struct {
-	Package          string
-	IntermediatePath android.WritablePath
+func optionalVariable(prefix string, value string) string {
+	var sb strings.Builder
+	if value != "" {
+		sb.WriteString(prefix)
+		sb.WriteString(value)
+	}
+	return sb.String()
 }
 
-var declarationsProviderKey = blueprint.NewProvider(declarationsProviderData{})
-
 func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
+	valuesFiles := make([]android.Path, 0)
 	ctx.VisitDirectDeps(func(dep android.Module) {
-		if !ctx.OtherModuleHasProvider(dep, valueSetProviderKey) {
-			// Other modules get injected as dependencies too, for example the license modules
-			return
-		}
-		depData := ctx.OtherModuleProvider(dep, valueSetProviderKey).(valueSetProviderData)
-		valuesFiles, ok := depData.AvailablePackages[module.properties.Package]
-		if ok {
-			for _, path := range valuesFiles {
-				module.properties.Values = append(module.properties.Values, path.String())
+		if depData, ok := android.OtherModuleProvider(ctx, dep, valueSetProviderKey); ok {
+			paths, ok := depData.AvailablePackages[module.properties.Package]
+			if ok {
+				valuesFiles = append(valuesFiles, paths...)
+				for _, path := range paths {
+					module.properties.Values = append(module.properties.Values, path.String())
+				}
 			}
 		}
 	})
 
 	// Intermediate format
-	inputFiles := android.PathsForModuleSrc(ctx, module.properties.Srcs)
-	intermediatePath := android.PathForModuleOut(ctx, "intermediate.pb")
+	declarationFiles := android.PathsForModuleSrc(ctx, module.properties.Srcs)
+	intermediateCacheFilePath := android.PathForModuleOut(ctx, "intermediate.pb")
+	defaultPermission := ctx.Config().ReleaseAconfigFlagDefaultPermission()
+	inputFiles := make([]android.Path, len(declarationFiles))
+	copy(inputFiles, declarationFiles)
+	inputFiles = append(inputFiles, valuesFiles...)
+	args := map[string]string{
+		"release_version":    ctx.Config().ReleaseVersion(),
+		"package":            module.properties.Package,
+		"declarations":       android.JoinPathsWithPrefix(declarationFiles, "--declarations "),
+		"values":             joinAndPrefix(" --values ", module.properties.Values),
+		"default-permission": optionalVariable(" --default-permission ", defaultPermission),
+	}
+	if len(module.properties.Container) > 0 {
+		args["container"] = "--container " + module.properties.Container
+	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        aconfigRule,
-		Output:      intermediatePath,
+		Output:      intermediateCacheFilePath,
+		Inputs:      inputFiles,
 		Description: "aconfig_declarations",
-		Args: map[string]string{
-			"release_version": ctx.Config().ReleaseVersion(),
-			"package":         module.properties.Package,
-			"declarations":    android.JoinPathsWithPrefix(inputFiles, "--declarations "),
-			"values":          joinAndPrefix(" --values ", module.properties.Values),
-		},
+		Args:        args,
 	})
 
-	ctx.SetProvider(declarationsProviderKey, declarationsProviderData{
-		Package:          module.properties.Package,
-		IntermediatePath: intermediatePath,
+	intermediateDumpFilePath := android.PathForModuleOut(ctx, "intermediate.txt")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        aconfigTextRule,
+		Output:      intermediateDumpFilePath,
+		Inputs:      android.Paths{intermediateCacheFilePath},
+		Description: "aconfig_text",
+	})
+
+	android.SetProvider(ctx, android.AconfigDeclarationsProviderKey, android.AconfigDeclarationsProviderData{
+		Package:                     module.properties.Package,
+		Container:                   module.properties.Container,
+		Exportable:                  module.properties.Exportable,
+		IntermediateCacheOutputPath: intermediateCacheFilePath,
+		IntermediateDumpOutputPath:  intermediateDumpFilePath,
 	})
 
 }
diff --git a/aconfig/aconfig_declarations_test.go b/aconfig/aconfig_declarations_test.go
index e0d8f7d..5201fed 100644
--- a/aconfig/aconfig_declarations_test.go
+++ b/aconfig/aconfig_declarations_test.go
@@ -26,6 +26,8 @@
 		aconfig_declarations {
 			name: "module_name",
 			package: "com.example.package",
+			container: "com.android.foo",
+			exportable: true,
 			srcs: [
 				"foo.aconfig",
 				"bar.aconfig",
@@ -37,9 +39,68 @@
 	module := result.ModuleForTests("module_name", "").Module().(*DeclarationsModule)
 
 	// Check that the provider has the right contents
-	depData := result.ModuleProvider(module, declarationsProviderKey).(declarationsProviderData)
+	depData, _ := android.SingletonModuleProvider(result, module, android.AconfigDeclarationsProviderKey)
 	android.AssertStringEquals(t, "package", depData.Package, "com.example.package")
-	if !strings.HasSuffix(depData.IntermediatePath.String(), "/intermediate.pb") {
-		t.Errorf("Missing intermediates path in provider: %s", depData.IntermediatePath.String())
+	android.AssertStringEquals(t, "container", depData.Container, "com.android.foo")
+	android.AssertBoolEquals(t, "exportable", depData.Exportable, true)
+	if !strings.HasSuffix(depData.IntermediateCacheOutputPath.String(), "/intermediate.pb") {
+		t.Errorf("Missing intermediates proto path in provider: %s", depData.IntermediateCacheOutputPath.String())
 	}
+	if !strings.HasSuffix(depData.IntermediateDumpOutputPath.String(), "/intermediate.txt") {
+		t.Errorf("Missing intermediates text path in provider: %s", depData.IntermediateDumpOutputPath.String())
+	}
+}
+
+func TestAconfigDeclarationsWithExportableUnset(t *testing.T) {
+	bp := `
+		aconfig_declarations {
+			name: "module_name",
+			package: "com.example.package",
+			container: "com.android.foo",
+			srcs: [
+				"foo.aconfig",
+				"bar.aconfig",
+			],
+		}
+	`
+	result := runTest(t, android.FixtureExpectsNoErrors, bp)
+
+	module := result.ModuleForTests("module_name", "").Module().(*DeclarationsModule)
+	depData, _ := android.SingletonModuleProvider(result, module, android.AconfigDeclarationsProviderKey)
+	android.AssertBoolEquals(t, "exportable", depData.Exportable, false)
+}
+
+func TestAconfigDeclarationsWithContainer(t *testing.T) {
+	bp := `
+		aconfig_declarations {
+			name: "module_name",
+			package: "com.example.package",
+			container: "com.android.foo",
+			srcs: [
+				"foo.aconfig",
+			],
+		}
+	`
+	result := runTest(t, android.FixtureExpectsNoErrors, bp)
+
+	module := result.ModuleForTests("module_name", "")
+	rule := module.Rule("aconfig")
+	android.AssertStringEquals(t, "rule must contain container", rule.Args["container"], "--container com.android.foo")
+}
+
+func TestAconfigDeclarationsWithoutContainer(t *testing.T) {
+	bp := `
+		aconfig_declarations {
+			name: "module_name",
+			package: "com.example.package",
+			srcs: [
+				"foo.aconfig",
+			],
+		}
+	`
+	result := runTest(t, android.FixtureExpectsNoErrors, bp)
+
+	module := result.ModuleForTests("module_name", "")
+	rule := module.Rule("aconfig")
+	android.AssertIntEquals(t, "rule must not contain container", len(rule.Args["container"]), 0)
 }
diff --git a/aconfig/aconfig_value_set.go b/aconfig/aconfig_value_set.go
index 252908f..7ba76c0 100644
--- a/aconfig/aconfig_value_set.go
+++ b/aconfig/aconfig_value_set.go
@@ -36,8 +36,6 @@
 	android.InitAndroidModule(module)
 	android.InitDefaultableModule(module)
 	module.AddProperties(&module.properties)
-	// TODO: bp2build
-	//android.InitBazelModule(module)
 
 	return module
 }
@@ -56,7 +54,7 @@
 	AvailablePackages map[string]android.Paths
 }
 
-var valueSetProviderKey = blueprint.NewProvider(valueSetProviderData{})
+var valueSetProviderKey = blueprint.NewProvider[valueSetProviderData]()
 
 func (module *ValueSetModule) DepsMutator(ctx android.BottomUpMutatorContext) {
 	deps := ctx.AddDependency(ctx.Module(), valueSetTag, module.properties.Values...)
@@ -75,18 +73,14 @@
 	// to append values to their aconfig actions.
 	packages := make(map[string]android.Paths)
 	ctx.VisitDirectDeps(func(dep android.Module) {
-		if !ctx.OtherModuleHasProvider(dep, valuesProviderKey) {
-			// Other modules get injected as dependencies too, for example the license modules
-			return
+		if depData, ok := android.OtherModuleProvider(ctx, dep, valuesProviderKey); ok {
+			srcs := make([]android.Path, len(depData.Values))
+			copy(srcs, depData.Values)
+			packages[depData.Package] = srcs
 		}
-		depData := ctx.OtherModuleProvider(dep, valuesProviderKey).(valuesProviderData)
-
-		srcs := make([]android.Path, len(depData.Values))
-		copy(srcs, depData.Values)
-		packages[depData.Package] = srcs
 
 	})
-	ctx.SetProvider(valueSetProviderKey, valueSetProviderData{
+	android.SetProvider(ctx, valueSetProviderKey, valueSetProviderData{
 		AvailablePackages: packages,
 	})
 }
diff --git a/aconfig/aconfig_value_set_test.go b/aconfig/aconfig_value_set_test.go
index 9127872..7d18999 100644
--- a/aconfig/aconfig_value_set_test.go
+++ b/aconfig/aconfig_value_set_test.go
@@ -38,6 +38,6 @@
 	module := result.ModuleForTests("module_name", "").Module().(*ValueSetModule)
 
 	// Check that the provider has the right contents
-	depData := result.ModuleProvider(module, valueSetProviderKey).(valueSetProviderData)
+	depData, _ := android.SingletonModuleProvider(result, module, valueSetProviderKey)
 	android.AssertStringEquals(t, "AvailablePackages", "blah.aconfig_values", depData.AvailablePackages["foo.package"][0].String())
 }
diff --git a/aconfig/aconfig_values.go b/aconfig/aconfig_values.go
index 91f1c90..239b10c 100644
--- a/aconfig/aconfig_values.go
+++ b/aconfig/aconfig_values.go
@@ -39,8 +39,6 @@
 	android.InitAndroidModule(module)
 	android.InitDefaultableModule(module)
 	module.AddProperties(&module.properties)
-	// TODO: bp2build
-	//android.InitBazelModule(module)
 
 	return module
 }
@@ -54,7 +52,7 @@
 	Values android.Paths
 }
 
-var valuesProviderKey = blueprint.NewProvider(valuesProviderData{})
+var valuesProviderKey = blueprint.NewProvider[valuesProviderData]()
 
 func (module *ValuesModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if len(module.properties.Package) == 0 {
@@ -66,5 +64,5 @@
 		Package: module.properties.Package,
 		Values:  android.PathsForModuleSrc(ctx, module.properties.Srcs),
 	}
-	ctx.SetProvider(valuesProviderKey, providerData)
+	android.SetProvider(ctx, valuesProviderKey, providerData)
 }
diff --git a/aconfig/aconfig_values_test.go b/aconfig/aconfig_values_test.go
index ab457f0..526579c 100644
--- a/aconfig/aconfig_values_test.go
+++ b/aconfig/aconfig_values_test.go
@@ -33,7 +33,7 @@
 	module := result.ModuleForTests("module_name", "").Module().(*ValuesModule)
 
 	// Check that the provider has the right contents
-	depData := result.ModuleProvider(module, valuesProviderKey).(valuesProviderData)
+	depData, _ := android.SingletonModuleProvider(result, module, valuesProviderKey)
 	android.AssertStringEquals(t, "package", "foo.package", depData.Package)
 	android.AssertPathsEndWith(t, "srcs", []string{"blah.aconfig_values"}, depData.Values)
 }
diff --git a/aconfig/all_aconfig_declarations.go b/aconfig/all_aconfig_declarations.go
index 6096c6c..e771d05 100644
--- a/aconfig/all_aconfig_declarations.go
+++ b/aconfig/all_aconfig_declarations.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+	"fmt"
 )
 
 // A singleton module that collects all of the aconfig flags declared in the
@@ -30,34 +31,66 @@
 }
 
 type allAconfigDeclarationsSingleton struct {
-	intermediatePath android.OutputPath
+	intermediateBinaryProtoPath android.OutputPath
+	intermediateTextProtoPath   android.OutputPath
 }
 
 func (this *allAconfigDeclarationsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	// Find all of the aconfig_declarations modules
+	var packages = make(map[string]int)
 	var cacheFiles android.Paths
 	ctx.VisitAllModules(func(module android.Module) {
-		if !ctx.ModuleHasProvider(module, declarationsProviderKey) {
+		decl, ok := android.SingletonModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey)
+		if !ok {
 			return
 		}
-		decl := ctx.ModuleProvider(module, declarationsProviderKey).(declarationsProviderData)
-		cacheFiles = append(cacheFiles, decl.IntermediatePath)
+		cacheFiles = append(cacheFiles, decl.IntermediateCacheOutputPath)
+		packages[decl.Package]++
 	})
 
-	// Generate build action for aconfig
-	this.intermediatePath = android.PathForIntermediates(ctx, "all_aconfig_declarations.pb")
+	var numOffendingPkg = 0
+	for pkg, cnt := range packages {
+		if cnt > 1 {
+			fmt.Printf("%d aconfig_declarations found for package %s\n", cnt, pkg)
+			numOffendingPkg++
+		}
+	}
+
+	if numOffendingPkg > 0 {
+		panic(fmt.Errorf("Only one aconfig_declarations allowed for each package."))
+	}
+
+	// Generate build action for aconfig (binary proto output)
+	this.intermediateBinaryProtoPath = android.PathForIntermediates(ctx, "all_aconfig_declarations.pb")
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        allDeclarationsRule,
+		Rule:        AllDeclarationsRule,
 		Inputs:      cacheFiles,
-		Output:      this.intermediatePath,
+		Output:      this.intermediateBinaryProtoPath,
 		Description: "all_aconfig_declarations",
 		Args: map[string]string{
 			"cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "),
 		},
 	})
-	ctx.Phony("all_aconfig_declarations", this.intermediatePath)
+	ctx.Phony("all_aconfig_declarations", this.intermediateBinaryProtoPath)
+
+	// Generate build action for aconfig (text proto output)
+	this.intermediateTextProtoPath = android.PathForIntermediates(ctx, "all_aconfig_declarations.textproto")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        AllDeclarationsRuleTextProto,
+		Inputs:      cacheFiles,
+		Output:      this.intermediateTextProtoPath,
+		Description: "all_aconfig_declarations_textproto",
+		Args: map[string]string{
+			"cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "),
+		},
+	})
+	ctx.Phony("all_aconfig_declarations_textproto", this.intermediateTextProtoPath)
 }
 
 func (this *allAconfigDeclarationsSingleton) MakeVars(ctx android.MakeVarsContext) {
-	ctx.DistForGoal("droid", this.intermediatePath)
+	ctx.DistForGoal("droid", this.intermediateBinaryProtoPath)
+	for _, goal := range []string{"docs", "droid", "sdk"} {
+		ctx.DistForGoalWithFilename(goal, this.intermediateBinaryProtoPath, "flags.pb")
+		ctx.DistForGoalWithFilename(goal, this.intermediateTextProtoPath, "flags.textproto")
+	}
 }
diff --git a/aconfig/all_aconfig_declarations_test.go b/aconfig/all_aconfig_declarations_test.go
new file mode 100644
index 0000000..0b2021e
--- /dev/null
+++ b/aconfig/all_aconfig_declarations_test.go
@@ -0,0 +1,48 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package aconfig
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestTwoAconfigDeclarationsPerPackage(t *testing.T) {
+	bp := `
+		aconfig_declarations {
+			name: "module_name.foo",
+			package: "com.example.package",
+			container: "com.android.foo",
+			srcs: [
+				"foo.aconfig",
+			],
+		}
+
+		aconfig_declarations {
+			name: "module_name.bar",
+			package: "com.example.package",
+			container: "com.android.foo",
+			srcs: [
+				"bar.aconfig",
+			],
+		}
+	`
+	errMsg := "Only one aconfig_declarations allowed for each package."
+	android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents).
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(errMsg)).
+		RunTestWithBp(t, bp)
+}
diff --git a/aconfig/codegen/Android.bp b/aconfig/codegen/Android.bp
new file mode 100644
index 0000000..0c78b94
--- /dev/null
+++ b/aconfig/codegen/Android.bp
@@ -0,0 +1,34 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-aconfig-codegen",
+    pkgPath: "android/soong/aconfig/codegen",
+    deps: [
+        "blueprint",
+        "blueprint-pathtools",
+        "sbox_proto",
+        "soong",
+        "soong-aconfig",
+        "soong-android",
+        "soong-bazel",
+        "soong-java",
+        "soong-rust",
+    ],
+    srcs: [
+        "aconfig_declarations_group.go",
+        "cc_aconfig_library.go",
+        "init.go",
+        "java_aconfig_library.go",
+        "rust_aconfig_library.go",
+        "testing.go",
+    ],
+    testSrcs: [
+        "aconfig_declarations_group_test.go",
+        "java_aconfig_library_test.go",
+        "cc_aconfig_library_test.go",
+        "rust_aconfig_library_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/aconfig/codegen/aconfig_declarations_group.go b/aconfig/codegen/aconfig_declarations_group.go
new file mode 100644
index 0000000..1c91bee
--- /dev/null
+++ b/aconfig/codegen/aconfig_declarations_group.go
@@ -0,0 +1,139 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package codegen
+
+import (
+	"fmt"
+	"maps"
+
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+)
+
+type dependencyTag struct {
+	blueprint.BaseDependencyTag
+	name string
+}
+
+var (
+	aconfigDeclarationsGroupTag = dependencyTag{name: "aconfigDeclarationsGroup"}
+	javaAconfigLibraryTag       = dependencyTag{name: "javaAconfigLibrary"}
+	ccAconfigLibraryTag         = dependencyTag{name: "ccAconfigLibrary"}
+	rustAconfigLibraryTag       = dependencyTag{name: "rustAconfigLibrary"}
+)
+
+type AconfigDeclarationsGroup struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+
+	properties AconfigDeclarationsGroupProperties
+
+	aconfigDeclarationNames      []string
+	intermediateCacheOutputPaths android.Paths
+	javaSrcjars                  android.Paths
+	modeInfos                    map[string]android.ModeInfo
+}
+
+type AconfigDeclarationsGroupProperties struct {
+
+	// Name of the aconfig_declarations_group modules
+	Aconfig_declarations_groups []string
+
+	// Name of the java_aconfig_library modules
+	Java_aconfig_libraries []string
+
+	// Name of the cc_aconfig_library modules
+	Cc_aconfig_libraries []string
+
+	// Name of the rust_aconfig_library modules
+	Rust_aconfig_libraries []string
+}
+
+func AconfigDeclarationsGroupFactory() android.Module {
+	module := &AconfigDeclarationsGroup{}
+	module.AddProperties(&module.properties)
+	android.InitAndroidModule(module)
+	android.InitDefaultableModule(module)
+	return module
+}
+
+func (adg *AconfigDeclarationsGroup) DepsMutator(ctx android.BottomUpMutatorContext) {
+	ctx.AddDependency(ctx.Module(), aconfigDeclarationsGroupTag, adg.properties.Aconfig_declarations_groups...)
+	ctx.AddDependency(ctx.Module(), javaAconfigLibraryTag, adg.properties.Java_aconfig_libraries...)
+	ctx.AddDependency(ctx.Module(), ccAconfigLibraryTag, adg.properties.Cc_aconfig_libraries...)
+	ctx.AddDependency(ctx.Module(), rustAconfigLibraryTag, adg.properties.Rust_aconfig_libraries...)
+}
+
+func (adg *AconfigDeclarationsGroup) VisitDeps(ctx android.ModuleContext) {
+	adg.modeInfos = make(map[string]android.ModeInfo)
+	ctx.VisitDirectDeps(func(dep android.Module) {
+		tag := ctx.OtherModuleDependencyTag(dep)
+		if provider, ok := android.OtherModuleProvider(ctx, dep, android.CodegenInfoProvider); ok {
+
+			// aconfig declaration names and cache files are collected for all aconfig library dependencies
+			adg.aconfigDeclarationNames = append(adg.aconfigDeclarationNames, provider.AconfigDeclarations...)
+			adg.intermediateCacheOutputPaths = append(adg.intermediateCacheOutputPaths, provider.IntermediateCacheOutputPaths...)
+
+			switch tag {
+			case aconfigDeclarationsGroupTag:
+				// Will retrieve outputs from another language codegen modules when support is added
+				adg.javaSrcjars = append(adg.javaSrcjars, provider.Srcjars...)
+				maps.Copy(adg.modeInfos, provider.ModeInfos)
+			case javaAconfigLibraryTag:
+				adg.javaSrcjars = append(adg.javaSrcjars, provider.Srcjars...)
+				maps.Copy(adg.modeInfos, provider.ModeInfos)
+			case ccAconfigLibraryTag:
+				maps.Copy(adg.modeInfos, provider.ModeInfos)
+			case rustAconfigLibraryTag:
+				maps.Copy(adg.modeInfos, provider.ModeInfos)
+			}
+		}
+	})
+}
+
+func (adg *AconfigDeclarationsGroup) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	adg.VisitDeps(ctx)
+	adg.aconfigDeclarationNames = android.FirstUniqueStrings(adg.aconfigDeclarationNames)
+	adg.intermediateCacheOutputPaths = android.FirstUniquePaths(adg.intermediateCacheOutputPaths)
+
+	android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{
+		AconfigDeclarations:          adg.aconfigDeclarationNames,
+		IntermediateCacheOutputPaths: adg.intermediateCacheOutputPaths,
+		Srcjars:                      adg.javaSrcjars,
+		ModeInfos:                    adg.modeInfos,
+	})
+}
+
+var _ android.OutputFileProducer = (*AconfigDeclarationsGroup)(nil)
+
+func (adg *AconfigDeclarationsGroup) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		return adg.intermediateCacheOutputPaths, nil
+	case ".srcjars":
+		return adg.javaSrcjars, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %s", tag)
+	}
+}
+
+func (adg *AconfigDeclarationsGroup) Srcjars() android.Paths {
+	return adg.javaSrcjars
+}
+
+func (adg *AconfigDeclarationsGroup) AconfigDeclarations() []string {
+	return adg.aconfigDeclarationNames
+}
diff --git a/aconfig/codegen/aconfig_declarations_group_test.go b/aconfig/codegen/aconfig_declarations_group_test.go
new file mode 100644
index 0000000..ec7cea3
--- /dev/null
+++ b/aconfig/codegen/aconfig_declarations_group_test.go
@@ -0,0 +1,79 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package codegen
+
+import (
+	"android/soong/android"
+	"android/soong/java"
+	"testing"
+)
+
+func TestAconfigDeclarationsGroup(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		java.PrepareForTestWithJavaDefaultModules,
+	).RunTestWithBp(t, `
+		aconfig_declarations {
+			name: "foo-aconfig",
+			package: "com.example.package",
+			srcs: ["foo.aconfig"],
+		}
+
+		java_aconfig_library {
+			name: "foo-java",
+			aconfig_declarations: "foo-aconfig",
+		}
+
+		aconfig_declarations {
+			name: "bar-aconfig",
+			package: "com.example.package",
+			srcs: ["foo.aconfig"],
+		}
+
+		java_aconfig_library {
+			name: "bar-java",
+			aconfig_declarations: "bar-aconfig",
+		}
+
+		aconfig_declarations_group {
+			name: "my_group",
+			java_aconfig_libraries: [
+				"foo-java",
+				"bar-java",
+			],
+		}
+
+		java_library {
+			name: "baz",
+			srcs: [
+				":my_group{.srcjars}",
+			],
+		}
+	`)
+
+	// Check if aconfig_declarations_group module depends on the aconfig_library modules
+	java.CheckModuleDependencies(t, result.TestContext, "my_group", "", []string{
+		`bar-java`,
+		`foo-java`,
+	})
+
+	// Check if srcjar files are correctly passed to the reverse dependency of
+	// aconfig_declarations_group module
+	bazModule := result.ModuleForTests("baz", "android_common")
+	bazJavacSrcjars := bazModule.Rule("javac").Args["srcJars"]
+	errorMessage := "baz javac argument expected to contain srcjar provided by aconfig_declrations_group"
+	android.AssertStringDoesContain(t, errorMessage, bazJavacSrcjars, "foo-java.srcjar")
+	android.AssertStringDoesContain(t, errorMessage, bazJavacSrcjars, "bar-java.srcjar")
+}
diff --git a/aconfig/cc_aconfig_library.go b/aconfig/codegen/cc_aconfig_library.go
similarity index 67%
rename from aconfig/cc_aconfig_library.go
rename to aconfig/codegen/cc_aconfig_library.go
index 14090bc..ec0a6b6 100644
--- a/aconfig/cc_aconfig_library.go
+++ b/aconfig/codegen/cc_aconfig_library.go
@@ -12,14 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package aconfig
+package codegen
 
 import (
 	"android/soong/android"
 	"android/soong/cc"
+
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"fmt"
+	"strconv"
 	"strings"
 )
 
@@ -29,9 +32,22 @@
 
 var ccDeclarationsTag = ccDeclarationsTagType{}
 
+const baseLibDep = "server_configurable_flags"
+
+const libBaseDep = "libbase"
+const libLogDep = "liblog"
+const libAconfigStorageReadApiCcDep = "libaconfig_storage_read_api_cc"
+
 type CcAconfigLibraryProperties struct {
 	// name of the aconfig_declarations module to generate a library for
 	Aconfig_declarations string
+
+	// default mode is "production", the other accepted modes are:
+	// "test": to generate test mode version of the library
+	// "exported": to generate exported mode version of the library
+	// "force-read-only": to generate force-read-only mode version of the library
+	// an error will be thrown if the mode is not supported
+	Mode *string
 }
 
 type CcAconfigLibraryCallbacks struct {
@@ -66,8 +82,19 @@
 		ctx.AddDependency(ctx.Module(), ccDeclarationsTag, declarations)
 	}
 
-	// Add a dependency for the aconfig flags base library
-	deps.SharedLibs = append(deps.SharedLibs, "server_configurable_flags")
+	mode := proptools.StringDefault(this.properties.Mode, "production")
+
+	// Add a dependency for the aconfig flags base library if it is not forced read only
+	if mode != "force-read-only" {
+		deps.SharedLibs = append(deps.SharedLibs, baseLibDep)
+
+	}
+
+	// TODO: after storage migration is over, don't add these in force-read-only-mode.
+	deps.SharedLibs = append(deps.SharedLibs, libAconfigStorageReadApiCcDep)
+	deps.SharedLibs = append(deps.SharedLibs, libBaseDep)
+	deps.SharedLibs = append(deps.SharedLibs, libLogDep)
+
 	// TODO: It'd be really nice if we could reexport this library and not make everyone do it.
 
 	return deps
@@ -81,7 +108,7 @@
 	if len(declarationsModules) != 1 {
 		panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
 	}
-	declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData)
+	declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey)
 
 	// Figure out the generated file paths.  This has to match aconfig's codegen_cpp.rs.
 	this.generatedDir = android.PathForModuleGen(ctx)
@@ -111,11 +138,16 @@
 	if len(declarationsModules) != 1 {
 		panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
 	}
-	declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData)
+	declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey)
+
+	mode := proptools.StringDefault(this.properties.Mode, "production")
+	if !isModeSupported(mode) {
+		ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
+	}
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:  cppRule,
-		Input: declarations.IntermediatePath,
+		Input: declarations.IntermediateCacheOutputPath,
 		Outputs: []android.WritablePath{
 			this.generatedCpp,
 			this.generatedH,
@@ -123,6 +155,16 @@
 		Description: "cc_aconfig_library",
 		Args: map[string]string{
 			"gendir": this.generatedDir.String(),
+			"mode":   mode,
+			"debug":  strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorageCc()),
 		},
 	})
+
+	android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{
+		ModeInfos: map[string]android.ModeInfo{
+			ctx.ModuleName(): {
+				Container: declarations.Container,
+				Mode:      mode,
+			}},
+	})
 }
diff --git a/aconfig/codegen/cc_aconfig_library_test.go b/aconfig/codegen/cc_aconfig_library_test.go
new file mode 100644
index 0000000..cf9ffbd
--- /dev/null
+++ b/aconfig/codegen/cc_aconfig_library_test.go
@@ -0,0 +1,279 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package codegen
+
+import (
+	"fmt"
+	"testing"
+
+	"android/soong/android"
+	"android/soong/cc"
+
+	"github.com/google/blueprint"
+)
+
+var ccCodegenModeTestData = []struct {
+	setting, expected string
+}{
+	{"", "production"},
+	{"mode: `production`,", "production"},
+	{"mode: `test`,", "test"},
+	{"mode: `exported`,", "exported"},
+	{"mode: `force-read-only`,", "force-read-only"},
+}
+
+func TestCCCodegenMode(t *testing.T) {
+	for _, testData := range ccCodegenModeTestData {
+		testCCCodegenModeHelper(t, testData.setting, testData.expected)
+	}
+}
+
+func testCCCodegenModeHelper(t *testing.T, bpMode string, ruleMode string) {
+	t.Helper()
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		cc.PrepareForTestWithCcDefaultModules).
+		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
+		RunTestWithBp(t, fmt.Sprintf(`
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+
+			cc_library {
+    		name: "server_configurable_flags",
+    		srcs: ["server_configurable_flags.cc"],
+			}
+
+			cc_library {
+    		name: "libbase",
+    		srcs: ["libbase.cc"],
+			}
+
+			cc_library {
+    		name: "liblog",
+    		srcs: ["liblog.cc"],
+			}
+
+			cc_library {
+    		name: "libaconfig_storage_read_api_cc",
+    		srcs: ["libaconfig_storage_read_api_cc.cc"],
+			}
+
+			cc_library {
+    		name: "libaconfig_storage_protos_cc",
+    		srcs: ["libaconfig_storage_protos_cc.cc"],
+			}
+
+			cc_aconfig_library {
+				name: "my_cc_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+				%s
+			}
+		`, bpMode))
+
+	module := result.ModuleForTests("my_cc_aconfig_library", "android_arm64_armv8-a_shared")
+	rule := module.Rule("cc_aconfig_library")
+	android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode)
+}
+
+var incorrectCCCodegenModeTestData = []struct {
+	setting, expectedErr string
+}{
+	{"mode: `unsupported`,", "mode: \"unsupported\" is not a supported mode"},
+}
+
+func TestIncorrectCCCodegenMode(t *testing.T) {
+	for _, testData := range incorrectCCCodegenModeTestData {
+		testIncorrectCCCodegenModeHelper(t, testData.setting, testData.expectedErr)
+	}
+}
+
+func testIncorrectCCCodegenModeHelper(t *testing.T, bpMode string, err string) {
+	t.Helper()
+	android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		cc.PrepareForTestWithCcDefaultModules).
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(err)).
+		RunTestWithBp(t, fmt.Sprintf(`
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+
+			cc_library {
+    		name: "server_configurable_flags",
+    		srcs: ["server_configurable_flags.cc"],
+			}
+
+			cc_library {
+    		name: "libbase",
+    		srcs: ["libbase.cc"],
+			}
+
+			cc_library {
+    		name: "liblog",
+    		srcs: ["liblog.cc"],
+			}
+
+			cc_library {
+    		name: "libaconfig_storage_read_api_cc",
+    		srcs: ["libaconfig_storage_read_api_cc.cc"],
+			}
+
+			cc_library {
+    		name: "libaconfig_storage_protos_cc",
+    		srcs: ["libaconfig_storage_protos_cc.cc"],
+			}
+
+
+			cc_aconfig_library {
+				name: "my_cc_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+				%s
+			}
+		`, bpMode))
+}
+
+func TestAndroidMkCcLibrary(t *testing.T) {
+	bp := `
+		aconfig_declarations {
+			name: "my_aconfig_declarations_foo",
+			package: "com.example.package",
+			srcs: ["foo.aconfig"],
+			container: "vendor",
+		}
+
+		cc_aconfig_library {
+			name: "my_cc_aconfig_library_foo",
+			aconfig_declarations: "my_aconfig_declarations_foo",
+			vendor_available: true,
+		}
+
+		aconfig_declarations {
+			name: "my_aconfig_declarations_bar",
+			package: "com.example.package",
+			srcs: ["bar.aconfig"],
+		}
+
+		cc_aconfig_library {
+			name: "my_cc_aconfig_library_bar",
+			aconfig_declarations: "my_aconfig_declarations_bar",
+			vendor_available: true,
+		}
+
+		cc_library {
+			name: "my_cc_library",
+			srcs: [
+				"src/foo.cc",
+			],
+			static_libs: [
+				"my_cc_aconfig_library_foo",
+				"my_cc_aconfig_library_bar",
+			],
+			vendor: true,
+		}
+
+		cc_library {
+			name: "server_configurable_flags",
+			srcs: ["server_configurable_flags.cc"],
+			vendor_available: true,
+		}
+
+		cc_library {
+			name: "libbase",
+			srcs: ["libbase.cc"],
+			vendor_available: true,
+		}
+
+		cc_library {
+			name: "liblog",
+			srcs: ["liblog.cc"],
+			vendor_available: true,
+		}
+
+		cc_library {
+			name: "libaconfig_storage_read_api_cc",
+			srcs: ["libaconfig_storage_read_api_cc.cc"],
+			vendor_available: true,
+		}
+
+		cc_library {
+			name: "libaconfig_storage_protos_cc",
+			srcs: ["libaconfig_storage_protos_cc.cc"],
+			vendor_available: true,
+		}
+	`
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		cc.PrepareForTestWithCcDefaultModules).
+		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).RunTestWithBp(t, bp)
+
+	module := result.ModuleForTests("my_cc_library", "android_vendor_arm64_armv8-a_shared").Module()
+
+	entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0]
+
+	makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"]
+	android.EnsureListContainsSuffix(t, makeVar, "my_aconfig_declarations_foo/intermediate.pb")
+}
+
+func TestForceReadOnly(t *testing.T) {
+	t.Helper()
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		cc.PrepareForTestWithCcDefaultModules).
+		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
+		RunTestWithBp(t, fmt.Sprintf(`
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+
+			cc_aconfig_library {
+				name: "my_cc_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+				mode: "force-read-only",
+			}
+
+
+			cc_library {
+    		                name: "libbase",
+    		                srcs: ["libbase.cc"],
+			}
+
+			cc_library {
+    		                name: "liblog",
+    		                srcs: ["liblog.cc"],
+			}
+
+			cc_library {
+    		                name: "libaconfig_storage_read_api_cc",
+    		                srcs: ["libaconfig_storage_read_api_cc.cc"],
+			}
+		`))
+
+	module := result.ModuleForTests("my_cc_aconfig_library", "android_arm64_armv8-a_shared").Module()
+	dependOnBaseLib := false
+	result.VisitDirectDeps(module, func(dep blueprint.Module) {
+		if dep.Name() == baseLibDep {
+			dependOnBaseLib = true
+		}
+	})
+	android.AssertBoolEquals(t, "should not have dependency on server_configuriable_flags",
+		dependOnBaseLib, false)
+}
diff --git a/aconfig/codegen/init.go b/aconfig/codegen/init.go
new file mode 100644
index 0000000..6182e14
--- /dev/null
+++ b/aconfig/codegen/init.go
@@ -0,0 +1,85 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package codegen
+
+import (
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+)
+
+var (
+	pctx = android.NewPackageContext("android/soong/aconfig/codegen")
+
+	// For java_aconfig_library: Generate java library
+	javaRule = pctx.AndroidStaticRule("java_aconfig_library",
+		blueprint.RuleParams{
+			Command: `rm -rf ${out}.tmp` +
+				` && mkdir -p ${out}.tmp` +
+				` && ${aconfig} create-java-lib` +
+				`    --mode ${mode}` +
+				`    --cache ${in}` +
+				`    --out ${out}.tmp` +
+				` && $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` +
+				` && rm -rf ${out}.tmp`,
+			CommandDeps: []string{
+				"$aconfig",
+				"$soong_zip",
+			},
+			Restat: true,
+		}, "mode")
+
+	// For cc_aconfig_library: Generate C++ library
+	cppRule = pctx.AndroidStaticRule("cc_aconfig_library",
+		blueprint.RuleParams{
+			Command: `rm -rf ${gendir}` +
+				` && mkdir -p ${gendir}` +
+				` && ${aconfig} create-cpp-lib` +
+				`    --mode ${mode}` +
+				`    --cache ${in}` +
+				`    --out ${gendir}` +
+				`    --allow-instrumentation ${debug}`,
+			CommandDeps: []string{
+				"$aconfig",
+			},
+		}, "gendir", "mode", "debug")
+
+	// For rust_aconfig_library: Generate Rust library
+	rustRule = pctx.AndroidStaticRule("rust_aconfig_library",
+		blueprint.RuleParams{
+			Command: `rm -rf ${gendir}` +
+				` && mkdir -p ${gendir}` +
+				` && ${aconfig} create-rust-lib` +
+				`    --mode ${mode}` +
+				`    --cache ${in}` +
+				`    --out ${gendir}`,
+			CommandDeps: []string{
+				"$aconfig",
+			},
+		}, "gendir", "mode")
+)
+
+func init() {
+	RegisterBuildComponents(android.InitRegistrationContext)
+	pctx.HostBinToolVariable("aconfig", "aconfig")
+	pctx.HostBinToolVariable("soong_zip", "soong_zip")
+}
+
+func RegisterBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("aconfig_declarations_group", AconfigDeclarationsGroupFactory)
+	ctx.RegisterModuleType("cc_aconfig_library", CcAconfigLibraryFactory)
+	ctx.RegisterModuleType("java_aconfig_library", JavaDeclarationsLibraryFactory)
+	ctx.RegisterModuleType("rust_aconfig_library", RustAconfigLibraryFactory)
+}
diff --git a/aconfig/codegen/java_aconfig_library.go b/aconfig/codegen/java_aconfig_library.go
new file mode 100644
index 0000000..9f42e21
--- /dev/null
+++ b/aconfig/codegen/java_aconfig_library.go
@@ -0,0 +1,142 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package codegen
+
+import (
+	"fmt"
+
+	"android/soong/android"
+	"android/soong/java"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+type declarationsTagType struct {
+	blueprint.BaseDependencyTag
+}
+
+var declarationsTag = declarationsTagType{}
+
+var aconfigSupportedModes = []string{"production", "test", "exported", "force-read-only"}
+
+type JavaAconfigDeclarationsLibraryProperties struct {
+	// name of the aconfig_declarations module to generate a library for
+	Aconfig_declarations string
+
+	// default mode is "production", the other accepted modes are:
+	// "test": to generate test mode version of the library
+	// "exported": to generate exported mode version of the library
+	// "force-read-only": to generate force-read-only mode version of the library
+	// an error will be thrown if the mode is not supported
+	Mode *string
+}
+
+type JavaAconfigDeclarationsLibraryCallbacks struct {
+	properties JavaAconfigDeclarationsLibraryProperties
+}
+
+func JavaDeclarationsLibraryFactory() android.Module {
+	callbacks := &JavaAconfigDeclarationsLibraryCallbacks{}
+	return java.GeneratedJavaLibraryModuleFactory("java_aconfig_library", callbacks, &callbacks.properties)
+}
+
+func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) DepsMutator(module *java.GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext) {
+	declarations := callbacks.properties.Aconfig_declarations
+	if len(declarations) == 0 {
+		// TODO: Add test for this case
+		ctx.PropertyErrorf("aconfig_declarations", "aconfig_declarations property required")
+	} else {
+		ctx.AddDependency(ctx.Module(), declarationsTag, declarations)
+	}
+
+	// "libcore_aconfig_flags_lib" module has a circular dependency because the shared libraries
+	// are built on core_current and the module is used to flag the APIs in the core_current.
+	// http://b/316554963#comment2 has the details of the circular dependency chain.
+	// If a java_aconfig_library uses "none" sdk_version, it should include and build these
+	// annotation files as the shared library themselves.
+	var addLibraries bool = module.Library.Module.SdkVersion(ctx).Kind != android.SdkNone
+	if addLibraries {
+		// Add aconfig-annotations-lib as a dependency for the optimization / code stripping annotations
+		module.AddSharedLibrary("aconfig-annotations-lib")
+		// TODO(b/303773055): Remove the annotation after access issue is resolved.
+		module.AddSharedLibrary("unsupportedappusage")
+	}
+}
+
+func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuildActions(module *java.GeneratedJavaLibraryModule, ctx android.ModuleContext) (android.Path, android.Path) {
+	// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
+	declarationsModules := ctx.GetDirectDepsWithTag(declarationsTag)
+	if len(declarationsModules) != 1 {
+		panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
+	}
+	declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey)
+
+	// Generate the action to build the srcjar
+	srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar")
+
+	mode := proptools.StringDefault(callbacks.properties.Mode, "production")
+	if !isModeSupported(mode) {
+		ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
+	}
+
+	if mode == "exported" && !declarations.Exportable {
+		// if mode is exported, the corresponding aconfig_declaration must mark its
+		// exportable property true
+		ctx.PropertyErrorf("mode", "exported mode requires its aconfig_declaration has exportable prop true")
+	}
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        javaRule,
+		Input:       declarations.IntermediateCacheOutputPath,
+		Output:      srcJarPath,
+		Description: "aconfig.srcjar",
+		Args: map[string]string{
+			"mode": mode,
+		},
+	})
+
+	if declarations.Exportable {
+		// Mark our generated code as possibly needing jarjar repackaging
+		// The repackaging only happens when the corresponding aconfig_declaration
+		// has property exportable true
+		module.AddJarJarRenameRule(declarations.Package+".Flags", "")
+		module.AddJarJarRenameRule(declarations.Package+".FeatureFlags", "")
+		module.AddJarJarRenameRule(declarations.Package+".FeatureFlagsImpl", "")
+		module.AddJarJarRenameRule(declarations.Package+".CustomFeatureFlags", "")
+		module.AddJarJarRenameRule(declarations.Package+".FakeFeatureFlagsImpl", "")
+	}
+
+	android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{
+		AconfigDeclarations:          []string{declarationsModules[0].Name()},
+		IntermediateCacheOutputPaths: android.Paths{declarations.IntermediateCacheOutputPath},
+		Srcjars:                      android.Paths{srcJarPath},
+		ModeInfos: map[string]android.ModeInfo{
+			ctx.ModuleName(): {
+				Container: declarations.Container,
+				Mode:      mode,
+			}},
+	})
+
+	return srcJarPath, declarations.IntermediateCacheOutputPath
+}
+
+func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) AconfigDeclarations() *string {
+	return proptools.StringPtr(callbacks.properties.Aconfig_declarations)
+}
+
+func isModeSupported(mode string) bool {
+	return android.InList(mode, aconfigSupportedModes)
+}
diff --git a/aconfig/java_aconfig_library_test.go b/aconfig/codegen/java_aconfig_library_test.go
similarity index 68%
rename from aconfig/java_aconfig_library_test.go
rename to aconfig/codegen/java_aconfig_library_test.go
index af50848..de45b5c 100644
--- a/aconfig/java_aconfig_library_test.go
+++ b/aconfig/codegen/java_aconfig_library_test.go
@@ -12,11 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package aconfig
+package codegen
 
 import (
 	"fmt"
-	"strings"
 	"testing"
 
 	"android/soong/android"
@@ -34,14 +33,25 @@
 		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
 		RunTestWithBp(t, bp+`
 			aconfig_declarations {
-				name: "my_aconfig_declarations",
-				package: "com.example.package",
+				name: "my_aconfig_declarations_foo",
+				package: "com.example.package.foo",
 				srcs: ["foo.aconfig"],
 			}
 
 			java_aconfig_library {
-				name: "my_java_aconfig_library",
-				aconfig_declarations: "my_aconfig_declarations",
+				name: "my_java_aconfig_library_foo",
+				aconfig_declarations: "my_aconfig_declarations_foo",
+			}
+
+			aconfig_declarations {
+				name: "my_aconfig_declarations_bar",
+				package: "com.example.package.bar",
+				srcs: ["bar.aconfig"],
+			}
+
+			java_aconfig_library {
+				name: "my_java_aconfig_library_bar",
+				aconfig_declarations: "my_aconfig_declarations_bar",
 			}
 		`)
 
@@ -50,10 +60,7 @@
 	entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0]
 
 	makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"]
-	android.AssertIntEquals(t, "len(LOCAL_ACONFIG_FILES)", 1, len(makeVar))
-	if !strings.HasSuffix(makeVar[0], "intermediate.pb") {
-		t.Errorf("LOCAL_ACONFIG_FILES should end with /intermediates.pb, instead it is: %s", makeVar[0])
-	}
+	android.EnsureListContainsSuffix(t, makeVar, "android_common/aconfig_merged.pb")
 }
 
 func TestAndroidMkJavaLibrary(t *testing.T) {
@@ -64,7 +71,8 @@
 				"src/foo.java",
 			],
 			static_libs: [
-				"my_java_aconfig_library",
+				"my_java_aconfig_library_foo",
+				"my_java_aconfig_library_bar",
 			],
 			platform_apis: true,
 		}
@@ -81,7 +89,8 @@
 				"src/foo.java",
 			],
 			static_libs: [
-				"my_java_aconfig_library",
+				"my_java_aconfig_library_foo",
+				"my_java_aconfig_library_bar",
 			],
 			platform_apis: true,
 		}
@@ -98,7 +107,8 @@
 				"src/foo.java",
 			],
 			static_libs: [
-				"my_java_aconfig_library",
+				"my_java_aconfig_library_foo",
+				"my_java_aconfig_library_bar",
 			],
 			platform_apis: true,
 			main_class: "foo",
@@ -116,7 +126,8 @@
 				"src/foo.java",
 			],
 			static_libs: [
-				"my_java_aconfig_library",
+				"my_java_aconfig_library_foo",
+				"my_java_aconfig_library_bar",
 			],
 			platform_apis: true,
 		}
@@ -134,7 +145,8 @@
 				"src/foo.java",
 			],
 			static_libs: [
-				"my_java_aconfig_library",
+				"my_java_aconfig_library_foo",
+				"my_java_aconfig_library_bar",
 			],
 			platform_apis: true,
 		}
@@ -164,6 +176,7 @@
 				name: "my_aconfig_declarations",
 				package: "com.example.package",
 				srcs: ["foo.aconfig"],
+				exportable: true,
 			}
 
 			java_aconfig_library {
@@ -178,14 +191,46 @@
 	android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode)
 }
 
+func testCodegenModeWithError(t *testing.T, bpMode string, err string) {
+	android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		java.PrepareForTestWithJavaDefaultModules).
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(err)).
+		RunTestWithBp(t, fmt.Sprintf(`
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+
+			java_aconfig_library {
+				name: "my_java_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+				%s
+			}
+		`, bpMode))
+}
+
 func TestDefaultProdMode(t *testing.T) {
 	testCodegenMode(t, "", "production")
 }
 
 func TestProdMode(t *testing.T) {
-	testCodegenMode(t, "test: false,", "production")
+	testCodegenMode(t, "mode: `production`,", "production")
 }
 
 func TestTestMode(t *testing.T) {
-	testCodegenMode(t, "test: true,", "test")
+	testCodegenMode(t, "mode: `test`,", "test")
+}
+
+func TestExportedMode(t *testing.T) {
+	testCodegenMode(t, "mode: `exported`,", "exported")
+}
+
+func TestForceReadOnlyMode(t *testing.T) {
+	testCodegenMode(t, "mode: `force-read-only`,", "force-read-only")
+}
+
+func TestUnsupportedMode(t *testing.T) {
+	testCodegenModeWithError(t, "mode: `unsupported`,", "mode: \"unsupported\" is not a supported mode")
 }
diff --git a/aconfig/rust_aconfig_library.go b/aconfig/codegen/rust_aconfig_library.go
similarity index 66%
rename from aconfig/rust_aconfig_library.go
rename to aconfig/codegen/rust_aconfig_library.go
index 8b16372..ad8d632 100644
--- a/aconfig/rust_aconfig_library.go
+++ b/aconfig/codegen/rust_aconfig_library.go
@@ -1,11 +1,13 @@
-package aconfig
+package codegen
 
 import (
-	"android/soong/android"
-	"android/soong/rust"
 	"fmt"
 
+	"android/soong/android"
+	"android/soong/rust"
+
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
 type rustDeclarationsTagType struct {
@@ -17,6 +19,13 @@
 type RustAconfigLibraryProperties struct {
 	// name of the aconfig_declarations module to generate a library for
 	Aconfig_declarations string
+
+	// default mode is "production", the other accepted modes are:
+	// "test": to generate test mode version of the library
+	// "exported": to generate exported mode version of the library
+	// "force-read-only": to generate force-read-only mode version of the library
+	// an error will be thrown if the mode is not supported
+	Mode *string
 }
 
 type aconfigDecorator struct {
@@ -56,28 +65,45 @@
 	if len(declarationsModules) != 1 {
 		panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
 	}
-	declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData)
+	declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey)
+
+	mode := proptools.StringDefault(a.Properties.Mode, "production")
+	if !isModeSupported(mode) {
+		ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
+	}
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:  rustRule,
-		Input: declarations.IntermediatePath,
+		Input: declarations.IntermediateCacheOutputPath,
 		Outputs: []android.WritablePath{
 			generatedSource,
 		},
 		Description: "rust_aconfig_library",
 		Args: map[string]string{
 			"gendir": generatedDir.String(),
-			// TODO: Add test mode
-			"mode": "production",
+			"mode":   mode,
 		},
 	})
 	a.BaseSourceProvider.OutputFiles = android.Paths{generatedSource}
+
+	android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{
+		ModeInfos: map[string]android.ModeInfo{
+			ctx.ModuleName(): {
+				Container: declarations.Container,
+				Mode:      mode,
+			}},
+	})
+
 	return generatedSource
 }
 
 func (a *aconfigDecorator) SourceProviderDeps(ctx rust.DepsContext, deps rust.Deps) rust.Deps {
 	deps = a.BaseSourceProvider.SourceProviderDeps(ctx, deps)
+	deps.Rustlibs = append(deps.Rustlibs, "libaconfig_storage_read_api")
 	deps.Rustlibs = append(deps.Rustlibs, "libflags_rust")
+	deps.Rustlibs = append(deps.Rustlibs, "liblazy_static")
+	deps.Rustlibs = append(deps.Rustlibs, "liblogger")
+	deps.Rustlibs = append(deps.Rustlibs, "liblog_rust")
 	ctx.AddDependency(ctx.Module(), rustDeclarationsTag, a.Properties.Aconfig_declarations)
 	return deps
 }
diff --git a/aconfig/codegen/rust_aconfig_library_test.go b/aconfig/codegen/rust_aconfig_library_test.go
new file mode 100644
index 0000000..fe28f94
--- /dev/null
+++ b/aconfig/codegen/rust_aconfig_library_test.go
@@ -0,0 +1,205 @@
+package codegen
+
+import (
+	"fmt"
+	"testing"
+
+	"android/soong/android"
+	"android/soong/rust"
+)
+
+func TestRustAconfigLibrary(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		rust.PrepareForIntegrationTestWithRust,
+		android.PrepareForTestWithArchMutator,
+		android.PrepareForTestWithDefaults,
+		android.PrepareForTestWithPrebuilts,
+	).
+		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
+		RunTestWithBp(t, fmt.Sprintf(`
+			rust_library {
+				name: "libflags_rust", // test mock
+				crate_name: "flags_rust",
+				srcs: ["lib.rs"],
+			}
+			rust_library {
+				name: "liblazy_static", // test mock
+				crate_name: "lazy_static",
+				srcs: ["src/lib.rs"],
+			}
+			rust_library {
+				name: "libaconfig_storage_read_api", // test mock
+				crate_name: "aconfig_storage_read_api",
+				srcs: ["lib.rs"],
+                        }
+			rust_library {
+				name: "liblogger", // test mock
+				crate_name: "logger",
+				srcs: ["lib.rs"],
+                        }
+			rust_library {
+				name: "liblog_rust", // test mock
+				crate_name: "log_rust",
+				srcs: ["lib.rs"],
+                        }
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+
+			rust_aconfig_library {
+				name: "libmy_rust_aconfig_library",
+				crate_name: "my_rust_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+			}
+		`))
+
+	sourceVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_source")
+	rule := sourceVariant.Rule("rust_aconfig_library")
+	android.AssertStringEquals(t, "rule must contain production mode", rule.Args["mode"], "production")
+
+	dylibVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_dylib")
+	rlibRlibStdVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_rlib_rlib-std")
+	rlibDylibStdVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_rlib_dylib-std")
+
+	variants := []android.TestingModule{
+		dylibVariant,
+		rlibDylibStdVariant,
+		rlibRlibStdVariant,
+	}
+
+	for _, variant := range variants {
+		android.AssertStringEquals(
+			t,
+			"dylib variant builds from generated rust code",
+			"out/soong/.intermediates/libmy_rust_aconfig_library/android_arm64_armv8-a_source/gen/src/lib.rs",
+			variant.Rule("rustc").Inputs[0].RelativeToTop().String(),
+		)
+	}
+}
+
+var rustCodegenModeTestData = []struct {
+	setting, expected string
+}{
+	{"", "production"},
+	{"mode: `production`,", "production"},
+	{"mode: `test`,", "test"},
+	{"mode: `exported`,", "exported"},
+	{"mode: `force-read-only`,", "force-read-only"},
+}
+
+func TestRustCodegenMode(t *testing.T) {
+	for _, testData := range rustCodegenModeTestData {
+		testRustCodegenModeHelper(t, testData.setting, testData.expected)
+	}
+}
+
+func testRustCodegenModeHelper(t *testing.T, bpMode string, ruleMode string) {
+	t.Helper()
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		rust.PrepareForIntegrationTestWithRust).
+		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
+		RunTestWithBp(t, fmt.Sprintf(`
+			rust_library {
+				name: "libflags_rust", // test mock
+				crate_name: "flags_rust",
+				srcs: ["lib.rs"],
+			}
+			rust_library {
+				name: "liblazy_static", // test mock
+				crate_name: "lazy_static",
+				srcs: ["src/lib.rs"],
+			}
+			rust_library {
+				name: "libaconfig_storage_read_api", // test mock
+				crate_name: "aconfig_storage_read_api",
+				srcs: ["lib.rs"],
+                        }
+			rust_library {
+				name: "liblogger", // test mock
+				crate_name: "logger",
+				srcs: ["lib.rs"],
+                        }
+			rust_library {
+				name: "liblog_rust", // test mock
+				crate_name: "log_rust",
+				srcs: ["lib.rs"],
+                        }
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+			rust_aconfig_library {
+				name: "libmy_rust_aconfig_library",
+				crate_name: "my_rust_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+				%s
+			}
+		`, bpMode))
+
+	module := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_source")
+	rule := module.Rule("rust_aconfig_library")
+	android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode)
+}
+
+var incorrectRustCodegenModeTestData = []struct {
+	setting, expectedErr string
+}{
+	{"mode: `unsupported`,", "mode: \"unsupported\" is not a supported mode"},
+}
+
+func TestIncorrectRustCodegenMode(t *testing.T) {
+	for _, testData := range incorrectRustCodegenModeTestData {
+		testIncorrectRustCodegenModeHelper(t, testData.setting, testData.expectedErr)
+	}
+}
+
+func testIncorrectRustCodegenModeHelper(t *testing.T, bpMode string, err string) {
+	t.Helper()
+	android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		rust.PrepareForIntegrationTestWithRust).
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(err)).
+		RunTestWithBp(t, fmt.Sprintf(`
+			rust_library {
+				name: "libflags_rust", // test mock
+				crate_name: "flags_rust",
+				srcs: ["lib.rs"],
+			}
+			rust_library {
+				name: "liblazy_static", // test mock
+				crate_name: "lazy_static",
+				srcs: ["src/lib.rs"],
+			}
+			rust_library {
+				name: "libaconfig_storage_read_api", // test mock
+				crate_name: "aconfig_storage_read_api",
+				srcs: ["lib.rs"],
+                        }
+			rust_library {
+				name: "liblogger", // test mock
+				crate_name: "logger",
+				srcs: ["lib.rs"],
+                        }
+			rust_library {
+				name: "liblog_rust", // test mock
+				crate_name: "log_rust",
+				srcs: ["lib.rs"],
+                        }
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+			rust_aconfig_library {
+				name: "libmy_rust_aconfig_library",
+				crate_name: "my_rust_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+				%s
+			}
+		`, bpMode))
+}
diff --git a/aconfig/codegen/testing.go b/aconfig/codegen/testing.go
new file mode 100644
index 0000000..3e1c22e
--- /dev/null
+++ b/aconfig/codegen/testing.go
@@ -0,0 +1,25 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package codegen
+
+import (
+	"android/soong/aconfig"
+	"android/soong/android"
+)
+
+var PrepareForTestWithAconfigBuildComponents = android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("aconfig_declarations", aconfig.DeclarationsFactory)
+	RegisterBuildComponents(ctx)
+})
diff --git a/aconfig/exported_java_aconfig_library.go b/aconfig/exported_java_aconfig_library.go
new file mode 100644
index 0000000..291938f
--- /dev/null
+++ b/aconfig/exported_java_aconfig_library.go
@@ -0,0 +1,56 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package aconfig
+
+import (
+	"android/soong/android"
+)
+
+func ExportedJavaDeclarationsLibraryFactory() android.Singleton {
+	return &exportedJavaDeclarationsLibrarySingleton{}
+}
+
+type exportedJavaDeclarationsLibrarySingleton struct {
+	intermediatePath android.OutputPath
+}
+
+func (this *exportedJavaDeclarationsLibrarySingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	// Find all of the aconfig_declarations modules
+	var cacheFiles android.Paths
+	ctx.VisitAllModules(func(module android.Module) {
+		decl, ok := android.SingletonModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey)
+		if !ok {
+			return
+		}
+		cacheFiles = append(cacheFiles, decl.IntermediateCacheOutputPath)
+	})
+
+	// Generate build action for aconfig
+	this.intermediatePath = android.PathForIntermediates(ctx, "exported_java_aconfig_library.jar")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        exportedJavaRule,
+		Inputs:      cacheFiles,
+		Output:      this.intermediatePath,
+		Description: "exported_java_aconfig_library",
+		Args: map[string]string{
+			"cache_files": android.JoinPathsWithPrefix(cacheFiles, " "),
+		},
+	})
+	ctx.Phony("exported_java_aconfig_library", this.intermediatePath)
+}
+
+func (this *exportedJavaDeclarationsLibrarySingleton) MakeVars(ctx android.MakeVarsContext) {
+	ctx.DistForGoalWithFilename("sdk", this.intermediatePath, "android-flags.jar")
+}
diff --git a/aconfig/init.go b/aconfig/init.go
index cfbd79d..4655467 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -28,8 +28,10 @@
 		blueprint.RuleParams{
 			Command: `${aconfig} create-cache` +
 				` --package ${package}` +
+				` ${container}` +
 				` ${declarations}` +
 				` ${values}` +
+				` ${default-permission}` +
 				` --cache ${out}.tmp` +
 				` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
 			//				` --build-id ${release_version}` +
@@ -37,76 +39,79 @@
 				"${aconfig}",
 			},
 			Restat: true,
-		}, "release_version", "package", "declarations", "values")
+		}, "release_version", "package", "container", "declarations", "values", "default-permission")
 
-	// For java_aconfig_library: Generate java file
-	javaRule = pctx.AndroidStaticRule("java_aconfig_library",
+	// For create-device-config-sysprops: Generate aconfig flag value map text file
+	aconfigTextRule = pctx.AndroidStaticRule("aconfig_text",
 		blueprint.RuleParams{
-			Command: `rm -rf ${out}.tmp` +
-				` && mkdir -p ${out}.tmp` +
-				` && ${aconfig} create-java-lib` +
-				`    --mode ${mode}` +
-				`    --cache ${in}` +
-				`    --out ${out}.tmp` +
-				` && $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` +
-				` && rm -rf ${out}.tmp`,
-			CommandDeps: []string{
-				"$aconfig",
-				"$soong_zip",
-			},
-			Restat: true,
-		}, "mode")
-
-	// For java_aconfig_library: Generate java file
-	cppRule = pctx.AndroidStaticRule("cc_aconfig_library",
-		blueprint.RuleParams{
-			Command: `rm -rf ${gendir}` +
-				` && mkdir -p ${gendir}` +
-				` && ${aconfig} create-cpp-lib` +
-				`    --cache ${in}` +
-				`    --out ${gendir}`,
-			CommandDeps: []string{
-				"$aconfig",
-				"$soong_zip",
-			},
-		}, "gendir")
-
-	rustRule = pctx.AndroidStaticRule("rust_aconfig_library",
-		blueprint.RuleParams{
-			Command: `rm -rf ${gendir}` +
-				` && mkdir -p ${gendir}` +
-				` && ${aconfig} create-rust-lib` +
-				`    --mode ${mode}` +
-				`    --cache ${in}` +
-				`    --out ${gendir}`,
-			CommandDeps: []string{
-				"$aconfig",
-				"$soong_zip",
-			},
-		}, "gendir", "mode")
-
-	// For all_aconfig_declarations
-	allDeclarationsRule = pctx.AndroidStaticRule("all_aconfig_declarations_dump",
-		blueprint.RuleParams{
-			Command: `${aconfig} dump --format protobuf --out ${out} ${cache_files}`,
+			Command: `${aconfig} dump-cache --dedup --format='{fully_qualified_name}={state:bool}'` +
+				` --cache ${in}` +
+				` --out ${out}.tmp` +
+				` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
 			CommandDeps: []string{
 				"${aconfig}",
 			},
+			Restat: true,
+		})
+
+	// For all_aconfig_declarations: Combine all parsed_flags proto files
+	AllDeclarationsRule = pctx.AndroidStaticRule("All_aconfig_declarations_dump",
+		blueprint.RuleParams{
+			Command: `${aconfig} dump-cache --dedup --format protobuf --out ${out} ${cache_files}`,
+			CommandDeps: []string{
+				"${aconfig}",
+			},
+		}, "cache_files")
+	AllDeclarationsRuleTextProto = pctx.AndroidStaticRule("All_aconfig_declarations_dump_textproto",
+		blueprint.RuleParams{
+			Command: `${aconfig} dump-cache --dedup --format textproto --out ${out} ${cache_files}`,
+			CommandDeps: []string{
+				"${aconfig}",
+			},
+		}, "cache_files")
+
+	CreateStorageRule = pctx.AndroidStaticRule("aconfig_create_storage",
+		blueprint.RuleParams{
+			Command: `${aconfig} create-storage --container ${container} --file ${file_type} --out ${out} ${cache_files}`,
+			CommandDeps: []string{
+				"${aconfig}",
+			},
+		}, "container", "file_type", "cache_files")
+
+	// For exported_java_aconfig_library: Generate a JAR from all
+	// java_aconfig_libraries to be consumed by apps built outside the
+	// platform
+	exportedJavaRule = pctx.AndroidStaticRule("exported_java_aconfig_library",
+		// For each aconfig cache file, if the cache contains any
+		// exported flags, generate Java flag lookup code for the
+		// exported flags (only). Finally collect all generated code
+		// into the ${out} JAR file.
+		blueprint.RuleParams{
+			Command: `rm -rf ${out}.tmp` +
+				`&& for cache in ${cache_files}; do ` +
+				`  if [ -n "$$(${aconfig} dump-cache --dedup --cache $$cache --filter=is_exported:true --format='{fully_qualified_name}')" ]; then ` +
+				`    ${aconfig} create-java-lib --cache $$cache --mode=exported --out ${out}.tmp; ` +
+				`  fi ` +
+				`done` +
+				`&& $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` +
+				`&& rm -rf ${out}.tmp`,
+			CommandDeps: []string{
+				"$aconfig",
+				"$soong_zip",
+			},
 		}, "cache_files")
 )
 
 func init() {
-	registerBuildComponents(android.InitRegistrationContext)
+	RegisterBuildComponents(android.InitRegistrationContext)
 	pctx.HostBinToolVariable("aconfig", "aconfig")
 	pctx.HostBinToolVariable("soong_zip", "soong_zip")
 }
 
-func registerBuildComponents(ctx android.RegistrationContext) {
+func RegisterBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("aconfig_declarations", DeclarationsFactory)
 	ctx.RegisterModuleType("aconfig_values", ValuesFactory)
 	ctx.RegisterModuleType("aconfig_value_set", ValueSetFactory)
-	ctx.RegisterModuleType("cc_aconfig_library", CcAconfigLibraryFactory)
-	ctx.RegisterModuleType("java_aconfig_library", JavaDeclarationsLibraryFactory)
-	ctx.RegisterModuleType("rust_aconfig_library", RustAconfigLibraryFactory)
 	ctx.RegisterParallelSingletonType("all_aconfig_declarations", AllAconfigDeclarationsFactory)
+	ctx.RegisterParallelSingletonType("exported_java_aconfig_library", ExportedJavaDeclarationsLibraryFactory)
 }
diff --git a/aconfig/java_aconfig_library.go b/aconfig/java_aconfig_library.go
deleted file mode 100644
index 53f8bd1..0000000
--- a/aconfig/java_aconfig_library.go
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package aconfig
-
-import (
-	"android/soong/android"
-	"android/soong/java"
-	"fmt"
-	"github.com/google/blueprint"
-)
-
-type declarationsTagType struct {
-	blueprint.BaseDependencyTag
-}
-
-var declarationsTag = declarationsTagType{}
-
-type JavaAconfigDeclarationsLibraryProperties struct {
-	// name of the aconfig_declarations module to generate a library for
-	Aconfig_declarations string
-
-	// whether to generate test mode version of the library
-	Test bool
-}
-
-type JavaAconfigDeclarationsLibraryCallbacks struct {
-	properties JavaAconfigDeclarationsLibraryProperties
-}
-
-func JavaDeclarationsLibraryFactory() android.Module {
-	callbacks := &JavaAconfigDeclarationsLibraryCallbacks{}
-	return java.GeneratedJavaLibraryModuleFactory("java_aconfig_library", callbacks, &callbacks.properties)
-}
-
-func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) DepsMutator(module *java.GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext) {
-	declarations := callbacks.properties.Aconfig_declarations
-	if len(declarations) == 0 {
-		// TODO: Add test for this case
-		ctx.PropertyErrorf("aconfig_declarations", "aconfig_declarations property required")
-	} else {
-		ctx.AddDependency(ctx.Module(), declarationsTag, declarations)
-	}
-}
-
-func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuildActions(module *java.GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path {
-	// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
-	declarationsModules := ctx.GetDirectDepsWithTag(declarationsTag)
-	if len(declarationsModules) != 1 {
-		panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
-	}
-	declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData)
-
-	// Generate the action to build the srcjar
-	srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar")
-	var mode string
-	if callbacks.properties.Test {
-		mode = "test"
-	} else {
-		mode = "production"
-	}
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        javaRule,
-		Input:       declarations.IntermediatePath,
-		Output:      srcJarPath,
-		Description: "aconfig.srcjar",
-		Args: map[string]string{
-			"mode": mode,
-		},
-	})
-
-	// Tell the java module about the .aconfig files, so they can be propagated up the dependency chain.
-	// TODO: It would be nice to have that propagation code here instead of on java.Module and java.JavaInfo.
-	module.AddAconfigIntermediate(declarations.IntermediatePath)
-
-	return srcJarPath
-}
diff --git a/aconfig/rust_aconfig_library_test.go b/aconfig/rust_aconfig_library_test.go
deleted file mode 100644
index 17385c3..0000000
--- a/aconfig/rust_aconfig_library_test.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package aconfig
-
-import (
-	"android/soong/android"
-	"android/soong/rust"
-	"fmt"
-	"testing"
-)
-
-func TestRustAconfigLibrary(t *testing.T) {
-	result := android.GroupFixturePreparers(
-		PrepareForTestWithAconfigBuildComponents,
-		rust.PrepareForTestWithRustIncludeVndk,
-		android.PrepareForTestWithArchMutator,
-		android.PrepareForTestWithDefaults,
-		android.PrepareForTestWithPrebuilts,
-	).
-		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
-		RunTestWithBp(t, fmt.Sprintf(`
-			rust_library {
-				name: "libflags_rust", // test mock
-				crate_name: "flags_rust",
-				srcs: ["lib.rs"],
-			}
-			aconfig_declarations {
-				name: "my_aconfig_declarations",
-				package: "com.example.package",
-				srcs: ["foo.aconfig"],
-			}
-
-			rust_aconfig_library {
-				name: "libmy_rust_aconfig_library",
-				crate_name: "my_rust_aconfig_library",
-				aconfig_declarations: "my_aconfig_declarations",
-			}
-		`))
-
-	sourceVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_source")
-	rule := sourceVariant.Rule("rust_aconfig_library")
-	android.AssertStringEquals(t, "rule must contain production mode", rule.Args["mode"], "production")
-
-	dylibVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_dylib")
-	rlibRlibStdVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_rlib_rlib-std")
-	rlibDylibStdVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_rlib_dylib-std")
-
-	variants := []android.TestingModule{
-		dylibVariant,
-		rlibDylibStdVariant,
-		rlibRlibStdVariant,
-	}
-
-	for _, variant := range variants {
-		android.AssertStringEquals(
-			t,
-			"dylib variant builds from generated rust code",
-			"out/soong/.intermediates/libmy_rust_aconfig_library/android_arm64_armv8-a_source/gen/src/lib.rs",
-			variant.Rule("rustc").Inputs[0].RelativeToTop().String(),
-		)
-	}
-}
diff --git a/aconfig/testing.go b/aconfig/testing.go
index 60cefeb..f6489ec 100644
--- a/aconfig/testing.go
+++ b/aconfig/testing.go
@@ -20,7 +20,7 @@
 	"android/soong/android"
 )
 
-var PrepareForTestWithAconfigBuildComponents = android.FixtureRegisterWithContext(registerBuildComponents)
+var PrepareForTestWithAconfigBuildComponents = android.FixtureRegisterWithContext(RegisterBuildComponents)
 
 func runTest(t *testing.T, errorHandler android.FixtureErrorHandler, bp string) *android.TestResult {
 	return android.GroupFixturePreparers(PrepareForTestWithAconfigBuildComponents).
diff --git a/aidl_library/aidl_library.go b/aidl_library/aidl_library.go
index 7449d67..0141545 100644
--- a/aidl_library/aidl_library.go
+++ b/aidl_library/aidl_library.go
@@ -16,8 +16,6 @@
 
 import (
 	"android/soong/android"
-	"android/soong/bazel"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -53,57 +51,9 @@
 
 type AidlLibrary struct {
 	android.ModuleBase
-	android.BazelModuleBase
 	properties aidlLibraryProperties
 }
 
-type bazelAidlLibraryAttributes struct {
-	Srcs                bazel.LabelListAttribute
-	Hdrs                bazel.LabelListAttribute
-	Strip_import_prefix *string
-	Deps                bazel.LabelListAttribute
-}
-
-func (lib *AidlLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	srcs := bazel.MakeLabelListAttribute(
-		android.BazelLabelForModuleSrc(
-			ctx,
-			lib.properties.Srcs,
-		),
-	)
-
-	hdrs := bazel.MakeLabelListAttribute(
-		android.BazelLabelForModuleSrc(
-			ctx,
-			lib.properties.Hdrs,
-		),
-	)
-
-	tags := []string{"apex_available=//apex_available:anyapex"}
-	deps := bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, lib.properties.Deps))
-
-	attrs := &bazelAidlLibraryAttributes{
-		Srcs:                srcs,
-		Hdrs:                hdrs,
-		Strip_import_prefix: lib.properties.Strip_import_prefix,
-		Deps:                deps,
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "aidl_library",
-		Bzl_load_location: "//build/bazel/rules/aidl:aidl_library.bzl",
-	}
-
-	ctx.CreateBazelTargetModule(
-		props,
-		android.CommonAttributes{
-			Name: lib.Name(),
-			Tags: bazel.MakeStringListAttribute(tags),
-		},
-		attrs,
-	)
-}
-
 type AidlLibraryInfo struct {
 	// The direct aidl files of the module
 	Srcs android.Paths
@@ -114,7 +64,7 @@
 }
 
 // AidlLibraryProvider provides the srcs and the transitive include dirs
-var AidlLibraryProvider = blueprint.NewProvider(AidlLibraryInfo{})
+var AidlLibraryProvider = blueprint.NewProvider[AidlLibraryInfo]()
 
 func (lib *AidlLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	includeDirsDepSetBuilder := android.NewDepSetBuilder[android.Path](android.PREORDER)
@@ -149,14 +99,13 @@
 	includeDirsDepSetBuilder.Direct(includeDir)
 
 	for _, dep := range ctx.GetDirectDepsWithTag(aidlLibraryTag) {
-		if ctx.OtherModuleHasProvider(dep, AidlLibraryProvider) {
-			info := ctx.OtherModuleProvider(dep, AidlLibraryProvider).(AidlLibraryInfo)
+		if info, ok := android.OtherModuleProvider(ctx, dep, AidlLibraryProvider); ok {
 			includeDirsDepSetBuilder.Transitive(&info.IncludeDirs)
 			hdrsDepSetBuilder.Transitive(&info.Hdrs)
 		}
 	}
 
-	ctx.SetProvider(AidlLibraryProvider, AidlLibraryInfo{
+	android.SetProvider(ctx, AidlLibraryProvider, AidlLibraryInfo{
 		Srcs:        srcs,
 		IncludeDirs: *includeDirsDepSetBuilder.Build(),
 		Hdrs:        *hdrsDepSetBuilder.Build(),
@@ -170,7 +119,6 @@
 	module := &AidlLibrary{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidModule(module)
-	android.InitBazelModule(module)
 	return module
 }
 
diff --git a/aidl_library/aidl_library_test.go b/aidl_library/aidl_library_test.go
index 0205629..01eab0e 100644
--- a/aidl_library/aidl_library_test.go
+++ b/aidl_library/aidl_library_test.go
@@ -46,7 +46,7 @@
 	).RunTest(t).TestContext
 
 	foo := ctx.ModuleForTests("foo", "").Module().(*AidlLibrary)
-	actualInfo := ctx.ModuleProvider(foo, AidlLibraryProvider).(AidlLibraryInfo)
+	actualInfo, _ := android.SingletonModuleProvider(ctx, foo, AidlLibraryProvider)
 
 	android.AssertArrayString(
 		t,
@@ -95,7 +95,7 @@
 	).RunTest(t).TestContext
 
 	foo := ctx.ModuleForTests("foo", "").Module().(*AidlLibrary)
-	actualInfo := ctx.ModuleProvider(foo, AidlLibraryProvider).(AidlLibraryInfo)
+	actualInfo, _ := android.SingletonModuleProvider(ctx, foo, AidlLibraryProvider)
 
 	android.AssertArrayString(
 		t,
diff --git a/android/Android.bp b/android/Android.bp
index f5bb785..f130d3a 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -11,15 +11,12 @@
         "blueprint-metrics",
         "sbox_proto",
         "soong",
+        "soong-android_team_proto",
         "soong-android-soongconfig",
-        "soong-bazel",
-        "soong-cquery",
         "soong-remoteexec",
         "soong-response",
         "soong-shared",
-        "soong-starlark",
         "soong-starlark-format",
-        "soong-ui-bp2build_metrics_proto",
         "soong-ui-metrics_proto",
         "soong-android-allowlists",
 
@@ -30,19 +27,20 @@
         "androidmk-parser",
     ],
     srcs: [
+        "aconfig_providers.go",
+        "all_teams.go",
         "androidmk.go",
         "apex.go",
+        "apex_contributions.go",
         "api_domain.go",
         "api_levels.go",
         "arch.go",
         "arch_list.go",
-        "bazel.go",
-        "bazel_handler.go",
-        "bazel_paths.go",
+        "arch_module_context.go",
+        "base_module_context.go",
         "buildinfo_prop.go",
         "config.go",
         "test_config.go",
-        "config_bp2build.go",
         "configured_jars.go",
         "csuite_config.go",
         "deapexer.go",
@@ -50,6 +48,7 @@
         "defs.go",
         "depset_generic.go",
         "deptag.go",
+        "early_module_context.go",
         "expand.go",
         "filegroup.go",
         "fixture.go",
@@ -64,6 +63,8 @@
         "makevars.go",
         "metrics.go",
         "module.go",
+        "module_context.go",
+        "module_info_json.go",
         "mutator.go",
         "namespace.go",
         "neverallow.go",
@@ -81,14 +82,18 @@
         "prebuilt.go",
         "prebuilt_build_tool.go",
         "proto.go",
+        "provider.go",
+        "raw_files.go",
         "register.go",
         "rule_builder.go",
         "sandbox.go",
         "sdk.go",
         "sdk_version.go",
+        "shared_properties.go",
         "singleton.go",
         "singleton_module.go",
         "soong_config_modules.go",
+        "team.go",
         "test_asserts.go",
         "test_suites.go",
         "testing.go",
@@ -98,15 +103,12 @@
         "visibility.go",
     ],
     testSrcs: [
+        "all_teams_test.go",
         "android_test.go",
         "androidmk_test.go",
         "apex_test.go",
         "arch_test.go",
-        "bazel_handler_test.go",
-        "bazel_paths_test.go",
-        "bazel_test.go",
         "config_test.go",
-        "config_bp2build_test.go",
         "configured_jars_test.go",
         "csuite_config_test.go",
         "defaults_test.go",
@@ -133,8 +135,10 @@
         "rule_builder_test.go",
         "sdk_version_test.go",
         "sdk_test.go",
+        "selects_test.go",
         "singleton_module_test.go",
         "soong_config_modules_test.go",
+        "test_suites_test.go",
         "util_test.go",
         "variable_test.go",
         "visibility_test.go",
diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go
new file mode 100644
index 0000000..4c1782b
--- /dev/null
+++ b/android/aconfig_providers.go
@@ -0,0 +1,288 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"fmt"
+	"io"
+	"maps"
+	"reflect"
+
+	"github.com/google/blueprint"
+)
+
+var (
+	mergeAconfigFilesRule = pctx.AndroidStaticRule("mergeAconfigFilesRule",
+		blueprint.RuleParams{
+			Command:     `${aconfig} dump --dedup --format protobuf --out $out $flags`,
+			CommandDeps: []string{"${aconfig}"},
+		}, "flags")
+	_ = pctx.HostBinToolVariable("aconfig", "aconfig")
+)
+
+// Provider published by aconfig_value_set
+type AconfigDeclarationsProviderData struct {
+	Package                     string
+	Container                   string
+	Exportable                  bool
+	IntermediateCacheOutputPath WritablePath
+	IntermediateDumpOutputPath  WritablePath
+}
+
+var AconfigDeclarationsProviderKey = blueprint.NewProvider[AconfigDeclarationsProviderData]()
+
+// This is used to collect the aconfig declarations info on the transitive closure,
+// the data is keyed on the container.
+type AconfigTransitiveDeclarationsInfo struct {
+	AconfigFiles map[string]Paths
+}
+
+var AconfigTransitiveDeclarationsInfoProvider = blueprint.NewProvider[AconfigTransitiveDeclarationsInfo]()
+
+type ModeInfo struct {
+	Container string
+	Mode      string
+}
+type CodegenInfo struct {
+	// AconfigDeclarations is the name of the aconfig_declarations modules that
+	// the codegen module is associated with
+	AconfigDeclarations []string
+
+	// Paths to the cache files of the associated aconfig_declaration modules
+	IntermediateCacheOutputPaths Paths
+
+	// Paths to the srcjar files generated from the java_aconfig_library modules
+	Srcjars Paths
+
+	ModeInfos map[string]ModeInfo
+}
+
+var CodegenInfoProvider = blueprint.NewProvider[CodegenInfo]()
+
+func propagateModeInfos(ctx ModuleContext, module Module, to, from map[string]ModeInfo) {
+	if len(from) > 0 {
+		depTag := ctx.OtherModuleDependencyTag(module)
+		if tag, ok := depTag.(PropagateAconfigValidationDependencyTag); ok && tag.PropagateAconfigValidation() {
+			maps.Copy(to, from)
+		}
+	}
+}
+
+// CollectDependencyAconfigFiles is used by some module types to provide finer dependency graphing than
+// we can do in ModuleBase.
+func CollectDependencyAconfigFiles(ctx ModuleContext, mergedAconfigFiles *map[string]Paths) {
+	if *mergedAconfigFiles == nil {
+		*mergedAconfigFiles = make(map[string]Paths)
+	}
+	ctx.VisitDirectDepsIgnoreBlueprint(func(module Module) {
+		if dep, _ := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); dep.IntermediateCacheOutputPath != nil {
+			(*mergedAconfigFiles)[dep.Container] = append((*mergedAconfigFiles)[dep.Container], dep.IntermediateCacheOutputPath)
+			return
+		}
+		if dep, ok := OtherModuleProvider(ctx, module, aconfigPropagatingProviderKey); ok {
+			for container, v := range dep.AconfigFiles {
+				(*mergedAconfigFiles)[container] = append((*mergedAconfigFiles)[container], v...)
+			}
+		}
+		// We process these last, so that they determine the final value, eliminating any duplicates that we picked up
+		// from UpdateAndroidBuildActions.
+		if dep, ok := OtherModuleProvider(ctx, module, AconfigTransitiveDeclarationsInfoProvider); ok {
+			for container, v := range dep.AconfigFiles {
+				(*mergedAconfigFiles)[container] = append((*mergedAconfigFiles)[container], v...)
+			}
+		}
+	})
+
+	for _, container := range SortedKeys(*mergedAconfigFiles) {
+		aconfigFiles := (*mergedAconfigFiles)[container]
+		(*mergedAconfigFiles)[container] = mergeAconfigFiles(ctx, container, aconfigFiles, false)
+	}
+
+	SetProvider(ctx, AconfigTransitiveDeclarationsInfoProvider, AconfigTransitiveDeclarationsInfo{
+		AconfigFiles: *mergedAconfigFiles,
+	})
+}
+
+func SetAconfigFileMkEntries(m *ModuleBase, entries *AndroidMkEntries, aconfigFiles map[string]Paths) {
+	setAconfigFileMkEntries(m, entries, aconfigFiles)
+}
+
+type aconfigPropagatingDeclarationsInfo struct {
+	AconfigFiles map[string]Paths
+	ModeInfos    map[string]ModeInfo
+}
+
+var aconfigPropagatingProviderKey = blueprint.NewProvider[aconfigPropagatingDeclarationsInfo]()
+
+func VerifyAconfigBuildMode(ctx ModuleContext, container string, module blueprint.Module, asError bool) {
+	if dep, ok := OtherModuleProvider(ctx, module, aconfigPropagatingProviderKey); ok {
+		for k, v := range dep.ModeInfos {
+			msg := fmt.Sprintf("%s/%s depends on %s/%s/%s across containers\n",
+				module.Name(), container, k, v.Container, v.Mode)
+			if v.Container != container && v.Mode != "exported" && v.Mode != "force-read-only" {
+				if asError {
+					ctx.ModuleErrorf(msg)
+				} else {
+					fmt.Printf("WARNING: " + msg)
+				}
+			} else {
+				if !asError {
+					fmt.Printf("PASSED: " + msg)
+				}
+			}
+		}
+	}
+}
+
+func aconfigUpdateAndroidBuildActions(ctx ModuleContext) {
+	mergedAconfigFiles := make(map[string]Paths)
+	mergedModeInfos := make(map[string]ModeInfo)
+
+	ctx.VisitDirectDepsIgnoreBlueprint(func(module Module) {
+		if aconfig_dep, ok := OtherModuleProvider(ctx, module, CodegenInfoProvider); ok && len(aconfig_dep.ModeInfos) > 0 {
+			maps.Copy(mergedModeInfos, aconfig_dep.ModeInfos)
+		}
+
+		// If any of our dependencies have aconfig declarations (directly or propagated), then merge those and provide them.
+		if dep, ok := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); ok {
+			mergedAconfigFiles[dep.Container] = append(mergedAconfigFiles[dep.Container], dep.IntermediateCacheOutputPath)
+		}
+		if dep, ok := OtherModuleProvider(ctx, module, aconfigPropagatingProviderKey); ok {
+			for container, v := range dep.AconfigFiles {
+				mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...)
+			}
+			propagateModeInfos(ctx, module, mergedModeInfos, dep.ModeInfos)
+		}
+		if dep, ok := OtherModuleProvider(ctx, module, AconfigTransitiveDeclarationsInfoProvider); ok {
+			for container, v := range dep.AconfigFiles {
+				mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...)
+			}
+		}
+	})
+	// We only need to set the provider if we have aconfig files.
+	if len(mergedAconfigFiles) > 0 {
+		for _, container := range SortedKeys(mergedAconfigFiles) {
+			aconfigFiles := mergedAconfigFiles[container]
+			mergedAconfigFiles[container] = mergeAconfigFiles(ctx, container, aconfigFiles, true)
+		}
+
+		SetProvider(ctx, aconfigPropagatingProviderKey, aconfigPropagatingDeclarationsInfo{
+			AconfigFiles: mergedAconfigFiles,
+			ModeInfos:    mergedModeInfos,
+		})
+	}
+}
+
+func aconfigUpdateAndroidMkData(ctx fillInEntriesContext, mod Module, data *AndroidMkData) {
+	info, ok := SingletonModuleProvider(ctx, mod, aconfigPropagatingProviderKey)
+	// If there is no aconfigPropagatingProvider, or there are no AconfigFiles, then we are done.
+	if !ok || len(info.AconfigFiles) == 0 {
+		return
+	}
+	data.Extra = append(data.Extra, func(w io.Writer, outputFile Path) {
+		AndroidMkEmitAssignList(w, "LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles).Strings())
+	})
+	// If there is a Custom writer, it needs to support this provider.
+	if data.Custom != nil {
+		switch reflect.TypeOf(mod).String() {
+		case "*aidl.aidlApi": // writes non-custom before adding .phony
+		case "*android_sdk.sdkRepoHost": // doesn't go through base_rules
+		case "*apex.apexBundle": // aconfig_file properties written
+		case "*bpf.bpf": // properties written (both for module and objs)
+		case "*genrule.Module": // writes non-custom before adding .phony
+		case "*java.SystemModules": // doesn't go through base_rules
+		case "*phony.phony": // properties written
+		case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY`
+		case "*sysprop.syspropLibrary": // properties written
+		default:
+			panic(fmt.Errorf("custom make rules do not handle aconfig files for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), mod))
+		}
+	}
+}
+
+func aconfigUpdateAndroidMkEntries(ctx fillInEntriesContext, mod Module, entries *[]AndroidMkEntries) {
+	// If there are no entries, then we can ignore this module, even if it has aconfig files.
+	if len(*entries) == 0 {
+		return
+	}
+	info, ok := SingletonModuleProvider(ctx, mod, aconfigPropagatingProviderKey)
+	if !ok || len(info.AconfigFiles) == 0 {
+		return
+	}
+	// All of the files in the module potentially depend on the aconfig flag values.
+	for idx, _ := range *entries {
+		(*entries)[idx].ExtraEntries = append((*entries)[idx].ExtraEntries,
+			func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries) {
+				setAconfigFileMkEntries(mod.base(), entries, info.AconfigFiles)
+			},
+		)
+
+	}
+}
+
+func mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths, generateRule bool) Paths {
+	inputs = SortedUniquePaths(inputs)
+	if len(inputs) == 1 {
+		return Paths{inputs[0]}
+	}
+
+	output := PathForModuleOut(ctx, container, "aconfig_merged.pb")
+
+	if generateRule {
+		ctx.Build(pctx, BuildParams{
+			Rule:        mergeAconfigFilesRule,
+			Description: "merge aconfig files",
+			Inputs:      inputs,
+			Output:      output,
+			Args: map[string]string{
+				"flags": JoinWithPrefix(inputs.Strings(), "--cache "),
+			},
+		})
+	}
+
+	return Paths{output}
+}
+
+func setAconfigFileMkEntries(m *ModuleBase, entries *AndroidMkEntries, aconfigFiles map[string]Paths) {
+	entries.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(m, aconfigFiles))
+}
+
+func getAconfigFilePaths(m *ModuleBase, aconfigFiles map[string]Paths) (paths Paths) {
+	// TODO(b/311155208): The default container here should be system.
+	container := "system"
+
+	if m.SocSpecific() {
+		container = "vendor"
+	} else if m.ProductSpecific() {
+		container = "product"
+	} else if m.SystemExtSpecific() {
+		container = "system_ext"
+	}
+
+	paths = append(paths, aconfigFiles[container]...)
+	if container == "system" {
+		// TODO(b/311155208): Once the default container is system, we can drop this.
+		paths = append(paths, aconfigFiles[""]...)
+	}
+	if container != "system" {
+		if len(aconfigFiles[container]) == 0 && len(aconfigFiles[""]) > 0 {
+			// TODO(b/308625757): Either we guessed the container wrong, or the flag is misdeclared.
+			// For now, just include the system (aka "") container if we get here.
+			//fmt.Printf("container_mismatch: module=%v container=%v files=%v\n", m, container, aconfigFiles)
+		}
+		paths = append(paths, aconfigFiles[""]...)
+	}
+	return
+}
diff --git a/android/all_teams.go b/android/all_teams.go
new file mode 100644
index 0000000..d4bf7d0
--- /dev/null
+++ b/android/all_teams.go
@@ -0,0 +1,177 @@
+package android
+
+import (
+	"android/soong/android/team_proto"
+	"path/filepath"
+
+	"google.golang.org/protobuf/proto"
+)
+
+const ownershipDirectory = "ownership"
+const allTeamsFile = "all_teams.pb"
+
+func AllTeamsFactory() Singleton {
+	return &allTeamsSingleton{}
+}
+
+func init() {
+	registerAllTeamBuildComponents(InitRegistrationContext)
+}
+
+func registerAllTeamBuildComponents(ctx RegistrationContext) {
+	ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
+}
+
+// For each module, list the team or the bpFile the module is defined in.
+type moduleTeamAndTestInfo struct {
+	// Name field from bp file for the team
+	teamName string
+	// Blueprint file the module is located in.
+	bpFile string
+	// Is this module only used by tests.
+	testOnly bool
+	// Is this a directly testable target by running the module directly
+	// or via tradefed.
+	topLevelTestTarget bool
+	// String name indicating the module, like `java_library` for reporting.
+	kind string
+}
+
+type allTeamsSingleton struct {
+	// Path where the collected metadata is stored after successful validation.
+	outputPath OutputPath
+
+	// Map of all package modules we visit during GenerateBuildActions
+	packages map[string]packageProperties
+	// Map of all team modules we visit during GenerateBuildActions
+	teams map[string]teamProperties
+	// Keeps track of team information or bp file for each module we visit.
+	teams_for_mods map[string]moduleTeamAndTestInfo
+}
+
+// See if there is a package module for the given bpFilePath with a team defined, if so return the team.
+// If not ascend up to the parent directory and do the same.
+func (t *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamProperties, bool) {
+	// return the Default_team listed in the package if is there.
+	if p, ok := t.packages[bpFilePath]; ok {
+		if defaultTeam := p.Default_team; defaultTeam != nil {
+			return t.teams[*defaultTeam], true
+		}
+	}
+	// Strip a directory and go up.
+	// Does android/paths.go basePath,SourcePath help?
+	current, base := filepath.Split(bpFilePath)
+	current = filepath.Clean(current) // removes trailing slash, convert "" -> "."
+	parent, _ := filepath.Split(current)
+	if current == "." {
+		return teamProperties{}, false
+	}
+	return t.lookupDefaultTeam(filepath.Join(parent, base))
+}
+
+// Visit all modules and collect all teams and use WriteFileRuleVerbatim
+// to write it out.
+func (t *allTeamsSingleton) GenerateBuildActions(ctx SingletonContext) {
+	t.packages = make(map[string]packageProperties)
+	t.teams = make(map[string]teamProperties)
+	t.teams_for_mods = make(map[string]moduleTeamAndTestInfo)
+
+	ctx.VisitAllModules(func(module Module) {
+		bpFile := ctx.BlueprintFile(module)
+
+		// Package Modules and Team Modules are stored in a map so we can look them up by name for
+		// modules without a team.
+		if pack, ok := module.(*packageModule); ok {
+			// Packages don't have names, use the blueprint file as the key. we can't get qualifiedModuleId in t context.
+			pkgKey := bpFile
+			t.packages[pkgKey] = pack.properties
+			return
+		}
+		if team, ok := module.(*teamModule); ok {
+			t.teams[team.Name()] = team.properties
+			return
+		}
+
+		testModInfo := TestModuleInformation{}
+		if tmi, ok := SingletonModuleProvider(ctx, module, TestOnlyProviderKey); ok {
+			testModInfo = tmi
+		}
+
+		// Some modules, like java_test_host don't set the provider when the module isn't enabled:
+		//                                                test_only, top_level
+		//     AVFHostTestCases{os:linux_glibc,arch:common} {true true}
+		//     AVFHostTestCases{os:windows,arch:common} {false false}
+		// Generally variant information of true override false or unset.
+		if testModInfo.TestOnly == false {
+			if prevValue, exists := t.teams_for_mods[module.Name()]; exists {
+				if prevValue.testOnly == true {
+					return
+				}
+			}
+		}
+		entry := moduleTeamAndTestInfo{
+			bpFile:             bpFile,
+			testOnly:           testModInfo.TestOnly,
+			topLevelTestTarget: testModInfo.TopLevelTarget,
+			kind:               ctx.ModuleType(module),
+			teamName:           module.base().Team(),
+		}
+		t.teams_for_mods[module.Name()] = entry
+
+	})
+
+	// Visit all modules again and lookup the team name in the package or parent package if the team
+	// isn't assignged at the module level.
+	allTeams := t.lookupTeamForAllModules()
+
+	t.outputPath = PathForOutput(ctx, ownershipDirectory, allTeamsFile)
+	data, err := proto.Marshal(allTeams)
+	if err != nil {
+		ctx.Errorf("Unable to marshal team data. %s", err)
+	}
+
+	WriteFileRuleVerbatim(ctx, t.outputPath, string(data))
+	ctx.Phony("all_teams", t.outputPath)
+}
+
+func (t *allTeamsSingleton) MakeVars(ctx MakeVarsContext) {
+	ctx.DistForGoal("all_teams", t.outputPath)
+}
+
+// Visit every (non-package, non-team) module and write out a proto containing
+// either the declared team data for that module or the package default team data for that module.
+func (t *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams {
+	teamsProto := make([]*team_proto.Team, len(t.teams_for_mods))
+	for i, moduleName := range SortedKeys(t.teams_for_mods) {
+		m, _ := t.teams_for_mods[moduleName]
+		teamName := m.teamName
+		var teamProperties teamProperties
+		found := false
+		if teamName != "" {
+			teamProperties, found = t.teams[teamName]
+		} else {
+			teamProperties, found = t.lookupDefaultTeam(m.bpFile)
+		}
+
+		trendy_team_id := ""
+		if found {
+			trendy_team_id = *teamProperties.Trendy_team_id
+		}
+
+		teamData := new(team_proto.Team)
+		*teamData = team_proto.Team{
+			TargetName:     proto.String(moduleName),
+			Path:           proto.String(m.bpFile),
+			TestOnly:       proto.Bool(m.testOnly),
+			TopLevelTarget: proto.Bool(m.topLevelTestTarget),
+			Kind:           proto.String(m.kind),
+		}
+		if trendy_team_id != "" {
+			teamData.TrendyTeamId = proto.String(trendy_team_id)
+		} else {
+			// Clients rely on the TrendyTeamId optional field not being set.
+		}
+		teamsProto[i] = teamData
+	}
+	return &team_proto.AllTeams{Teams: teamsProto}
+}
diff --git a/android/all_teams_test.go b/android/all_teams_test.go
new file mode 100644
index 0000000..96ed92f
--- /dev/null
+++ b/android/all_teams_test.go
@@ -0,0 +1,299 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package android
+
+import (
+	"android/soong/android/team_proto"
+	"log"
+	"testing"
+
+	"google.golang.org/protobuf/proto"
+)
+
+func TestAllTeams(t *testing.T) {
+	t.Parallel()
+	ctx := GroupFixturePreparers(
+		prepareForTestWithTeamAndFakes,
+		// This adds two variants, one armv7-a-neon, one armv8-a
+		PrepareForTestWithArchMutator,
+		FixtureRegisterWithContext(func(ctx RegistrationContext) {
+			ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
+		}),
+	).RunTestWithBp(t, `
+		fake {
+			name: "main_test",
+			team: "someteam",
+		}
+		team {
+			name: "someteam",
+			trendy_team_id: "cool_team",
+		}
+
+		team {
+			name: "team2",
+			trendy_team_id: "22222",
+		}
+
+		fake {
+			name: "tool",
+			team: "team2",
+		}
+
+		fake {
+			name: "noteam",
+                        test_only: true,
+		}
+                // write the test-only provider value once
+		fake {
+                        name: "test-and-team-and-top1",
+                        test_only: true,
+                        team: "team2",
+                        arch: {arm: { skip: false},
+                               arm64: { skip: true}},
+		}
+                // write the test-only provider once, but on the other arch
+		fake {
+                        name: "test-and-team-and-top2",
+                        test_only: true,
+                        team: "team2",
+                        arch: {arm: { skip: true},
+                               arm64: { skip: false}},
+		}
+                // write the test-only provider value twice
+		fake {
+                        name: "test-and-team-and-top3",
+                        test_only: true,
+                        team: "team2",
+		}
+                // Don't write the test-only provider value
+		fake {
+                        name: "test-and-team-and-top4",
+                        test_only: true,
+                        team: "team2",
+                        arch: {arm: { skip: true},
+                               arm64: { skip: true}},
+		}
+	`)
+
+	var teams *team_proto.AllTeams
+	teams = getTeamProtoOutput(t, ctx)
+
+	// map of module name -> trendy team name.
+	actualTeams := make(map[string]string)
+	actualTests := []string{}
+	actualTopLevelTests := []string{}
+
+	for _, teamProto := range teams.Teams {
+		if teamProto.TrendyTeamId != nil {
+			actualTeams[teamProto.GetTargetName()] = *teamProto.TrendyTeamId
+		} else {
+			actualTeams[teamProto.GetTargetName()] = ""
+		}
+		if teamProto.GetTestOnly() {
+			actualTests = append(actualTests, teamProto.GetTargetName())
+		}
+		if teamProto.GetTopLevelTarget() {
+			actualTopLevelTests = append(actualTopLevelTests, teamProto.GetTargetName())
+		}
+	}
+	expectedTeams := map[string]string{
+		"main_test":              "cool_team",
+		"tool":                   "22222",
+		"test-and-team-and-top1": "22222",
+		"test-and-team-and-top2": "22222",
+		"test-and-team-and-top3": "22222",
+		"test-and-team-and-top4": "22222",
+		"noteam":                 "",
+	}
+
+	expectedTests := []string{
+		"noteam",
+		"test-and-team-and-top1",
+		"test-and-team-and-top2",
+		"test-and-team-and-top3",
+		// There should be no test-and-team-top4 as we skip writing all variants
+		// test-only for all variants
+	}
+	AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams)
+	AssertDeepEquals(t, "test matchup", expectedTests, actualTests)
+}
+
+func getTeamProtoOutput(t *testing.T, ctx *TestResult) *team_proto.AllTeams {
+	teams := new(team_proto.AllTeams)
+	config := ctx.SingletonForTests("all_teams")
+	allOutputs := config.AllOutputs()
+
+	protoPath := allOutputs[0]
+
+	out := config.MaybeOutput(protoPath)
+	outProto := []byte(ContentFromFileRuleForTests(t, ctx.TestContext, out))
+	if err := proto.Unmarshal(outProto, teams); err != nil {
+		log.Fatalln("Failed to parse teams proto:", err)
+	}
+	return teams
+}
+
+// Android.bp
+//
+//	team: team_top
+//
+// # dir1 has no modules with teams,
+// # but has a dir with no Android.bp
+// dir1/Android.bp
+//
+//	module_dir1
+//
+// # dirs without and Android.bp should be fine.
+// dir1/dir2/dir3/Android.bp
+//
+//	package {}
+//	module_dir123
+//
+// teams_dir/Android.bp
+//
+//	module_with_team1: team1
+//	team1: 111
+//
+// # team comes from upper package default
+// teams_dir/deeper/Android.bp
+//
+//	module2_with_team1: team1
+//
+// package_defaults/Android.bp
+// package_defaults/pd2/Android.bp
+//
+//	package{ default_team: team_top}
+//	module_pd2   ## should get team_top
+//
+// package_defaults/pd2/pd3/Android.bp
+//
+//	module_pd3  ## should get team_top
+func TestPackageLookup(t *testing.T) {
+	t.Parallel()
+	rootBp := `
+		team {
+			name: "team_top",
+			trendy_team_id: "trendy://team_top",
+		} `
+
+	dir1Bp := `
+		fake {
+			name: "module_dir1",
+		} `
+	dir3Bp := `
+                package {}
+		fake {
+			name: "module_dir123",
+		} `
+	teamsDirBp := `
+		fake {
+			name: "module_with_team1",
+                        team: "team1"
+
+		}
+		team {
+			name: "team1",
+			trendy_team_id: "111",
+		} `
+	teamsDirDeeper := `
+		fake {
+			name: "module2_with_team1",
+                        team: "team1"
+		} `
+	// create an empty one.
+	packageDefaultsBp := ""
+	packageDefaultspd2 := `
+                package { default_team: "team_top"}
+		fake {
+			name: "modulepd2",
+		} `
+
+	packageDefaultspd3 := `
+		fake {
+			name: "modulepd3",
+		}
+		fake {
+			name: "modulepd3b",
+			team: "team1"
+		} `
+
+	ctx := GroupFixturePreparers(
+		prepareForTestWithTeamAndFakes,
+		PrepareForTestWithPackageModule,
+		FixtureRegisterWithContext(func(ctx RegistrationContext) {
+			ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
+		}),
+		FixtureAddTextFile("Android.bp", rootBp),
+		FixtureAddTextFile("dir1/Android.bp", dir1Bp),
+		FixtureAddTextFile("dir1/dir2/dir3/Android.bp", dir3Bp),
+		FixtureAddTextFile("teams_dir/Android.bp", teamsDirBp),
+		FixtureAddTextFile("teams_dir/deeper/Android.bp", teamsDirDeeper),
+		FixtureAddTextFile("package_defaults/Android.bp", packageDefaultsBp),
+		FixtureAddTextFile("package_defaults/pd2/Android.bp", packageDefaultspd2),
+		FixtureAddTextFile("package_defaults/pd2/pd3/Android.bp", packageDefaultspd3),
+	).RunTest(t)
+
+	var teams *team_proto.AllTeams
+	teams = getTeamProtoOutput(t, ctx)
+
+	// map of module name -> trendy team name.
+	actualTeams := make(map[string]*string)
+	for _, teamProto := range teams.Teams {
+		actualTeams[teamProto.GetTargetName()] = teamProto.TrendyTeamId
+	}
+	expectedTeams := map[string]*string{
+		"module_with_team1":  proto.String("111"),
+		"module2_with_team1": proto.String("111"),
+		"modulepd2":          proto.String("trendy://team_top"),
+		"modulepd3":          proto.String("trendy://team_top"),
+		"modulepd3b":         proto.String("111"),
+		"module_dir1":        nil,
+		"module_dir123":      nil,
+	}
+	AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams)
+}
+
+type fakeForTests struct {
+	ModuleBase
+
+	sourceProperties SourceProperties
+	props            struct {
+		// If true, don't write test-only value in provider
+		Skip bool `android:"arch_variant"`
+	}
+}
+
+func fakeFactory() Module {
+	module := &fakeForTests{}
+	module.AddProperties(&module.sourceProperties, &module.props)
+	InitAndroidArchModule(module, HostAndDeviceSupported, MultilibBoth)
+
+	return module
+}
+
+var prepareForTestWithTeamAndFakes = GroupFixturePreparers(
+	FixtureRegisterWithContext(RegisterTeamBuildComponents),
+	FixtureRegisterWithContext(func(ctx RegistrationContext) {
+		ctx.RegisterModuleType("fake", fakeFactory)
+	}),
+)
+
+func (f *fakeForTests) GenerateAndroidBuildActions(ctx ModuleContext) {
+	if Bool(f.sourceProperties.Test_only) {
+		SetProvider(ctx, TestOnlyProviderKey, TestModuleInformation{
+			TestOnly:       Bool(f.sourceProperties.Test_only) && !f.props.Skip,
+			TopLevelTarget: false,
+		})
+	}
+}
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index b921e41..a52bff3 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -14,30 +14,7 @@
 
 package allowlists
 
-// Configuration to decide if modules in a directory should default to true/false for bp2build_available
-type Bp2BuildConfig map[string]BazelConversionConfigEntry
-type BazelConversionConfigEntry int
-
 const (
-	// iota + 1 ensures that the int value is not 0 when used in the Bp2buildAllowlist map,
-	// which can also mean that the key doesn't exist in a lookup.
-
-	// all modules in this package and subpackages default to bp2build_available: true.
-	// allows modules to opt-out.
-	Bp2BuildDefaultTrueRecursively BazelConversionConfigEntry = iota + 1
-
-	// all modules in this package (not recursively) default to bp2build_available: true.
-	// allows modules to opt-out.
-	Bp2BuildDefaultTrue
-
-	// all modules in this package (not recursively) default to bp2build_available: false.
-	// allows modules to opt-in.
-	Bp2BuildDefaultFalse
-
-	// all modules in this package and subpackages default to bp2build_available: false.
-	// allows modules to opt-in.
-	Bp2BuildDefaultFalseRecursively
-
 	// Modules with build time of more than half a minute should have high priority.
 	DEFAULT_PRIORITIZED_WEIGHT = 1000
 	// Modules with build time of more than a few minute should have higher priority.
@@ -48,1562 +25,6 @@
 )
 
 var (
-	Bp2buildDefaultConfig = Bp2BuildConfig{
-		"art":                                   Bp2BuildDefaultTrue,
-		"art/libartbase":                        Bp2BuildDefaultTrueRecursively,
-		"art/libartpalette":                     Bp2BuildDefaultTrueRecursively,
-		"art/libdexfile":                        Bp2BuildDefaultTrueRecursively,
-		"art/libnativebridge":                   Bp2BuildDefaultTrueRecursively,
-		"art/runtime":                           Bp2BuildDefaultTrueRecursively,
-		"art/tools":                             Bp2BuildDefaultTrue,
-		"bionic":                                Bp2BuildDefaultTrueRecursively,
-		"bootable/recovery/applypatch":          Bp2BuildDefaultTrue,
-		"bootable/recovery/minadbd":             Bp2BuildDefaultTrue,
-		"bootable/recovery/minui":               Bp2BuildDefaultTrue,
-		"bootable/recovery/recovery_utils":      Bp2BuildDefaultTrue,
-		"bootable/recovery/tools/recovery_l10n": Bp2BuildDefaultTrue,
-
-		"build/bazel":                        Bp2BuildDefaultTrueRecursively,
-		"build/make/target/product/security": Bp2BuildDefaultTrue,
-		"build/make/tools/protos":            Bp2BuildDefaultTrue,
-		"build/make/tools/releasetools":      Bp2BuildDefaultTrue,
-		"build/make/tools/sbom":              Bp2BuildDefaultTrue,
-		"build/make/tools/signapk":           Bp2BuildDefaultTrue,
-		"build/make/tools/zipalign":          Bp2BuildDefaultTrueRecursively,
-		"build/soong":                        Bp2BuildDefaultTrue,
-		"build/soong/cc/libbuildversion":     Bp2BuildDefaultTrue, // Skip tests subdir
-		"build/soong/cc/ndkstubgen":          Bp2BuildDefaultTrue,
-		"build/soong/cc/symbolfile":          Bp2BuildDefaultTrue,
-		"build/soong/licenses":               Bp2BuildDefaultTrue,
-		"build/soong/linkerconfig":           Bp2BuildDefaultTrueRecursively,
-		"build/soong/scripts":                Bp2BuildDefaultTrueRecursively,
-
-		"cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively,
-
-		"dalvik/tools/dexdeps": Bp2BuildDefaultTrueRecursively,
-
-		"development/apps/DevelopmentSettings":        Bp2BuildDefaultTrue,
-		"development/apps/Fallback":                   Bp2BuildDefaultTrue,
-		"development/apps/WidgetPreview":              Bp2BuildDefaultTrue,
-		"development/python-packages/adb":             Bp2BuildDefaultTrueRecursively,
-		"development/samples/BasicGLSurfaceView":      Bp2BuildDefaultTrue,
-		"development/samples/BluetoothChat":           Bp2BuildDefaultTrue,
-		"development/samples/BrokenKeyDerivation":     Bp2BuildDefaultTrue,
-		"development/samples/Compass":                 Bp2BuildDefaultTrue,
-		"development/samples/ContactManager":          Bp2BuildDefaultTrue,
-		"development/samples/FixedGridLayout":         Bp2BuildDefaultTrue,
-		"development/samples/HelloEffects":            Bp2BuildDefaultTrue,
-		"development/samples/Home":                    Bp2BuildDefaultTrue,
-		"development/samples/HoneycombGallery":        Bp2BuildDefaultTrue,
-		"development/samples/JetBoy":                  Bp2BuildDefaultTrue,
-		"development/samples/KeyChainDemo":            Bp2BuildDefaultTrue,
-		"development/samples/LceDemo":                 Bp2BuildDefaultTrue,
-		"development/samples/LunarLander":             Bp2BuildDefaultTrue,
-		"development/samples/MultiResolution":         Bp2BuildDefaultTrue,
-		"development/samples/MultiWindow":             Bp2BuildDefaultTrue,
-		"development/samples/NotePad":                 Bp2BuildDefaultTrue,
-		"development/samples/Obb":                     Bp2BuildDefaultTrue,
-		"development/samples/RSSReader":               Bp2BuildDefaultTrue,
-		"development/samples/ReceiveShareDemo":        Bp2BuildDefaultTrue,
-		"development/samples/SearchableDictionary":    Bp2BuildDefaultTrue,
-		"development/samples/SipDemo":                 Bp2BuildDefaultTrue,
-		"development/samples/SkeletonApp":             Bp2BuildDefaultTrue,
-		"development/samples/Snake":                   Bp2BuildDefaultTrue,
-		"development/samples/SpellChecker/":           Bp2BuildDefaultTrueRecursively,
-		"development/samples/ThemedNavBarKeyboard":    Bp2BuildDefaultTrue,
-		"development/samples/ToyVpn":                  Bp2BuildDefaultTrue,
-		"development/samples/TtsEngine":               Bp2BuildDefaultTrue,
-		"development/samples/USB/AdbTest":             Bp2BuildDefaultTrue,
-		"development/samples/USB/MissileLauncher":     Bp2BuildDefaultTrue,
-		"development/samples/VoiceRecognitionService": Bp2BuildDefaultTrue,
-		"development/samples/VoicemailProviderDemo":   Bp2BuildDefaultTrue,
-		"development/samples/WiFiDirectDemo":          Bp2BuildDefaultTrue,
-		"development/sdk":                             Bp2BuildDefaultTrueRecursively,
-
-		"external/aac":                           Bp2BuildDefaultTrueRecursively,
-		"external/abseil-cpp":                    Bp2BuildDefaultTrueRecursively,
-		"external/arm-optimized-routines":        Bp2BuildDefaultTrueRecursively,
-		"external/auto":                          Bp2BuildDefaultTrue,
-		"external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively,
-		"external/auto/common":                   Bp2BuildDefaultTrueRecursively,
-		"external/auto/service":                  Bp2BuildDefaultTrueRecursively,
-		"external/boringssl":                     Bp2BuildDefaultTrueRecursively,
-		"external/bouncycastle":                  Bp2BuildDefaultTrue,
-		"external/brotli":                        Bp2BuildDefaultTrue,
-		"external/bsdiff":                        Bp2BuildDefaultTrueRecursively,
-		"external/bzip2":                         Bp2BuildDefaultTrueRecursively,
-		"external/clang/lib":                     Bp2BuildDefaultTrue,
-		"external/conscrypt":                     Bp2BuildDefaultTrue,
-		"external/e2fsprogs":                     Bp2BuildDefaultTrueRecursively,
-		"external/eigen":                         Bp2BuildDefaultTrueRecursively,
-		"external/erofs-utils":                   Bp2BuildDefaultTrueRecursively,
-		"external/error_prone":                   Bp2BuildDefaultTrueRecursively,
-		"external/escapevelocity":                Bp2BuildDefaultTrueRecursively,
-		"external/expat":                         Bp2BuildDefaultTrueRecursively,
-		"external/f2fs-tools":                    Bp2BuildDefaultTrue,
-		"external/flac":                          Bp2BuildDefaultTrueRecursively,
-		"external/flatbuffers":                   Bp2BuildDefaultTrueRecursively,
-		"external/fmtlib":                        Bp2BuildDefaultTrueRecursively,
-		"external/fsverity-utils":                Bp2BuildDefaultTrueRecursively,
-		"external/google-benchmark":              Bp2BuildDefaultTrueRecursively,
-		"external/googletest":                    Bp2BuildDefaultTrueRecursively,
-		"external/guava":                         Bp2BuildDefaultTrueRecursively,
-		"external/gwp_asan":                      Bp2BuildDefaultTrueRecursively,
-		"external/hamcrest":                      Bp2BuildDefaultTrueRecursively,
-		"external/icu":                           Bp2BuildDefaultTrueRecursively,
-		"external/icu/android_icu4j":             Bp2BuildDefaultFalse, // java rules incomplete
-		"external/icu/icu4j":                     Bp2BuildDefaultFalse, // java rules incomplete
-		"external/jacoco":                        Bp2BuildDefaultTrueRecursively,
-		"external/jarjar":                        Bp2BuildDefaultTrueRecursively,
-		"external/javaparser":                    Bp2BuildDefaultTrueRecursively,
-		"external/javapoet":                      Bp2BuildDefaultTrueRecursively,
-		"external/javassist":                     Bp2BuildDefaultTrueRecursively,
-		"external/jemalloc_new":                  Bp2BuildDefaultTrueRecursively,
-		"external/jsoncpp":                       Bp2BuildDefaultTrueRecursively,
-		"external/jsr305":                        Bp2BuildDefaultTrueRecursively,
-		"external/jsr330":                        Bp2BuildDefaultTrueRecursively,
-		"external/junit":                         Bp2BuildDefaultTrueRecursively,
-		"external/kotlinc":                       Bp2BuildDefaultTrueRecursively,
-		"external/libaom":                        Bp2BuildDefaultTrueRecursively,
-		"external/libavc":                        Bp2BuildDefaultTrueRecursively,
-		"external/libcap":                        Bp2BuildDefaultTrueRecursively,
-		"external/libcxx":                        Bp2BuildDefaultTrueRecursively,
-		"external/libcxxabi":                     Bp2BuildDefaultTrueRecursively,
-		"external/libdivsufsort":                 Bp2BuildDefaultTrueRecursively,
-		"external/libdrm":                        Bp2BuildDefaultTrue,
-		"external/libevent":                      Bp2BuildDefaultTrueRecursively,
-		"external/libgav1":                       Bp2BuildDefaultTrueRecursively,
-		"external/libhevc":                       Bp2BuildDefaultTrueRecursively,
-		"external/libjpeg-turbo":                 Bp2BuildDefaultTrueRecursively,
-		"external/libmpeg2":                      Bp2BuildDefaultTrueRecursively,
-		"external/libpng":                        Bp2BuildDefaultTrueRecursively,
-		"external/libvpx":                        Bp2BuildDefaultTrueRecursively,
-		"external/libyuv":                        Bp2BuildDefaultTrueRecursively,
-		"external/lz4/lib":                       Bp2BuildDefaultTrue,
-		"external/lz4/programs":                  Bp2BuildDefaultTrue,
-		"external/lzma/C":                        Bp2BuildDefaultTrueRecursively,
-		"external/mdnsresponder":                 Bp2BuildDefaultTrueRecursively,
-		"external/minijail":                      Bp2BuildDefaultTrueRecursively,
-		"external/musl":                          Bp2BuildDefaultTrueRecursively,
-		"external/objenesis":                     Bp2BuildDefaultTrueRecursively,
-		"external/openscreen":                    Bp2BuildDefaultTrueRecursively,
-		"external/ow2-asm":                       Bp2BuildDefaultTrueRecursively,
-		"external/pcre":                          Bp2BuildDefaultTrueRecursively,
-		"external/protobuf":                      Bp2BuildDefaultTrueRecursively,
-		"external/python/pyyaml/lib/yaml":        Bp2BuildDefaultTrueRecursively,
-		"external/python/six":                    Bp2BuildDefaultTrueRecursively,
-		"external/python/jinja/src":              Bp2BuildDefaultTrueRecursively,
-		"external/python/markupsafe/src":         Bp2BuildDefaultTrueRecursively,
-		"external/python/setuptools":             Bp2BuildDefaultTrueRecursively,
-		"external/rappor":                        Bp2BuildDefaultTrueRecursively,
-		"external/scudo":                         Bp2BuildDefaultTrueRecursively,
-		"external/selinux/checkpolicy":           Bp2BuildDefaultTrueRecursively,
-		"external/selinux/libselinux":            Bp2BuildDefaultTrueRecursively,
-		"external/selinux/libsepol":              Bp2BuildDefaultTrueRecursively,
-		"external/speex":                         Bp2BuildDefaultTrueRecursively,
-		"external/sqlite":                        Bp2BuildDefaultTrueRecursively,
-		"external/tinyalsa":                      Bp2BuildDefaultTrueRecursively,
-		"external/tinyalsa_new":                  Bp2BuildDefaultTrueRecursively,
-		"external/toybox":                        Bp2BuildDefaultTrueRecursively,
-		"external/zlib":                          Bp2BuildDefaultTrueRecursively,
-		"external/zopfli":                        Bp2BuildDefaultTrueRecursively,
-		"external/zstd":                          Bp2BuildDefaultTrueRecursively,
-
-		"frameworks/av": Bp2BuildDefaultTrue,
-		"frameworks/av/media/audioaidlconversion":            Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/codec2/components/aom":          Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/codecs":                         Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/liberror":                       Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/libmediahelper":                 Bp2BuildDefaultTrue,
-		"frameworks/av/media/libshmem":                       Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/module/codecs":                  Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/module/foundation":              Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/module/minijail":                Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/services/minijail":                    Bp2BuildDefaultTrueRecursively,
-		"frameworks/base/libs/androidfw":                     Bp2BuildDefaultTrue,
-		"frameworks/base/libs/services":                      Bp2BuildDefaultTrue,
-		"frameworks/base/media/tests/MediaDump":              Bp2BuildDefaultTrue,
-		"frameworks/base/proto":                              Bp2BuildDefaultTrue,
-		"frameworks/base/services/tests/servicestests/aidl":  Bp2BuildDefaultTrue,
-		"frameworks/base/startop/apps/test":                  Bp2BuildDefaultTrue,
-		"frameworks/base/tests/appwidgets/AppWidgetHostTest": Bp2BuildDefaultTrueRecursively,
-		"frameworks/base/tools/aapt2":                        Bp2BuildDefaultTrue,
-		"frameworks/base/tools/codegen":                      Bp2BuildDefaultTrueRecursively,
-		"frameworks/base/tools/streaming_proto":              Bp2BuildDefaultTrueRecursively,
-		"frameworks/hardware/interfaces/stats/aidl":          Bp2BuildDefaultTrue,
-		"frameworks/libs/modules-utils/build":                Bp2BuildDefaultTrueRecursively,
-		"frameworks/libs/net/common/native":                  Bp2BuildDefaultTrueRecursively,
-		"frameworks/native":                                  Bp2BuildDefaultTrue,
-		"frameworks/native/libs/adbd_auth":                   Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/libs/arect":                       Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/libs/gui":                         Bp2BuildDefaultTrue,
-		"frameworks/native/libs/math":                        Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/libs/nativebase":                  Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/libs/permission":                  Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/libs/vr":                          Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/opengl/tests/gl2_cameraeye":       Bp2BuildDefaultTrue,
-		"frameworks/native/opengl/tests/gl2_java":            Bp2BuildDefaultTrue,
-		"frameworks/native/opengl/tests/testLatency":         Bp2BuildDefaultTrue,
-		"frameworks/native/opengl/tests/testPauseResume":     Bp2BuildDefaultTrue,
-		"frameworks/native/opengl/tests/testViewport":        Bp2BuildDefaultTrue,
-		"frameworks/native/services/batteryservice":          Bp2BuildDefaultTrue,
-		"frameworks/proto_logging/stats":                     Bp2BuildDefaultTrueRecursively,
-
-		"hardware/interfaces":                                     Bp2BuildDefaultTrue,
-		"hardware/interfaces/audio/aidl":                          Bp2BuildDefaultTrue,
-		"hardware/interfaces/audio/aidl/common":                   Bp2BuildDefaultTrue,
-		"hardware/interfaces/audio/aidl/default":                  Bp2BuildDefaultTrue,
-		"hardware/interfaces/audio/aidl/sounddose":                Bp2BuildDefaultTrue,
-		"hardware/interfaces/common/aidl":                         Bp2BuildDefaultTrue,
-		"hardware/interfaces/common/fmq/aidl":                     Bp2BuildDefaultTrue,
-		"hardware/interfaces/common/support":                      Bp2BuildDefaultTrue,
-		"hardware/interfaces/configstore/1.0":                     Bp2BuildDefaultTrue,
-		"hardware/interfaces/configstore/1.1":                     Bp2BuildDefaultTrue,
-		"hardware/interfaces/configstore/utils":                   Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/allocator/2.0":              Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/allocator/3.0":              Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/allocator/4.0":              Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/allocator/aidl":             Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/bufferqueue/1.0":            Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/bufferqueue/2.0":            Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/common/1.0":                 Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/common/1.1":                 Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/common/1.2":                 Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/common/aidl":                Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/mapper/2.0":                 Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/mapper/2.1":                 Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/mapper/3.0":                 Bp2BuildDefaultTrue,
-		"hardware/interfaces/graphics/mapper/4.0":                 Bp2BuildDefaultTrue,
-		"hardware/interfaces/health/1.0":                          Bp2BuildDefaultTrue,
-		"hardware/interfaces/health/1.0/default":                  Bp2BuildDefaultTrue,
-		"hardware/interfaces/health/2.0":                          Bp2BuildDefaultTrue,
-		"hardware/interfaces/health/2.0/default":                  Bp2BuildDefaultTrue,
-		"hardware/interfaces/health/2.0/utils":                    Bp2BuildDefaultTrueRecursively,
-		"hardware/interfaces/health/2.1":                          Bp2BuildDefaultTrue,
-		"hardware/interfaces/health/aidl":                         Bp2BuildDefaultTrue,
-		"hardware/interfaces/health/utils":                        Bp2BuildDefaultTrueRecursively,
-		"hardware/interfaces/media/1.0":                           Bp2BuildDefaultTrue,
-		"hardware/interfaces/media/bufferpool":                    Bp2BuildDefaultTrueRecursively,
-		"hardware/interfaces/media/bufferpool/aidl/default/tests": Bp2BuildDefaultFalseRecursively,
-		"hardware/interfaces/media/c2/1.0":                        Bp2BuildDefaultTrue,
-		"hardware/interfaces/media/c2/1.1":                        Bp2BuildDefaultTrue,
-		"hardware/interfaces/media/c2/1.2":                        Bp2BuildDefaultTrue,
-		"hardware/interfaces/media/omx/1.0":                       Bp2BuildDefaultTrue,
-		"hardware/interfaces/neuralnetworks":                      Bp2BuildDefaultTrueRecursively,
-		"hardware/interfaces/neuralnetworks/aidl/vts":             Bp2BuildDefaultFalseRecursively,
-		"hardware/interfaces/neuralnetworks/1.0/vts":              Bp2BuildDefaultFalseRecursively,
-		"hardware/interfaces/neuralnetworks/1.1/vts":              Bp2BuildDefaultFalseRecursively,
-		"hardware/interfaces/neuralnetworks/1.2/vts":              Bp2BuildDefaultFalseRecursively,
-		"hardware/interfaces/neuralnetworks/1.3/vts":              Bp2BuildDefaultFalseRecursively,
-		"hardware/interfaces/neuralnetworks/1.4/vts":              Bp2BuildDefaultFalseRecursively,
-
-		"libnativehelper": Bp2BuildDefaultTrueRecursively,
-
-		"packages/apps/DevCamera":                            Bp2BuildDefaultTrue,
-		"packages/apps/HTMLViewer":                           Bp2BuildDefaultTrue,
-		"packages/apps/Protips":                              Bp2BuildDefaultTrue,
-		"packages/apps/SafetyRegulatoryInfo":                 Bp2BuildDefaultTrue,
-		"packages/apps/WallpaperPicker":                      Bp2BuildDefaultTrue,
-		"packages/modules/NeuralNetworks/driver/cache":       Bp2BuildDefaultTrueRecursively,
-		"packages/modules/StatsD/lib/libstatssocket":         Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb":                               Bp2BuildDefaultTrue,
-		"packages/modules/adb/apex":                          Bp2BuildDefaultTrue,
-		"packages/modules/adb/crypto":                        Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/libs":                          Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/pairing_auth":                  Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/pairing_connection":            Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/proto":                         Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/tls":                           Bp2BuildDefaultTrueRecursively,
-		"packages/modules/Gki/libkver":                       Bp2BuildDefaultTrue,
-		"packages/modules/NetworkStack/common/captiveportal": Bp2BuildDefaultTrue,
-		"packages/modules/NeuralNetworks/apex":               Bp2BuildDefaultTrue,
-		"packages/modules/NeuralNetworks/apex/testing":       Bp2BuildDefaultTrue,
-		"packages/providers/MediaProvider/tools/dialogs":     Bp2BuildDefaultFalse, // TODO(b/242834374)
-		"packages/screensavers/Basic":                        Bp2BuildDefaultTrue,
-		"packages/services/Car/tests/SampleRearViewCamera":   Bp2BuildDefaultFalse, // TODO(b/242834321)
-
-		"platform_testing/tests/example": Bp2BuildDefaultTrueRecursively,
-
-		"prebuilts/clang/host/linux-x86":                   Bp2BuildDefaultTrueRecursively,
-		"prebuilts/gradle-plugin":                          Bp2BuildDefaultTrueRecursively,
-		"prebuilts/runtime/mainline/platform/sdk":          Bp2BuildDefaultTrueRecursively,
-		"prebuilts/sdk":                                    Bp2BuildDefaultTrue,
-		"prebuilts/sdk/current/androidx":                   Bp2BuildDefaultTrue,
-		"prebuilts/sdk/current/androidx-legacy":            Bp2BuildDefaultTrue,
-		"prebuilts/sdk/current/extras/constraint-layout-x": Bp2BuildDefaultTrue,
-		"prebuilts/sdk/current/extras/material-design-x":   Bp2BuildDefaultTrue,
-		"prebuilts/sdk/current/extras/app-toolkit":         Bp2BuildDefaultTrue,
-		"prebuilts/sdk/current/support":                    Bp2BuildDefaultTrue,
-		"prebuilts/tools":                                  Bp2BuildDefaultTrue,
-		"prebuilts/tools/common/m2":                        Bp2BuildDefaultTrue,
-
-		"sdk/dumpeventlog":  Bp2BuildDefaultTrue,
-		"sdk/eventanalyzer": Bp2BuildDefaultTrue,
-
-		"system/apex":                                            Bp2BuildDefaultFalse, // TODO(b/207466993): flaky failures
-		"system/apex/apexer":                                     Bp2BuildDefaultTrue,
-		"system/apex/libs":                                       Bp2BuildDefaultTrueRecursively,
-		"system/apex/libs/libapexsupport":                        Bp2BuildDefaultFalseRecursively, // TODO(b/267572288): depends on rust
-		"system/apex/proto":                                      Bp2BuildDefaultTrueRecursively,
-		"system/apex/tools":                                      Bp2BuildDefaultTrueRecursively,
-		"system/core/debuggerd":                                  Bp2BuildDefaultTrueRecursively,
-		"system/core/diagnose_usb":                               Bp2BuildDefaultTrueRecursively,
-		"system/core/healthd":                                    Bp2BuildDefaultTrue,
-		"system/core/healthd/testdata":                           Bp2BuildDefaultTrue,
-		"system/core/libasyncio":                                 Bp2BuildDefaultTrue,
-		"system/core/libcrypto_utils":                            Bp2BuildDefaultTrueRecursively,
-		"system/core/libcutils":                                  Bp2BuildDefaultTrueRecursively,
-		"system/core/libpackagelistparser":                       Bp2BuildDefaultTrueRecursively,
-		"system/core/libprocessgroup":                            Bp2BuildDefaultTrue,
-		"system/core/libprocessgroup/cgrouprc":                   Bp2BuildDefaultTrue,
-		"system/core/libprocessgroup/cgrouprc_format":            Bp2BuildDefaultTrue,
-		"system/core/libsparse":                                  Bp2BuildDefaultTrueRecursively,
-		"system/core/libsuspend":                                 Bp2BuildDefaultTrue,
-		"system/core/libsystem":                                  Bp2BuildDefaultTrueRecursively,
-		"system/core/libsysutils":                                Bp2BuildDefaultTrueRecursively,
-		"system/core/libutils":                                   Bp2BuildDefaultTrueRecursively,
-		"system/core/libvndksupport":                             Bp2BuildDefaultTrueRecursively,
-		"system/core/mkbootfs":                                   Bp2BuildDefaultTrueRecursively,
-		"system/core/property_service/libpropertyinfoparser":     Bp2BuildDefaultTrueRecursively,
-		"system/core/property_service/libpropertyinfoserializer": Bp2BuildDefaultTrueRecursively,
-		"system/extras/f2fs_utils":                               Bp2BuildDefaultTrueRecursively,
-		"system/extras/toolchain-extras":                         Bp2BuildDefaultTrue,
-		"system/extras/verity":                                   Bp2BuildDefaultTrueRecursively,
-		"system/hardware/interfaces/media":                       Bp2BuildDefaultTrueRecursively,
-		"system/incremental_delivery/incfs":                      Bp2BuildDefaultTrue,
-		"system/libartpalette":                                   Bp2BuildDefaultTrueRecursively,
-		"system/libbase":                                         Bp2BuildDefaultTrueRecursively,
-		"system/libfmq":                                          Bp2BuildDefaultTrue,
-		"system/libhidl/libhidlmemory":                           Bp2BuildDefaultTrue,
-		"system/libhidl/transport":                               Bp2BuildDefaultTrue,
-		"system/libhidl/transport/allocator/1.0":                 Bp2BuildDefaultTrue,
-		"system/libhidl/transport/base/1.0":                      Bp2BuildDefaultTrue,
-		"system/libhidl/transport/manager/1.0":                   Bp2BuildDefaultTrue,
-		"system/libhidl/transport/manager/1.1":                   Bp2BuildDefaultTrue,
-		"system/libhidl/transport/manager/1.2":                   Bp2BuildDefaultTrue,
-		"system/libhidl/transport/memory/1.0":                    Bp2BuildDefaultTrue,
-		"system/libhidl/transport/memory/token/1.0":              Bp2BuildDefaultTrue,
-		"system/libhidl/transport/safe_union/1.0":                Bp2BuildDefaultTrue,
-		"system/libhidl/transport/token/1.0":                     Bp2BuildDefaultTrue,
-		"system/libhidl/transport/token/1.0/utils":               Bp2BuildDefaultTrue,
-		"system/libhwbinder":                                     Bp2BuildDefaultTrueRecursively,
-		"system/libprocinfo":                                     Bp2BuildDefaultTrue,
-		"system/libvintf":                                        Bp2BuildDefaultTrue,
-		"system/libziparchive":                                   Bp2BuildDefaultTrueRecursively,
-		"system/logging":                                         Bp2BuildDefaultTrueRecursively,
-		"system/media":                                           Bp2BuildDefaultTrue,
-		"system/media/audio":                                     Bp2BuildDefaultTrueRecursively,
-		"system/media/alsa_utils":                                Bp2BuildDefaultTrueRecursively,
-		"system/media/audio_utils":                               Bp2BuildDefaultTrueRecursively,
-		"system/memory/libion":                                   Bp2BuildDefaultTrueRecursively,
-		"system/memory/libmemunreachable":                        Bp2BuildDefaultTrueRecursively,
-		"system/sepolicy/apex":                                   Bp2BuildDefaultTrueRecursively,
-		"system/security/fsverity":                               Bp2BuildDefaultTrueRecursively,
-		"system/testing/gtest_extras":                            Bp2BuildDefaultTrueRecursively,
-		"system/timezone/apex":                                   Bp2BuildDefaultTrueRecursively,
-		"system/timezone/output_data":                            Bp2BuildDefaultTrueRecursively,
-		"system/timezone/testdata":                               Bp2BuildDefaultTrueRecursively,
-		"system/timezone/testing":                                Bp2BuildDefaultTrueRecursively,
-		"system/tools/aidl/build/tests_bp2build":                 Bp2BuildDefaultTrue,
-		"system/tools/aidl/metadata":                             Bp2BuildDefaultTrue,
-		"system/tools/hidl/metadata":                             Bp2BuildDefaultTrue,
-		"system/tools/mkbootimg":                                 Bp2BuildDefaultTrueRecursively,
-		"system/tools/sysprop":                                   Bp2BuildDefaultTrue,
-		"system/tools/xsdc/utils":                                Bp2BuildDefaultTrueRecursively,
-		"system/unwinding/libunwindstack":                        Bp2BuildDefaultTrueRecursively,
-
-		"tools/apifinder":                            Bp2BuildDefaultTrue,
-		"tools/apksig":                               Bp2BuildDefaultTrue,
-		"tools/external_updater":                     Bp2BuildDefaultTrueRecursively,
-		"tools/metalava":                             Bp2BuildDefaultTrue,
-		"tools/platform-compat/java/android/compat":  Bp2BuildDefaultTrueRecursively,
-		"tools/tradefederation/prebuilts/filegroups": Bp2BuildDefaultTrueRecursively,
-	}
-
-	Bp2buildKeepExistingBuildFile = map[string]bool{
-		// This is actually build/bazel/build.BAZEL symlinked to ./BUILD
-		".":/*recursive = */ false,
-
-		"build/bazel":/* recursive = */ true,
-		"build/make/core":/* recursive = */ false,
-		"build/bazel_common_rules":/* recursive = */ true,
-		"build/make/target/product/security":/* recursive = */ false,
-		// build/make/tools/signapk BUILD file is generated, so build/make/tools is not recursive.
-		"build/make/tools":/* recursive = */ false,
-		"build/pesto":/* recursive = */ true,
-		"build/soong":/* recursive = */ true,
-
-		// external/bazelbuild-rules_android/... is needed by mixed builds, otherwise mixed builds analysis fails
-		// e.g. ERROR: Analysis of target '@soong_injection//mixed_builds:buildroot' failed
-		"external/bazelbuild-rules_android":/* recursive = */ true,
-		"external/bazelbuild-rules_java":/* recursive = */ true,
-		"external/bazelbuild-rules_license":/* recursive = */ true,
-		"external/bazelbuild-rules_go":/* recursive = */ true,
-		"external/bazelbuild-rules_python":/* recursive = */ true,
-		"external/bazelbuild-kotlin-rules":/* recursive = */ true,
-		"external/bazel-skylib":/* recursive = */ true,
-		"external/protobuf":/* recursive = */ false,
-		"external/python/absl-py":/* recursive = */ true,
-
-		"external/compiler-rt/lib/cfi":/* recursive = */ false,
-
-		// this BUILD file is globbed by //external/icu/icu4c/source:icu4c_test_data's "data/**/*".
-		"external/icu/icu4c/source/data/unidata/norm2":/* recursive = */ false,
-
-		// Building manually due to b/179889880: resource files cross package boundary
-		"packages/apps/Music":/* recursive = */ true,
-
-		"prebuilts/abi-dumps/platform":/* recursive = */ true,
-		"prebuilts/abi-dumps/ndk":/* recursive = */ true,
-		"prebuilts/bazel":/* recursive = */ true,
-		"prebuilts/bundletool":/* recursive = */ true,
-		"prebuilts/clang/host/linux-x86":/* recursive = */ false,
-		"prebuilts/clang-tools":/* recursive = */ true,
-		"prebuilts/gcc":/* recursive = */ true,
-		"prebuilts/build-tools":/* recursive = */ true,
-		"prebuilts/jdk/jdk17":/* recursive = */ true,
-		"prebuilts/misc":/* recursive = */ false, // not recursive because we need bp2build converted build files in prebuilts/misc/common/asm
-		"prebuilts/sdk":/* recursive = */ false,
-		"prebuilts/sdk/tools":/* recursive = */ false,
-		"prebuilts/r8":/* recursive = */ false,
-		"prebuilts/runtime":/* recursive = */ false,
-
-		// not recursive due to conflicting workspace paths in tools/atest/bazel/rules
-		"tools/asuite/atest":/* recursive = */ false,
-		"tools/asuite/atest/bazel/reporter":/* recursive = */ true,
-
-		// TODO(b/266459895): remove this and the placeholder BUILD file after re-enabling libunwindstack
-		"external/rust/crates/rustc-demangle-capi":/* recursive = */ false,
-
-		// Used for testing purposes only. Should not actually exist in the real source tree.
-		"testpkg/keep_build_file":/* recursive = */ false,
-	}
-
-	Bp2buildModuleAlwaysConvertList = []string{
-		// ext
-		"tagsoup",
-
-		// framework-res
-		"remote-color-resources-compile-public",
-		"remote-color-resources-compile-colors",
-
-		// framework-minus-apex
-		"android.mime.types.minimized",
-		"debian.mime.types.minimized",
-		"framework-javastream-protos",
-		"libview-inspector-annotation-processor",
-
-		// services
-		"apache-commons-math",
-		"cbor-java",
-		"icu4j_calendar_astronomer",
-		"json",
-		"remote-color-resources-compile-public",
-		"statslog-art-java-gen",
-		"statslog-framework-java-gen",
-
-		"AndroidCommonLint",
-		"ImmutabilityAnnotation",
-		"ImmutabilityAnnotationProcessorHostLibrary",
-
-		"libidmap2_policies",
-		"libSurfaceFlingerProp",
-		"toolbox_input_labels",
-
-		// cc mainline modules
-
-		// com.android.media.swcodec
-		"com.android.media.swcodec",
-		"com.android.media.swcodec-androidManifest",
-		"com.android.media.swcodec-ld.config.txt",
-		"com.android.media.swcodec-mediaswcodec.32rc",
-		"com.android.media.swcodec-mediaswcodec.rc",
-		"com.android.media.swcodec.certificate",
-		"com.android.media.swcodec.key",
-		"test_com.android.media.swcodec",
-
-		// deps
-		"code_coverage.policy",
-		"code_coverage.policy.other",
-		"codec2_soft_exports",
-		"compatibility_matrix_schema",
-		"framework-connectivity-protos",
-		"gemmlowp_headers",
-		"gl_headers",
-		"libandroid_runtime_lazy",
-		"libandroid_runtime_vm_headers",
-		"libaudioclient_aidl_conversion_util",
-		"libbinder",
-		"libbinder_device_interface_sources",
-		"libbinder_aidl",
-		"libbinder_headers",
-		"libbinder_headers_platform_shared",
-		"libbinderthreadstateutils",
-		"libbluetooth-types-header",
-		"libcodec2",
-		"libcodec2_headers",
-		"libcodec2_internal",
-		"libdmabufheap",
-		"libgsm",
-		"libgrallocusage",
-		"libgralloctypes",
-		"libnativewindow",
-		"libneuralnetworks",
-		"libneuralnetworks_static",
-		"libgraphicsenv",
-		"libhardware",
-		"libhardware_headers",
-		"libnativeloader-headers",
-		"libnativewindow_headers",
-		"libneuralnetworks_headers",
-		"libneuralnetworks_packageinfo",
-		"libopus",
-		"libprocpartition",
-		"libruy_static",
-		"libandroidio",
-		"libandroidio_srcs",
-		"libserviceutils",
-		"libsurfaceflinger_headers",
-		"libsync",
-		"libtextclassifier_hash_headers",
-		"libtextclassifier_hash_static",
-		"libtflite_kernel_utils",
-		"libtinyxml2",
-		"libui",
-		"libui-types",
-		"libui_headers",
-		"libvorbisidec",
-		"media_ndk_headers",
-		"media_plugin_headers",
-		"mediaswcodec.policy",
-		"mediaswcodec.xml",
-		"neuralnetworks_types",
-		"libneuralnetworks_common",
-		// packagemanager_aidl_interface is created implicitly in packagemanager_aidl module
-		"packagemanager_aidl_interface",
-		"philox_random",
-		"philox_random_headers",
-		"server_configurable_flags",
-		"service-permission-streaming-proto-sources",
-		"statslog_neuralnetworks.cpp",
-		"statslog_neuralnetworks.h",
-		"tensorflow_headers",
-
-		"libstagefright_bufferpool@2.0",
-		"libstagefright_bufferpool@2.0.1",
-		"libSurfaceFlingerProp",
-
-		// prebuilts
-		"prebuilt_stats-log-api-gen",
-
-		// fastboot
-		"fastboot",
-		"libfastboot",
-		"liblp",
-		"libstorage_literals_headers",
-
-		"PluginCoreLib",
-		"dagger2",
-		"dagger2-android-annotation-stubs",
-		"dagger2-bootstrap-compiler",
-		"dagger2-producers",
-		"okio-lib",
-		"setupdesign-strings",
-
-		//external/avb
-		"avbtool",
-		"libavb",
-		"avb_headers",
-
-		//external/libxml2
-		"xmllint",
-		"libxml2",
-
-		//external/fec
-		"libfec_rs",
-
-		//frameworks/base/core/java
-		"IDropBoxManagerService_aidl",
-
-		//system/extras/ext4_utils
-		"libext4_utils",
-		"mke2fs_conf",
-		"mkuserimg_mke2fs",
-		"blk_alloc_to_base_fs",
-
-		//system/extras/libfec
-		"libfec",
-
-		//system/extras/squashfs_utils
-		"libsquashfs_utils",
-
-		//packages/apps/Car/libs/car-ui-lib/car-ui-androidx
-		// genrule dependencies for java_imports
-		"car-ui-androidx-annotation-nodeps",
-		"car-ui-androidx-collection-nodeps",
-		"car-ui-androidx-core-common-nodeps",
-		"car-ui-androidx-lifecycle-common-nodeps",
-		"car-ui-androidx-constraintlayout-solver-nodeps",
-
-		//system/libhidl
-		"libhidlbase", // needed by cc_hidl_library
-		"libhidl_gtest_helper",
-
-		//frameworks/native/libs/input
-		"inputconstants_aidl",
-
-		// needed for aidl_interface's ndk backend
-		"libbinder_ndk",
-
-		"libusb",
-
-		// needed by liblogd
-		"ILogcatManagerService_aidl",
-		"libincremental_aidl-cpp",
-		"incremental_aidl",
-
-		//frameworks/native/cmds/cmd
-		"libcmd",
-
-		//system/core/fs_mgr/libdm
-		"libdm",
-
-		//system/core/fs_mgr/libfiemap
-		"libfiemap_headers",
-		"libfiemap_passthrough_srcs",
-		"libfiemap_srcs",
-
-		//system/gsid
-		"libgsi",
-		"libgsi_headers",
-
-		//system/core/libkeyutils
-		"libkeyutils",
-
-		//bootable/recovery/otautil
-		"libotautil",
-
-		//system/vold
-		"libvold_headers",
-
-		//system/extras/libfscrypt
-		"libfscrypt",
-
-		//system/core/fs_mgr
-		"libfstab",
-
-		//bootable/recovery/fuse_sideload
-		"libfusesideload",
-
-		//system/core/fs_mgr/libfs_avb
-		"libfs_avb",
-
-		//system/core/fs_mgr
-		"libfs_mgr",
-
-		"libcodec2_hidl@1.0",
-		"libcodec2_hidl@1.1",
-		"libcodec2_hidl@1.2",
-		"libcodec2_hidl_plugin_stub",
-		"libcodec2_hidl_plugin",
-		"libcodec2_hal_common",
-		"libstagefright_bufferqueue_helper_novndk",
-		"libGLESv2",
-		"libEGL",
-		"libcodec2_vndk",
-		"libnativeloader_lazy",
-		"libnativeloader",
-		"libEGL_getProcAddress",
-		"libEGL_blobCache",
-
-		"mediaswcodec",
-		"libmedia_headers",
-		"libmedia_codecserviceregistrant",
-		"libsfplugin_ccodec_utils",
-		"libcodec2_soft_aacenc",
-		"libcodec2_soft_amrnbdec",
-		"libcodec2_soft_amrnbenc",
-		"libcodec2_soft_amrwbdec",
-		"libcodec2_soft_amrwbenc",
-		"libcodec2_soft_hevcdec",
-		"libcodec2_soft_hevcenc",
-		"libcodec2_soft_g711alawdec",
-		"libcodec2_soft_g711mlawdec",
-		"libcodec2_soft_mpeg2dec",
-		"libcodec2_soft_h263dec",
-		"libcodec2_soft_h263enc",
-		"libcodec2_soft_mpeg4dec",
-		"libcodec2_soft_mpeg4enc",
-		"libcodec2_soft_mp3dec",
-		"libcodec2_soft_vorbisdec",
-		"libcodec2_soft_opusdec",
-		"libcodec2_soft_opusenc",
-		"libcodec2_soft_vp8dec",
-		"libcodec2_soft_vp9dec",
-		"libcodec2_soft_av1dec_gav1",
-		"libcodec2_soft_vp8enc",
-		"libcodec2_soft_vp9enc",
-		"libcodec2_soft_rawdec",
-		"libcodec2_soft_flacdec",
-		"libcodec2_soft_flacenc",
-		"libcodec2_soft_gsmdec",
-		"libcodec2_soft_avcdec",
-		"libcodec2_soft_avcenc",
-		"libcodec2_soft_aacdec",
-		"libcodec2_soft_common",
-
-		// kotlin srcs in java libs
-		"kotlinx_atomicfu",
-
-		// kotlin srcs in java binary
-		"AnalyzerKt",
-		"trebuchet-core",
-
-		// kotlin srcs in android_library
-		"renderscript_toolkit",
-
-		//kotlin srcs in android_binary
-		"MusicKotlin",
-
-		// java_library with prebuilt sdk_version
-		"android-common",
-
-		// checked in current.txt for merged_txts
-		"non-updatable-current.txt",
-		"non-updatable-system-current.txt",
-		"non-updatable-module-lib-current.txt",
-		"non-updatable-system-server-current.txt",
-
-		// for api_fingerprint.txt generation
-		"api_fingerprint",
-
-		// allowlisting for kotlinx_coroutines
-		"annotations",
-		"kotlinx-coroutines-android-annotation-stubs",
-		"kotlinx-coroutines-core",
-		"kotlinx_coroutines",
-		"kotlinx_coroutines-device",
-		"kotlinx_coroutines-host",
-
-		// for building com.android.neuralnetworks
-		"libimapper_stablec",
-		"libimapper_providerutils",
-
-		// min_sdk_version in android_app
-		"CtsShimUpgrade",
-
-		"art_cmdlineparser_headers",
-
-		// Mainline Module Apps
-		"CaptivePortalLogin",
-		"ModuleMetadata",
-
-		"libstagefright_headers",
-
-		// aidl
-		"aidl",
-		"libaidl-common",
-
-		// java_resources containing only a single filegroup
-		"libauto_value_plugin",
-		"auto_value_plugin_resources",
-		"auto_value_extension",
-
-		// Used by xsd_config
-		"xsdc",
-
-		// cc_test that can be run by b test
-		"binderRpcWireProtocolTest",
-		"binderUnitTest",
-		"cpu_features-bit_utils_test",
-		"liblp_test",
-		"android.hardware.audio.common.test.utility_tests",
-		"HalAudioStreamWorkerTest",
-		"libjavacore-unit-tests",
-		"NeuralNetworksTest_utils",
-		"NeuralNetworksTest_logtag",
-		"NeuralNetworksTest_operations",
-		"nanoapp_chqts_shared_tests",
-		"fakeservicemanager_test",
-		"tristate_test",
-		"binderUtilsHostTest",
-		"run_dex2oat_test",
-		"bluetooth-address-unit-tests",
-
-		// for platform_compat_config
-		"process-compat-config",
-
-		// cc_* modules with rscript srcs
-		"rstest-latency",
-		"libRScpp_static",
-		"rs-headers",
-		"rs_script_api",
-		"libRSDispatch",
-
-		// hal_unit_tests and deps
-		"android.hardware.contexthub_interface", // created implicitly by android.hardware.contexthub
-		"chre_flatbuffers",
-		"event_logger",
-		"hal_unit_tests",
-
-		"merge_annotation_zips_test",
-	}
-
-	Bp2buildModuleTypeAlwaysConvertList = []string{
-		"aidl_interface_headers",
-		"bpf",
-		"combined_apis",
-		"license",
-		"linker_config",
-		"java_import",
-		"java_import_host",
-		"java_sdk_library",
-		"sysprop_library",
-		"xsd_config",
-	}
-
-	// Add the names of modules that bp2build should never convert, if it is
-	// in the package allowlist.  An error will be thrown if a module must
-	// not be here and in the alwaysConvert lists.
-	//
-	// For prebuilt modules (e.g. android_library_import), remember to add
-	// the "prebuilt_" prefix to the name, so that it's differentiable from
-	// the source versions within Soong's module graph.
-	Bp2buildModuleDoNotConvertList = []string{
-		// TODO(b/263326760): Failed already.
-		"minijail_compiler_unittest",
-		"minijail_parser_unittest",
-
-		// Depends on unconverted libandroid, libgui
-		"dvr_buffer_queue-test",
-		"dvr_display-test",
-		// Depends on unconverted libchrome
-		"pdx_benchmarks",
-		"buffer_hub_queue-test",
-		"buffer_hub_queue_producer-test",
-
-		// cc bugs
-
-		// TODO(b/198619163) module has same name as source
-		"logtagd.rc",
-
-		"libgtest_ndk_c++", "libgtest_main_ndk_c++", // TODO(b/201816222): Requires sdk_version support.
-
-		// TODO(b/202876379): has arch-variant static_executable
-		"linkerconfig",
-		"mdnsd",
-		"libcutils_test_static",
-		"KernelLibcutilsTest",
-
-		"linker",    // TODO(b/228316882): cc_binary uses link_crt
-		"versioner", // TODO(b/228313961):  depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
-
-		// requires host tools for apexer
-		"apexer_test", "apexer_test_host_tools", "host_apex_verifier",
-
-		// java bugs
-		"libbase_ndk",  // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
-		"bouncycastle", // TODO(b/274474005): Need support for custom system_modules.
-
-		// genrule incompatibilities
-		"brotli-fuzzer-corpus",                                       // TODO(b/202015218): outputs are in location incompatible with bazel genrule handling.
-		"platform_tools_properties", "build_tools_source_properties", // TODO(b/203369847): multiple genrules in the same package creating the same file
-
-		// aar support
-		"prebuilt_car-ui-androidx-core-common", // TODO(b/224773339), genrule dependency creates an .aar, not a .jar
-		// ERROR: The dependencies for the following 1 jar(s) are not complete.
-		// 1.bazel-out/android_target-fastbuild/bin/prebuilts/tools/common/m2/_aar/robolectric-monitor-1.0.2-alpha1/classes_and_libs_merged.jar
-		"prebuilt_robolectric-monitor-1.0.2-alpha1",
-
-		// path property for filegroups
-		"conscrypt",                        // TODO(b/210751803), we don't handle path property for filegroups
-		"conscrypt-for-host",               // TODO(b/210751803), we don't handle path property for filegroups
-		"host-libprotobuf-java-full",       // TODO(b/210751803), we don't handle path property for filegroups
-		"libprotobuf-internal-python-srcs", // TODO(b/210751803), we don't handle path property for filegroups
-		"libprotobuf-java-full",            // TODO(b/210751803), we don't handle path property for filegroups
-		"libprotobuf-java-util-full",       // TODO(b/210751803), we don't handle path property for filegroups
-
-		// go deps:
-		"analyze_bcpf",              // depends on bpmodify a blueprint_go_binary.
-		"analyze_bcpf_test",         // depends on bpmodify a blueprint_go_binary.
-		"host_bionic_linker_asm",    // depends on extract_linker, a go binary.
-		"host_bionic_linker_script", // depends on extract_linker, a go binary.
-
-		// rust support
-		"libtombstoned_client_rust_bridge_code", "libtombstoned_client_wrapper", // rust conversions are not supported
-
-		// unconverted deps
-		"apexer_with_DCLA_preprocessing_test",                        // depends on unconverted modules: apexer_test_host_tools, com.android.example.apex
-		"adb",                                                        // depends on unconverted modules: AdbWinApi, libandroidfw, libopenscreen-discovery, libopenscreen-platform-impl, libusb, bin2c_fastdeployagent, AdbWinUsbApi
-		"android_icu4j_srcgen",                                       // depends on unconverted modules: currysrc
-		"android_icu4j_srcgen_binary",                                // depends on unconverted modules: android_icu4j_srcgen, currysrc
-		"apex_compression_test",                                      // depends on unconverted modules: soong_zip, com.android.example.apex
-		"apex_manifest_proto_java",                                   // b/210751803, depends on libprotobuf-java-full
-		"art-script",                                                 // depends on unconverted modules: dalvikvm, dex2oat
-		"bin2c_fastdeployagent",                                      // depends on unconverted modules: deployagent
-		"CarHTMLViewer",                                              // depends on unconverted modules android.car-stubs, car-ui-lib
-		"com.android.runtime",                                        // depends on unconverted modules: bionic-linker-config, linkerconfig
-		"currysrc",                                                   // depends on unconverted modules: currysrc_org.eclipse, guavalib, jopt-simple-4.9
-		"dex2oat-script",                                             // depends on unconverted modules: dex2oat
-		"generated_android_icu4j_resources",                          // depends on unconverted modules: android_icu4j_srcgen_binary
-		"generated_android_icu4j_test_resources",                     // depends on unconverted modules: android_icu4j_srcgen_binary
-		"host-libprotobuf-java-nano",                                 // b/220869005, depends on libprotobuf-java-nano
-		"jacoco-stubs",                                               // b/245767077, depends on droidstubs
-		"libapexutil",                                                // depends on unconverted modules: apex-info-list-tinyxml
-		"libart",                                                     // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api, art_operator_srcs, libcpu_features, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfile, libnativebridge, libnativeloader, libsigchain, libartbase, libprofile, cpp-define-generator-asm-support
-		"libart-runtime-gtest",                                       // depends on unconverted modules: libgtest_isolated, libart-compiler, libdexfile, libprofile, libartbase, libartbase-art-gtest
-		"libart_headers",                                             // depends on unconverted modules: art_libartbase_headers
-		"libartbase-art-gtest",                                       // depends on unconverted modules: libgtest_isolated, libart, libart-compiler, libdexfile, libprofile
-		"libartbased-art-gtest",                                      // depends on unconverted modules: libgtest_isolated, libartd, libartd-compiler, libdexfiled, libprofiled
-		"libart-runtime",                                             // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api, art_operator_srcs, libcpu_features, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfile, libnativebridge, libnativeloader, libsigchain, libartbase, libprofile, cpp-define-generator-asm-support
-		"libart-runtime-for-test",                                    // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api, art_operator_srcs, libcpu_features, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfile, libnativebridge, libnativeloader, libsigchain, libartbase, libprofile, cpp-define-generator-asm-support
-		"libartd",                                                    // depends on unconverted modules: art_operator_srcs, libcpu_features, libodrstatslog, libelffiled, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfiled, libnativebridge, libnativeloader, libsigchain, libartbased, libprofiled, cpp-define-generator-asm-support, apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api
-		"libartd-runtime",                                            // depends on unconverted modules: art_operator_srcs, libcpu_features, libodrstatslog, libelffiled, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfiled, libnativebridge, libnativeloader, libsigchain, libartbased, libprofiled, cpp-define-generator-asm-support, apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api
-		"libartd-runtime-gtest",                                      // depends on unconverted modules: libgtest_isolated, libartd-compiler, libdexfiled, libprofiled, libartbased, libartbased-art-gtest
-		"libdebuggerd",                                               // depends on unconverted module: libdexfile
-		"libdebuggerd_handler",                                       // depends on unconverted module libdebuggerd_handler_core
-		"libdebuggerd_handler_core", "libdebuggerd_handler_fallback", // depends on unconverted module libdebuggerd
-		"libdexfiled",                                             // depends on unconverted modules: dexfile_operator_srcs, libartbased, libartpalette
-		"libgmock_main_ndk",                                       // depends on unconverted modules: libgtest_ndk_c++
-		"libgmock_ndk",                                            // depends on unconverted modules: libgtest_ndk_c++
-		"libnativehelper_lazy_mts_jni", "libnativehelper_mts_jni", // depends on unconverted modules: libnativetesthelper_jni, libgmock_ndk
-		"libnativetesthelper_jni",   // depends on unconverted modules: libgtest_ndk_c++
-		"libstatslog",               // depends on unconverted modules: libstatspull, statsd-aidl-ndk
-		"libstatslog_art",           // depends on unconverted modules: statslog_art.cpp, statslog_art.h
-		"linker_reloc_bench_main",   // depends on unconverted modules: liblinker_reloc_bench_*
-		"malloc-rss-benchmark",      // depends on unconverted modules: libmeminfo
-		"pbtombstone", "crash_dump", // depends on libdebuggerd, libunwindstack
-		"releasetools_test",             // depends on unconverted modules: com.android.apex.compressed.v1
-		"robolectric-sqlite4java-0.282", // depends on unconverted modules: robolectric-sqlite4java-import, robolectric-sqlite4java-native
-		"static_crasher",                // depends on unconverted modules: libdebuggerd_handler
-		"test_fips",                     // depends on unconverted modules: adb
-		"timezone-host",                 // depends on unconverted modules: art.module.api.annotations
-
-		// aidl files not created
-		"overlayable_policy_aidl_interface",
-
-		//prebuilts/tools/common/m2
-		// depends on //external/okio:okio-lib, which uses kotlin
-		"wire-runtime",
-
-		// depends on adbd_system_api_recovery, which is a unconverted `phony` module type
-		"minadbd",
-
-		// depends on android.hardware.health-V2.0-java
-		"android.hardware.health-translate-java",
-
-		//system/libvintf
-		// depends on apex-info-list-tinyxml, unconverted xsd_config Soong module type.
-		"libassemblevintf",
-		"assemble_vintf",
-		"checkvintf",
-
-		// depends on audio_policy_configuration_aidl_default, xsd_config module.
-		"libaudioserviceexampleimpl",
-		"android.hardware.audio.service-aidl.example",
-
-		// depends on //system/tools/aidl/build:aidl_metadata_json, which is an aidl_interfaces_metadata custom Soong type.
-		"aidl_metadata_in_cpp",
-		"libaidlmetadata",
-		"libaidlmetadata_test",
-
-		// depends on //system/tools/hidl/build:hidl_metadata_json, which is an hidl_interfaces_metadata custom Soong type.
-		"hidl_metadata_in_cpp",
-		"libhidlmetadata",
-		"hidl_metadata_test",
-
-		// cc_test related.
-		// b/274164834 "Could not open Configuration file test.cfg"
-		"svcenc", "svcdec",
-
-		// Failing host cc_tests
-		"gtest_isolated_tests",
-		"libunwindstack_unit_test",
-		"power_tests", // failing test on server, but not on host
-
-		// reflect: call of reflect.Value.NumField on interface Value
-		// affects all cc_tests that depend on art_defaults
-		"libnativebridge-tests",
-		"libnativeloader_test",
-		"art_libnativebridge_cts_tests",
-		"art_standalone_libdexfile_external_tests",
-		"art_standalone_libdexfile_support_tests",
-		"libnativebridge-lazy-tests",
-		"libnativebridge-test-case",
-		"libnativebridge2-test-case",
-		"libnativebridge3-test-case",
-		"libnativebridge6-test-case",
-		"libnativebridge6prezygotefork",
-
-		"libandroidfw_tests", // failing due to data path issues
-
-		// error: overriding commands for target
-		// `out/host/linux-x86/nativetest64/gmock_tests/gmock_tests__cc_runner_test',
-		// previously defined at out/soong/installs-aosp_arm.mk:64919`
-		"gmock_tests",
-
-		// cc_test with unconverted deps, or are device-only (and not verified to pass yet)
-		"AMRWBEncTest",
-		"AmrnbDecoderTest", // depends on unconverted modules: libaudioutils, libsndfile
-		"AmrnbEncoderTest", // depends on unconverted modules: libaudioutils, libsndfile
-		"AmrwbDecoderTest", // depends on unconverted modules: libsndfile, libaudioutils
-		"AmrwbEncoderTest", // depends on unconverted modules: libaudioutils, libsndfile
-		"Mp3DecoderTest",   // depends on unconverted modules: libsndfile, libaudioutils
-		"avcdec",
-		"avcenc",
-		"bionic-benchmarks-tests",
-		"bionic-fortify-runtime-asan-test",
-		"bionic-stress-tests",
-		"bionic-unit-tests",
-		"bionic-unit-tests-glibc",
-		"bionic-unit-tests-static",
-		"boringssl_crypto_test",
-		"boringssl_ssl_test",
-		"boringssl_test_support", //b/244431896
-		"cfi_test_helper",
-		"cfi_test_helper2",
-		"cintltst32",
-		"cintltst64",
-		"compare",
-		"cpuid",
-		"debuggerd_test", // depends on unconverted modules: libdebuggerd
-		"elftls_dlopen_ie_error_helper",
-		"exec_linker_helper",
-		"fastdeploy_test", // depends on unconverted modules: AdbWinApi, libadb_host, libandroidfw, libfastdeploy_host, libopenscreen-discovery, libopenscreen-platform-impl, libusb
-		"fdtrack_test",
-		"google-benchmark-test",
-		"googletest-param-test-test_ndk", // depends on unconverted modules: libgtest_ndk_c++
-		"gtest-typed-test_test",
-		"gtest-typed-test_test_ndk", // depends on unconverted modules: libgtest_ndk_c++, libgtest_main_ndk_c++
-		"gtest_ndk_tests",           // depends on unconverted modules: libgtest_ndk_c++, libgtest_main_ndk_c++
-		"gtest_ndk_tests_no_main",   // depends on unconverted modules: libgtest_ndk_c++
-		"gtest_prod_test_ndk",       // depends on unconverted modules: libgtest_ndk_c++, libgtest_main_ndk_c++
-		"gtest_tests",
-		"gtest_tests_no_main",
-		"gwp_asan_unittest",
-		"half_test",
-		"hashcombine_test",
-		"hevcdec",
-		"hevcenc",
-		"hwbinderThroughputTest", // depends on unconverted modules: android.hardware.tests.libhwbinder@1.0-impl.test, android.hardware.tests.libhwbinder@1.0
-		"i444tonv12_eg",
-		"icu4c_sample_break",
-		"intltest32",
-		"intltest64",
-		"ion-unit-tests",
-		"jemalloc5_integrationtests",
-		"jemalloc5_unittests",
-		"ld_config_test_helper",
-		"ld_preload_test_helper",
-		"libBionicCtsGtestMain", // depends on unconverted modules: libgtest_isolated
-		"libBionicLoaderTests",  // depends on unconverted modules: libmeminfo
-		"libapexutil_tests",     // depends on unconverted modules: apex-info-list-tinyxml, libapexutil
-		"libcutils_sockets_test",
-		"libhwbinder_latency",
-		"liblog-host-test", // failing tests
-		"libminijail_test",
-		"libminijail_unittest_gtest",
-		"libpackagelistparser_test",
-		"libprotobuf_vendor_suffix_test",
-		"libstagefright_amrnbdec_test", // depends on unconverted modules: libsndfile, libaudioutils
-		"libstagefright_amrnbenc_test",
-		"libstagefright_amrwbdec_test", // depends on unconverted modules: libsndfile, libaudioutils
-		"libstagefright_m4vh263enc_test",
-		"libstagefright_mp3dec_test", // depends on unconverted modules: libsndfile, libaudioutils
-		"libstatssocket_test",
-		"libvndksupport-tests",
-		"libyuv_unittest",
-		"linker-unit-tests",
-		"malloc_debug_system_tests",
-		"malloc_debug_unit_tests",
-		"malloc_hooks_system_tests",
-		"mat_test",
-		"mathtest",
-		"memunreachable_binder_test", // depends on unconverted modules: libbinder
-		"memunreachable_test",
-		"metadata_tests",
-		"mpeg2dec",
-		"mvcdec",
-		"ns_hidden_child_helper",
-		"pngtest",
-		"preinit_getauxval_test_helper",
-		"preinit_syscall_test_helper",
-		"psnr",
-		"quat_test",
-		"rappor-tests", // depends on unconverted modules: jsr305, guava
-		"scudo_unit_tests",
-		"stats-log-api-gen-test", // depends on unconverted modules: libstats_proto_host
-		"thread_exit_cb_helper",
-		"tls_properties_helper",
-		"ulp",
-		"vec_test",
-		"yuvconstants",
-		"yuvconvert",
-
-		// cc_test_library
-		"clang_diagnostic_tests",
-		"exec_linker_helper_lib",
-		"fortify_disabled_for_tidy",
-		"ld_config_test_helper_lib1",
-		"ld_config_test_helper_lib2",
-		"ld_config_test_helper_lib3",
-		"ld_preload_test_helper_lib1",
-		"ld_preload_test_helper_lib2",
-		"libBionicElfTlsLoaderTests",
-		"libBionicElfTlsTests",
-		"libBionicElfTlsTests",
-		"libBionicFramePointerTests",
-		"libBionicFramePointerTests",
-		"libBionicStandardTests",
-		"libBionicStandardTests",
-		"libBionicTests",
-		"libart-broken",
-		"libatest_simple_zip",
-		"libcfi-test",
-		"libcfi-test-bad",
-		"libcrash_test",
-		"libcrypto_fuzz_unsafe",
-		"libdl_preempt_test_1",
-		"libdl_preempt_test_2",
-		"libdl_test_df_1_global",
-		"libdlext_test",
-		"libdlext_test_different_soname",
-		"libdlext_test_fd",
-		"libdlext_test_norelro",
-		"libdlext_test_recursive",
-		"libdlext_test_zip",
-		"libdvrcommon_test",
-		"libfortify1-new-tests-clang",
-		"libfortify1-new-tests-clang",
-		"libfortify1-tests-clang",
-		"libfortify1-tests-clang",
-		"libfortify2-new-tests-clang",
-		"libfortify2-new-tests-clang",
-		"libfortify2-tests-clang",
-		"libfortify2-tests-clang",
-		"libgnu-hash-table-library",
-		"libicutest_static",
-		"liblinker_reloc_bench_000",
-		"liblinker_reloc_bench_001",
-		"liblinker_reloc_bench_002",
-		"liblinker_reloc_bench_003",
-		"liblinker_reloc_bench_004",
-		"liblinker_reloc_bench_005",
-		"liblinker_reloc_bench_006",
-		"liblinker_reloc_bench_007",
-		"liblinker_reloc_bench_008",
-		"liblinker_reloc_bench_009",
-		"liblinker_reloc_bench_010",
-		"liblinker_reloc_bench_011",
-		"liblinker_reloc_bench_012",
-		"liblinker_reloc_bench_013",
-		"liblinker_reloc_bench_014",
-		"liblinker_reloc_bench_015",
-		"liblinker_reloc_bench_016",
-		"liblinker_reloc_bench_017",
-		"liblinker_reloc_bench_018",
-		"liblinker_reloc_bench_019",
-		"liblinker_reloc_bench_020",
-		"liblinker_reloc_bench_021",
-		"liblinker_reloc_bench_022",
-		"liblinker_reloc_bench_023",
-		"liblinker_reloc_bench_024",
-		"liblinker_reloc_bench_025",
-		"liblinker_reloc_bench_026",
-		"liblinker_reloc_bench_027",
-		"liblinker_reloc_bench_028",
-		"liblinker_reloc_bench_029",
-		"liblinker_reloc_bench_030",
-		"liblinker_reloc_bench_031",
-		"liblinker_reloc_bench_032",
-		"liblinker_reloc_bench_033",
-		"liblinker_reloc_bench_034",
-		"liblinker_reloc_bench_035",
-		"liblinker_reloc_bench_036",
-		"liblinker_reloc_bench_037",
-		"liblinker_reloc_bench_038",
-		"liblinker_reloc_bench_039",
-		"liblinker_reloc_bench_040",
-		"liblinker_reloc_bench_041",
-		"liblinker_reloc_bench_042",
-		"liblinker_reloc_bench_043",
-		"liblinker_reloc_bench_044",
-		"liblinker_reloc_bench_045",
-		"liblinker_reloc_bench_046",
-		"liblinker_reloc_bench_047",
-		"liblinker_reloc_bench_048",
-		"liblinker_reloc_bench_049",
-		"liblinker_reloc_bench_050",
-		"liblinker_reloc_bench_051",
-		"liblinker_reloc_bench_052",
-		"liblinker_reloc_bench_053",
-		"liblinker_reloc_bench_054",
-		"liblinker_reloc_bench_055",
-		"liblinker_reloc_bench_056",
-		"liblinker_reloc_bench_057",
-		"liblinker_reloc_bench_058",
-		"liblinker_reloc_bench_059",
-		"liblinker_reloc_bench_060",
-		"liblinker_reloc_bench_061",
-		"liblinker_reloc_bench_062",
-		"liblinker_reloc_bench_063",
-		"liblinker_reloc_bench_064",
-		"liblinker_reloc_bench_065",
-		"liblinker_reloc_bench_066",
-		"liblinker_reloc_bench_067",
-		"liblinker_reloc_bench_068",
-		"liblinker_reloc_bench_069",
-		"liblinker_reloc_bench_070",
-		"liblinker_reloc_bench_071",
-		"liblinker_reloc_bench_072",
-		"liblinker_reloc_bench_073",
-		"liblinker_reloc_bench_074",
-		"liblinker_reloc_bench_075",
-		"liblinker_reloc_bench_076",
-		"liblinker_reloc_bench_077",
-		"liblinker_reloc_bench_078",
-		"liblinker_reloc_bench_079",
-		"liblinker_reloc_bench_080",
-		"liblinker_reloc_bench_081",
-		"liblinker_reloc_bench_082",
-		"liblinker_reloc_bench_083",
-		"liblinker_reloc_bench_084",
-		"liblinker_reloc_bench_085",
-		"liblinker_reloc_bench_086",
-		"liblinker_reloc_bench_087",
-		"liblinker_reloc_bench_088",
-		"liblinker_reloc_bench_089",
-		"liblinker_reloc_bench_090",
-		"liblinker_reloc_bench_091",
-		"liblinker_reloc_bench_092",
-		"liblinker_reloc_bench_093",
-		"liblinker_reloc_bench_094",
-		"liblinker_reloc_bench_095",
-		"liblinker_reloc_bench_096",
-		"liblinker_reloc_bench_097",
-		"liblinker_reloc_bench_098",
-		"liblinker_reloc_bench_099",
-		"liblinker_reloc_bench_100",
-		"liblinker_reloc_bench_101",
-		"liblinker_reloc_bench_102",
-		"liblinker_reloc_bench_103",
-		"liblinker_reloc_bench_104",
-		"liblinker_reloc_bench_105",
-		"liblinker_reloc_bench_106",
-		"liblinker_reloc_bench_107",
-		"liblinker_reloc_bench_108",
-		"liblinker_reloc_bench_109",
-		"liblinker_reloc_bench_110",
-		"liblinker_reloc_bench_111",
-		"liblinker_reloc_bench_112",
-		"liblinker_reloc_bench_113",
-		"liblinker_reloc_bench_114",
-		"liblinker_reloc_bench_115",
-		"liblinker_reloc_bench_116",
-		"liblinker_reloc_bench_117",
-		"liblinker_reloc_bench_118",
-		"liblinker_reloc_bench_119",
-		"liblinker_reloc_bench_120",
-		"liblinker_reloc_bench_121",
-		"liblinker_reloc_bench_122",
-		"liblinker_reloc_bench_123",
-		"liblinker_reloc_bench_124",
-		"liblinker_reloc_bench_125",
-		"liblinker_reloc_bench_126",
-		"liblinker_reloc_bench_127",
-		"liblinker_reloc_bench_128",
-		"liblinker_reloc_bench_129",
-		"liblinker_reloc_bench_130",
-		"liblinker_reloc_bench_131",
-		"liblinker_reloc_bench_132",
-		"liblinker_reloc_bench_133",
-		"liblinker_reloc_bench_134",
-		"liblinker_reloc_bench_135",
-		"liblinker_reloc_bench_136",
-		"liblinker_reloc_bench_137",
-		"liblinker_reloc_bench_138",
-		"liblinker_reloc_bench_139",
-		"liblinker_reloc_bench_140",
-		"liblinker_reloc_bench_141",
-		"liblinker_reloc_bench_142",
-		"liblinker_reloc_bench_143",
-		"liblinker_reloc_bench_144",
-		"liblinker_reloc_bench_145",
-		"liblinker_reloc_bench_146",
-		"liblinker_reloc_bench_147",
-		"liblinker_reloc_bench_148",
-		"liblinker_reloc_bench_149",
-		"liblinker_reloc_bench_150",
-		"liblinker_reloc_bench_151",
-		"liblinker_reloc_bench_152",
-		"liblinker_reloc_bench_153",
-		"liblinker_reloc_bench_154",
-		"liblinker_reloc_bench_155",
-		"liblinker_reloc_bench_156",
-		"liblinker_reloc_bench_157",
-		"liblinker_reloc_bench_158",
-		"liblinker_reloc_bench_159",
-		"liblinker_reloc_bench_160",
-		"liblinker_reloc_bench_161",
-		"liblinker_reloc_bench_162",
-		"liblinker_reloc_bench_163",
-		"liblinker_reloc_bench_164",
-		"liblinker_reloc_bench_165",
-		"liblinker_reloc_bench_166",
-		"liblinker_reloc_bench_167",
-		"liblinker_reloc_bench_168",
-		"libns_hidden_child_app",
-		"libns_hidden_child_global",
-		"libns_hidden_child_internal",
-		"libns_hidden_child_public",
-		"libnstest_dlopened",
-		"libnstest_ns_a_public1",
-		"libnstest_ns_a_public1_internal",
-		"libnstest_ns_b_public2",
-		"libnstest_ns_b_public3",
-		"libnstest_private",
-		"libnstest_private_external",
-		"libnstest_public",
-		"libnstest_public_internal",
-		"libnstest_root",
-		"libnstest_root_not_isolated",
-		"librelocations-ANDROID_REL",
-		"librelocations-ANDROID_RELR",
-		"librelocations-RELR",
-		"librelocations-fat",
-		"libsegment_gap_inner",
-		"libsegment_gap_outer",
-		"libssl_fuzz_unsafe",
-		"libstatssocket_private",
-		"libsysv-hash-table-library",
-		"libtest_atexit",
-		"libtest_check_order_dlsym",
-		"libtest_check_order_dlsym_1_left",
-		"libtest_check_order_dlsym_2_right",
-		"libtest_check_order_dlsym_3_c",
-		"libtest_check_order_dlsym_a",
-		"libtest_check_order_dlsym_b",
-		"libtest_check_order_dlsym_d",
-		"libtest_check_order_reloc_root",
-		"libtest_check_order_reloc_root_1",
-		"libtest_check_order_reloc_root_2",
-		"libtest_check_order_reloc_siblings",
-		"libtest_check_order_reloc_siblings_1",
-		"libtest_check_order_reloc_siblings_2",
-		"libtest_check_order_reloc_siblings_3",
-		"libtest_check_order_reloc_siblings_a",
-		"libtest_check_order_reloc_siblings_b",
-		"libtest_check_order_reloc_siblings_c",
-		"libtest_check_order_reloc_siblings_c_1",
-		"libtest_check_order_reloc_siblings_c_2",
-		"libtest_check_order_reloc_siblings_d",
-		"libtest_check_order_reloc_siblings_e",
-		"libtest_check_order_reloc_siblings_f",
-		"libtest_check_rtld_next_from_library",
-		"libtest_dlopen_df_1_global",
-		"libtest_dlopen_from_ctor",
-		"libtest_dlopen_from_ctor_main",
-		"libtest_dlopen_weak_undefined_func",
-		"libtest_dlsym_df_1_global",
-		"libtest_dlsym_from_this",
-		"libtest_dlsym_from_this_child",
-		"libtest_dlsym_from_this_grandchild",
-		"libtest_dlsym_weak_func",
-		"libtest_dt_runpath_a",
-		"libtest_dt_runpath_b",
-		"libtest_dt_runpath_c",
-		"libtest_dt_runpath_d",
-		"libtest_dt_runpath_d_zip",
-		"libtest_dt_runpath_x",
-		"libtest_dt_runpath_y",
-		"libtest_elftls_dynamic",
-		"libtest_elftls_dynamic_filler_1",
-		"libtest_elftls_dynamic_filler_2",
-		"libtest_elftls_dynamic_filler_3",
-		"libtest_elftls_shared_var",
-		"libtest_elftls_shared_var_ie",
-		"libtest_elftls_tprel",
-		"libtest_empty",
-		"libtest_ifunc",
-		"libtest_ifunc_variable",
-		"libtest_ifunc_variable_impl",
-		"libtest_indirect_thread_local_dtor",
-		"libtest_init_fini_order_child",
-		"libtest_init_fini_order_grand_child",
-		"libtest_init_fini_order_root",
-		"libtest_init_fini_order_root2",
-		"libtest_missing_symbol",
-		"libtest_missing_symbol_child_private",
-		"libtest_missing_symbol_child_public",
-		"libtest_missing_symbol_root",
-		"libtest_nodelete_1",
-		"libtest_nodelete_2",
-		"libtest_nodelete_dt_flags_1",
-		"libtest_pthread_atfork",
-		"libtest_relo_check_dt_needed_order",
-		"libtest_relo_check_dt_needed_order_1",
-		"libtest_relo_check_dt_needed_order_2",
-		"libtest_simple",
-		"libtest_thread_local_dtor",
-		"libtest_thread_local_dtor2",
-		"libtest_two_parents_child",
-		"libtest_two_parents_parent1",
-		"libtest_two_parents_parent2",
-		"libtest_versioned_lib",
-		"libtest_versioned_libv1",
-		"libtest_versioned_libv2",
-		"libtest_versioned_otherlib",
-		"libtest_versioned_otherlib_empty",
-		"libtest_versioned_uselibv1",
-		"libtest_versioned_uselibv2",
-		"libtest_versioned_uselibv2_other",
-		"libtest_versioned_uselibv3_other",
-		"libtest_with_dependency",
-		"libtest_with_dependency_loop",
-		"libtest_with_dependency_loop_a",
-		"libtest_with_dependency_loop_b",
-		"libtest_with_dependency_loop_b_tmp",
-		"libtest_with_dependency_loop_c",
-		"libtestshared",
-
-		// depends on unconverted libprotobuf-java-nano
-		"dnsresolverprotosnano",
-		"launcherprotosnano",
-		"datastallprotosnano",
-		"devicepolicyprotosnano",
-		"ota_metadata_proto_java",
-		"merge_ota",
-
-		// releasetools
-		"verity_utils",
-		"check_ota_package_signature",
-		"check_target_files_vintf",
-		"releasetools_check_target_files_vintf",
-		"ota_from_target_files",
-		"releasetools_ota_from_target_files",
-		"add_img_to_target_files",
-		"releasetools_add_img_to_target_files",
-		"fsverity_metadata_generator",
-		"sign_target_files_apks",
-
-		// depends on the support of yacc file
-		"libapplypatch",
-		"libapplypatch_modes",
-		"applypatch",
-
-		// TODO(b/254476335): disable the following due to this bug
-		"libapexinfo",
-		"libapexinfo_tests",
-
-		// uses glob in $(locations)
-		"libc_musl_sysroot",
-
-		// TODO(b/266459895): depends on libunwindstack
-		"libutils_test",
-
-		// Has dependencies on other tools like ziptool, bp2build'd data properties don't work with these tests atm
-		"ziparchive_tests_large",
-		"mkbootimg_test",
-		"certify_bootimg_test",
-
-		// Despite being _host module types, these require devices to run
-		"logd_integration_test",
-		"mobly-hello-world-test",
-		"mobly-multidevice-test",
-
-		// TODO(b/274805756): Support core_platform and current java APIs
-		"fake-framework",
-
-		// TODO(b/277616982): These modules depend on private java APIs, but maybe they don't need to.
-		"StreamingProtoTest",
-		"textclassifierprotoslite",
-		"styleprotoslite",
-		"CtsPkgInstallerConstants",
-		"guava-android-testlib",
-
-		"MetaDataBaseUnitTest", // depends on libstagefright
-		"AVCUtilsUnitTest",     // depends on libstagefright
-		"ColorUtilsTest",       // depends on libmediandk
-
-		// python_test_host with test data
-		"sbom_writers_test",
-
-		// TODO(B/283193845): tradefed and its java_test_host dependents
-		"tradefed",
-		"permissive_mte_test",
-		"ICU4CTestRunner",
-		"DeviceLongPollingStubTest",
-
-		"libprotobuf-full-test", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
-		"libprotobuf-lite-test", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
-
-		"logcat", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
-
-		"expresscatalogvalidator", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
-
-		// depends on other //art modules
-		"libart-for-test",
-		"libart_generated_headers",
-		"libart-runtime-gtest",
-		"libartd-runtime-gtest",
-		"libart-unstripped",
-
-		// depends on libart-unstripped and new module type llvm_prebuilt_build_tool
-		"check_cfi",
-	}
-
-	// Bazel prod-mode allowlist. Modules in this list are built by Bazel
-	// in either prod mode or staging mode.
-	ProdMixedBuildsEnabledList = []string{
-		// M5: tzdata launch
-		"com.android.tzdata",
-		"test1_com.android.tzdata",
-		"test3_com.android.tzdata",
-		// M7: adbd launch
-		"com.android.adbd",
-		"test_com.android.adbd",
-		"adbd_test",
-		"adb_crypto_test",
-		"adb_pairing_auth_test",
-		"adb_pairing_connection_test",
-		"adb_tls_connection_test",
-		// M9: mixed builds for mainline trains launch
-		"api_fingerprint",
-		// M11: neuralnetworks launch
-		"com.android.neuralnetworks",
-		"test_com.android.neuralnetworks",
-		"libneuralnetworks",
-		"libneuralnetworks_static",
-		// M13: media.swcodec launch
-		"com.android.media.swcodec",
-		"test_com.android.media.swcodec",
-		"libstagefright_foundation",
-		"libcodec2_hidl@1.0",
-	}
-
-	// Staging-mode allowlist. Modules in this list are only built
-	// by Bazel with --bazel-mode-staging. This list should contain modules
-	// which will soon be added to the prod allowlist.
-	// It is implicit that all modules in ProdMixedBuildsEnabledList will
-	// also be built - do not add them to this list.
-	StagingMixedBuildsEnabledList = []string{}
-
-	// These should be the libs that are included by the apexes in the ProdMixedBuildsEnabledList
-	ProdDclaMixedBuildsEnabledList = []string{
-		"libbase",
-		"libc++",
-		"libcrypto",
-		"libcutils",
-		"libstagefright_flacdec",
-		"libutils",
-	}
-
-	// These should be the libs that are included by the apexes in the StagingMixedBuildsEnabledList
-	StagingDclaMixedBuildsEnabledList = []string{}
-
-	// TODO(b/269342245): Enable the rest of the DCLA libs
-	// "libssl",
-
 	// The list of module types which are expected to spend lots of build time.
 	// With `--ninja_weight_source=soong`, ninja builds these module types and deps first.
 	HugeModuleTypePrefixMap = map[string]int{
@@ -1612,14 +33,4 @@
 		"art_":        DEFAULT_PRIORITIZED_WEIGHT,
 		"ndk_library": DEFAULT_PRIORITIZED_WEIGHT,
 	}
-
-	BazelSandwichTargets = []struct {
-		Label string
-		Host  bool
-	}{
-		{
-			Label: "//build/bazel/examples/partitions:system_image",
-			Host:  false,
-		},
-	}
 )
diff --git a/android/androidmk.go b/android/androidmk.go
index 62f82f2..07f7c58 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -30,6 +30,7 @@
 	"reflect"
 	"runtime"
 	"sort"
+	"strconv"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -159,7 +160,7 @@
 }
 
 type AndroidMkExtraEntriesContext interface {
-	Provider(provider blueprint.ProviderKey) interface{}
+	Provider(provider blueprint.AnyProviderKey) (any, bool)
 }
 
 type androidMkExtraEntriesContext struct {
@@ -167,8 +168,8 @@
 	mod blueprint.Module
 }
 
-func (a *androidMkExtraEntriesContext) Provider(provider blueprint.ProviderKey) interface{} {
-	return a.ctx.ModuleProvider(a.mod, provider)
+func (a *androidMkExtraEntriesContext) Provider(provider blueprint.AnyProviderKey) (any, bool) {
+	return a.ctx.moduleProvider(a.mod, provider)
 }
 
 type AndroidMkExtraEntriesFunc func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries)
@@ -275,14 +276,17 @@
 }
 
 // AddCompatibilityTestSuites adds the supplied test suites to the EntryMap, with special handling
-// for partial MTS test suites.
+// for partial MTS and MCTS test suites.
 func (a *AndroidMkEntries) AddCompatibilityTestSuites(suites ...string) {
-	// MTS supports a full test suite and partial per-module MTS test suites, with naming mts-${MODULE}.
-	// To reduce repetition, if we find a partial MTS test suite without an full MTS test suite,
+	// M(C)TS supports a full test suite and partial per-module MTS test suites, with naming mts-${MODULE}.
+	// To reduce repetition, if we find a partial M(C)TS test suite without an full M(C)TS test suite,
 	// we add the full test suite to our list.
 	if PrefixInList(suites, "mts-") && !InList("mts", suites) {
 		suites = append(suites, "mts")
 	}
+	if PrefixInList(suites, "mcts-") && !InList("mcts", suites) {
+		suites = append(suites, "mcts")
+	}
 	a.AddStrings("LOCAL_COMPATIBILITY_SUITE", suites...)
 }
 
@@ -486,25 +490,13 @@
 	return generateDistContributionsForMake(distContributions)
 }
 
-// Write the license variables to Make for AndroidMkData.Custom(..) methods that do not call WriteAndroidMkData(..)
-// It's required to propagate the license metadata even for module types that have non-standard interfaces to Make.
-func (a *AndroidMkEntries) WriteLicenseVariables(w io.Writer) {
-	AndroidMkEmitAssignList(w, "LOCAL_LICENSE_KINDS", a.EntryMap["LOCAL_LICENSE_KINDS"])
-	AndroidMkEmitAssignList(w, "LOCAL_LICENSE_CONDITIONS", a.EntryMap["LOCAL_LICENSE_CONDITIONS"])
-	AndroidMkEmitAssignList(w, "LOCAL_NOTICE_FILE", a.EntryMap["LOCAL_NOTICE_FILE"])
-	if pn, ok := a.EntryMap["LOCAL_LICENSE_PACKAGE_NAME"]; ok {
-		AndroidMkEmitAssignList(w, "LOCAL_LICENSE_PACKAGE_NAME", pn)
-	}
-}
-
 // fillInEntries goes through the common variable processing and calls the extra data funcs to
 // generate and fill in AndroidMkEntries's in-struct data, ready to be flushed to a file.
 type fillInEntriesContext interface {
 	ModuleDir(module blueprint.Module) string
 	ModuleSubDir(module blueprint.Module) string
 	Config() Config
-	ModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{}
-	ModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool
+	moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
 	ModuleType(module blueprint.Module) string
 }
 
@@ -534,15 +526,6 @@
 	// Collect make variable assignment entries.
 	a.SetString("LOCAL_PATH", ctx.ModuleDir(mod))
 	a.SetString("LOCAL_MODULE", name+a.SubName)
-	a.AddStrings("LOCAL_LICENSE_KINDS", base.commonProperties.Effective_license_kinds...)
-	a.AddStrings("LOCAL_LICENSE_CONDITIONS", base.commonProperties.Effective_license_conditions...)
-	a.AddStrings("LOCAL_NOTICE_FILE", base.commonProperties.Effective_license_text.Strings()...)
-	// TODO(b/151177513): Does this code need to set LOCAL_MODULE_IS_CONTAINER ?
-	if base.commonProperties.Effective_package_name != nil {
-		a.SetString("LOCAL_LICENSE_PACKAGE_NAME", *base.commonProperties.Effective_package_name)
-	} else if len(base.commonProperties.Effective_licenses) > 0 {
-		a.SetString("LOCAL_LICENSE_PACKAGE_NAME", strings.Join(base.commonProperties.Effective_licenses, " "))
-	}
 	a.SetString("LOCAL_MODULE_CLASS", a.Class)
 	a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String())
 	a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...)
@@ -560,6 +543,10 @@
 		a.SetPaths("LOCAL_SOONG_INSTALL_SYMLINKS", base.katiSymlinks.InstallPaths().Paths())
 	}
 
+	if len(base.testData) > 0 {
+		a.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(base.testData)...)
+	}
+
 	if am, ok := mod.(ApexModule); ok {
 		a.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", am.NotAvailableForPlatform())
 	}
@@ -639,11 +626,14 @@
 		}
 	}
 
-	if ctx.ModuleHasProvider(mod, LicenseMetadataProvider) {
-		licenseMetadata := ctx.ModuleProvider(mod, LicenseMetadataProvider).(*LicenseMetadataInfo)
+	if licenseMetadata, ok := SingletonModuleProvider(ctx, mod, LicenseMetadataProvider); ok {
 		a.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath)
 	}
 
+	if _, ok := SingletonModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
+		a.SetBool("LOCAL_SOONG_MODULE_INFO_JSON", true)
+	}
+
 	extraCtx := &androidMkExtraEntriesContext{
 		ctx: ctx,
 		mod: mod,
@@ -661,14 +651,14 @@
 	}
 }
 
+func (a *AndroidMkEntries) disabled() bool {
+	return a.Disabled || !a.OutputFile.Valid()
+}
+
 // write  flushes the AndroidMkEntries's in-struct data populated by AndroidMkEntries into the
 // given Writer object.
 func (a *AndroidMkEntries) write(w io.Writer) {
-	if a.Disabled {
-		return
-	}
-
-	if !a.OutputFile.Valid() {
+	if a.disabled() {
 		return
 	}
 
@@ -714,7 +704,9 @@
 		return
 	}
 
-	err := translateAndroidMk(ctx, absolutePath(transMk.String()), androidMkModulesList)
+	moduleInfoJSON := PathForOutput(ctx, "module-info"+String(ctx.Config().productVariables.Make_suffix)+".json")
+
+	err := translateAndroidMk(ctx, absolutePath(transMk.String()), moduleInfoJSON, androidMkModulesList)
 	if err != nil {
 		ctx.Errorf(err.Error())
 	}
@@ -725,14 +717,16 @@
 	})
 }
 
-func translateAndroidMk(ctx SingletonContext, absMkFile string, mods []blueprint.Module) error {
+func translateAndroidMk(ctx SingletonContext, absMkFile string, moduleInfoJSONPath WritablePath, mods []blueprint.Module) error {
 	buf := &bytes.Buffer{}
 
+	var moduleInfoJSONs []*ModuleInfoJSON
+
 	fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))")
 
 	typeStats := make(map[string]int)
 	for _, mod := range mods {
-		err := translateAndroidMkModule(ctx, buf, mod)
+		err := translateAndroidMkModule(ctx, buf, &moduleInfoJSONs, mod)
 		if err != nil {
 			os.Remove(absMkFile)
 			return err
@@ -754,10 +748,36 @@
 		fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, typeStats[mod_type])
 	}
 
-	return pathtools.WriteFileIfChanged(absMkFile, buf.Bytes(), 0666)
+	err := pathtools.WriteFileIfChanged(absMkFile, buf.Bytes(), 0666)
+	if err != nil {
+		return err
+	}
+
+	return writeModuleInfoJSON(ctx, moduleInfoJSONs, moduleInfoJSONPath)
 }
 
-func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.Module) error {
+func writeModuleInfoJSON(ctx SingletonContext, moduleInfoJSONs []*ModuleInfoJSON, moduleInfoJSONPath WritablePath) error {
+	moduleInfoJSONBuf := &strings.Builder{}
+	moduleInfoJSONBuf.WriteString("[")
+	for i, moduleInfoJSON := range moduleInfoJSONs {
+		if i != 0 {
+			moduleInfoJSONBuf.WriteString(",\n")
+		}
+		moduleInfoJSONBuf.WriteString("{")
+		moduleInfoJSONBuf.WriteString(strconv.Quote(moduleInfoJSON.core.RegisterName))
+		moduleInfoJSONBuf.WriteString(":")
+		err := encodeModuleInfoJSON(moduleInfoJSONBuf, moduleInfoJSON)
+		moduleInfoJSONBuf.WriteString("}")
+		if err != nil {
+			return err
+		}
+	}
+	moduleInfoJSONBuf.WriteString("]")
+	WriteFileRule(ctx, moduleInfoJSONPath, moduleInfoJSONBuf.String())
+	return nil
+}
+
+func translateAndroidMkModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON, mod blueprint.Module) error {
 	defer func() {
 		if r := recover(); r != nil {
 			panic(fmt.Errorf("%s in translateAndroidMkModule for module %s variant %s",
@@ -766,17 +786,23 @@
 	}()
 
 	// Additional cases here require review for correct license propagation to make.
+	var err error
 	switch x := mod.(type) {
 	case AndroidMkDataProvider:
-		return translateAndroidModule(ctx, w, mod, x)
+		err = translateAndroidModule(ctx, w, moduleInfoJSONs, mod, x)
 	case bootstrap.GoBinaryTool:
-		return translateGoBinaryModule(ctx, w, mod, x)
+		err = translateGoBinaryModule(ctx, w, mod, x)
 	case AndroidMkEntriesProvider:
-		return translateAndroidMkEntriesModule(ctx, w, mod, x)
+		err = translateAndroidMkEntriesModule(ctx, w, moduleInfoJSONs, mod, x)
 	default:
 		// Not exported to make so no make variables to set.
-		return nil
 	}
+
+	if err != nil {
+		return err
+	}
+
+	return err
 }
 
 // A simple, special Android.mk entry output func to make it possible to build blueprint tools using
@@ -819,8 +845,8 @@
 
 // A support func for the deprecated AndroidMkDataProvider interface. Use AndroidMkEntryProvider
 // instead.
-func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
-	provider AndroidMkDataProvider) error {
+func translateAndroidModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON,
+	mod blueprint.Module, provider AndroidMkDataProvider) error {
 
 	amod := mod.(Module).base()
 	if shouldSkipAndroidMkProcessing(amod) {
@@ -833,6 +859,7 @@
 	}
 
 	data.fillInData(ctx, mod)
+	aconfigUpdateAndroidMkData(ctx, mod.(Module), &data)
 
 	prefix := ""
 	if amod.ArchSpecific() {
@@ -870,6 +897,7 @@
 		case "*java.SystemModules": // doesn't go through base_rules
 		case "*java.systemModulesImport": // doesn't go through base_rules
 		case "*phony.phony": // license properties written
+		case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY`
 		case "*selinux.selinuxContextsModule": // license properties written
 		case "*sysprop.syspropLibrary": // license properties written
 		default:
@@ -882,17 +910,19 @@
 		WriteAndroidMkData(w, data)
 	}
 
+	if !data.Entries.disabled() {
+		if moduleInfoJSON, ok := SingletonModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
+			*moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON)
+		}
+	}
+
 	return nil
 }
 
 // A support func for the deprecated AndroidMkDataProvider interface. Use AndroidMkEntryProvider
 // instead.
 func WriteAndroidMkData(w io.Writer, data AndroidMkData) {
-	if data.Disabled {
-		return
-	}
-
-	if !data.OutputFile.Valid() {
+	if data.Entries.disabled() {
 		return
 	}
 
@@ -907,18 +937,27 @@
 	fmt.Fprintln(w, "include "+data.Include)
 }
 
-func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
-	provider AndroidMkEntriesProvider) error {
+func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON,
+	mod blueprint.Module, provider AndroidMkEntriesProvider) error {
 	if shouldSkipAndroidMkProcessing(mod.(Module).base()) {
 		return nil
 	}
 
+	entriesList := provider.AndroidMkEntries()
+	aconfigUpdateAndroidMkEntries(ctx, mod.(Module), &entriesList)
+
 	// Any new or special cases here need review to verify correct propagation of license information.
-	for _, entries := range provider.AndroidMkEntries() {
+	for _, entries := range entriesList {
 		entries.fillInEntries(ctx, mod)
 		entries.write(w)
 	}
 
+	if len(entriesList) > 0 && !entriesList[0].disabled() {
+		if moduleInfoJSON, ok := SingletonModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok {
+			*moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON)
+		}
+	}
+
 	return nil
 }
 
@@ -956,10 +995,13 @@
 
 // A utility func to format LOCAL_TEST_DATA outputs. See the comments on DataPath to understand how
 // to use this func.
-func AndroidMkDataPaths(data []DataPath) []string {
+func androidMkDataPaths(data []DataPath) []string {
 	var testFiles []string
 	for _, d := range data {
 		rel := d.SrcPath.Rel()
+		if d.WithoutRel {
+			rel = d.SrcPath.Base()
+		}
 		path := d.SrcPath.String()
 		// LOCAL_TEST_DATA requires the rel portion of the path to be removed from the path.
 		if !strings.HasSuffix(path, rel) {
diff --git a/android/apex.go b/android/apex.go
index 6119b08..dc0aeed 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"slices"
 	"sort"
 	"strconv"
 	"strings"
@@ -89,7 +90,13 @@
 	TestApexes []string
 }
 
-var ApexInfoProvider = blueprint.NewMutatorProvider(ApexInfo{}, "apex")
+// AllApexInfo holds the ApexInfo of all apexes that include this module.
+type AllApexInfo struct {
+	ApexInfos []ApexInfo
+}
+
+var ApexInfoProvider = blueprint.NewMutatorProvider[ApexInfo]("apex_mutate")
+var AllApexInfoProvider = blueprint.NewMutatorProvider[*AllApexInfo]("apex_info")
 
 func (i ApexInfo) AddJSONData(d *map[string]interface{}) {
 	(*d)["Apex"] = map[string]interface{}{
@@ -108,7 +115,7 @@
 // are configured to have the same alias variation named apex29. Whether platform APIs is allowed
 // or not also matters; if two APEXes don't have the same allowance, they get different names and
 // thus wouldn't be merged.
-func (i ApexInfo) mergedName(ctx PathContext) string {
+func (i ApexInfo) mergedName() string {
 	name := "apex" + strconv.Itoa(i.MinSdkVersion.FinalOrFutureInt())
 	return name
 }
@@ -145,7 +152,14 @@
 	ApexContents []*ApexContents
 }
 
-var ApexTestForInfoProvider = blueprint.NewMutatorProvider(ApexTestForInfo{}, "apex_test_for")
+var ApexTestForInfoProvider = blueprint.NewMutatorProvider[ApexTestForInfo]("apex_test_for")
+
+// ApexBundleInfo contains information about the dependencies of an apex
+type ApexBundleInfo struct {
+	Contents *ApexContents
+}
+
+var ApexBundleInfoProvider = blueprint.NewMutatorProvider[ApexBundleInfo]("apex_info")
 
 // DepIsInSameApex defines an interface that should be used to determine whether a given dependency
 // should be considered as part of the same APEX as the current module or not. Note: this was
@@ -482,7 +496,9 @@
 	}
 	return InList(what, apex_available) ||
 		(what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available)) ||
-		(strings.HasPrefix(what, "com.android.gki.") && InList(AvailableToGkiApex, apex_available))
+		(strings.HasPrefix(what, "com.android.gki.") && InList(AvailableToGkiApex, apex_available)) ||
+		(what == "com.google.mainline.primary.libs") || // TODO b/248601389
+		(what == "com.google.mainline.go.primary.libs") // TODO b/248601389
 }
 
 // Implements ApexModule
@@ -534,17 +550,10 @@
 	return true
 }
 
-type byApexName []ApexInfo
-
-func (a byApexName) Len() int           { return len(a) }
-func (a byApexName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
-func (a byApexName) Less(i, j int) bool { return a[i].ApexVariationName < a[j].ApexVariationName }
-
 // mergeApexVariations deduplicates apex variations that would build identically into a common
 // variation. It returns the reduced list of variations and a list of aliases from the original
 // variation names to the new variation names.
-func mergeApexVariations(ctx PathContext, apexInfos []ApexInfo) (merged []ApexInfo, aliases [][2]string) {
-	sort.Sort(byApexName(apexInfos))
+func mergeApexVariations(apexInfos []ApexInfo) (merged []ApexInfo, aliases [][2]string) {
 	seen := make(map[string]int)
 	for _, apexInfo := range apexInfos {
 		// If this is for a prebuilt apex then use the actual name of the apex variation to prevent this
@@ -558,7 +567,7 @@
 		// this one into it, otherwise create a new merged ApexInfo from this one and save it away so
 		// other ApexInfo instances can be merged into it.
 		variantName := apexInfo.ApexVariationName
-		mergedName := apexInfo.mergedName(ctx)
+		mergedName := apexInfo.mergedName()
 		if index, exists := seen[mergedName]; exists {
 			// Variants having the same mergedName are deduped
 			merged[index].InApexVariants = append(merged[index].InApexVariants, variantName)
@@ -583,73 +592,131 @@
 	return merged, aliases
 }
 
-// CreateApexVariations mutates a given module into multiple apex variants each of which is for an
-// apexBundle (and/or the platform) where the module is part of.
-func CreateApexVariations(mctx BottomUpMutatorContext, module ApexModule) []Module {
+// IncomingApexTransition is called by apexTransitionMutator.IncomingTransition on modules that can be in apexes.
+// The incomingVariation can be either the name of an apex if the dependency is coming directly from an apex
+// module, or it can be the name of an apex variation (e.g. apex10000) if it is coming from another module that
+// is in the apex.
+func IncomingApexTransition(ctx IncomingTransitionContext, incomingVariation string) string {
+	module := ctx.Module().(ApexModule)
 	base := module.apexModuleBase()
 
+	var apexInfos []ApexInfo
+	if allApexInfos, ok := ModuleProvider(ctx, AllApexInfoProvider); ok {
+		apexInfos = allApexInfos.ApexInfos
+	}
+
+	// Dependencies from platform variations go to the platform variation.
+	if incomingVariation == "" {
+		return ""
+	}
+
+	// If this module has no apex variations the use the platform variation.
+	if len(apexInfos) == 0 {
+		return ""
+	}
+
+	// Convert the list of apex infos into from the AllApexInfoProvider into the merged list
+	// of apex variations and the aliases from apex names to apex variations.
+	var aliases [][2]string
+	if !module.UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps {
+		apexInfos, aliases = mergeApexVariations(apexInfos)
+	}
+
+	// Check if the incoming variation matches an apex name, and if so use the corresponding
+	// apex variation.
+	aliasIndex := slices.IndexFunc(aliases, func(alias [2]string) bool {
+		return alias[0] == incomingVariation
+	})
+	if aliasIndex >= 0 {
+		return aliases[aliasIndex][1]
+	}
+
+	// Check if the incoming variation matches an apex variation.
+	apexIndex := slices.IndexFunc(apexInfos, func(info ApexInfo) bool {
+		return info.ApexVariationName == incomingVariation
+	})
+	if apexIndex >= 0 {
+		return incomingVariation
+	}
+
+	return ""
+}
+
+func MutateApexTransition(ctx BaseModuleContext, variation string) {
+	module := ctx.Module().(ApexModule)
+	base := module.apexModuleBase()
+	platformVariation := variation == ""
+
+	var apexInfos []ApexInfo
+	if allApexInfos, ok := ModuleProvider(ctx, AllApexInfoProvider); ok {
+		apexInfos = allApexInfos.ApexInfos
+	}
+
 	// Shortcut
-	if len(base.apexInfos) == 0 {
-		return nil
+	if len(apexInfos) == 0 {
+		return
 	}
 
 	// Do some validity checks.
 	// TODO(jiyong): is this the right place?
-	base.checkApexAvailableProperty(mctx)
+	base.checkApexAvailableProperty(ctx)
 
-	var apexInfos []ApexInfo
-	var aliases [][2]string
-	if !mctx.Module().(ApexModule).UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps {
-		apexInfos, aliases = mergeApexVariations(mctx, base.apexInfos)
-	} else {
-		apexInfos = base.apexInfos
+	if !module.UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps {
+		apexInfos, _ = mergeApexVariations(apexInfos)
 	}
-	// base.apexInfos is only needed to propagate the list of apexes from apexInfoMutator to
-	// apexMutator. It is no longer accurate after mergeApexVariations, and won't be copied to
-	// all but the first created variant. Clear it so it doesn't accidentally get used later.
-	base.apexInfos = nil
-	sort.Sort(byApexName(apexInfos))
 
 	var inApex ApexMembership
 	for _, a := range apexInfos {
 		for _, apexContents := range a.ApexContents {
-			inApex = inApex.merge(apexContents.contents[mctx.ModuleName()])
+			inApex = inApex.merge(apexContents.contents[ctx.ModuleName()])
 		}
 	}
 	base.ApexProperties.InAnyApex = true
 	base.ApexProperties.DirectlyInAnyApex = inApex == directlyInApex
 
-	defaultVariation := ""
-	mctx.SetDefaultDependencyVariation(&defaultVariation)
+	if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) {
+		// Do not install the module for platform, but still allow it to output
+		// uninstallable AndroidMk entries in certain cases when they have side
+		// effects.  TODO(jiyong): move this routine to somewhere else
+		module.MakeUninstallable()
+	}
+	if !platformVariation {
+		var thisApexInfo ApexInfo
 
-	variations := []string{defaultVariation}
-	testApexes := []string{}
+		apexIndex := slices.IndexFunc(apexInfos, func(info ApexInfo) bool {
+			return info.ApexVariationName == variation
+		})
+		if apexIndex >= 0 {
+			thisApexInfo = apexInfos[apexIndex]
+		} else {
+			panic(fmt.Errorf("failed to find apexInfo for incoming variation %q", variation))
+		}
+
+		SetProvider(ctx, ApexInfoProvider, thisApexInfo)
+	}
+
+	// Set the value of TestApexes in every single apex variant.
+	// This allows each apex variant to be aware of the test apexes in the user provided apex_available.
+	var testApexes []string
 	for _, a := range apexInfos {
-		variations = append(variations, a.ApexVariationName)
 		testApexes = append(testApexes, a.TestApexes...)
 	}
-	modules := mctx.CreateVariations(variations...)
-	for i, mod := range modules {
-		platformVariation := i == 0
-		if platformVariation && !mctx.Host() && !mod.(ApexModule).AvailableFor(AvailableToPlatform) {
-			// Do not install the module for platform, but still allow it to output
-			// uninstallable AndroidMk entries in certain cases when they have side
-			// effects.  TODO(jiyong): move this routine to somewhere else
-			mod.MakeUninstallable()
-		}
-		if !platformVariation {
-			mctx.SetVariationProvider(mod, ApexInfoProvider, apexInfos[i-1])
-		}
-		// Set the value of TestApexes in every single apex variant.
-		// This allows each apex variant to be aware of the test apexes in the user provided apex_available.
-		mod.(ApexModule).apexModuleBase().ApexProperties.TestApexes = testApexes
-	}
+	base.ApexProperties.TestApexes = testApexes
 
-	for _, alias := range aliases {
-		mctx.CreateAliasVariation(alias[0], alias[1])
-	}
+}
 
-	return modules
+func ApexInfoMutator(ctx TopDownMutatorContext, module ApexModule) {
+	base := module.apexModuleBase()
+	if len(base.apexInfos) > 0 {
+		apexInfos := slices.Clone(base.apexInfos)
+		slices.SortFunc(apexInfos, func(a, b ApexInfo) int {
+			return strings.Compare(a.ApexVariationName, b.ApexVariationName)
+		})
+		SetProvider(ctx, AllApexInfoProvider, &AllApexInfo{apexInfos})
+		// base.apexInfos is only needed to propagate the list of apexes from the apex module to its
+		// contents within apexInfoMutator. Clear it so it doesn't accidentally get used later.
+		base.apexInfos = nil
+	}
 }
 
 // UpdateUniqueApexVariationsForDeps sets UniqueApexVariationsForDeps if any dependencies that are
@@ -660,13 +727,16 @@
 	// InApexVariants list in common. It is used instead of DepIsInSameApex because it needs to
 	// determine if the dep is in the same APEX due to being directly included, not only if it
 	// is included _because_ it is a dependency.
-	anyInSameApex := func(a, b []ApexInfo) bool {
-		collectApexes := func(infos []ApexInfo) []string {
-			var ret []string
-			for _, info := range infos {
-				ret = append(ret, info.InApexVariants...)
+	anyInSameApex := func(a, b ApexModule) bool {
+		collectApexes := func(m ApexModule) []string {
+			if allApexInfo, ok := OtherModuleProvider(mctx, m, AllApexInfoProvider); ok {
+				var ret []string
+				for _, info := range allApexInfo.ApexInfos {
+					ret = append(ret, info.InApexVariants...)
+				}
+				return ret
 			}
-			return ret
+			return nil
 		}
 
 		aApexes := collectApexes(a)
@@ -684,7 +754,7 @@
 	// If any of the dependencies requires unique apex variations, so does this module.
 	mctx.VisitDirectDeps(func(dep Module) {
 		if depApexModule, ok := dep.(ApexModule); ok {
-			if anyInSameApex(depApexModule.apexModuleBase().apexInfos, am.apexModuleBase().apexInfos) &&
+			if anyInSameApex(depApexModule, am) &&
 				(depApexModule.UniqueApexVariations() ||
 					depApexModule.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps) {
 				am.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps = true
@@ -934,8 +1004,51 @@
 	})
 }
 
+// Construct ApiLevel object from min_sdk_version string value
+func MinSdkVersionFromValue(ctx EarlyModuleContext, value string) ApiLevel {
+	if value == "" {
+		return NoneApiLevel
+	}
+	apiLevel, err := ApiLevelFromUser(ctx, value)
+	if err != nil {
+		ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
+		return NoneApiLevel
+	}
+	return apiLevel
+}
+
 // Implemented by apexBundle.
 type ApexTestInterface interface {
 	// Return true if the apex bundle is an apex_test
 	IsTestApex() bool
 }
+
+var ApexExportsInfoProvider = blueprint.NewProvider[ApexExportsInfo]()
+
+// ApexExportsInfo contains information about the artifacts provided by apexes to dexpreopt and hiddenapi
+type ApexExportsInfo struct {
+	// Canonical name of this APEX. Used to determine the path to the activated APEX on
+	// device (/apex/<apex_name>)
+	ApexName string
+
+	// Path to the image profile file on host (or empty, if profile is not generated).
+	ProfilePathOnHost Path
+
+	// Map from the apex library name (without prebuilt_ prefix) to the dex file path on host
+	LibraryNameToDexJarPathOnHost map[string]Path
+}
+
+var PrebuiltInfoProvider = blueprint.NewProvider[PrebuiltInfo]()
+
+// contents of prebuilt_info.json
+type PrebuiltInfo struct {
+	// Name of the apex, without the prebuilt_ prefix
+	Name string
+
+	Is_prebuilt bool
+
+	// This is relative to root of the workspace.
+	// In case of mainline modules, this file contains the build_id that was used
+	// to generate the mainline module prebuilt.
+	Prebuilt_info_file_path string `json:",omitempty"`
+}
diff --git a/android/apex_contributions.go b/android/apex_contributions.go
new file mode 100644
index 0000000..f5c50d3
--- /dev/null
+++ b/android/apex_contributions.go
@@ -0,0 +1,194 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+func init() {
+	RegisterApexContributionsBuildComponents(InitRegistrationContext)
+}
+
+func RegisterApexContributionsBuildComponents(ctx RegistrationContext) {
+	ctx.RegisterModuleType("apex_contributions", apexContributionsFactory)
+	ctx.RegisterModuleType("apex_contributions_defaults", apexContributionsDefaultsFactory)
+	ctx.RegisterSingletonModuleType("all_apex_contributions", allApexContributionsFactory)
+}
+
+type apexContributions struct {
+	ModuleBase
+	DefaultableModuleBase
+	properties contributionProps
+}
+
+type contributionProps struct {
+	// Name of the mainline module
+	Api_domain *string
+	// A list of module names that should be used when this contribution
+	// is selected via product_config
+	// The name should be explicit (foo or prebuilt_foo)
+	Contents []string
+}
+
+func (m *apexContributions) ApiDomain() string {
+	return proptools.String(m.properties.Api_domain)
+}
+
+func (m *apexContributions) Contents() []string {
+	return m.properties.Contents
+}
+
+// apex_contributions contains a list of module names (source or
+// prebuilt) belonging to the mainline module
+// An apex can have multiple apex_contributions modules
+// with different combinations of source or prebuilts, but only one can be
+// selected via product_config.
+func apexContributionsFactory() Module {
+	module := &apexContributions{}
+	module.AddProperties(&module.properties)
+	InitAndroidModule(module)
+	InitDefaultableModule(module)
+	return module
+}
+
+// This module type does not have any build actions.
+// It provides metadata that is used in post-deps mutator phase for source vs
+// prebuilts selection.
+func (m *apexContributions) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+type apexContributionsDefaults struct {
+	ModuleBase
+	DefaultsModuleBase
+}
+
+func apexContributionsDefaultsFactory() Module {
+	module := &apexContributionsDefaults{}
+	module.AddProperties(&contributionProps{})
+	InitDefaultsModule(module)
+	return module
+}
+
+// A container for apex_contributions.
+// Based on product_config, it will create a dependency on the selected
+// apex_contributions per mainline module
+type allApexContributions struct {
+	SingletonModuleBase
+}
+
+func allApexContributionsFactory() SingletonModule {
+	module := &allApexContributions{}
+	InitAndroidModule(module)
+	return module
+}
+
+type apexContributionsDepTag struct {
+	blueprint.BaseDependencyTag
+}
+
+var (
+	acDepTag = apexContributionsDepTag{}
+)
+
+// Creates a dep to each selected apex_contributions
+func (a *allApexContributions) DepsMutator(ctx BottomUpMutatorContext) {
+	ctx.AddDependency(ctx.Module(), acDepTag, ctx.Config().AllApexContributions()...)
+}
+
+// Set PrebuiltSelectionInfoProvider in post deps phase
+func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BaseModuleContext) {
+	addContentsToProvider := func(p *PrebuiltSelectionInfoMap, m *apexContributions) {
+		for _, content := range m.Contents() {
+			if !ctx.OtherModuleExists(content) && !ctx.Config().AllowMissingDependencies() {
+				ctx.ModuleErrorf("%s listed in apex_contributions %s does not exist\n", content, m.Name())
+			}
+			pi := &PrebuiltSelectionInfo{
+				selectedModuleName: content,
+				metadataModuleName: m.Name(),
+				apiDomain:          m.ApiDomain(),
+			}
+			p.Add(ctx, pi)
+		}
+	}
+
+	p := PrebuiltSelectionInfoMap{}
+	// Skip apex_contributions if BuildApexContributionContents is true
+	// This product config var allows some products in the same family to use mainline modules from source
+	// (e.g. shiba and shiba_fullmte)
+	// Eventually these product variants will have their own release config maps.
+	if !proptools.Bool(ctx.Config().BuildIgnoreApexContributionContents()) {
+		ctx.VisitDirectDepsWithTag(acDepTag, func(child Module) {
+			if m, ok := child.(*apexContributions); ok {
+				addContentsToProvider(&p, m)
+			} else {
+				ctx.ModuleErrorf("%s is not an apex_contributions module\n", child.Name())
+			}
+		})
+	}
+	SetProvider(ctx, PrebuiltSelectionInfoProvider, p)
+}
+
+// A provider containing metadata about whether source or prebuilt should be used
+// This provider will be used in prebuilt_select mutator to redirect deps
+var PrebuiltSelectionInfoProvider = blueprint.NewMutatorProvider[PrebuiltSelectionInfoMap]("prebuilt_select")
+
+// Map of selected module names to a metadata object
+// The metadata contains information about the api_domain of the selected module
+type PrebuiltSelectionInfoMap map[string]PrebuiltSelectionInfo
+
+// Add a new entry to the map with some validations
+func (pm *PrebuiltSelectionInfoMap) Add(ctx BaseModuleContext, p *PrebuiltSelectionInfo) {
+	if p == nil {
+		return
+	}
+	(*pm)[p.selectedModuleName] = *p
+}
+
+type PrebuiltSelectionInfo struct {
+	// e.g. (libc|prebuilt_libc)
+	selectedModuleName string
+	// Name of the apex_contributions module
+	metadataModuleName string
+	// e.g. com.android.runtime
+	apiDomain string
+}
+
+// Returns true if `name` is explicitly requested using one of the selected
+// apex_contributions metadata modules.
+func (p *PrebuiltSelectionInfoMap) IsSelected(name string) bool {
+	_, exists := (*p)[name]
+	return exists
+}
+
+// Return the list of soong modules selected for this api domain
+// In the case of apexes, it is the canonical name of the apex on device (/apex/<apex_name>)
+func (p *PrebuiltSelectionInfoMap) GetSelectedModulesForApiDomain(apiDomain string) []string {
+	selected := []string{}
+	for _, entry := range *p {
+		if entry.apiDomain == apiDomain {
+			selected = append(selected, entry.selectedModuleName)
+		}
+	}
+	return selected
+}
+
+// This module type does not have any build actions.
+func (a *allApexContributions) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+func (a *allApexContributions) GenerateSingletonBuildActions(ctx SingletonContext) {
+}
diff --git a/android/apex_test.go b/android/apex_test.go
index ddc730d..347bf7d 100644
--- a/android/apex_test.go
+++ b/android/apex_test.go
@@ -33,10 +33,22 @@
 		{
 			name: "single",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{
+					ApexVariationName: "foo",
+					MinSdkVersion:     FutureApiLevel,
+					InApexVariants:    []string{"foo"},
+					InApexModules:     []string{"foo"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{
+					ApexVariationName: "apex10000",
+					MinSdkVersion:     FutureApiLevel,
+					InApexVariants:    []string{"foo"},
+					InApexModules:     []string{"foo"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
 			},
 			wantAliases: [][2]string{
 				{"foo", "apex10000"},
@@ -45,98 +57,231 @@
 		{
 			name: "merge",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
-				{"bar", FutureApiLevel, false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
+				{
+					ApexVariationName: "foo",
+					MinSdkVersion:     FutureApiLevel,
+					InApexVariants:    []string{"foo"},
+					InApexModules:     []string{"foo"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
+				{
+					ApexVariationName: "bar",
+					MinSdkVersion:     FutureApiLevel,
+					InApexVariants:    []string{"bar"},
+					InApexModules:     []string{"bar"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false, nil}},
+				{
+					ApexVariationName: "apex10000",
+					MinSdkVersion:     FutureApiLevel,
+					InApexVariants:    []string{"foo", "bar"},
+					InApexModules:     []string{"foo", "bar"},
+				}},
 			wantAliases: [][2]string{
-				{"bar", "apex10000"},
 				{"foo", "apex10000"},
+				{"bar", "apex10000"},
 			},
 		},
 		{
 			name: "don't merge version",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
-				{"bar", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
+				{
+					ApexVariationName: "foo",
+					MinSdkVersion:     FutureApiLevel,
+					InApexVariants:    []string{"foo"},
+					InApexModules:     []string{"foo"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
+				{
+					ApexVariationName: "bar",
+					MinSdkVersion:     uncheckedFinalApiLevel(30),
+					InApexVariants:    []string{"bar"},
+					InApexModules:     []string{"bar"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
 			},
 			wantMerged: []ApexInfo{
-				{"apex30", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
-				{"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{
+					ApexVariationName: "apex10000",
+					MinSdkVersion:     FutureApiLevel,
+					InApexVariants:    []string{"foo"},
+					InApexModules:     []string{"foo"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
+				{
+					ApexVariationName: "apex30",
+					MinSdkVersion:     uncheckedFinalApiLevel(30),
+					InApexVariants:    []string{"bar"},
+					InApexModules:     []string{"bar"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
 			},
 			wantAliases: [][2]string{
-				{"bar", "apex30"},
 				{"foo", "apex10000"},
+				{"bar", "apex30"},
 			},
 		},
 		{
 			name: "merge updatable",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
-				{"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
+				{
+					ApexVariationName: "foo",
+					MinSdkVersion:     FutureApiLevel,
+					InApexVariants:    []string{"foo"},
+					InApexModules:     []string{"foo"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
+				{
+					ApexVariationName: "bar",
+					MinSdkVersion:     FutureApiLevel,
+					Updatable:         true,
+					InApexVariants:    []string{"bar"},
+					InApexModules:     []string{"bar"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
+				{
+					ApexVariationName: "apex10000",
+					MinSdkVersion:     FutureApiLevel,
+					Updatable:         true,
+					InApexVariants:    []string{"foo", "bar"},
+					InApexModules:     []string{"foo", "bar"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
 			},
 			wantAliases: [][2]string{
-				{"bar", "apex10000"},
 				{"foo", "apex10000"},
+				{"bar", "apex10000"},
 			},
 		},
 		{
 			name: "don't merge when for prebuilt_apex",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
-				{"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
+				{
+					ApexVariationName: "foo",
+					MinSdkVersion:     FutureApiLevel,
+					InApexVariants:    []string{"foo"},
+					InApexModules:     []string{"foo"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
+				{
+					ApexVariationName: "bar",
+					MinSdkVersion:     FutureApiLevel,
+					Updatable:         true,
+					InApexVariants:    []string{"bar"},
+					InApexModules:     []string{"bar"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
 				// This one should not be merged in with the others because it is for
 				// a prebuilt_apex.
-				{"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex, nil},
+				{
+					ApexVariationName: "baz",
+					MinSdkVersion:     FutureApiLevel,
+					Updatable:         true,
+					InApexVariants:    []string{"baz"},
+					InApexModules:     []string{"baz"},
+					ForPrebuiltApex:   ForPrebuiltApex,
+				},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
-				{"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex, nil},
+				{
+					ApexVariationName: "apex10000",
+					MinSdkVersion:     FutureApiLevel,
+					Updatable:         true,
+					InApexVariants:    []string{"foo", "bar"},
+					InApexModules:     []string{"foo", "bar"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
+				{
+					ApexVariationName: "baz",
+					MinSdkVersion:     FutureApiLevel,
+					Updatable:         true,
+					InApexVariants:    []string{"baz"},
+					InApexModules:     []string{"baz"},
+					ForPrebuiltApex:   ForPrebuiltApex,
+				},
 			},
 			wantAliases: [][2]string{
-				{"bar", "apex10000"},
 				{"foo", "apex10000"},
+				{"bar", "apex10000"},
 			},
 		},
 		{
 			name: "merge different UsePlatformApis but don't allow using platform api",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
-				{"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
+				{
+					ApexVariationName: "foo",
+					MinSdkVersion:     FutureApiLevel,
+					InApexVariants:    []string{"foo"},
+					InApexModules:     []string{"foo"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
+				{
+					ApexVariationName: "bar",
+					MinSdkVersion:     FutureApiLevel,
+					UsePlatformApis:   true,
+					InApexVariants:    []string{"bar"},
+					InApexModules:     []string{"bar"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
+				{
+					ApexVariationName: "apex10000",
+					MinSdkVersion:     FutureApiLevel,
+					InApexVariants:    []string{"foo", "bar"},
+					InApexModules:     []string{"foo", "bar"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
 			},
 			wantAliases: [][2]string{
-				{"bar", "apex10000"},
 				{"foo", "apex10000"},
+				{"bar", "apex10000"},
 			},
 		},
 		{
 			name: "merge same UsePlatformApis and allow using platform api",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, true, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
-				{"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
+				{
+					ApexVariationName: "foo",
+					MinSdkVersion:     FutureApiLevel,
+					UsePlatformApis:   true,
+					InApexVariants:    []string{"foo"},
+					InApexModules:     []string{"foo"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
+				{
+					ApexVariationName: "bar",
+					MinSdkVersion:     FutureApiLevel,
+					UsePlatformApis:   true,
+					InApexVariants:    []string{"bar"},
+					InApexModules:     []string{"bar"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, false, true, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
+				{
+					ApexVariationName: "apex10000",
+					MinSdkVersion:     FutureApiLevel,
+					UsePlatformApis:   true,
+					InApexVariants:    []string{"foo", "bar"},
+					InApexModules:     []string{"foo", "bar"},
+					ForPrebuiltApex:   NotForPrebuiltApex,
+				},
 			},
 			wantAliases: [][2]string{
-				{"bar", "apex10000"},
 				{"foo", "apex10000"},
+				{"bar", "apex10000"},
 			},
 		},
 	}
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			config := TestConfig(t.TempDir(), nil, "", nil)
-			ctx := &configErrorWrapper{config: config}
-			gotMerged, gotAliases := mergeApexVariations(ctx, tt.in)
+			gotMerged, gotAliases := mergeApexVariations(tt.in)
 			if !reflect.DeepEqual(gotMerged, tt.wantMerged) {
 				t.Errorf("mergeApexVariations() gotMerged = %v, want %v", gotMerged, tt.wantMerged)
 			}
diff --git a/android/api_domain.go b/android/api_domain.go
index 587ceae..0a66c3d 100644
--- a/android/api_domain.go
+++ b/android/api_domain.go
@@ -14,20 +14,6 @@
 
 package android
 
-import (
-	"github.com/google/blueprint"
-
-	"android/soong/bazel"
-)
-
-func init() {
-	RegisterApiDomainBuildComponents(InitRegistrationContext)
-}
-
-func RegisterApiDomainBuildComponents(ctx RegistrationContext) {
-	ctx.RegisterModuleType("api_domain", ApiDomainFactory)
-}
-
 type ApiSurface int
 
 // TODO(b/246656800): Reconcile with android.SdkKind
@@ -50,81 +36,3 @@
 		return "invalid"
 	}
 }
-
-type apiDomain struct {
-	ModuleBase
-	BazelModuleBase
-
-	properties apiDomainProperties
-}
-
-type apiDomainProperties struct {
-	// cc library contributions (.h files/.map.txt) of this API domain
-	// This dependency is a no-op in Soong, but the corresponding Bazel target in the api_bp2build workspace
-	// will provide a `CcApiContributionInfo` provider
-	Cc_api_contributions []string
-
-	// java library contributions (as .txt) of this API domain
-	// This dependency is a no-op in Soong, but the corresponding Bazel target in the api_bp2build workspace
-	// will provide a `JavaApiContributionInfo` provider
-	Java_api_contributions []string
-}
-
-func ApiDomainFactory() Module {
-	m := &apiDomain{}
-	m.AddProperties(&m.properties)
-	InitAndroidArchModule(m, DeviceSupported, MultilibBoth)
-	return m
-}
-
-// Do not create any dependency edges in Soong for now to skip visibility checks for some systemapi libraries.
-// Currently, all api_domain modules reside in build/orchestrator/apis/Android.bp
-// However, cc libraries like libsigchain (com.android.art) restrict their visibility to art/*
-// When the api_domain module types are collocated with their contributions, this dependency edge can be restored
-func (a *apiDomain) DepsMutator(ctx BottomUpMutatorContext) {
-}
-
-// API domain does not have any builld actions yet
-func (a *apiDomain) GenerateAndroidBuildActions(ctx ModuleContext) {
-}
-
-const (
-	apiContributionSuffix = ".contribution"
-)
-
-// ApiContributionTargetName returns the name of the bp2build target (e.g. cc_api_contribution)  of contribution modules (e.g. ndk_library)
-// A suffix is necessary to prevent a name collision with the base target in the same bp2build bazel package
-func ApiContributionTargetName(moduleName string) string {
-	return moduleName + apiContributionSuffix
-}
-
-// For each contributing cc_library, format the name to its corresponding contribution bazel target in the bp2build workspace
-func contributionBazelAttributes(ctx TopDownMutatorContext, contributions []string) bazel.LabelListAttribute {
-	addSuffix := func(ctx BazelConversionPathContext, module blueprint.Module) string {
-		baseLabel := BazelModuleLabel(ctx, module)
-		return ApiContributionTargetName(baseLabel)
-	}
-	bazelLabels := BazelLabelForModuleDepsWithFn(ctx, contributions, addSuffix)
-	return bazel.MakeLabelListAttribute(bazelLabels)
-}
-
-type bazelApiDomainAttributes struct {
-	Cc_api_contributions   bazel.LabelListAttribute
-	Java_api_contributions bazel.LabelListAttribute
-}
-
-var _ ApiProvider = (*apiDomain)(nil)
-
-func (a *apiDomain) ConvertWithApiBp2build(ctx TopDownMutatorContext) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "api_domain",
-		Bzl_load_location: "//build/bazel/rules/apis:api_domain.bzl",
-	}
-	attrs := &bazelApiDomainAttributes{
-		Cc_api_contributions:   contributionBazelAttributes(ctx, a.properties.Cc_api_contributions),
-		Java_api_contributions: contributionBazelAttributes(ctx, a.properties.Java_api_contributions),
-	}
-	ctx.CreateBazelTargetModule(props, CommonAttributes{
-		Name: ctx.ModuleName(),
-	}, attrs)
-}
diff --git a/android/api_levels.go b/android/api_levels.go
index 44c8640..fab5fc7 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -15,10 +15,10 @@
 package android
 
 import (
-	"android/soong/starlark_import"
 	"encoding/json"
 	"fmt"
 	"strconv"
+	"strings"
 )
 
 func init() {
@@ -237,6 +237,14 @@
 	}
 }
 
+func uncheckedFinalIncrementalApiLevel(num int, increment int) ApiLevel {
+	return ApiLevel{
+		value:     strconv.Itoa(num) + "." + strconv.Itoa(increment),
+		number:    num,
+		isPreview: false,
+	}
+}
+
 var NoneApiLevel = ApiLevel{
 	value: "(no version)",
 	// Not 0 because we don't want this to compare equal with the first preview.
@@ -279,6 +287,10 @@
 // a core-for-system-modules.jar for the module-lib API scope.
 var LastWithoutModuleLibCoreSystemModules = uncheckedFinalApiLevel(31)
 
+var ApiLevelR = uncheckedFinalApiLevel(30)
+
+var ApiLevelUpsideDownCake = uncheckedFinalApiLevel(34)
+
 // ReplaceFinalizedCodenames returns the API level number associated with that API level
 // if the `raw` input is the codename of an API level has been finalized.
 // If the input is *not* a finalized codename, the input is returned unmodified.
@@ -327,7 +339,7 @@
 // ApiLevelFromUser for more details.
 func ApiLevelFromUserWithConfig(config Config, raw string) (ApiLevel, error) {
 	// This logic is replicated in starlark, if changing logic here update starlark code too
-	// https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/common/api.bzl;l=42;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
+	// https://cs.android.com/android/platform/superproject/+/main:build/bazel/rules/common/api.bzl;l=42;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
 	if raw == "" {
 		panic("API level string must be non-empty")
 	}
@@ -371,6 +383,22 @@
 		return FutureApiLevel
 	}
 
+	if strings.Contains(raw, ".") {
+		// Check prebuilt incremental API format MM.m for major (API level) and minor (incremental) revisions
+		parts := strings.Split(raw, ".")
+		if len(parts) != 2 {
+			panic(fmt.Errorf("Found unexpected version '%s' for incremental API - expect MM.m format for incremental API with both major (MM) an minor (m) revision.", raw))
+		}
+		sdk, sdk_err := strconv.Atoi(parts[0])
+		qpr, qpr_err := strconv.Atoi(parts[1])
+		if sdk_err != nil || qpr_err != nil {
+			panic(fmt.Errorf("Unable to read version number for incremental api '%s'", raw))
+		}
+
+		apiLevel := uncheckedFinalIncrementalApiLevel(sdk, qpr)
+		return apiLevel
+	}
+
 	asInt, err := strconv.Atoi(raw)
 	if err != nil {
 		panic(fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", raw))
@@ -413,7 +441,28 @@
 }
 
 func getApiLevelsMapReleasedVersions() (map[string]int, error) {
-	return starlark_import.GetStarlarkValue[map[string]int]("api_levels_released_versions")
+	return map[string]int{
+		"G":              9,
+		"I":              14,
+		"J":              16,
+		"J-MR1":          17,
+		"J-MR2":          18,
+		"K":              19,
+		"L":              21,
+		"L-MR1":          22,
+		"M":              23,
+		"N":              24,
+		"N-MR1":          25,
+		"O":              26,
+		"O-MR1":          27,
+		"P":              28,
+		"Q":              29,
+		"R":              30,
+		"S":              31,
+		"S-V2":           32,
+		"Tiramisu":       33,
+		"UpsideDownCake": 34,
+	}, nil
 }
 
 var finalCodenamesMapKey = NewOnceKey("FinalCodenamesMap")
@@ -424,7 +473,7 @@
 		err    error
 	}
 	// This logic is replicated in starlark, if changing logic here update starlark code too
-	// https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/common/api.bzl;l=30;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
+	// https://cs.android.com/android/platform/superproject/+/main:build/bazel/rules/common/api.bzl;l=30;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
 	result := config.Once(finalCodenamesMapKey, func() interface{} {
 		apiLevelsMap, err := getApiLevelsMapReleasedVersions()
 
@@ -457,7 +506,7 @@
 		err    error
 	}
 	// This logic is replicated in starlark, if changing logic here update starlark code too
-	// https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/common/api.bzl;l=23;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
+	// https://cs.android.com/android/platform/superproject/+/main:build/bazel/rules/common/api.bzl;l=23;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
 	result := config.Once(apiLevelsMapKey, func() interface{} {
 		apiLevelsMap, err := getApiLevelsMapReleasedVersions()
 		if err == nil {
diff --git a/android/arch.go b/android/arch.go
index 152016c..cd8882b 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -16,16 +16,11 @@
 
 import (
 	"encoding"
-	"encoding/json"
 	"fmt"
 	"reflect"
 	"runtime"
-	"sort"
 	"strings"
 
-	"android/soong/bazel"
-	"android/soong/starlark_fmt"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
@@ -425,7 +420,8 @@
 	// blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
 	// filters out non-Soong modules.  Now that we've handled them, create a
 	// normal android.BottomUpMutatorContext.
-	mctx := bottomUpMutatorContextFactory(bpctx, module, false, false)
+	mctx := bottomUpMutatorContextFactory(bpctx, module, false)
+	defer bottomUpMutatorContextPool.Put(mctx)
 
 	base := module.base()
 
@@ -446,8 +442,10 @@
 		}
 	}
 
+	createCommonOSVariant := base.commonProperties.CreateCommonOSVariant
+
 	// If there are no supported OSes then disable the module.
-	if len(moduleOSList) == 0 {
+	if len(moduleOSList) == 0 && !createCommonOSVariant {
 		base.Disable()
 		return
 	}
@@ -458,7 +456,6 @@
 		osNames[i] = os.String()
 	}
 
-	createCommonOSVariant := base.commonProperties.CreateCommonOSVariant
 	if createCommonOSVariant {
 		// A CommonOS variant was requested so add it to the list of OS variants to
 		// create. It needs to be added to the end because it needs to depend on the
@@ -570,7 +567,8 @@
 	// blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
 	// filters out non-Soong modules.  Now that we've handled them, create a
 	// normal android.BottomUpMutatorContext.
-	mctx := bottomUpMutatorContextFactory(bpctx, module, false, false)
+	mctx := bottomUpMutatorContextFactory(bpctx, module, false)
+	defer bottomUpMutatorContextPool.Put(mctx)
 
 	base := module.base()
 
@@ -690,6 +688,7 @@
 	m.base().commonProperties.CompileTarget = target
 	m.base().commonProperties.CompileMultiTargets = multiTargets
 	m.base().commonProperties.CompilePrimary = primaryTarget
+	m.base().commonProperties.ArchReady = true
 }
 
 // decodeMultilib returns the appropriate compile_multilib property for the module, or the default
@@ -976,12 +975,18 @@
 			panic(fmt.Errorf("unexpected tag format %q", field.Tag))
 		}
 		// these tags don't need to be present in the runtime generated struct type.
+		// However replace_instead_of_append does, because it's read by the blueprint
+		// property extending util functions, which can operate on these generated arch
+		// property structs.
 		values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend", "path"})
 		if len(values) > 0 {
-			panic(fmt.Errorf("unknown tags %q in field %q", values, prefix+field.Name))
+			if values[0] != "replace_instead_of_append" || len(values) > 1 {
+				panic(fmt.Errorf("unknown tags %q in field %q", values, prefix+field.Name))
+			}
+			field.Tag = `android:"replace_instead_of_append"`
+		} else {
+			field.Tag = ``
 		}
-
-		field.Tag = ``
 		return true, field
 	}
 	return false, field
@@ -1057,9 +1062,7 @@
 	// order checks the `android:"variant_prepend"` tag to handle properties where the
 	// arch-specific value needs to come before the generic value, for example for lists of
 	// include directories.
-	order := func(property string,
-		dstField, srcField reflect.StructField,
-		dstValue, srcValue interface{}) (proptools.Order, error) {
+	order := func(dstField, srcField reflect.StructField) (proptools.Order, error) {
 		if proptools.HasTag(dstField, "android", "variant_prepend") {
 			return proptools.Prepend, nil
 		} else {
@@ -1897,428 +1900,8 @@
 	return buildTargets, nil
 }
 
-func (m *ModuleBase) getArchPropertySet(propertySet interface{}, archType ArchType) interface{} {
-	archString := archType.Field
-	for i := range m.archProperties {
-		if m.archProperties[i] == nil {
-			// Skip over nil properties
-			continue
-		}
-
-		// Not archProperties are usable; this function looks for properties of a very specific
-		// form, and ignores the rest.
-		for _, archProperty := range m.archProperties[i] {
-			// archPropValue is a property struct, we are looking for the form:
-			// `arch: { arm: { key: value, ... }}`
-			archPropValue := reflect.ValueOf(archProperty).Elem()
-
-			// Unwrap src so that it should looks like a pointer to `arm: { key: value, ... }`
-			src := archPropValue.FieldByName("Arch").Elem()
-
-			// Step into non-nil pointers to structs in the src value.
-			if src.Kind() == reflect.Ptr {
-				if src.IsNil() {
-					continue
-				}
-				src = src.Elem()
-			}
-
-			// Find the requested field (e.g. arm, x86) in the src struct.
-			src = src.FieldByName(archString)
-
-			// We only care about structs.
-			if !src.IsValid() || src.Kind() != reflect.Struct {
-				continue
-			}
-
-			// If the value of the field is a struct then step into the
-			// BlueprintEmbed field. The special "BlueprintEmbed" name is
-			// used by createArchPropTypeDesc to embed the arch properties
-			// in the parent struct, so the src arch prop should be in this
-			// field.
-			//
-			// See createArchPropTypeDesc for more details on how Arch-specific
-			// module properties are processed from the nested props and written
-			// into the module's archProperties.
-			src = src.FieldByName("BlueprintEmbed")
-
-			// Clone the destination prop, since we want a unique prop struct per arch.
-			propertySetClone := reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface()
-
-			// Copy the located property struct into the cloned destination property struct.
-			err := proptools.ExtendMatchingProperties([]interface{}{propertySetClone}, src.Interface(), nil, proptools.OrderReplace)
-			if err != nil {
-				// This is fine, it just means the src struct doesn't match the type of propertySet.
-				continue
-			}
-
-			return propertySetClone
-		}
-	}
-	// No property set was found specific to the given arch, so return an empty
-	// property set.
-	return reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface()
-}
-
-// getMultilibPropertySet returns a property set struct matching the type of
-// `propertySet`, containing multilib-specific module properties for the given architecture.
-// If no multilib-specific properties exist for the given architecture, returns an empty property
-// set matching `propertySet`'s type.
-func (m *ModuleBase) getMultilibPropertySet(propertySet interface{}, archType ArchType) interface{} {
-	// archType.Multilib is lowercase (for example, lib32) but property struct field is
-	// capitalized, such as Lib32, so use strings.Title to capitalize it.
-	multiLibString := strings.Title(archType.Multilib)
-
-	for i := range m.archProperties {
-		if m.archProperties[i] == nil {
-			// Skip over nil properties
-			continue
-		}
-
-		// Not archProperties are usable; this function looks for properties of a very specific
-		// form, and ignores the rest.
-		for _, archProperties := range m.archProperties[i] {
-			// archPropValue is a property struct, we are looking for the form:
-			// `multilib: { lib32: { key: value, ... }}`
-			archPropValue := reflect.ValueOf(archProperties).Elem()
-
-			// Unwrap src so that it should looks like a pointer to `lib32: { key: value, ... }`
-			src := archPropValue.FieldByName("Multilib").Elem()
-
-			// Step into non-nil pointers to structs in the src value.
-			if src.Kind() == reflect.Ptr {
-				if src.IsNil() {
-					// Ignore nil pointers.
-					continue
-				}
-				src = src.Elem()
-			}
-
-			// Find the requested field (e.g. lib32) in the src struct.
-			src = src.FieldByName(multiLibString)
-
-			// We only care about valid struct pointers.
-			if !src.IsValid() || src.Kind() != reflect.Ptr || src.Elem().Kind() != reflect.Struct {
-				continue
-			}
-
-			// Get the zero value for the requested property set.
-			propertySetClone := reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface()
-
-			// Copy the located property struct into the "zero" property set struct.
-			err := proptools.ExtendMatchingProperties([]interface{}{propertySetClone}, src.Interface(), nil, proptools.OrderReplace)
-
-			if err != nil {
-				// This is fine, it just means the src struct doesn't match.
-				continue
-			}
-
-			return propertySetClone
-		}
-	}
-
-	// There were no multilib properties specifically matching the given archtype.
-	// Return zeroed value.
-	return reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface()
-}
-
 // ArchVariantContext defines the limited context necessary to retrieve arch_variant properties.
 type ArchVariantContext interface {
 	ModuleErrorf(fmt string, args ...interface{})
 	PropertyErrorf(property, fmt string, args ...interface{})
 }
-
-// ArchVariantProperties represents a map of arch-variant config strings to a property interface{}.
-type ArchVariantProperties map[string]interface{}
-
-// ConfigurationAxisToArchVariantProperties represents a map of bazel.ConfigurationAxis to
-// ArchVariantProperties, such that each independent arch-variant axis maps to the
-// configs/properties for that axis.
-type ConfigurationAxisToArchVariantProperties map[bazel.ConfigurationAxis]ArchVariantProperties
-
-// GetArchVariantProperties returns a ConfigurationAxisToArchVariantProperties where the
-// arch-variant properties correspond to the values of the properties of the 'propertySet' struct
-// that are specific to that axis/configuration. Each axis is independent, containing
-// non-overlapping configs that correspond to the various "arch-variant" support, at this time:
-//
-//	arches (including multilib)
-//	oses
-//	arch+os combinations
-//
-// For example, passing a struct { Foo bool, Bar string } will return an interface{} that can be
-// type asserted back into the same struct, containing the config-specific property value specified
-// by the module if defined.
-//
-// Arch-specific properties may come from an arch stanza or a multilib stanza; properties
-// in these stanzas are combined.
-// For example: `arch: { x86: { Foo: ["bar"] } }, multilib: { lib32: {` Foo: ["baz"] } }`
-// will result in `Foo: ["bar", "baz"]` being returned for architecture x86, if the given
-// propertyset contains `Foo []string`.
-func (m *ModuleBase) GetArchVariantProperties(ctx ArchVariantContext, propertySet interface{}) ConfigurationAxisToArchVariantProperties {
-	// Return value of the arch types to the prop values for that arch.
-	axisToProps := ConfigurationAxisToArchVariantProperties{}
-
-	// Nothing to do for non-arch-specific modules.
-	if !m.ArchSpecific() {
-		return axisToProps
-	}
-
-	dstType := reflect.ValueOf(propertySet).Type()
-	var archProperties []interface{}
-
-	// First find the property set in the module that corresponds to the requested
-	// one. m.archProperties[i] corresponds to m.GetProperties()[i].
-	for i, generalProp := range m.GetProperties() {
-		srcType := reflect.ValueOf(generalProp).Type()
-		if srcType == dstType {
-			archProperties = m.archProperties[i]
-			axisToProps[bazel.NoConfigAxis] = ArchVariantProperties{"": generalProp}
-			break
-		}
-	}
-
-	if archProperties == nil {
-		// This module does not have the property set requested
-		return axisToProps
-	}
-
-	archToProp := ArchVariantProperties{}
-	// For each arch type (x86, arm64, etc.)
-	for _, arch := range ArchTypeList() {
-		// Arch properties are sometimes sharded (see createArchPropTypeDesc() ).
-		// Iterate over every shard and extract a struct with the same type as the
-		// input one that contains the data specific to that arch.
-		propertyStructs := make([]reflect.Value, 0)
-		archFeaturePropertyStructs := make(map[string][]reflect.Value, 0)
-		for _, archProperty := range archProperties {
-			archTypeStruct, ok := getArchTypeStruct(ctx, archProperty, arch)
-			if ok {
-				propertyStructs = append(propertyStructs, archTypeStruct)
-
-				// For each feature this arch supports (arm: neon, x86: ssse3, sse4, ...)
-				for _, feature := range archFeatures[arch] {
-					prefix := "arch." + arch.Name + "." + feature
-					if featureProperties, ok := getChildPropertyStruct(ctx, archTypeStruct, feature, prefix); ok {
-						archFeaturePropertyStructs[feature] = append(archFeaturePropertyStructs[feature], featureProperties)
-					}
-				}
-			}
-			multilibStruct, ok := getMultilibStruct(ctx, archProperty, arch)
-			if ok {
-				propertyStructs = append(propertyStructs, multilibStruct)
-			}
-		}
-
-		archToProp[arch.Name] = mergeStructs(ctx, propertyStructs, propertySet)
-
-		// In soong, if multiple features match the current configuration, they're
-		// all used. In bazel, we have to have unambiguous select() statements, so
-		// we can't have two features that are both active in the same select().
-		// One alternative is to split out each feature into a separate select(),
-		// but then it's difficult to support exclude_srcs, which may need to
-		// exclude things from the regular arch select() statement if a certain
-		// feature is active. Instead, keep the features in the same select
-		// statement as the arches, but emit the power set of all possible
-		// combinations of features, so that bazel can match the most precise one.
-		allFeatures := make([]string, 0, len(archFeaturePropertyStructs))
-		for feature := range archFeaturePropertyStructs {
-			allFeatures = append(allFeatures, feature)
-		}
-		for _, features := range bazel.PowerSetWithoutEmptySet(allFeatures) {
-			sort.Strings(features)
-			propsForCurrentFeatureSet := make([]reflect.Value, 0)
-			propsForCurrentFeatureSet = append(propsForCurrentFeatureSet, propertyStructs...)
-			for _, feature := range features {
-				propsForCurrentFeatureSet = append(propsForCurrentFeatureSet, archFeaturePropertyStructs[feature]...)
-			}
-			archToProp[arch.Name+"-"+strings.Join(features, "-")] =
-				mergeStructs(ctx, propsForCurrentFeatureSet, propertySet)
-		}
-	}
-	axisToProps[bazel.ArchConfigurationAxis] = archToProp
-
-	osToProp := ArchVariantProperties{}
-	archOsToProp := ArchVariantProperties{}
-
-	linuxStructs := getTargetStructs(ctx, archProperties, "Linux")
-	bionicStructs := getTargetStructs(ctx, archProperties, "Bionic")
-	hostStructs := getTargetStructs(ctx, archProperties, "Host")
-	hostLinuxStructs := getTargetStructs(ctx, archProperties, "Host_linux")
-	hostNotWindowsStructs := getTargetStructs(ctx, archProperties, "Not_windows")
-
-	// For android, linux, ...
-	for _, os := range osTypeList {
-		if os == CommonOS {
-			// It looks like this OS value is not used in Blueprint files
-			continue
-		}
-		osStructs := make([]reflect.Value, 0)
-
-		osSpecificStructs := getTargetStructs(ctx, archProperties, os.Field)
-		if os.Class == Host {
-			osStructs = append(osStructs, hostStructs...)
-		}
-		if os.Linux() {
-			osStructs = append(osStructs, linuxStructs...)
-		}
-		if os.Bionic() {
-			osStructs = append(osStructs, bionicStructs...)
-		}
-		if os.Linux() && os.Class == Host {
-			osStructs = append(osStructs, hostLinuxStructs...)
-		}
-
-		if os == LinuxMusl {
-			osStructs = append(osStructs, getTargetStructs(ctx, archProperties, "Musl")...)
-		}
-		if os == Linux {
-			osStructs = append(osStructs, getTargetStructs(ctx, archProperties, "Glibc")...)
-		}
-
-		osStructs = append(osStructs, osSpecificStructs...)
-
-		if os.Class == Host && os != Windows {
-			osStructs = append(osStructs, hostNotWindowsStructs...)
-		}
-		osToProp[os.Name] = mergeStructs(ctx, osStructs, propertySet)
-
-		// For arm, x86, ...
-		for _, arch := range osArchTypeMap[os] {
-			osArchStructs := make([]reflect.Value, 0)
-
-			// Auto-combine with Linux_ and Bionic_ targets. This potentially results in
-			// repetition and select() bloat, but use of Linux_* and Bionic_* targets is rare.
-			// TODO(b/201423152): Look into cleanup.
-			if os.Linux() {
-				targetField := "Linux_" + arch.Name
-				targetStructs := getTargetStructs(ctx, archProperties, targetField)
-				osArchStructs = append(osArchStructs, targetStructs...)
-			}
-			if os.Bionic() {
-				targetField := "Bionic_" + arch.Name
-				targetStructs := getTargetStructs(ctx, archProperties, targetField)
-				osArchStructs = append(osArchStructs, targetStructs...)
-			}
-			if os == LinuxMusl {
-				targetField := "Musl_" + arch.Name
-				targetStructs := getTargetStructs(ctx, archProperties, targetField)
-				osArchStructs = append(osArchStructs, targetStructs...)
-			}
-			if os == Linux {
-				targetField := "Glibc_" + arch.Name
-				targetStructs := getTargetStructs(ctx, archProperties, targetField)
-				osArchStructs = append(osArchStructs, targetStructs...)
-			}
-
-			targetField := GetCompoundTargetField(os, arch)
-			targetName := fmt.Sprintf("%s_%s", os.Name, arch.Name)
-			targetStructs := getTargetStructs(ctx, archProperties, targetField)
-			osArchStructs = append(osArchStructs, targetStructs...)
-
-			archOsToProp[targetName] = mergeStructs(ctx, osArchStructs, propertySet)
-		}
-	}
-
-	axisToProps[bazel.OsConfigurationAxis] = osToProp
-	axisToProps[bazel.OsArchConfigurationAxis] = archOsToProp
-	return axisToProps
-}
-
-// Returns a struct matching the propertySet interface, containing properties specific to the targetName
-// For example, given these arguments:
-//
-//	propertySet = BaseCompilerProperties
-//	targetName = "android_arm"
-//
-// And given this Android.bp fragment:
-//
-//	target:
-//	   android_arm: {
-//	      srcs: ["foo.c"],
-//	   }
-//	   android_arm64: {
-//	      srcs: ["bar.c"],
-//	  }
-//	}
-//
-// This would return a BaseCompilerProperties with BaseCompilerProperties.Srcs = ["foo.c"]
-func getTargetStructs(ctx ArchVariantContext, archProperties []interface{}, targetName string) []reflect.Value {
-	var propertyStructs []reflect.Value
-	for _, archProperty := range archProperties {
-		archPropValues := reflect.ValueOf(archProperty).Elem()
-		targetProp := archPropValues.FieldByName("Target").Elem()
-		targetStruct, ok := getChildPropertyStruct(ctx, targetProp, targetName, targetName)
-		if ok {
-			propertyStructs = append(propertyStructs, targetStruct)
-		} else {
-			return []reflect.Value{}
-		}
-	}
-
-	return propertyStructs
-}
-
-func mergeStructs(ctx ArchVariantContext, propertyStructs []reflect.Value, propertySet interface{}) interface{} {
-	// Create a new instance of the requested property set
-	value := reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface()
-
-	// Merge all the structs together
-	for _, propertyStruct := range propertyStructs {
-		mergePropertyStruct(ctx, value, propertyStruct)
-	}
-
-	return value
-}
-
-func printArchTypeStarlarkDict(dict map[ArchType][]string) string {
-	valDict := make(map[string]string, len(dict))
-	for k, v := range dict {
-		valDict[k.String()] = starlark_fmt.PrintStringList(v, 1)
-	}
-	return starlark_fmt.PrintDict(valDict, 0)
-}
-
-func printArchTypeNestedStarlarkDict(dict map[ArchType]map[string][]string) string {
-	valDict := make(map[string]string, len(dict))
-	for k, v := range dict {
-		valDict[k.String()] = starlark_fmt.PrintStringListDict(v, 1)
-	}
-	return starlark_fmt.PrintDict(valDict, 0)
-}
-
-func printArchConfigList(arches []archConfig) string {
-	jsonOut, err := json.MarshalIndent(arches, "", starlark_fmt.Indention(1))
-	if err != nil {
-		panic(fmt.Errorf("Error converting arch configs %#v to json: %q", arches, err))
-	}
-	return fmt.Sprintf("json.decode('''%s''')", string(jsonOut))
-}
-
-func StarlarkArchConfigurations() string {
-	return fmt.Sprintf(`
-_arch_to_variants = %s
-
-_arch_to_cpu_variants = %s
-
-_arch_to_features = %s
-
-_android_arch_feature_for_arch_variant = %s
-
-_aml_arches = %s
-
-_ndk_arches = %s
-
-arch_to_variants = _arch_to_variants
-arch_to_cpu_variants = _arch_to_cpu_variants
-arch_to_features = _arch_to_features
-android_arch_feature_for_arch_variants = _android_arch_feature_for_arch_variant
-aml_arches = _aml_arches
-ndk_arches = _ndk_arches
-`, printArchTypeStarlarkDict(archVariants),
-		printArchTypeStarlarkDict(cpuVariants),
-		printArchTypeStarlarkDict(archFeatures),
-		printArchTypeNestedStarlarkDict(androidArchFeatureMap),
-		printArchConfigList(getAmlAbisConfig()),
-		printArchConfigList(getNdkAbisConfig()),
-	)
-}
diff --git a/android/arch_list.go b/android/arch_list.go
index ab644a4..f4409a9 100644
--- a/android/arch_list.go
+++ b/android/arch_list.go
@@ -34,6 +34,11 @@
 		"broadwell",
 		"goldmont",
 		"goldmont-plus",
+		// Target arch is goldmont, but without supporting SHA and XSAVES.
+		// This ensures efficient execution on a broad range of Intel/AMD CPUs used
+		// in Chromebooks, including those lacking SHA or XSAVES support.
+		// (e.g. Kaby Lake, Gemini Lake, Alder Lake and AMD Zen series)
+		"goldmont-without-sha-xsaves",
 		"haswell",
 		"icelake",
 		"ivybridge",
@@ -52,6 +57,7 @@
 		"broadwell",
 		"goldmont",
 		"goldmont-plus",
+		"goldmont-without-sha-xsaves",
 		"haswell",
 		"icelake",
 		"ivybridge",
@@ -197,6 +203,15 @@
 			"popcnt",
 			"movbe",
 		},
+		"goldmont-without-sha-xsaves": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"aes_ni",
+			"popcnt",
+			"movbe",
+		},
 		"haswell": {
 			"ssse3",
 			"sse4",
@@ -358,6 +373,14 @@
 			"aes_ni",
 			"popcnt",
 		},
+		"goldmont-without-sha-xsaves": {
+			"ssse3",
+			"sse4",
+			"sse4_1",
+			"sse4_2",
+			"aes_ni",
+			"popcnt",
+		},
 		"haswell": {
 			"ssse3",
 			"sse4",
diff --git a/android/arch_module_context.go b/android/arch_module_context.go
new file mode 100644
index 0000000..a3a03af
--- /dev/null
+++ b/android/arch_module_context.go
@@ -0,0 +1,91 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+// ArchModuleContext can be embedded in other contexts to provide information about the module set by
+// the archMutator.
+type ArchModuleContext interface {
+	Target() Target
+	TargetPrimary() bool
+
+	// The additional arch specific targets (e.g. 32/64 bit) that this module variant is
+	// responsible for creating.
+	MultiTargets() []Target
+	Arch() Arch
+	Os() OsType
+	Host() bool
+	Device() bool
+	Darwin() bool
+	Windows() bool
+	PrimaryArch() bool
+}
+
+type archModuleContext struct {
+	// TODO: these should eventually go through a (possibly cached) provider like any other configuration instead
+	//  of being special cased.
+	ready         bool
+	os            OsType
+	target        Target
+	targetPrimary bool
+	multiTargets  []Target
+	primaryArch   bool
+}
+
+// ArchReady returns true if the arch mutator has run on the module. Before this returns
+// true, the module essentially doesn't have an arch and cannot make decisions based on
+// architecture.
+func (a *archModuleContext) ArchReady() bool {
+	return a.ready
+}
+
+func (a *archModuleContext) Target() Target {
+	return a.target
+}
+
+func (a *archModuleContext) TargetPrimary() bool {
+	return a.targetPrimary
+}
+
+func (a *archModuleContext) MultiTargets() []Target {
+	return a.multiTargets
+}
+
+func (a *archModuleContext) Arch() Arch {
+	return a.target.Arch
+}
+
+func (a *archModuleContext) Os() OsType {
+	return a.os
+}
+
+func (a *archModuleContext) Host() bool {
+	return a.os.Class == Host
+}
+
+func (a *archModuleContext) Device() bool {
+	return a.os.Class == Device
+}
+
+func (a *archModuleContext) Darwin() bool {
+	return a.os == Darwin
+}
+
+func (a *archModuleContext) Windows() bool {
+	return a.os == Windows
+}
+
+func (b *archModuleContext) PrimaryArch() bool {
+	return b.primaryArch
+}
diff --git a/android/base_module_context.go b/android/base_module_context.go
new file mode 100644
index 0000000..c5fe585
--- /dev/null
+++ b/android/base_module_context.go
@@ -0,0 +1,582 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"fmt"
+	"regexp"
+	"strings"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns
+// a Config instead of an interface{}, and some methods have been wrapped to use an android.Module
+// instead of a blueprint.Module, plus some extra methods that return Android-specific information
+// about the current module.
+type BaseModuleContext interface {
+	ArchModuleContext
+	EarlyModuleContext
+
+	blueprintBaseModuleContext() blueprint.BaseModuleContext
+
+	// OtherModuleName returns the name of another Module.  See BaseModuleContext.ModuleName for more information.
+	// It is intended for use inside the visit functions of Visit* and WalkDeps.
+	OtherModuleName(m blueprint.Module) string
+
+	// OtherModuleDir returns the directory of another Module.  See BaseModuleContext.ModuleDir for more information.
+	// It is intended for use inside the visit functions of Visit* and WalkDeps.
+	OtherModuleDir(m blueprint.Module) string
+
+	// OtherModuleErrorf reports an error on another Module.  See BaseModuleContext.ModuleErrorf for more information.
+	// It is intended for use inside the visit functions of Visit* and WalkDeps.
+	OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
+
+	// OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency
+	// on the module.  When called inside a Visit* method with current module being visited, and there are multiple
+	// dependencies on the module being visited, it returns the dependency tag used for the current dependency.
+	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
+
+	// OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface
+	// passed to Context.SetNameInterface, or SimpleNameInterface if it was not called.
+	OtherModuleExists(name string) bool
+
+	// OtherModuleDependencyVariantExists returns true if a module with the
+	// specified name and variant exists. The variant must match the given
+	// variations. It must also match all the non-local variations of the current
+	// module. In other words, it checks for the module that AddVariationDependencies
+	// would add a dependency on with the same arguments.
+	OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool
+
+	// OtherModuleFarDependencyVariantExists returns true if a module with the
+	// specified name and variant exists. The variant must match the given
+	// variations, but not the non-local variations of the current module. In
+	// other words, it checks for the module that AddFarVariationDependencies
+	// would add a dependency on with the same arguments.
+	OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool
+
+	// OtherModuleReverseDependencyVariantExists returns true if a module with the
+	// specified name exists with the same variations as the current module. In
+	// other words, it checks for the module that AddReverseDependency would add a
+	// dependency on with the same argument.
+	OtherModuleReverseDependencyVariantExists(name string) bool
+
+	// OtherModuleType returns the type of another Module.  See BaseModuleContext.ModuleType for more information.
+	// It is intended for use inside the visit functions of Visit* and WalkDeps.
+	OtherModuleType(m blueprint.Module) string
+
+	// otherModuleProvider returns the value for a provider for the given module.  If the value is
+	// not set it returns nil and false.  The value returned may be a deep copy of the value originally
+	// passed to SetProvider.
+	//
+	// This method shouldn't be used directly, prefer the type-safe android.OtherModuleProvider instead.
+	otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
+
+	// Provider returns the value for a provider for the current module.  If the value is
+	// not set it returns nil and false.  It panics if called before the appropriate
+	// mutator or GenerateBuildActions pass for the provider.  The value returned may be a deep
+	// copy of the value originally passed to SetProvider.
+	//
+	// This method shouldn't be used directly, prefer the type-safe android.ModuleProvider instead.
+	provider(provider blueprint.AnyProviderKey) (any, bool)
+
+	// setProvider sets the value for a provider for the current module.  It panics if not called
+	// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value
+	// is not of the appropriate type, or if the value has already been set.  The value should not
+	// be modified after being passed to SetProvider.
+	//
+	// This method shouldn't be used directly, prefer the type-safe android.SetProvider instead.
+	setProvider(provider blueprint.AnyProviderKey, value any)
+
+	GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
+
+	// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if
+	// none exists.  It panics if the dependency does not have the specified tag.  It skips any
+	// dependencies that are not an android.Module.
+	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.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.
+	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
+
+	// VisitDirectDepsBlueprint calls visit for each direct dependency.  If there are multiple
+	// direct dependencies on the same module visit will be called multiple times on that module
+	// and OtherModuleDependencyTag will return a different tag for each.
+	//
+	// The Module passed to the visit function should not be retained outside of the visit
+	// function, it may be invalidated by future mutators.
+	VisitDirectDepsBlueprint(visit func(blueprint.Module))
+
+	// VisitDirectDepsIgnoreBlueprint calls visit for each direct dependency.  If there are multiple
+	// direct dependencies on the same module visit will be called multiple times on that module
+	// and OtherModuleDependencyTag will return a different tag for each.  It silently ignores any
+	// dependencies that are not an android.Module.
+	//
+	// The Module passed to the visit function should not be retained outside of the visit
+	// function, it may be invalidated by future mutators.
+	VisitDirectDepsIgnoreBlueprint(visit func(Module))
+
+	// VisitDirectDeps calls visit for each direct dependency.  If there are multiple
+	// direct dependencies on the same module visit will be called multiple times on that module
+	// and OtherModuleDependencyTag will return a different tag for each.  It raises an error if any of the
+	// dependencies are not an android.Module.
+	//
+	// The Module passed to the visit function should not be retained outside of the visit
+	// function, it may be invalidated by future mutators.
+	VisitDirectDeps(visit func(Module))
+
+	VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
+
+	// VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit.  If there are
+	// multiple direct dependencies on the same module pred and visit will be called multiple times on that module and
+	// OtherModuleDependencyTag will return a different tag for each.  It skips any
+	// dependencies that are not an android.Module.
+	//
+	// The Module passed to the visit function should not be retained outside of the visit function, it may be
+	// invalidated by future mutators.
+	VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
+	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
+	VisitDepsDepthFirst(visit func(Module))
+	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
+	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
+
+	// WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order.  visit may
+	// be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the
+	// child and parent with different tags.  OtherModuleDependencyTag will return the tag for the currently visited
+	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down to child.  It skips
+	// any dependencies that are not an android.Module.
+	//
+	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
+	// invalidated by future mutators.
+	WalkDeps(visit func(child, parent Module) bool)
+
+	// WalkDepsBlueprint calls visit for each transitive dependency, traversing the dependency
+	// tree in top down order.  visit may be called multiple times for the same (child, parent)
+	// pair if there are multiple direct dependencies between the child and parent with different
+	// tags.  OtherModuleDependencyTag will return the tag for the currently visited
+	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down
+	// to child.
+	//
+	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
+	// invalidated by future mutators.
+	WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool)
+
+	// GetWalkPath is supposed to be called in visit function passed in WalkDeps()
+	// and returns a top-down dependency path from a start module to current child module.
+	GetWalkPath() []Module
+
+	// PrimaryModule returns the first variant of the current module.  Variants of a module are always visited in
+	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the
+	// Module returned by PrimaryModule without data races.  This can be used to perform singleton actions that are
+	// only done once for all variants of a module.
+	PrimaryModule() Module
+
+	// FinalModule returns the last variant of the current module.  Variants of a module are always visited in
+	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all
+	// variants using VisitAllModuleVariants if the current module == FinalModule().  This can be used to perform
+	// singleton actions that are only done once for all variants of a module.
+	FinalModule() Module
+
+	// VisitAllModuleVariants calls visit for each variant of the current module.  Variants of a module are always
+	// visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read
+	// from all variants if the current module == FinalModule().  Otherwise, care must be taken to not access any
+	// data modified by the current mutator.
+	VisitAllModuleVariants(visit func(Module))
+
+	// GetTagPath is supposed to be called in visit function passed in WalkDeps()
+	// and returns a top-down dependency tags path from a start module to current child module.
+	// It has one less entry than GetWalkPath() as it contains the dependency tags that
+	// exist between each adjacent pair of modules in the GetWalkPath().
+	// GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1]
+	GetTagPath() []blueprint.DependencyTag
+
+	// GetPathString is supposed to be called in visit function passed in WalkDeps()
+	// and returns a multi-line string showing the modules and dependency tags
+	// among them along the top-down dependency path from a start module to current child module.
+	// skipFirst when set to true, the output doesn't include the start module,
+	// which is already printed when this function is used along with ModuleErrorf().
+	GetPathString(skipFirst bool) string
+
+	AddMissingDependencies(missingDeps []string)
+
+	// getMissingDependencies returns the list of missing dependencies.
+	// Calling this function prevents adding new dependencies.
+	getMissingDependencies() []string
+
+	// EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context
+	// can be used to evaluate the final value of Configurable properties.
+	EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue
+}
+
+type baseModuleContext struct {
+	bp blueprint.BaseModuleContext
+	earlyModuleContext
+	archModuleContext
+
+	walkPath []Module
+	tagPath  []blueprint.DependencyTag
+
+	strictVisitDeps bool // If true, enforce that all dependencies are enabled
+
+}
+
+func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string {
+	return b.bp.OtherModuleName(m)
+}
+func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string { return b.bp.OtherModuleDir(m) }
+func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) {
+	b.bp.OtherModuleErrorf(m, fmt, args...)
+}
+func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag {
+	return b.bp.OtherModuleDependencyTag(m)
+}
+func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) }
+func (b *baseModuleContext) OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool {
+	return b.bp.OtherModuleDependencyVariantExists(variations, name)
+}
+func (b *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool {
+	return b.bp.OtherModuleFarDependencyVariantExists(variations, name)
+}
+func (b *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool {
+	return b.bp.OtherModuleReverseDependencyVariantExists(name)
+}
+func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string {
+	return b.bp.OtherModuleType(m)
+}
+
+func (b *baseModuleContext) otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
+	return b.bp.OtherModuleProvider(m, provider)
+}
+
+func (b *baseModuleContext) provider(provider blueprint.AnyProviderKey) (any, bool) {
+	return b.bp.Provider(provider)
+}
+
+func (b *baseModuleContext) setProvider(provider blueprint.AnyProviderKey, value any) {
+	b.bp.SetProvider(provider, value)
+}
+
+func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
+	return b.bp.GetDirectDepWithTag(name, tag)
+}
+
+func (b *baseModuleContext) blueprintBaseModuleContext() blueprint.BaseModuleContext {
+	return b.bp
+}
+
+func (b *baseModuleContext) AddMissingDependencies(deps []string) {
+	if deps != nil {
+		missingDeps := &b.Module().base().commonProperties.MissingDeps
+		*missingDeps = append(*missingDeps, deps...)
+		*missingDeps = FirstUniqueStrings(*missingDeps)
+	}
+}
+
+func (b *baseModuleContext) checkedMissingDeps() bool {
+	return b.Module().base().commonProperties.CheckedMissingDeps
+}
+
+func (b *baseModuleContext) getMissingDependencies() []string {
+	checked := &b.Module().base().commonProperties.CheckedMissingDeps
+	*checked = true
+	var missingDeps []string
+	missingDeps = append(missingDeps, b.Module().base().commonProperties.MissingDeps...)
+	missingDeps = append(missingDeps, b.bp.EarlyGetMissingDependencies()...)
+	missingDeps = FirstUniqueStrings(missingDeps)
+	return missingDeps
+}
+
+type AllowDisabledModuleDependency interface {
+	blueprint.DependencyTag
+	AllowDisabledModuleDependency(target Module) bool
+}
+
+type AlwaysAllowDisabledModuleDependencyTag struct{}
+
+func (t AlwaysAllowDisabledModuleDependencyTag) AllowDisabledModuleDependency(Module) bool {
+	return true
+}
+
+func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool, ignoreBlueprint bool) Module {
+	aModule, _ := module.(Module)
+
+	if !strict {
+		return aModule
+	}
+
+	if aModule == nil {
+		if !ignoreBlueprint {
+			b.ModuleErrorf("module %q (%#v) not an android module", b.OtherModuleName(module), tag)
+		}
+		return nil
+	}
+
+	if !aModule.Enabled() {
+		if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependency(aModule) {
+			if b.Config().AllowMissingDependencies() {
+				b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
+			} else {
+				b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
+			}
+		}
+		return nil
+	}
+	return aModule
+}
+
+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 {
+			if aModule.base().BaseModuleName() == name {
+				returnedTag := b.bp.OtherModuleDependencyTag(aModule)
+				if tag == nil || returnedTag == tag {
+					deps = append(deps, dep{aModule, returnedTag})
+				}
+			}
+		} else if b.bp.OtherModuleName(module) == name {
+			returnedTag := b.bp.OtherModuleDependencyTag(module)
+			if tag == nil || returnedTag == tag {
+				deps = append(deps, dep{module, returnedTag})
+			}
+		}
+	})
+	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 {
+		panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
+			name, b.ModuleName()))
+	} else {
+		return nil, nil
+	}
+}
+
+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) {
+		if aModule, _ := module.(Module); aModule != nil {
+			if b.bp.OtherModuleDependencyTag(aModule) == tag {
+				deps = append(deps, aModule)
+			}
+		}
+	})
+	return deps
+}
+
+// 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.getDirectDepFirstTag(name)
+}
+
+func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) {
+	b.bp.VisitDirectDeps(visit)
+}
+
+func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) {
+	b.visitDirectDeps(visit, false)
+}
+
+func (b *baseModuleContext) VisitDirectDepsIgnoreBlueprint(visit func(Module)) {
+	b.visitDirectDeps(visit, true)
+}
+
+func (b *baseModuleContext) visitDirectDeps(visit func(Module), ignoreBlueprint bool) {
+	b.bp.VisitDirectDeps(func(module blueprint.Module) {
+		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, ignoreBlueprint); aModule != nil {
+			visit(aModule)
+		}
+	})
+}
+
+func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
+	b.bp.VisitDirectDeps(func(module blueprint.Module) {
+		if b.bp.OtherModuleDependencyTag(module) == tag {
+			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil {
+				visit(aModule)
+			}
+		}
+	})
+}
+
+func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
+	b.bp.VisitDirectDepsIf(
+		// pred
+		func(module blueprint.Module) bool {
+			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil {
+				return pred(aModule)
+			} else {
+				return false
+			}
+		},
+		// visit
+		func(module blueprint.Module) {
+			visit(module.(Module))
+		})
+}
+
+func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
+	b.bp.VisitDepsDepthFirst(func(module blueprint.Module) {
+		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil {
+			visit(aModule)
+		}
+	})
+}
+
+func (b *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) {
+	b.bp.VisitDepsDepthFirstIf(
+		// pred
+		func(module blueprint.Module) bool {
+			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps, false); aModule != nil {
+				return pred(aModule)
+			} else {
+				return false
+			}
+		},
+		// visit
+		func(module blueprint.Module) {
+			visit(module.(Module))
+		})
+}
+
+func (b *baseModuleContext) WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) {
+	b.bp.WalkDeps(visit)
+}
+
+func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
+	b.walkPath = []Module{b.Module()}
+	b.tagPath = []blueprint.DependencyTag{}
+	b.bp.WalkDeps(func(child, parent blueprint.Module) bool {
+		childAndroidModule, _ := child.(Module)
+		parentAndroidModule, _ := parent.(Module)
+		if childAndroidModule != nil && parentAndroidModule != nil {
+			// record walkPath before visit
+			for b.walkPath[len(b.walkPath)-1] != parentAndroidModule {
+				b.walkPath = b.walkPath[0 : len(b.walkPath)-1]
+				b.tagPath = b.tagPath[0 : len(b.tagPath)-1]
+			}
+			b.walkPath = append(b.walkPath, childAndroidModule)
+			b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule))
+			return visit(childAndroidModule, parentAndroidModule)
+		} else {
+			return false
+		}
+	})
+}
+
+func (b *baseModuleContext) GetWalkPath() []Module {
+	return b.walkPath
+}
+
+func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag {
+	return b.tagPath
+}
+
+func (b *baseModuleContext) VisitAllModuleVariants(visit func(Module)) {
+	b.bp.VisitAllModuleVariants(func(module blueprint.Module) {
+		visit(module.(Module))
+	})
+}
+
+func (b *baseModuleContext) PrimaryModule() Module {
+	return b.bp.PrimaryModule().(Module)
+}
+
+func (b *baseModuleContext) FinalModule() Module {
+	return b.bp.FinalModule().(Module)
+}
+
+// IsMetaDependencyTag returns true for cross-cutting metadata dependencies.
+func IsMetaDependencyTag(tag blueprint.DependencyTag) bool {
+	if tag == licenseKindTag {
+		return true
+	} else if tag == licensesTag {
+		return true
+	} else if tag == acDepTag {
+		return true
+	}
+	return false
+}
+
+// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
+// a dependency tag.
+var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:{}\E(, )?`)
+
+// PrettyPrintTag returns string representation of the tag, but prefers
+// custom String() method if available.
+func PrettyPrintTag(tag blueprint.DependencyTag) string {
+	// Use tag's custom String() method if available.
+	if stringer, ok := tag.(fmt.Stringer); ok {
+		return stringer.String()
+	}
+
+	// Otherwise, get a default string representation of the tag's struct.
+	tagString := fmt.Sprintf("%T: %+v", tag, tag)
+
+	// Remove the boilerplate from BaseDependencyTag as it adds no value.
+	tagString = tagCleaner.ReplaceAllString(tagString, "")
+	return tagString
+}
+
+func (b *baseModuleContext) GetPathString(skipFirst bool) string {
+	sb := strings.Builder{}
+	tagPath := b.GetTagPath()
+	walkPath := b.GetWalkPath()
+	if !skipFirst {
+		sb.WriteString(walkPath[0].String())
+	}
+	for i, m := range walkPath[1:] {
+		sb.WriteString("\n")
+		sb.WriteString(fmt.Sprintf("           via tag %s\n", PrettyPrintTag(tagPath[i])))
+		sb.WriteString(fmt.Sprintf("    -> %s", m.String()))
+	}
+	return sb.String()
+}
+
+func (m *baseModuleContext) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue {
+	return m.Module().ConfigurableEvaluator(m).EvaluateConfiguration(condition, property)
+}
diff --git a/android/bazel.go b/android/bazel.go
deleted file mode 100644
index df30ff2..0000000
--- a/android/bazel.go
+++ /dev/null
@@ -1,644 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package android
-
-import (
-	"bufio"
-	"errors"
-	"fmt"
-	"strings"
-
-	"android/soong/ui/metrics/bp2build_metrics_proto"
-	"github.com/google/blueprint"
-	"github.com/google/blueprint/bootstrap"
-	"github.com/google/blueprint/proptools"
-
-	"android/soong/android/allowlists"
-)
-
-const (
-	// A sentinel value to be used as a key in Bp2BuildConfig for modules with
-	// no package path. This is also the module dir for top level Android.bp
-	// modules.
-	Bp2BuildTopLevel = "."
-)
-
-type MixedBuildEnabledStatus int
-
-const (
-	// This module can be mixed_built.
-	MixedBuildEnabled = iota
-
-	// There is a technical incompatibility preventing this module from being
-	// bazel-analyzed. Note: the module might also be incompatible.
-	TechnicalIncompatibility
-
-	// This module cannot be mixed_built due to some incompatibility with it
-	// that is not a platform incompatibility. Example: the module-type is not
-	// enabled, or is not bp2build-converted.
-	ModuleIncompatibility
-
-	// Missing dependencies. We can't query Bazel for modules if it has missing dependencies, there
-	// will be failures.
-	ModuleMissingDeps
-)
-
-// FileGroupAsLibrary describes a filegroup module that is converted to some library
-// such as aidl_library or proto_library.
-type FileGroupAsLibrary interface {
-	ShouldConvertToAidlLibrary(ctx BazelConversionPathContext) bool
-	ShouldConvertToProtoLibrary(ctx BazelConversionPathContext) bool
-	GetAidlLibraryLabel(ctx BazelConversionPathContext) string
-	GetProtoLibraryLabel(ctx BazelConversionPathContext) string
-}
-
-type BazelConversionStatus struct {
-	// Information about _all_ bp2build targets generated by this module. Multiple targets are
-	// supported as Soong handles some things within a single target that we may choose to split into
-	// multiple targets, e.g. renderscript, protos, yacc within a cc module.
-	Bp2buildInfo []bp2buildInfo `blueprint:"mutated"`
-
-	// UnconvertedBp2buildDep stores the module names of direct dependency that were not converted to
-	// Bazel
-	UnconvertedDeps []string `blueprint:"mutated"`
-
-	// MissingBp2buildDep stores the module names of direct dependency that were not found
-	MissingDeps []string `blueprint:"mutated"`
-
-	// If non-nil, indicates that the module could not be converted successfully
-	// with bp2build. This will describe the reason the module could not be converted.
-	UnconvertedReason *UnconvertedReason
-}
-
-// The reason a module could not be converted to a BUILD target via bp2build.
-// This should match bp2build_metrics_proto.UnconvertedReason, but omits private
-// proto-related fields that prevent copying this struct.
-type UnconvertedReason struct {
-	// Should correspond to a valid value in bp2build_metrics_proto.UnconvertedReasonType.
-	// A raw int is used here instead, because blueprint logic requires that all transitive
-	// fields of module definitions be primitives.
-	ReasonType int
-	Detail     string
-}
-
-type BazelModuleProperties struct {
-	// The label of the Bazel target replacing this Soong module. When run in conversion mode, this
-	// will import the handcrafted build target into the autogenerated file. Note: this may result in
-	// a conflict due to duplicate targets if bp2build_available is also set.
-	Label *string
-
-	// If true, bp2build will generate the converted Bazel target for this module. Note: this may
-	// cause a conflict due to the duplicate targets if label is also set.
-	//
-	// This is a bool pointer to support tristates: true, false, not set.
-	//
-	// To opt in a module, set bazel_module: { bp2build_available: true }
-	// To opt out a module, set bazel_module: { bp2build_available: false }
-	// To defer the default setting for the directory, do not set the value.
-	Bp2build_available *bool
-
-	// CanConvertToBazel is set via InitBazelModule to indicate that a module type can be converted to
-	// Bazel with Bp2build.
-	CanConvertToBazel bool `blueprint:"mutated"`
-}
-
-// Properties contains common module properties for Bazel migration purposes.
-type properties struct {
-	// In "Bazel mixed build" mode, this represents the Bazel target replacing
-	// this Soong module.
-	Bazel_module BazelModuleProperties
-}
-
-// namespacedVariableProperties is a map from a string representing a Soong
-// config variable namespace, like "android" or "vendor_name" to a slice of
-// pointer to a struct containing a single field called Soong_config_variables
-// whose value mirrors the structure in the Blueprint file.
-type namespacedVariableProperties map[string][]interface{}
-
-// BazelModuleBase contains the property structs with metadata for modules which can be converted to
-// Bazel.
-type BazelModuleBase struct {
-	bazelProperties properties
-
-	// namespacedVariableProperties is used for soong_config_module_type support
-	// in bp2build. Soong config modules allow users to set module properties
-	// based on custom product variables defined in Android.bp files. These
-	// variables are namespaced to prevent clobbering, especially when set from
-	// Makefiles.
-	namespacedVariableProperties namespacedVariableProperties
-
-	// baseModuleType is set when this module was created from a module type
-	// defined by a soong_config_module_type. Every soong_config_module_type
-	// "wraps" another module type, e.g. a soong_config_module_type can wrap a
-	// cc_defaults to a custom_cc_defaults, or cc_binary to a custom_cc_binary.
-	// This baseModuleType is set to the wrapped module type.
-	baseModuleType string
-}
-
-// Bazelable is specifies the interface for modules that can be converted to Bazel.
-type Bazelable interface {
-	bazelProps() *properties
-	HasHandcraftedLabel() bool
-	HandcraftedLabel() string
-	GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string
-	ShouldConvertWithBp2build(ctx BazelConversionContext) bool
-	shouldConvertWithBp2build(ctx bazelOtherModuleContext, module blueprint.Module) bool
-
-	// ConvertWithBp2build either converts the module to a Bazel build target or
-	// declares the module as unconvertible (for logging and metrics).
-	// Modules must implement this function to be bp2build convertible. The function
-	// must either create at least one Bazel target module (using ctx.CreateBazelTargetModule or
-	// its related functions), or declare itself unconvertible using ctx.MarkBp2buildUnconvertible.
-	ConvertWithBp2build(ctx TopDownMutatorContext)
-
-	// namespacedVariableProps is a map from a soong config variable namespace
-	// (e.g. acme, android) to a map of interfaces{}, which are really
-	// reflect.Struct pointers, representing the value of the
-	// soong_config_variables property of a module. The struct pointer is the
-	// one with the single member called Soong_config_variables, which itself is
-	// a struct containing fields for each supported feature in that namespace.
-	//
-	// The reason for using a slice of interface{} is to support defaults
-	// propagation of the struct pointers.
-	namespacedVariableProps() namespacedVariableProperties
-	setNamespacedVariableProps(props namespacedVariableProperties)
-	BaseModuleType() string
-	SetBaseModuleType(baseModuleType string)
-}
-
-// ApiProvider is implemented by modules that contribute to an API surface
-type ApiProvider interface {
-	ConvertWithApiBp2build(ctx TopDownMutatorContext)
-}
-
-// MixedBuildBuildable is an interface that module types should implement in order
-// to be "handled by Bazel" in a mixed build.
-type MixedBuildBuildable interface {
-	// IsMixedBuildSupported returns true if and only if this module should be
-	// "handled by Bazel" in a mixed build.
-	// This "escape hatch" allows modules with corner-case scenarios to opt out
-	// of being built with Bazel.
-	IsMixedBuildSupported(ctx BaseModuleContext) bool
-
-	// QueueBazelCall invokes request-queueing functions on the BazelContext
-	// so that these requests are handled when Bazel's cquery is invoked.
-	QueueBazelCall(ctx BaseModuleContext)
-
-	// ProcessBazelQueryResponse uses Bazel information (obtained from the BazelContext)
-	// to set module fields and providers to propagate this module's metadata upstream.
-	// This effectively "bridges the gap" between Bazel and Soong in a mixed build.
-	// Soong modules depending on this module should be oblivious to the fact that
-	// this module was handled by Bazel.
-	ProcessBazelQueryResponse(ctx ModuleContext)
-}
-
-// BazelModule is a lightweight wrapper interface around Module for Bazel-convertible modules.
-type BazelModule interface {
-	Module
-	Bazelable
-}
-
-// InitBazelModule is a wrapper function that decorates a BazelModule with Bazel-conversion
-// properties.
-func InitBazelModule(module BazelModule) {
-	module.AddProperties(module.bazelProps())
-	module.bazelProps().Bazel_module.CanConvertToBazel = true
-}
-
-// bazelProps returns the Bazel properties for the given BazelModuleBase.
-func (b *BazelModuleBase) bazelProps() *properties {
-	return &b.bazelProperties
-}
-
-func (b *BazelModuleBase) namespacedVariableProps() namespacedVariableProperties {
-	return b.namespacedVariableProperties
-}
-
-func (b *BazelModuleBase) setNamespacedVariableProps(props namespacedVariableProperties) {
-	b.namespacedVariableProperties = props
-}
-
-func (b *BazelModuleBase) BaseModuleType() string {
-	return b.baseModuleType
-}
-
-func (b *BazelModuleBase) SetBaseModuleType(baseModuleType string) {
-	b.baseModuleType = baseModuleType
-}
-
-// HasHandcraftedLabel returns whether this module has a handcrafted Bazel label.
-func (b *BazelModuleBase) HasHandcraftedLabel() bool {
-	return b.bazelProperties.Bazel_module.Label != nil
-}
-
-// HandcraftedLabel returns the handcrafted label for this module, or empty string if there is none
-func (b *BazelModuleBase) HandcraftedLabel() string {
-	return proptools.String(b.bazelProperties.Bazel_module.Label)
-}
-
-// GetBazelLabel returns the Bazel label for the given BazelModuleBase.
-func (b *BazelModuleBase) GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string {
-	if b.HasHandcraftedLabel() {
-		return b.HandcraftedLabel()
-	}
-	if b.ShouldConvertWithBp2build(ctx) {
-		return bp2buildModuleLabel(ctx, module)
-	}
-	panic(fmt.Errorf("requested non-existent label for module %s", module.Name()))
-}
-
-type Bp2BuildConversionAllowlist struct {
-	// Configure modules in these directories to enable bp2build_available: true or false by default.
-	defaultConfig allowlists.Bp2BuildConfig
-
-	// Keep any existing BUILD files (and do not generate new BUILD files) for these directories
-	// in the synthetic Bazel workspace.
-	keepExistingBuildFile map[string]bool
-
-	// Per-module allowlist to always opt modules into both bp2build and Bazel Dev Mode mixed
-	// builds. These modules are usually in directories with many other modules that are not ready
-	// for conversion.
-	//
-	// A module can either be in this list or its directory allowlisted entirely
-	// in bp2buildDefaultConfig, but not both at the same time.
-	moduleAlwaysConvert map[string]bool
-
-	// Per-module-type allowlist to always opt modules in to both bp2build and
-	// Bazel Dev Mode mixed builds when they have the same type as one listed.
-	moduleTypeAlwaysConvert map[string]bool
-
-	// Per-module denylist to always opt modules out of bp2build conversion.
-	moduleDoNotConvert map[string]bool
-}
-
-// NewBp2BuildAllowlist creates a new, empty Bp2BuildConversionAllowlist
-// which can be populated using builder pattern Set* methods
-func NewBp2BuildAllowlist() Bp2BuildConversionAllowlist {
-	return Bp2BuildConversionAllowlist{
-		allowlists.Bp2BuildConfig{},
-		map[string]bool{},
-		map[string]bool{},
-		map[string]bool{},
-		map[string]bool{},
-	}
-}
-
-// SetDefaultConfig copies the entries from defaultConfig into the allowlist
-func (a Bp2BuildConversionAllowlist) SetDefaultConfig(defaultConfig allowlists.Bp2BuildConfig) Bp2BuildConversionAllowlist {
-	if a.defaultConfig == nil {
-		a.defaultConfig = allowlists.Bp2BuildConfig{}
-	}
-	for k, v := range defaultConfig {
-		a.defaultConfig[k] = v
-	}
-
-	return a
-}
-
-// SetKeepExistingBuildFile copies the entries from keepExistingBuildFile into the allowlist
-func (a Bp2BuildConversionAllowlist) SetKeepExistingBuildFile(keepExistingBuildFile map[string]bool) Bp2BuildConversionAllowlist {
-	if a.keepExistingBuildFile == nil {
-		a.keepExistingBuildFile = map[string]bool{}
-	}
-	for k, v := range keepExistingBuildFile {
-		a.keepExistingBuildFile[k] = v
-	}
-
-	return a
-}
-
-// SetModuleAlwaysConvertList copies the entries from moduleAlwaysConvert into the allowlist
-func (a Bp2BuildConversionAllowlist) SetModuleAlwaysConvertList(moduleAlwaysConvert []string) Bp2BuildConversionAllowlist {
-	if a.moduleAlwaysConvert == nil {
-		a.moduleAlwaysConvert = map[string]bool{}
-	}
-	for _, m := range moduleAlwaysConvert {
-		a.moduleAlwaysConvert[m] = true
-	}
-
-	return a
-}
-
-// SetModuleTypeAlwaysConvertList copies the entries from moduleTypeAlwaysConvert into the allowlist
-func (a Bp2BuildConversionAllowlist) SetModuleTypeAlwaysConvertList(moduleTypeAlwaysConvert []string) Bp2BuildConversionAllowlist {
-	if a.moduleTypeAlwaysConvert == nil {
-		a.moduleTypeAlwaysConvert = map[string]bool{}
-	}
-	for _, m := range moduleTypeAlwaysConvert {
-		a.moduleTypeAlwaysConvert[m] = true
-	}
-
-	return a
-}
-
-// SetModuleDoNotConvertList copies the entries from moduleDoNotConvert into the allowlist
-func (a Bp2BuildConversionAllowlist) SetModuleDoNotConvertList(moduleDoNotConvert []string) Bp2BuildConversionAllowlist {
-	if a.moduleDoNotConvert == nil {
-		a.moduleDoNotConvert = map[string]bool{}
-	}
-	for _, m := range moduleDoNotConvert {
-		a.moduleDoNotConvert[m] = true
-	}
-
-	return a
-}
-
-// ShouldKeepExistingBuildFileForDir returns whether an existing BUILD file should be
-// added to the build symlink forest based on the current global configuration.
-func (a Bp2BuildConversionAllowlist) ShouldKeepExistingBuildFileForDir(dir string) bool {
-	if _, ok := a.keepExistingBuildFile[dir]; ok {
-		// Exact dir match
-		return true
-	}
-	var i int
-	// Check if subtree match
-	for {
-		j := strings.Index(dir[i:], "/")
-		if j == -1 {
-			return false //default
-		}
-		prefix := dir[0 : i+j]
-		i = i + j + 1 // skip the "/"
-		if recursive, ok := a.keepExistingBuildFile[prefix]; ok && recursive {
-			return true
-		}
-	}
-}
-
-var bp2BuildAllowListKey = NewOnceKey("Bp2BuildAllowlist")
-var bp2buildAllowlist OncePer
-
-func GetBp2BuildAllowList() Bp2BuildConversionAllowlist {
-	return bp2buildAllowlist.Once(bp2BuildAllowListKey, func() interface{} {
-		return NewBp2BuildAllowlist().SetDefaultConfig(allowlists.Bp2buildDefaultConfig).
-			SetKeepExistingBuildFile(allowlists.Bp2buildKeepExistingBuildFile).
-			SetModuleAlwaysConvertList(allowlists.Bp2buildModuleAlwaysConvertList).
-			SetModuleTypeAlwaysConvertList(allowlists.Bp2buildModuleTypeAlwaysConvertList).
-			SetModuleDoNotConvertList(allowlists.Bp2buildModuleDoNotConvertList)
-	}).(Bp2BuildConversionAllowlist)
-}
-
-// MixedBuildsEnabled returns a MixedBuildEnabledStatus regarding whether
-// a module is ready to be replaced by a converted or handcrafted Bazel target.
-// As a side effect, calling this method will also log whether this module is
-// mixed build enabled for metrics reporting.
-func MixedBuildsEnabled(ctx BaseModuleContext) MixedBuildEnabledStatus {
-	platformIncompatible := isPlatformIncompatible(ctx.Os(), ctx.Arch().ArchType)
-	if platformIncompatible {
-		ctx.Config().LogMixedBuild(ctx, false)
-		return TechnicalIncompatibility
-	}
-
-	if ctx.Config().AllowMissingDependencies() {
-		missingDeps := ctx.getMissingDependencies()
-		// If there are missing dependencies, querying Bazel will fail. Soong instead fails at execution
-		// time, not loading/analysis. disable mixed builds and fall back to Soong to maintain that
-		// behavior.
-		if len(missingDeps) > 0 {
-			ctx.Config().LogMixedBuild(ctx, false)
-			return ModuleMissingDeps
-		}
-	}
-
-	module := ctx.Module()
-	apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo)
-	withinApex := !apexInfo.IsForPlatform()
-	mixedBuildEnabled := ctx.Config().IsMixedBuildsEnabled() &&
-		module.Enabled() &&
-		convertedToBazel(ctx, module) &&
-		ctx.Config().BazelContext.IsModuleNameAllowed(module.Name(), withinApex)
-	ctx.Config().LogMixedBuild(ctx, mixedBuildEnabled)
-
-	if mixedBuildEnabled {
-		return MixedBuildEnabled
-	}
-	return ModuleIncompatibility
-}
-
-func isGoModule(module blueprint.Module) bool {
-	if _, ok := module.(*bootstrap.GoPackage); ok {
-		return true
-	}
-	if _, ok := module.(*bootstrap.GoBinary); ok {
-		return true
-	}
-	return false
-}
-
-// ConvertedToBazel returns whether this module has been converted (with bp2build or manually) to Bazel.
-func convertedToBazel(ctx BazelConversionContext, module blueprint.Module) bool {
-	// Special-case bootstrap_go_package and bootstrap_go_binary
-	// These do not implement Bazelable, but have been converted
-	if isGoModule(module) {
-		return true
-	}
-	b, ok := module.(Bazelable)
-	if !ok {
-		return false
-	}
-	return b.shouldConvertWithBp2build(ctx, module) || b.HasHandcraftedLabel()
-}
-
-// ShouldConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build
-func (b *BazelModuleBase) ShouldConvertWithBp2build(ctx BazelConversionContext) bool {
-	return b.shouldConvertWithBp2build(ctx, ctx.Module())
-}
-
-type bazelOtherModuleContext interface {
-	ModuleErrorf(format string, args ...interface{})
-	Config() Config
-	OtherModuleType(m blueprint.Module) string
-	OtherModuleName(m blueprint.Module) string
-	OtherModuleDir(m blueprint.Module) string
-}
-
-func isPlatformIncompatible(osType OsType, arch ArchType) bool {
-	return osType == Windows || // Windows toolchains are not currently supported.
-		osType == LinuxBionic || // Linux Bionic toolchains are not currently supported.
-		osType == LinuxMusl || // Linux musl toolchains are not currently supported (b/259266326).
-		arch == Riscv64 // TODO(b/262192655) Riscv64 toolchains are not currently supported.
-}
-
-func (b *BazelModuleBase) shouldConvertWithBp2build(ctx bazelOtherModuleContext, module blueprint.Module) bool {
-	if !b.bazelProps().Bazel_module.CanConvertToBazel {
-		return false
-	}
-
-	// In api_bp2build mode, all soong modules that can provide API contributions should be converted
-	// This is irrespective of its presence/absence in bp2build allowlists
-	if ctx.Config().BuildMode == ApiBp2build {
-		_, providesApis := module.(ApiProvider)
-		return providesApis
-	}
-
-	propValue := b.bazelProperties.Bazel_module.Bp2build_available
-	packagePath := moduleDirWithPossibleOverride(ctx, module)
-
-	// Modules in unit tests which are enabled in the allowlist by type or name
-	// trigger this conditional because unit tests run under the "." package path
-	isTestModule := packagePath == Bp2BuildTopLevel && proptools.BoolDefault(propValue, false)
-	if isTestModule {
-		return true
-	}
-
-	moduleName := moduleNameWithPossibleOverride(ctx, module)
-	allowlist := ctx.Config().Bp2buildPackageConfig
-	moduleNameAllowed := allowlist.moduleAlwaysConvert[moduleName]
-	moduleTypeAllowed := allowlist.moduleTypeAlwaysConvert[ctx.OtherModuleType(module)]
-	allowlistConvert := moduleNameAllowed || moduleTypeAllowed
-	if moduleNameAllowed && moduleTypeAllowed {
-		ctx.ModuleErrorf("A module cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert")
-		return false
-	}
-
-	if allowlist.moduleDoNotConvert[moduleName] {
-		if moduleNameAllowed {
-			ctx.ModuleErrorf("a module cannot be in moduleDoNotConvert and also be in moduleAlwaysConvert")
-		}
-		return false
-	}
-
-	// This is a tristate value: true, false, or unset.
-	if ok, directoryPath := bp2buildDefaultTrueRecursively(packagePath, allowlist.defaultConfig); ok {
-		if moduleNameAllowed {
-			ctx.ModuleErrorf("A module cannot be in a directory marked Bp2BuildDefaultTrue"+
-				" or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: '%s'"+
-				" Module: '%s'", directoryPath, moduleName)
-			return false
-		}
-
-		// Allow modules to explicitly opt-out.
-		return proptools.BoolDefault(propValue, true)
-	}
-
-	// Allow modules to explicitly opt-in.
-	return proptools.BoolDefault(propValue, allowlistConvert)
-}
-
-// bp2buildDefaultTrueRecursively checks that the package contains a prefix from the
-// set of package prefixes where all modules must be converted. That is, if the
-// package is x/y/z, and the list contains either x, x/y, or x/y/z, this function will
-// return true.
-//
-// However, if the package is x/y, and it matches a Bp2BuildDefaultFalse "x/y" entry
-// exactly, this module will return false early.
-//
-// This function will also return false if the package doesn't match anything in
-// the config.
-//
-// This function will also return the allowlist entry which caused a particular
-// package to be enabled. Since packages can be enabled via a recursive declaration,
-// the path returned will not always be the same as the one provided.
-func bp2buildDefaultTrueRecursively(packagePath string, config allowlists.Bp2BuildConfig) (bool, string) {
-	// Check if the package path has an exact match in the config.
-	if config[packagePath] == allowlists.Bp2BuildDefaultTrue || config[packagePath] == allowlists.Bp2BuildDefaultTrueRecursively {
-		return true, packagePath
-	} else if config[packagePath] == allowlists.Bp2BuildDefaultFalse || config[packagePath] == allowlists.Bp2BuildDefaultFalseRecursively {
-		return false, packagePath
-	}
-
-	// If not, check for the config recursively.
-	packagePrefix := packagePath
-
-	// e.g. for x/y/z, iterate over x/y, then x, taking the most-specific value from the allowlist.
-	for strings.Contains(packagePrefix, "/") {
-		dirIndex := strings.LastIndex(packagePrefix, "/")
-		packagePrefix = packagePrefix[:dirIndex]
-		switch value := config[packagePrefix]; value {
-		case allowlists.Bp2BuildDefaultTrueRecursively:
-			// package contains this prefix and this prefix should convert all modules
-			return true, packagePrefix
-		case allowlists.Bp2BuildDefaultFalseRecursively:
-			//package contains this prefix and this prefix should NOT convert any modules
-			return false, packagePrefix
-		}
-		// Continue to the next part of the package dir.
-
-	}
-
-	return false, packagePath
-}
-
-func registerBp2buildConversionMutator(ctx RegisterMutatorsContext) {
-	ctx.TopDown("bp2build_conversion", bp2buildConversionMutator).Parallel()
-}
-
-func bp2buildConversionMutator(ctx TopDownMutatorContext) {
-	if ctx.Config().HasBazelBuildTargetInSource(ctx) {
-		// Defer to the BUILD target. Generating an additional target would
-		// cause a BUILD file conflict.
-		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE, "")
-		return
-	}
-
-	bModule, ok := ctx.Module().(Bazelable)
-	if !ok {
-		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
-		return
-	}
-	// TODO: b/285631638 - Differentiate between denylisted modules and missing bp2build capabilities.
-	if !bModule.shouldConvertWithBp2build(ctx, ctx.Module()) {
-		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "")
-		return
-	}
-	bModule.ConvertWithBp2build(ctx)
-
-	if !ctx.Module().base().IsConvertedByBp2build() && ctx.Module().base().GetUnconvertedReason() == nil {
-		panic(fmt.Errorf("illegal bp2build invariant: module '%s' was neither converted nor marked unconvertible", ctx.ModuleName()))
-	}
-}
-
-func registerApiBp2buildConversionMutator(ctx RegisterMutatorsContext) {
-	ctx.TopDown("apiBp2build_conversion", convertWithApiBp2build).Parallel()
-}
-
-// Generate API contribution targets if the Soong module provides APIs
-func convertWithApiBp2build(ctx TopDownMutatorContext) {
-	if m, ok := ctx.Module().(ApiProvider); ok {
-		m.ConvertWithApiBp2build(ctx)
-	}
-}
-
-// GetMainClassInManifest scans the manifest file specified in filepath and returns
-// the value of attribute Main-Class in the manifest file if it exists, or returns error.
-// WARNING: this is for bp2build converters of java_* modules only.
-func GetMainClassInManifest(c Config, filepath string) (string, error) {
-	file, err := c.fs.Open(filepath)
-	if err != nil {
-		return "", err
-	}
-	defer file.Close()
-	scanner := bufio.NewScanner(file)
-	for scanner.Scan() {
-		line := scanner.Text()
-		if strings.HasPrefix(line, "Main-Class:") {
-			return strings.TrimSpace(line[len("Main-Class:"):]), nil
-		}
-	}
-
-	return "", errors.New("Main-Class is not found.")
-}
-
-func AttachValidationActions(ctx ModuleContext, outputFilePath Path, validations Paths) ModuleOutPath {
-	validatedOutputFilePath := PathForModuleOut(ctx, "validated", outputFilePath.Base())
-	ctx.Build(pctx, BuildParams{
-		Rule:        CpNoPreserveSymlink,
-		Description: "run validations " + outputFilePath.Base(),
-		Output:      validatedOutputFilePath,
-		Input:       outputFilePath,
-		Validations: validations,
-	})
-	return validatedOutputFilePath
-}
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
deleted file mode 100644
index fda8a22..0000000
--- a/android/bazel_handler.go
+++ /dev/null
@@ -1,1587 +0,0 @@
-// Copyright 2020 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package android
-
-import (
-	"bytes"
-	"crypto/sha1"
-	"encoding/hex"
-	"fmt"
-	"os"
-	"path"
-	"path/filepath"
-	"regexp"
-	"runtime"
-	"sort"
-	"strings"
-	"sync"
-
-	"android/soong/android/allowlists"
-	"android/soong/bazel/cquery"
-	"android/soong/shared"
-	"android/soong/starlark_import"
-
-	"github.com/google/blueprint"
-	"github.com/google/blueprint/metrics"
-
-	"android/soong/bazel"
-)
-
-var (
-	_                 = pctx.HostBinToolVariable("bazelBuildRunfilesTool", "build-runfiles")
-	buildRunfilesRule = pctx.AndroidStaticRule("bazelBuildRunfiles", blueprint.RuleParams{
-		Command:     "${bazelBuildRunfilesTool} ${in} ${outDir}",
-		Depfile:     "",
-		Description: "",
-		CommandDeps: []string{"${bazelBuildRunfilesTool}"},
-	}, "outDir")
-)
-
-func registerMixedBuildsMutator(ctx RegisterMutatorsContext) {
-	ctx.BottomUp("mixed_builds_prep", mixedBuildsPrepareMutator).Parallel()
-}
-
-func RegisterMixedBuildsMutator(ctx RegistrationContext) {
-	ctx.FinalDepsMutators(registerMixedBuildsMutator)
-}
-
-func mixedBuildsPrepareMutator(ctx BottomUpMutatorContext) {
-	if m := ctx.Module(); m.Enabled() {
-		if mixedBuildMod, ok := m.(MixedBuildBuildable); ok {
-			mixedBuildEnabled := MixedBuildsEnabled(ctx)
-			queueMixedBuild := mixedBuildMod.IsMixedBuildSupported(ctx) && mixedBuildEnabled == MixedBuildEnabled
-			if queueMixedBuild {
-				mixedBuildMod.QueueBazelCall(ctx)
-			}
-		}
-	}
-}
-
-type cqueryRequest interface {
-	// Name returns a string name for this request type. Such request type names must be unique,
-	// and must only consist of alphanumeric characters.
-	Name() string
-
-	// StarlarkFunctionBody returns a starlark function body to process this request type.
-	// The returned string is the body of a Starlark function which obtains
-	// all request-relevant information about a target and returns a string containing
-	// this information.
-	// The function should have the following properties:
-	//   - The arguments are `target` (a configured target) and `id_string` (the label + configuration).
-	//   - The return value must be a string.
-	//   - The function body should not be indented outside of its own scope.
-	StarlarkFunctionBody() string
-}
-
-// Portion of cquery map key to describe target configuration.
-type configKey struct {
-	arch    string
-	osType  OsType
-	apexKey ApexConfigKey
-}
-
-type ApexConfigKey struct {
-	WithinApex     bool
-	ApexSdkVersion string
-	ApiDomain      string
-}
-
-func (c ApexConfigKey) String() string {
-	return fmt.Sprintf("%s_%s_%s", withinApexToString(c.WithinApex), c.ApexSdkVersion, c.ApiDomain)
-}
-
-func withinApexToString(withinApex bool) string {
-	if withinApex {
-		return "within_apex"
-	}
-	return ""
-}
-
-func (c configKey) String() string {
-	return fmt.Sprintf("%s::%s::%s", c.arch, c.osType, c.apexKey)
-}
-
-// Map key to describe bazel cquery requests.
-type cqueryKey struct {
-	label       string
-	requestType cqueryRequest
-	configKey   configKey
-}
-
-func makeCqueryKey(label string, cqueryRequest cqueryRequest, cfgKey configKey) cqueryKey {
-	if strings.HasPrefix(label, "//") {
-		// Normalize Bazel labels to specify main repository explicitly.
-		label = "@" + label
-	}
-	return cqueryKey{label, cqueryRequest, cfgKey}
-}
-
-func (c cqueryKey) String() string {
-	return fmt.Sprintf("cquery(%s,%s,%s)", c.label, c.requestType.Name(), c.configKey)
-}
-
-type invokeBazelContext interface {
-	GetEventHandler() *metrics.EventHandler
-}
-
-// BazelContext is a context object useful for interacting with Bazel during
-// the course of a build. Use of Bazel to evaluate part of the build graph
-// is referred to as a "mixed build". (Some modules are managed by Soong,
-// some are managed by Bazel). To facilitate interop between these build
-// subgraphs, Soong may make requests to Bazel and evaluate their responses
-// so that Soong modules may accurately depend on Bazel targets.
-type BazelContext interface {
-	// Add a cquery request to the bazel request queue. All queued requests
-	// will be sent to Bazel on a subsequent invocation of InvokeBazel.
-	QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey)
-
-	// ** Cquery Results Retrieval Functions
-	// The below functions pertain to retrieving cquery results from a prior
-	// InvokeBazel function call and parsing the results.
-
-	// Returns result files built by building the given bazel target label.
-	GetOutputFiles(label string, cfgKey configKey) ([]string, error)
-
-	// Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order).
-	GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, error)
-
-	// Returns the results of the GetApexInfo query (including output files)
-	GetApexInfo(label string, cfgkey configKey) (cquery.ApexInfo, error)
-
-	// Returns the results of the GetCcUnstrippedInfo query
-	GetCcUnstrippedInfo(label string, cfgkey configKey) (cquery.CcUnstrippedInfo, error)
-
-	// Returns the results of the GetPrebuiltFileInfo query
-	GetPrebuiltFileInfo(label string, cfgKey configKey) (cquery.PrebuiltFileInfo, error)
-
-	// ** end Cquery Results Retrieval Functions
-
-	// Issues commands to Bazel to receive results for all cquery requests
-	// queued in the BazelContext. The ctx argument is optional and is only
-	// used for performance data collection
-	InvokeBazel(config Config, ctx invokeBazelContext) error
-
-	// Returns true if Bazel handling is enabled for the module with the given name.
-	// Note that this only implies "bazel mixed build" allowlisting. The caller
-	// should independently verify the module is eligible for Bazel handling
-	// (for example, that it is MixedBuildBuildable).
-	IsModuleNameAllowed(moduleName string, withinApex bool) bool
-
-	// Returns the bazel output base (the root directory for all bazel intermediate outputs).
-	OutputBase() string
-
-	// Returns build statements which should get registered to reflect Bazel's outputs.
-	BuildStatementsToRegister() []*bazel.BuildStatement
-
-	// Returns the depsets defined in Bazel's aquery response.
-	AqueryDepsets() []bazel.AqueryDepset
-
-	QueueBazelSandwichCqueryRequests(config Config) error
-}
-
-type bazelRunner interface {
-	issueBazelCommand(cmdRequest bazel.CmdRequest, paths *bazelPaths, eventHandler *metrics.EventHandler) (output string, errorMessage string, error error)
-}
-
-type bazelPaths struct {
-	homeDir       string
-	bazelPath     string
-	outputBase    string
-	workspaceDir  string
-	soongOutDir   string
-	metricsDir    string
-	bazelDepsFile string
-}
-
-// A context object which tracks queued requests that need to be made to Bazel,
-// and their results after the requests have been made.
-type mixedBuildBazelContext struct {
-	bazelRunner
-	paths *bazelPaths
-	// cquery requests that have not yet been issued to Bazel. This list is maintained
-	// in a sorted state, and is guaranteed to have no duplicates.
-	requests     []cqueryKey
-	requestMutex sync.Mutex // requests can be written in parallel
-
-	results map[cqueryKey]string // Results of cquery requests after Bazel invocations
-
-	// Build statements which should get registered to reflect Bazel's outputs.
-	buildStatements []*bazel.BuildStatement
-
-	// Depsets which should be used for Bazel's build statements.
-	depsets []bazel.AqueryDepset
-
-	// Per-module allowlist/denylist functionality to control whether analysis of
-	// modules are handled by Bazel. For modules which do not have a Bazel definition
-	// (or do not sufficiently support bazel handling via MixedBuildBuildable),
-	// this allowlist will have no effect, even if the module is explicitly allowlisted here.
-	// Per-module denylist to opt modules out of bazel handling.
-	bazelDisabledModules map[string]bool
-	// Per-module allowlist to opt modules in to bazel handling.
-	bazelEnabledModules map[string]bool
-	// DCLA modules are enabled when used in apex.
-	bazelDclaEnabledModules map[string]bool
-
-	targetProduct      string
-	targetBuildVariant string
-}
-
-var _ BazelContext = &mixedBuildBazelContext{}
-
-// A bazel context to use when Bazel is disabled.
-type noopBazelContext struct{}
-
-var _ BazelContext = noopBazelContext{}
-
-// A bazel context to use for tests.
-type MockBazelContext struct {
-	OutputBaseDir string
-
-	LabelToOutputFiles      map[string][]string
-	LabelToCcInfo           map[string]cquery.CcInfo
-	LabelToPythonBinary     map[string]string
-	LabelToApexInfo         map[string]cquery.ApexInfo
-	LabelToCcBinary         map[string]cquery.CcUnstrippedInfo
-	LabelToPrebuiltFileInfo map[string]cquery.PrebuiltFileInfo
-
-	BazelRequests map[string]bool
-}
-
-func (m MockBazelContext) QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey) {
-	key := BuildMockBazelContextRequestKey(label, requestType, cfgKey.arch, cfgKey.osType, cfgKey.apexKey)
-	if m.BazelRequests == nil {
-		m.BazelRequests = make(map[string]bool)
-	}
-	m.BazelRequests[key] = true
-}
-
-func (m MockBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
-	panic("unimplemented")
-}
-
-func (m MockBazelContext) GetOutputFiles(label string, _ configKey) ([]string, error) {
-	result, ok := m.LabelToOutputFiles[label]
-	if !ok {
-		return []string{}, fmt.Errorf("no target with label %q in LabelToOutputFiles", label)
-	}
-	return result, nil
-}
-
-func (m MockBazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, error) {
-	result, ok := m.LabelToCcInfo[label]
-	if !ok {
-		key := BuildMockBazelContextResultKey(label, cfgKey.arch, cfgKey.osType, cfgKey.apexKey)
-		result, ok = m.LabelToCcInfo[key]
-		if !ok {
-			return cquery.CcInfo{}, fmt.Errorf("no target with label %q in LabelToCcInfo", label)
-		}
-	}
-	return result, nil
-}
-
-func (m MockBazelContext) GetApexInfo(label string, _ configKey) (cquery.ApexInfo, error) {
-	result, ok := m.LabelToApexInfo[label]
-	if !ok {
-		return cquery.ApexInfo{}, fmt.Errorf("no target with label %q in LabelToApexInfo", label)
-	}
-	return result, nil
-}
-
-func (m MockBazelContext) GetCcUnstrippedInfo(label string, _ configKey) (cquery.CcUnstrippedInfo, error) {
-	result, ok := m.LabelToCcBinary[label]
-	if !ok {
-		return cquery.CcUnstrippedInfo{}, fmt.Errorf("no target with label %q in LabelToCcBinary", label)
-	}
-	return result, nil
-}
-
-func (m MockBazelContext) GetPrebuiltFileInfo(label string, _ configKey) (cquery.PrebuiltFileInfo, error) {
-	result, ok := m.LabelToPrebuiltFileInfo[label]
-	if !ok {
-		return cquery.PrebuiltFileInfo{}, fmt.Errorf("no target with label %q in LabelToPrebuiltFileInfo", label)
-	}
-	return result, nil
-}
-
-func (m MockBazelContext) InvokeBazel(_ Config, _ invokeBazelContext) error {
-	panic("unimplemented")
-}
-
-func (m MockBazelContext) IsModuleNameAllowed(_ string, _ bool) bool {
-	return true
-}
-
-func (m MockBazelContext) OutputBase() string { return m.OutputBaseDir }
-
-func (m MockBazelContext) BuildStatementsToRegister() []*bazel.BuildStatement {
-	return []*bazel.BuildStatement{}
-}
-
-func (m MockBazelContext) AqueryDepsets() []bazel.AqueryDepset {
-	return []bazel.AqueryDepset{}
-}
-
-var _ BazelContext = MockBazelContext{}
-
-func BuildMockBazelContextRequestKey(label string, request cqueryRequest, arch string, osType OsType, apexKey ApexConfigKey) string {
-	cfgKey := configKey{
-		arch:    arch,
-		osType:  osType,
-		apexKey: apexKey,
-	}
-
-	return strings.Join([]string{label, request.Name(), cfgKey.String()}, "_")
-}
-
-func BuildMockBazelContextResultKey(label string, arch string, osType OsType, apexKey ApexConfigKey) string {
-	cfgKey := configKey{
-		arch:    arch,
-		osType:  osType,
-		apexKey: apexKey,
-	}
-
-	return strings.Join([]string{label, cfgKey.String()}, "_")
-}
-
-func (bazelCtx *mixedBuildBazelContext) QueueBazelRequest(label string, requestType cqueryRequest, cfgKey configKey) {
-	key := makeCqueryKey(label, requestType, cfgKey)
-	bazelCtx.requestMutex.Lock()
-	defer bazelCtx.requestMutex.Unlock()
-
-	// Insert key into requests, maintaining the sort, and only if it's not duplicate.
-	keyString := key.String()
-	foundEqual := false
-	notLessThanKeyString := func(i int) bool {
-		s := bazelCtx.requests[i].String()
-		v := strings.Compare(s, keyString)
-		if v == 0 {
-			foundEqual = true
-		}
-		return v >= 0
-	}
-	targetIndex := sort.Search(len(bazelCtx.requests), notLessThanKeyString)
-	if foundEqual {
-		return
-	}
-
-	if targetIndex == len(bazelCtx.requests) {
-		bazelCtx.requests = append(bazelCtx.requests, key)
-	} else {
-		bazelCtx.requests = append(bazelCtx.requests[:targetIndex+1], bazelCtx.requests[targetIndex:]...)
-		bazelCtx.requests[targetIndex] = key
-	}
-}
-
-func (bazelCtx *mixedBuildBazelContext) GetOutputFiles(label string, cfgKey configKey) ([]string, error) {
-	key := makeCqueryKey(label, cquery.GetOutputFiles, cfgKey)
-	if rawString, ok := bazelCtx.results[key]; ok {
-		bazelOutput := strings.TrimSpace(rawString)
-
-		return cquery.GetOutputFiles.ParseResult(bazelOutput), nil
-	}
-	return nil, fmt.Errorf("no bazel response found for %v", key)
-}
-
-func (bazelCtx *mixedBuildBazelContext) GetCcInfo(label string, cfgKey configKey) (cquery.CcInfo, error) {
-	key := makeCqueryKey(label, cquery.GetCcInfo, cfgKey)
-	if rawString, ok := bazelCtx.results[key]; ok {
-		bazelOutput := strings.TrimSpace(rawString)
-		return cquery.GetCcInfo.ParseResult(bazelOutput)
-	}
-	return cquery.CcInfo{}, fmt.Errorf("no bazel response found for %v", key)
-}
-
-func (bazelCtx *mixedBuildBazelContext) GetApexInfo(label string, cfgKey configKey) (cquery.ApexInfo, error) {
-	key := makeCqueryKey(label, cquery.GetApexInfo, cfgKey)
-	if rawString, ok := bazelCtx.results[key]; ok {
-		return cquery.GetApexInfo.ParseResult(strings.TrimSpace(rawString))
-	}
-	return cquery.ApexInfo{}, fmt.Errorf("no bazel response found for %v", key)
-}
-
-func (bazelCtx *mixedBuildBazelContext) GetCcUnstrippedInfo(label string, cfgKey configKey) (cquery.CcUnstrippedInfo, error) {
-	key := makeCqueryKey(label, cquery.GetCcUnstrippedInfo, cfgKey)
-	if rawString, ok := bazelCtx.results[key]; ok {
-		return cquery.GetCcUnstrippedInfo.ParseResult(strings.TrimSpace(rawString))
-	}
-	return cquery.CcUnstrippedInfo{}, fmt.Errorf("no bazel response for %s", key)
-}
-
-func (bazelCtx *mixedBuildBazelContext) GetPrebuiltFileInfo(label string, cfgKey configKey) (cquery.PrebuiltFileInfo, error) {
-	key := makeCqueryKey(label, cquery.GetPrebuiltFileInfo, cfgKey)
-	if rawString, ok := bazelCtx.results[key]; ok {
-		return cquery.GetPrebuiltFileInfo.ParseResult(strings.TrimSpace(rawString))
-	}
-	return cquery.PrebuiltFileInfo{}, fmt.Errorf("no bazel response for %s", key)
-}
-
-func (n noopBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
-	panic("unimplemented")
-}
-
-func (n noopBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
-	panic("unimplemented")
-}
-
-func (n noopBazelContext) GetOutputFiles(_ string, _ configKey) ([]string, error) {
-	panic("unimplemented")
-}
-
-func (n noopBazelContext) GetCcInfo(_ string, _ configKey) (cquery.CcInfo, error) {
-	panic("unimplemented")
-}
-
-func (n noopBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexInfo, error) {
-	panic("unimplemented")
-}
-
-func (n noopBazelContext) GetCcUnstrippedInfo(_ string, _ configKey) (cquery.CcUnstrippedInfo, error) {
-	//TODO implement me
-	panic("implement me")
-}
-
-func (n noopBazelContext) GetPrebuiltFileInfo(_ string, _ configKey) (cquery.PrebuiltFileInfo, error) {
-	panic("implement me")
-}
-
-func (n noopBazelContext) InvokeBazel(_ Config, _ invokeBazelContext) error {
-	panic("unimplemented")
-}
-
-func (m noopBazelContext) OutputBase() string {
-	return ""
-}
-
-func (n noopBazelContext) IsModuleNameAllowed(_ string, _ bool) bool {
-	return false
-}
-
-func (m noopBazelContext) BuildStatementsToRegister() []*bazel.BuildStatement {
-	return []*bazel.BuildStatement{}
-}
-
-func (m noopBazelContext) AqueryDepsets() []bazel.AqueryDepset {
-	return []bazel.AqueryDepset{}
-}
-
-func AddToStringSet(set map[string]bool, items []string) {
-	for _, item := range items {
-		set[item] = true
-	}
-}
-
-func GetBazelEnabledAndDisabledModules(buildMode SoongBuildMode, forceEnabled map[string]struct{}) (map[string]bool, map[string]bool) {
-	disabledModules := map[string]bool{}
-	enabledModules := map[string]bool{}
-
-	switch buildMode {
-	case BazelProdMode:
-		AddToStringSet(enabledModules, allowlists.ProdMixedBuildsEnabledList)
-		for enabledAdHocModule := range forceEnabled {
-			enabledModules[enabledAdHocModule] = true
-		}
-	case BazelStagingMode:
-		// Staging mode includes all prod modules plus all staging modules.
-		AddToStringSet(enabledModules, allowlists.ProdMixedBuildsEnabledList)
-		AddToStringSet(enabledModules, allowlists.StagingMixedBuildsEnabledList)
-		for enabledAdHocModule := range forceEnabled {
-			enabledModules[enabledAdHocModule] = true
-		}
-	default:
-		panic("Expected BazelProdMode or BazelStagingMode")
-	}
-	return enabledModules, disabledModules
-}
-
-func GetBazelEnabledModules(buildMode SoongBuildMode) []string {
-	enabledModules, disabledModules := GetBazelEnabledAndDisabledModules(buildMode, nil)
-	enabledList := make([]string, 0, len(enabledModules))
-	for module := range enabledModules {
-		if !disabledModules[module] {
-			enabledList = append(enabledList, module)
-		}
-	}
-	sort.Strings(enabledList)
-	return enabledList
-}
-
-func NewBazelContext(c *config) (BazelContext, error) {
-	if c.BuildMode != BazelProdMode && c.BuildMode != BazelStagingMode {
-		return noopBazelContext{}, nil
-	}
-
-	enabledModules, disabledModules := GetBazelEnabledAndDisabledModules(c.BuildMode, c.BazelModulesForceEnabledByFlag())
-
-	paths := bazelPaths{
-		soongOutDir: c.soongOutDir,
-	}
-	var missing []string
-	vars := []struct {
-		name string
-		ptr  *string
-
-		// True if the environment variable needs to be tracked so that changes to the variable
-		// cause the ninja file to be regenerated, false otherwise. False should only be set for
-		// environment variables that have no effect on the generated ninja file.
-		track bool
-	}{
-		{"BAZEL_HOME", &paths.homeDir, true},
-		{"BAZEL_PATH", &paths.bazelPath, true},
-		{"BAZEL_OUTPUT_BASE", &paths.outputBase, true},
-		{"BAZEL_WORKSPACE", &paths.workspaceDir, true},
-		{"BAZEL_METRICS_DIR", &paths.metricsDir, false},
-		{"BAZEL_DEPS_FILE", &paths.bazelDepsFile, true},
-	}
-	for _, v := range vars {
-		if v.track {
-			if s := c.Getenv(v.name); len(s) > 1 {
-				*v.ptr = s
-				continue
-			}
-		} else if s, ok := c.env[v.name]; ok {
-			*v.ptr = s
-		} else {
-			missing = append(missing, v.name)
-		}
-	}
-	if len(missing) > 0 {
-		return nil, fmt.Errorf("missing required env vars to use bazel: %s", missing)
-	}
-
-	targetBuildVariant := "user"
-	if c.Eng() {
-		targetBuildVariant = "eng"
-	} else if c.Debuggable() {
-		targetBuildVariant = "userdebug"
-	}
-	targetProduct := "unknown"
-	if c.HasDeviceProduct() {
-		targetProduct = c.DeviceProduct()
-	}
-	dclaMixedBuildsEnabledList := []string{}
-	if c.BuildMode == BazelProdMode {
-		dclaMixedBuildsEnabledList = allowlists.ProdDclaMixedBuildsEnabledList
-	} else if c.BuildMode == BazelStagingMode {
-		dclaMixedBuildsEnabledList = append(allowlists.ProdDclaMixedBuildsEnabledList,
-			allowlists.StagingDclaMixedBuildsEnabledList...)
-	}
-	dclaEnabledModules := map[string]bool{}
-	AddToStringSet(dclaEnabledModules, dclaMixedBuildsEnabledList)
-	return &mixedBuildBazelContext{
-		bazelRunner:             &builtinBazelRunner{c.UseBazelProxy, absolutePath(c.outDir)},
-		paths:                   &paths,
-		bazelEnabledModules:     enabledModules,
-		bazelDisabledModules:    disabledModules,
-		bazelDclaEnabledModules: dclaEnabledModules,
-		targetProduct:           targetProduct,
-		targetBuildVariant:      targetBuildVariant,
-	}, nil
-}
-
-func (p *bazelPaths) BazelMetricsDir() string {
-	return p.metricsDir
-}
-
-func (context *mixedBuildBazelContext) IsModuleNameAllowed(moduleName string, withinApex bool) bool {
-	if context.bazelDisabledModules[moduleName] {
-		return false
-	}
-	if context.bazelEnabledModules[moduleName] {
-		return true
-	}
-	if withinApex && context.bazelDclaEnabledModules[moduleName] {
-		return true
-	}
-
-	return false
-}
-
-func pwdPrefix() string {
-	// Darwin doesn't have /proc
-	if runtime.GOOS != "darwin" {
-		return "PWD=/proc/self/cwd"
-	}
-	return ""
-}
-
-type bazelCommand struct {
-	command string
-	// query or label
-	expression string
-}
-
-type builtinBazelRunner struct {
-	useBazelProxy bool
-	outDir        string
-}
-
-// Issues the given bazel command with given build label and additional flags.
-// Returns (stdout, stderr, error). The first and second return values are strings
-// containing the stdout and stderr of the run command, and an error is returned if
-// the invocation returned an error code.
-func (r *builtinBazelRunner) issueBazelCommand(cmdRequest bazel.CmdRequest, paths *bazelPaths, eventHandler *metrics.EventHandler) (string, string, error) {
-	if r.useBazelProxy {
-		eventHandler.Begin("client_proxy")
-		defer eventHandler.End("client_proxy")
-		proxyClient := bazel.NewProxyClient(r.outDir)
-		resp, err := proxyClient.IssueCommand(cmdRequest)
-
-		if err != nil {
-			return "", "", err
-		}
-		if len(resp.ErrorString) > 0 {
-			return "", "", fmt.Errorf(resp.ErrorString)
-		}
-		return resp.Stdout, resp.Stderr, nil
-	} else {
-		eventHandler.Begin("bazel command")
-		defer eventHandler.End("bazel command")
-
-		stdout, stderr, err := bazel.ExecBazel(paths.bazelPath, absolutePath(paths.syntheticWorkspaceDir()), cmdRequest)
-		return string(stdout), string(stderr), err
-	}
-}
-
-func (context *mixedBuildBazelContext) createBazelCommand(config Config, runName bazel.RunName, command bazelCommand,
-	extraFlags ...string) bazel.CmdRequest {
-	if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
-		panic("Unknown GOOS: " + runtime.GOOS)
-	}
-	cmdFlags := []string{
-		"--output_base=" + absolutePath(context.paths.outputBase),
-		command.command,
-		command.expression,
-		"--profile=" + shared.BazelMetricsFilename(context.paths, runName),
-
-		"--host_platform=@soong_injection//product_config_platforms:mixed_builds_product-" + context.targetBuildVariant + "_" + runtime.GOOS + "_x86_64",
-		// Don't specify --platforms, because on some products/branches (like kernel-build-tools)
-		// the main platform for mixed_builds_product-variant doesn't exist because an arch isn't
-		// specified in product config. The derivative platforms that config_node transitions into
-		// will still work.
-
-		// Suppress noise
-		"--ui_event_filters=-INFO",
-		"--noshow_progress",
-		"--norun_validations",
-	}
-	cmdFlags = append(cmdFlags, extraFlags...)
-
-	extraEnv := []string{
-		"HOME=" + context.paths.homeDir,
-		pwdPrefix(),
-		"BUILD_DIR=" + absolutePath(context.paths.soongOutDir),
-		// Make OUT_DIR absolute here so build/bazel/bin/bazel uses the correct
-		// OUT_DIR at <root>/out, instead of <root>/out/soong/workspace/out.
-		"OUT_DIR=" + absolutePath(context.paths.outDir()),
-		// Disables local host detection of gcc; toolchain information is defined
-		// explicitly in BUILD files.
-		"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
-	}
-	capturedEnvVars, err := starlark_import.GetStarlarkValue[[]string]("captured_env_vars")
-	if err != nil {
-		panic(err)
-	}
-	for _, envvar := range capturedEnvVars {
-		val := config.Getenv(envvar)
-		if val == "" {
-			continue
-		}
-		extraEnv = append(extraEnv, fmt.Sprintf("%s=%s", envvar, val))
-	}
-	envVars := append(os.Environ(), extraEnv...)
-
-	return bazel.CmdRequest{cmdFlags, envVars}
-}
-
-func (context *mixedBuildBazelContext) printableCqueryCommand(bazelCmd bazel.CmdRequest) string {
-	args := append([]string{context.paths.bazelPath}, bazelCmd.Argv...)
-	outputString := strings.Join(bazelCmd.Env, " ") + " \"" + strings.Join(args, "\" \"") + "\""
-	return outputString
-}
-
-func (context *mixedBuildBazelContext) mainBzlFileContents() []byte {
-	// TODO(cparsons): Define configuration transitions programmatically based
-	// on available archs.
-	contents := `
-#####################################################
-# This file is generated by soong_build. Do not edit.
-#####################################################
-def _config_node_transition_impl(settings, attr):
-    if attr.os == "android" and attr.arch == "target":
-        target = "mixed_builds_product-{VARIANT}"
-    else:
-        target = "mixed_builds_product-{VARIANT}_%s_%s" % (attr.os, attr.arch)
-    apex_name = ""
-    if attr.within_apex:
-        # //build/bazel/rules/apex:apex_name has to be set to a non_empty value,
-        # otherwise //build/bazel/rules/apex:non_apex will be true and the
-        # "-D__ANDROID_APEX__" compiler flag will be missing. Apex_name is used
-        # in some validation on bazel side which don't really apply in mixed
-        # build because soong will do the work, so we just set it to a fixed
-        # value here.
-        apex_name = "dcla_apex"
-    outputs = {
-        "//command_line_option:platforms": "@soong_injection//product_config_platforms:%s" % target,
-        "@//build/bazel/rules/apex:within_apex": attr.within_apex,
-        "@//build/bazel/rules/apex:min_sdk_version": attr.apex_sdk_version,
-        "@//build/bazel/rules/apex:apex_name": apex_name,
-        "@//build/bazel/rules/apex:api_domain": attr.api_domain,
-    }
-
-    return outputs
-
-_config_node_transition = transition(
-    implementation = _config_node_transition_impl,
-    inputs = [],
-    outputs = [
-        "//command_line_option:platforms",
-        "@//build/bazel/rules/apex:within_apex",
-        "@//build/bazel/rules/apex:min_sdk_version",
-        "@//build/bazel/rules/apex:apex_name",
-        "@//build/bazel/rules/apex:api_domain",
-    ],
-)
-
-def _passthrough_rule_impl(ctx):
-    return [DefaultInfo(files = depset(ctx.files.deps))]
-
-config_node = rule(
-    implementation = _passthrough_rule_impl,
-    attrs = {
-        "arch"    : attr.string(mandatory = True),
-        "os"      : attr.string(mandatory = True),
-        "within_apex" : attr.bool(default = False),
-        "apex_sdk_version" : attr.string(mandatory = True),
-        "api_domain" : attr.string(mandatory = True),
-        "deps"    : attr.label_list(cfg = _config_node_transition, allow_files = True),
-        "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"),
-    },
-)
-
-
-# Rule representing the root of the build, to depend on all Bazel targets that
-# are required for the build. Building this target will build the entire Bazel
-# build tree.
-mixed_build_root = rule(
-    implementation = _passthrough_rule_impl,
-    attrs = {
-        "deps" : attr.label_list(),
-    },
-)
-
-def _phony_root_impl(ctx):
-    return []
-
-# Rule to depend on other targets but build nothing.
-# This is useful as follows: building a target of this rule will generate
-# symlink forests for all dependencies of the target, without executing any
-# actions of the build.
-phony_root = rule(
-    implementation = _phony_root_impl,
-    attrs = {"deps" : attr.label_list()},
-)
-`
-
-	productReplacer := strings.NewReplacer(
-		"{PRODUCT}", context.targetProduct,
-		"{VARIANT}", context.targetBuildVariant)
-
-	return []byte(productReplacer.Replace(contents))
-}
-
-func (context *mixedBuildBazelContext) mainBuildFileContents() []byte {
-	// TODO(cparsons): Map label to attribute programmatically; don't use hard-coded
-	// architecture mapping.
-	formatString := `
-# This file is generated by soong_build. Do not edit.
-load(":main.bzl", "config_node", "mixed_build_root", "phony_root")
-
-%s
-
-mixed_build_root(name = "buildroot",
-    deps = [%s],
-    testonly = True, # Unblocks testonly deps.
-)
-
-phony_root(name = "phonyroot",
-    deps = [":buildroot"],
-    testonly = True, # Unblocks testonly deps.
-)
-`
-	configNodeFormatString := `
-config_node(name = "%s",
-    arch = "%s",
-    os = "%s",
-    within_apex = %s,
-    apex_sdk_version = "%s",
-    api_domain = "%s",
-    deps = [%s],
-    testonly = True, # Unblocks testonly deps.
-)
-`
-
-	configNodesSection := ""
-
-	labelsByConfig := map[string][]string{}
-
-	for _, val := range context.requests {
-		labelString := fmt.Sprintf("\"@%s\"", val.label)
-		configString := getConfigString(val)
-		labelsByConfig[configString] = append(labelsByConfig[configString], labelString)
-	}
-
-	// Configs need to be sorted to maintain determinism of the BUILD file.
-	sortedConfigs := make([]string, 0, len(labelsByConfig))
-	for val := range labelsByConfig {
-		sortedConfigs = append(sortedConfigs, val)
-	}
-	sort.Slice(sortedConfigs, func(i, j int) bool { return sortedConfigs[i] < sortedConfigs[j] })
-
-	allLabels := []string{}
-	for _, configString := range sortedConfigs {
-		labels := labelsByConfig[configString]
-		configTokens := strings.Split(configString, "|")
-		if len(configTokens) < 2 {
-			panic(fmt.Errorf("Unexpected config string format: %s", configString))
-		}
-		archString := configTokens[0]
-		osString := configTokens[1]
-		withinApex := "False"
-		apexSdkVerString := ""
-		apiDomainString := ""
-		if osString == "android" {
-			// api domains are meaningful only for device variants
-			apiDomainString = "system"
-		}
-		targetString := fmt.Sprintf("%s_%s", osString, archString)
-		if len(configTokens) > 2 {
-			targetString += "_" + configTokens[2]
-			if configTokens[2] == withinApexToString(true) {
-				withinApex = "True"
-			}
-		}
-		if len(configTokens) > 3 {
-			targetString += "_" + configTokens[3]
-			apexSdkVerString = configTokens[3]
-		}
-		if len(configTokens) > 4 {
-			apiDomainString = configTokens[4]
-			targetString += "_" + apiDomainString
-		}
-		allLabels = append(allLabels, fmt.Sprintf("\":%s\"", targetString))
-		labelsString := strings.Join(labels, ",\n            ")
-		configNodesSection += fmt.Sprintf(configNodeFormatString, targetString, archString, osString, withinApex, apexSdkVerString, apiDomainString,
-			labelsString)
-	}
-
-	return []byte(fmt.Sprintf(formatString, configNodesSection, strings.Join(allLabels, ",\n            ")))
-}
-
-func indent(original string) string {
-	result := ""
-	for _, line := range strings.Split(original, "\n") {
-		result += "  " + line + "\n"
-	}
-	return result
-}
-
-// Returns the file contents of the buildroot.cquery file that should be used for the cquery
-// expression in order to obtain information about buildroot and its dependencies.
-// The contents of this file depend on the mixedBuildBazelContext's requests; requests are enumerated
-// and grouped by their request type. The data retrieved for each label depends on its
-// request type.
-func (context *mixedBuildBazelContext) cqueryStarlarkFileContents() []byte {
-	requestTypeToCqueryIdEntries := map[cqueryRequest][]string{}
-	requestTypes := []cqueryRequest{}
-	for _, val := range context.requests {
-		cqueryId := getCqueryId(val)
-		mapEntryString := fmt.Sprintf("%q : True", cqueryId)
-		if _, seenKey := requestTypeToCqueryIdEntries[val.requestType]; !seenKey {
-			requestTypes = append(requestTypes, val.requestType)
-		}
-		requestTypeToCqueryIdEntries[val.requestType] =
-			append(requestTypeToCqueryIdEntries[val.requestType], mapEntryString)
-	}
-	labelRegistrationMapSection := ""
-	functionDefSection := ""
-	mainSwitchSection := ""
-
-	mapDeclarationFormatString := `
-%s = {
-  %s
-}
-`
-	functionDefFormatString := `
-def %s(target, id_string):
-%s
-`
-	mainSwitchSectionFormatString := `
-  if id_string in %s:
-    return id_string + ">>" + %s(target, id_string)
-`
-
-	for _, requestType := range requestTypes {
-		labelMapName := requestType.Name() + "_Labels"
-		functionName := requestType.Name() + "_Fn"
-		labelRegistrationMapSection += fmt.Sprintf(mapDeclarationFormatString,
-			labelMapName,
-			strings.Join(requestTypeToCqueryIdEntries[requestType], ",\n  "))
-		functionDefSection += fmt.Sprintf(functionDefFormatString,
-			functionName,
-			indent(requestType.StarlarkFunctionBody()))
-		mainSwitchSection += fmt.Sprintf(mainSwitchSectionFormatString,
-			labelMapName, functionName)
-	}
-
-	formatString := `
-# This file is generated by soong_build. Do not edit.
-
-{LABEL_REGISTRATION_MAP_SECTION}
-
-{FUNCTION_DEF_SECTION}
-
-def get_arch(target):
-  # TODO(b/199363072): filegroups and file targets aren't associated with any
-  # specific platform architecture in mixed builds. This is consistent with how
-  # Soong treats filegroups, but it may not be the case with manually-written
-  # filegroup BUILD targets.
-  buildoptions = build_options(target)
-
-  if buildoptions == None:
-    # File targets do not have buildoptions. File targets aren't associated with
-    #  any specific platform architecture in mixed builds, so use the host.
-    return "x86_64|linux"
-  platforms = buildoptions["//command_line_option:platforms"]
-  if len(platforms) != 1:
-    # An individual configured target should have only one platform architecture.
-    # Note that it's fine for there to be multiple architectures for the same label,
-    # but each is its own configured target.
-    fail("expected exactly 1 platform for " + str(target.label) + " but got " + str(platforms))
-  platform_name = platforms[0].name
-  if platform_name == "host":
-    return "HOST"
-  if not platform_name.startswith("mixed_builds_product-{TARGET_BUILD_VARIANT}"):
-    fail("expected platform name of the form 'mixed_builds_product-{TARGET_BUILD_VARIANT}_android_<arch>' or 'mixed_builds_product-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
-  platform_name = platform_name.removeprefix("mixed_builds_product-{TARGET_BUILD_VARIANT}").removeprefix("_")
-  config_key = ""
-  if not platform_name:
-    config_key = "target|android"
-  elif platform_name.startswith("android_"):
-    config_key = platform_name.removeprefix("android_") + "|android"
-  elif platform_name.startswith("linux_"):
-    config_key = platform_name.removeprefix("linux_") + "|linux"
-  else:
-    fail("expected platform name of the form 'mixed_builds_product-{TARGET_BUILD_VARIANT}_android_<arch>' or 'mixed_builds_product-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
-
-  within_apex = buildoptions.get("//build/bazel/rules/apex:within_apex")
-  apex_sdk_version = buildoptions.get("//build/bazel/rules/apex:min_sdk_version")
-  api_domain = buildoptions.get("//build/bazel/rules/apex:api_domain")
-
-  if within_apex:
-    config_key += "|within_apex"
-  if apex_sdk_version != None and len(apex_sdk_version) > 0:
-    config_key += "|" + apex_sdk_version
-  if api_domain != None and len(api_domain) > 0:
-    config_key += "|" + api_domain
-
-  return config_key
-
-def format(target):
-  id_string = str(target.label) + "|" + get_arch(target)
-
-  # TODO(b/248106697): Remove once Bazel is updated to always normalize labels.
-  if id_string.startswith("//"):
-    id_string = "@" + id_string
-
-  {MAIN_SWITCH_SECTION}
-
-  # This target was not requested via cquery, and thus must be a dependency
-  # of a requested target.
-  return id_string + ">>NONE"
-`
-	replacer := strings.NewReplacer(
-		"{TARGET_PRODUCT}", context.targetProduct,
-		"{TARGET_BUILD_VARIANT}", context.targetBuildVariant,
-		"{LABEL_REGISTRATION_MAP_SECTION}", labelRegistrationMapSection,
-		"{FUNCTION_DEF_SECTION}", functionDefSection,
-		"{MAIN_SWITCH_SECTION}", mainSwitchSection)
-
-	return []byte(replacer.Replace(formatString))
-}
-
-// Returns a path containing build-related metadata required for interfacing
-// with Bazel. Example: out/soong/bazel.
-func (p *bazelPaths) intermediatesDir() string {
-	return filepath.Join(p.soongOutDir, "bazel")
-}
-
-// Returns the path where the contents of the @soong_injection repository live.
-// It is used by Soong to tell Bazel things it cannot over the command line.
-func (p *bazelPaths) injectedFilesDir() string {
-	return filepath.Join(p.soongOutDir, bazel.SoongInjectionDirName)
-}
-
-// Returns the path of the synthetic Bazel workspace that contains a symlink
-// forest composed the whole source tree and BUILD files generated by bp2build.
-func (p *bazelPaths) syntheticWorkspaceDir() string {
-	return filepath.Join(p.soongOutDir, "workspace")
-}
-
-// Returns the path to the top level out dir ($OUT_DIR).
-func (p *bazelPaths) outDir() string {
-	return filepath.Dir(p.soongOutDir)
-}
-
-const buildrootLabel = "@soong_injection//mixed_builds:buildroot"
-
-var (
-	cqueryCmd        = bazelCommand{"cquery", fmt.Sprintf("deps(%s, 2)", buildrootLabel)}
-	aqueryCmd        = bazelCommand{"aquery", fmt.Sprintf("deps(%s)", buildrootLabel)}
-	buildCmd         = bazelCommand{"build", "@soong_injection//mixed_builds:phonyroot"}
-	allBazelCommands = []bazelCommand{aqueryCmd, cqueryCmd, buildCmd}
-)
-
-func GetBazelSandwichCqueryRequests(config Config) ([]cqueryKey, error) {
-	result := make([]cqueryKey, 0, len(allowlists.BazelSandwichTargets))
-	labelRegex := regexp.MustCompile("^@?//([a-zA-Z0-9/_-]+):[a-zA-Z0-9_-]+$")
-	// Note that bazel "targets" are different from soong "targets", the bazel targets are
-	// synonymous with soong modules, and soong targets are a configuration a module is built in.
-	for _, target := range allowlists.BazelSandwichTargets {
-		match := labelRegex.FindStringSubmatch(target.Label)
-		if match == nil {
-			return nil, fmt.Errorf("invalid label, must match `^@?//([a-zA-Z0-9/_-]+):[a-zA-Z0-9_-]+$`: %s", target.Label)
-		}
-		if _, err := os.Stat(absolutePath(match[1])); err != nil {
-			if os.IsNotExist(err) {
-				// Ignore bazel sandwich targets that don't exist.
-				continue
-			} else {
-				return nil, err
-			}
-		}
-
-		var soongTarget Target
-		if target.Host {
-			soongTarget = config.BuildOSTarget
-		} else {
-			soongTarget = config.AndroidCommonTarget
-			if soongTarget.Os.Class != Device {
-				// kernel-build-tools seems to set the AndroidCommonTarget to a linux host
-				// target for some reason, disable device builds in that case.
-				continue
-			}
-		}
-
-		result = append(result, cqueryKey{
-			label:       target.Label,
-			requestType: cquery.GetOutputFiles,
-			configKey: configKey{
-				arch:   soongTarget.Arch.String(),
-				osType: soongTarget.Os,
-			},
-		})
-	}
-	return result, nil
-}
-
-// QueueBazelSandwichCqueryRequests queues cquery requests for all the bazel labels in
-// bazel_sandwich_targets. These will later be given phony targets so that they can be built on the
-// command line.
-func (context *mixedBuildBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
-	requests, err := GetBazelSandwichCqueryRequests(config)
-	if err != nil {
-		return err
-	}
-	for _, request := range requests {
-		context.QueueBazelRequest(request.label, request.requestType, request.configKey)
-	}
-
-	return nil
-}
-
-// Issues commands to Bazel to receive results for all cquery requests
-// queued in the BazelContext.
-func (context *mixedBuildBazelContext) InvokeBazel(config Config, ctx invokeBazelContext) error {
-	eventHandler := ctx.GetEventHandler()
-	eventHandler.Begin("bazel")
-	defer eventHandler.End("bazel")
-
-	if metricsDir := context.paths.BazelMetricsDir(); metricsDir != "" {
-		if err := os.MkdirAll(metricsDir, 0777); err != nil {
-			return err
-		}
-	}
-	context.results = make(map[cqueryKey]string)
-	if err := context.runCquery(config, ctx); err != nil {
-		return err
-	}
-	if err := context.runAquery(config, ctx); err != nil {
-		return err
-	}
-	if err := context.generateBazelSymlinks(config, ctx); err != nil {
-		return err
-	}
-
-	// Clear requests.
-	context.requests = []cqueryKey{}
-	return nil
-}
-
-func (context *mixedBuildBazelContext) runCquery(config Config, ctx invokeBazelContext) error {
-	eventHandler := ctx.GetEventHandler()
-	eventHandler.Begin("cquery")
-	defer eventHandler.End("cquery")
-	soongInjectionPath := absolutePath(context.paths.injectedFilesDir())
-	mixedBuildsPath := filepath.Join(soongInjectionPath, "mixed_builds")
-	if _, err := os.Stat(mixedBuildsPath); os.IsNotExist(err) {
-		err = os.MkdirAll(mixedBuildsPath, 0777)
-		if err != nil {
-			return err
-		}
-	}
-	if err := writeFileBytesIfChanged(filepath.Join(soongInjectionPath, "WORKSPACE.bazel"), []byte{}, 0666); err != nil {
-		return err
-	}
-	if err := writeFileBytesIfChanged(filepath.Join(mixedBuildsPath, "main.bzl"), context.mainBzlFileContents(), 0666); err != nil {
-		return err
-	}
-	if err := writeFileBytesIfChanged(filepath.Join(mixedBuildsPath, "BUILD.bazel"), context.mainBuildFileContents(), 0666); err != nil {
-		return err
-	}
-	cqueryFileRelpath := filepath.Join(context.paths.injectedFilesDir(), "buildroot.cquery")
-	if err := writeFileBytesIfChanged(absolutePath(cqueryFileRelpath), context.cqueryStarlarkFileContents(), 0666); err != nil {
-		return err
-	}
-
-	extraFlags := []string{"--output=starlark", "--starlark:file=" + absolutePath(cqueryFileRelpath)}
-	if Bool(config.productVariables.ClangCoverage) {
-		extraFlags = append(extraFlags, "--collect_code_coverage")
-	}
-
-	cqueryCmdRequest := context.createBazelCommand(config, bazel.CqueryBuildRootRunName, cqueryCmd, extraFlags...)
-	cqueryOutput, cqueryErrorMessage, cqueryErr := context.issueBazelCommand(cqueryCmdRequest, context.paths, eventHandler)
-	if cqueryErr != nil {
-		return cqueryErr
-	}
-	cqueryCommandPrint := fmt.Sprintf("cquery command line:\n  %s \n\n\n", context.printableCqueryCommand(cqueryCmdRequest))
-	if err := os.WriteFile(filepath.Join(soongInjectionPath, "cquery.out"), []byte(cqueryCommandPrint+cqueryOutput), 0666); err != nil {
-		return err
-	}
-	cqueryResults := map[string]string{}
-	for _, outputLine := range strings.Split(cqueryOutput, "\n") {
-		if strings.Contains(outputLine, ">>") {
-			splitLine := strings.SplitN(outputLine, ">>", 2)
-			cqueryResults[splitLine[0]] = splitLine[1]
-		}
-	}
-	for _, val := range context.requests {
-		if cqueryResult, ok := cqueryResults[getCqueryId(val)]; ok {
-			context.results[val] = cqueryResult
-		} else {
-			return fmt.Errorf("missing result for bazel target %s. query output: [%s], cquery err: [%s]",
-				getCqueryId(val), cqueryOutput, cqueryErrorMessage)
-		}
-	}
-	return nil
-}
-
-func writeFileBytesIfChanged(path string, contents []byte, perm os.FileMode) error {
-	oldContents, err := os.ReadFile(path)
-	if err != nil || !bytes.Equal(contents, oldContents) {
-		err = os.WriteFile(path, contents, perm)
-	}
-	return nil
-}
-
-func (context *mixedBuildBazelContext) runAquery(config Config, ctx invokeBazelContext) error {
-	eventHandler := ctx.GetEventHandler()
-	eventHandler.Begin("aquery")
-	defer eventHandler.End("aquery")
-	// Issue an aquery command to retrieve action information about the bazel build tree.
-	//
-	// Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
-	// proto sources, which would add a number of unnecessary dependencies.
-	extraFlags := []string{"--output=proto", "--include_file_write_contents"}
-	if Bool(config.productVariables.ClangCoverage) {
-		extraFlags = append(extraFlags, "--collect_code_coverage")
-		paths := make([]string, 0, 2)
-		if p := config.productVariables.NativeCoveragePaths; len(p) > 0 {
-			for i := range p {
-				// TODO(b/259404593) convert path wildcard to regex values
-				if p[i] == "*" {
-					p[i] = ".*"
-				}
-			}
-			paths = append(paths, JoinWithPrefixAndSeparator(p, "+", ","))
-		}
-		if p := config.productVariables.NativeCoverageExcludePaths; len(p) > 0 {
-			paths = append(paths, JoinWithPrefixAndSeparator(p, "-", ","))
-		}
-		if len(paths) > 0 {
-			extraFlags = append(extraFlags, "--instrumentation_filter="+strings.Join(paths, ","))
-		}
-	}
-	aqueryOutput, _, err := context.issueBazelCommand(context.createBazelCommand(config, bazel.AqueryBuildRootRunName, aqueryCmd,
-		extraFlags...), context.paths, eventHandler)
-	if err != nil {
-		return err
-	}
-	context.buildStatements, context.depsets, err = bazel.AqueryBuildStatements([]byte(aqueryOutput), eventHandler)
-	return err
-}
-
-func (context *mixedBuildBazelContext) generateBazelSymlinks(config Config, ctx invokeBazelContext) error {
-	eventHandler := ctx.GetEventHandler()
-	eventHandler.Begin("symlinks")
-	defer eventHandler.End("symlinks")
-	// Issue a build command of the phony root to generate symlink forests for dependencies of the
-	// Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
-	// but some of symlinks may be required to resolve source dependencies of the build.
-	_, _, err := context.issueBazelCommand(context.createBazelCommand(config, bazel.BazelBuildPhonyRootRunName, buildCmd), context.paths, eventHandler)
-	return err
-}
-
-func (context *mixedBuildBazelContext) BuildStatementsToRegister() []*bazel.BuildStatement {
-	return context.buildStatements
-}
-
-func (context *mixedBuildBazelContext) AqueryDepsets() []bazel.AqueryDepset {
-	return context.depsets
-}
-
-func (context *mixedBuildBazelContext) OutputBase() string {
-	return context.paths.outputBase
-}
-
-// Singleton used for registering BUILD file ninja dependencies (needed
-// for correctness of builds which use Bazel.
-func BazelSingleton() Singleton {
-	return &bazelSingleton{}
-}
-
-type bazelSingleton struct{}
-
-func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) {
-	// bazelSingleton is a no-op if mixed-soong-bazel-builds are disabled.
-	if !ctx.Config().IsMixedBuildsEnabled() {
-		return
-	}
-
-	// Add ninja file dependencies for files which all bazel invocations require.
-	bazelBuildList := absolutePath(filepath.Join(
-		filepath.Dir(ctx.Config().moduleListFile), "bazel.list"))
-	ctx.AddNinjaFileDeps(bazelBuildList)
-
-	data, err := os.ReadFile(bazelBuildList)
-	if err != nil {
-		ctx.Errorf(err.Error())
-	}
-	files := strings.Split(strings.TrimSpace(string(data)), "\n")
-	for _, file := range files {
-		ctx.AddNinjaFileDeps(file)
-	}
-
-	depsetHashToDepset := map[string]bazel.AqueryDepset{}
-
-	for _, depset := range ctx.Config().BazelContext.AqueryDepsets() {
-		depsetHashToDepset[depset.ContentHash] = depset
-
-		var outputs []Path
-		var orderOnlies []Path
-		for _, depsetDepHash := range depset.TransitiveDepSetHashes {
-			otherDepsetName := bazelDepsetName(depsetDepHash)
-			outputs = append(outputs, PathForPhony(ctx, otherDepsetName))
-		}
-		for _, artifactPath := range depset.DirectArtifacts {
-			pathInBazelOut := PathForBazelOut(ctx, artifactPath)
-			if artifactPath == "bazel-out/volatile-status.txt" {
-				// See https://bazel.build/docs/user-manual#workspace-status
-				orderOnlies = append(orderOnlies, pathInBazelOut)
-			} else {
-				outputs = append(outputs, pathInBazelOut)
-			}
-		}
-		thisDepsetName := bazelDepsetName(depset.ContentHash)
-		ctx.Build(pctx, BuildParams{
-			Rule:      blueprint.Phony,
-			Outputs:   []WritablePath{PathForPhony(ctx, thisDepsetName)},
-			Implicits: outputs,
-			OrderOnly: orderOnlies,
-		})
-	}
-
-	executionRoot := path.Join(ctx.Config().BazelContext.OutputBase(), "execroot", "__main__")
-	bazelOutDir := path.Join(executionRoot, "bazel-out")
-	rel, err := filepath.Rel(ctx.Config().OutDir(), executionRoot)
-	if err != nil {
-		ctx.Errorf("%s", err.Error())
-	}
-	dotdotsToOutRoot := strings.Repeat("../", strings.Count(rel, "/")+1)
-	for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
-		// nil build statements are a valid case where we do not create an action because it is
-		// unnecessary or handled by other processing
-		if buildStatement == nil {
-			continue
-		}
-		if len(buildStatement.Command) > 0 {
-			rule := NewRuleBuilder(pctx, ctx)
-			intermediateDir, intermediateDirHash := intermediatePathForSboxMixedBuildAction(ctx, buildStatement)
-			if buildStatement.ShouldRunInSbox {
-				// Create a rule to build the output inside a sandbox
-				// This will create two changes of working directory
-				// 1. From ANDROID_BUILD_TOP to sbox top
-				// 2. From sbox top to a a synthetic mixed build execution root relative to it
-				// Finally, the outputs will be copied to intermediateDir
-				rule.Sbox(intermediateDir,
-					PathForOutput(ctx, "mixed_build_sbox_intermediates", intermediateDirHash+".textproto")).
-					SandboxInputs().
-					// Since we will cd to mixed build execution root, set sbox's out subdir to empty
-					// Without this, we will try to copy from $SBOX_SANDBOX_DIR/out/out/bazel/output/execroot/__main__/...
-					SetSboxOutDirDirAsEmpty()
-
-				// Create another set of rules to copy files from the intermediate dir to mixed build execution root
-				for _, outputPath := range buildStatement.OutputPaths {
-					ctx.Build(pctx, BuildParams{
-						Rule:   CpIfChanged,
-						Input:  intermediateDir.Join(ctx, executionRoot, outputPath),
-						Output: PathForBazelOut(ctx, outputPath),
-					})
-				}
-			}
-			createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx, depsetHashToDepset, dotdotsToOutRoot)
-
-			desc := fmt.Sprintf("%s: %s", buildStatement.Mnemonic, buildStatement.OutputPaths)
-			rule.Build(fmt.Sprintf("bazel %d", index), desc)
-			continue
-		}
-		// Certain actions returned by aquery (for instance FileWrite) do not contain a command
-		// and thus require special treatment. If BuildStatement were an interface implementing
-		// buildRule(ctx) function, the code here would just call it.
-		// Unfortunately, the BuildStatement is defined in
-		// the 'bazel' package, which cannot depend on 'android' package where ctx is defined,
-		// because this would cause circular dependency. So, until we move aquery processing
-		// to the 'android' package, we need to handle special cases here.
-		switch buildStatement.Mnemonic {
-		case "RepoMappingManifest":
-			// It appears RepoMappingManifest files currently have
-			// non-deterministic content. Just emit empty files for
-			// now because they're unused.
-			out := PathForBazelOut(ctx, buildStatement.OutputPaths[0])
-			WriteFileRuleVerbatim(ctx, out, "")
-		case "FileWrite", "SourceSymlinkManifest":
-			out := PathForBazelOut(ctx, buildStatement.OutputPaths[0])
-			WriteFileRuleVerbatim(ctx, out, buildStatement.FileContents)
-		case "SymlinkTree":
-			// build-runfiles arguments are the manifest file and the target directory
-			// where it creates the symlink tree according to this manifest (and then
-			// writes the MANIFEST file to it).
-			outManifest := PathForBazelOut(ctx, buildStatement.OutputPaths[0])
-			outManifestPath := outManifest.String()
-			if !strings.HasSuffix(outManifestPath, "MANIFEST") {
-				panic("the base name of the symlink tree action should be MANIFEST, got " + outManifestPath)
-			}
-			outDir := filepath.Dir(outManifestPath)
-			ctx.Build(pctx, BuildParams{
-				Rule:        buildRunfilesRule,
-				Output:      outManifest,
-				Inputs:      []Path{PathForBazelOut(ctx, buildStatement.InputPaths[0])},
-				Description: "symlink tree for " + outDir,
-				Args: map[string]string{
-					"outDir": outDir,
-				},
-			})
-		default:
-			panic(fmt.Sprintf("unhandled build statement: %v", buildStatement))
-		}
-	}
-
-	// Create phony targets for all the bazel sandwich output files
-	requests, err := GetBazelSandwichCqueryRequests(ctx.Config())
-	if err != nil {
-		ctx.Errorf(err.Error())
-	}
-	for _, request := range requests {
-		files, err := ctx.Config().BazelContext.GetOutputFiles(request.label, request.configKey)
-		if err != nil {
-			ctx.Errorf(err.Error())
-		}
-		filesAsPaths := make([]Path, 0, len(files))
-		for _, file := range files {
-			filesAsPaths = append(filesAsPaths, PathForBazelOut(ctx, file))
-		}
-		ctx.Phony("bazel_sandwich", filesAsPaths...)
-	}
-	ctx.Phony("checkbuild", PathForPhony(ctx, "bazel_sandwich"))
-}
-
-// Returns a out dir path for a sandboxed mixed build action
-func intermediatePathForSboxMixedBuildAction(ctx PathContext, statement *bazel.BuildStatement) (OutputPath, string) {
-	// An artifact can be generated by a single buildstatement.
-	// Use the hash of the first artifact to create a unique path
-	uniqueDir := sha1.New()
-	uniqueDir.Write([]byte(statement.OutputPaths[0]))
-	uniqueDirHashString := hex.EncodeToString(uniqueDir.Sum(nil))
-	return PathForOutput(ctx, "mixed_build_sbox_intermediates", uniqueDirHashString), uniqueDirHashString
-}
-
-// Register bazel-owned build statements (obtained from the aquery invocation).
-func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext, depsetHashToDepset map[string]bazel.AqueryDepset, dotdotsToOutRoot string) {
-	// executionRoot is the action cwd.
-	if buildStatement.ShouldRunInSbox {
-		// mkdir -p ensures that the directory exists when run via sbox
-		cmd.Text(fmt.Sprintf("mkdir -p '%s' && cd '%s' &&", executionRoot, executionRoot))
-	} else {
-		cmd.Text(fmt.Sprintf("cd '%s' &&", executionRoot))
-	}
-
-	// Remove old outputs, as some actions might not rerun if the outputs are detected.
-	if len(buildStatement.OutputPaths) > 0 {
-		cmd.Text("rm -rf") // -r because outputs can be Bazel dir/tree artifacts.
-		for _, outputPath := range buildStatement.OutputPaths {
-			cmd.Text(fmt.Sprintf("'%s'", outputPath))
-		}
-		cmd.Text("&&")
-	}
-
-	for _, pair := range buildStatement.Env {
-		// Set per-action env variables, if any.
-		cmd.Flag(pair.Key + "=" + pair.Value)
-	}
-
-	command := buildStatement.Command
-	command = strings.ReplaceAll(command, "{DOTDOTS_TO_OUTPUT_ROOT}", dotdotsToOutRoot)
-
-	// The actual Bazel action.
-	if len(command) > 16*1024 {
-		commandFile := PathForBazelOut(ctx, buildStatement.OutputPaths[0]+".sh")
-		WriteFileRule(ctx, commandFile, command)
-
-		cmd.Text("bash").Text(buildStatement.OutputPaths[0] + ".sh").Implicit(commandFile)
-	} else {
-		cmd.Text(command)
-	}
-
-	for _, outputPath := range buildStatement.OutputPaths {
-		if buildStatement.ShouldRunInSbox {
-			// The full path has three components that get joined together
-			// 1. intermediate output dir that `sbox` will place the artifacts at
-			// 2. mixed build execution root
-			// 3. artifact path returned by aquery
-			intermediateDir, _ := intermediatePathForSboxMixedBuildAction(ctx, buildStatement)
-			cmd.ImplicitOutput(intermediateDir.Join(ctx, executionRoot, outputPath))
-		} else {
-			cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
-		}
-	}
-	for _, inputPath := range buildStatement.InputPaths {
-		cmd.Implicit(PathForBazelOut(ctx, inputPath))
-	}
-	for _, inputDepsetHash := range buildStatement.InputDepsetHashes {
-		if buildStatement.ShouldRunInSbox {
-			// Bazel depsets are phony targets that are used to group files.
-			// We need to copy the grouped files into the sandbox
-			ds, _ := depsetHashToDepset[inputDepsetHash]
-			cmd.Implicits(PathsForBazelOut(ctx, ds.DirectArtifacts))
-		} else {
-			otherDepsetName := bazelDepsetName(inputDepsetHash)
-			cmd.Implicit(PathForPhony(ctx, otherDepsetName))
-		}
-	}
-	for _, implicitPath := range buildStatement.ImplicitDeps {
-		cmd.Implicit(PathForArbitraryOutput(ctx, implicitPath))
-	}
-
-	if depfile := buildStatement.Depfile; depfile != nil {
-		// The paths in depfile are relative to `executionRoot`.
-		// Hence, they need to be corrected by replacing "bazel-out"
-		// with the full `bazelOutDir`.
-		// Otherwise, implicit outputs and implicit inputs under "bazel-out/"
-		// would be deemed missing.
-		// (Note: The regexp uses a capture group because the version of sed
-		//  does not support a look-behind pattern.)
-		replacement := fmt.Sprintf(`&& sed -i'' -E 's@(^|\s|")bazel-out/@\1%s/@g' '%s'`,
-			bazelOutDir, *depfile)
-		cmd.Text(replacement)
-		cmd.ImplicitDepFile(PathForBazelOut(ctx, *depfile))
-	}
-
-	for _, symlinkPath := range buildStatement.SymlinkPaths {
-		cmd.ImplicitSymlinkOutput(PathForBazelOut(ctx, symlinkPath))
-	}
-}
-
-func getCqueryId(key cqueryKey) string {
-	return key.label + "|" + getConfigString(key)
-}
-
-func getConfigString(key cqueryKey) string {
-	arch := key.configKey.arch
-	if len(arch) == 0 || arch == "common" {
-		if key.configKey.osType.Class == Device {
-			// For the generic Android, the expected result is "target|android", which
-			// corresponds to the product_variable_config named "android_target" in
-			// build/bazel/platforms/BUILD.bazel.
-			arch = "target"
-		} else {
-			// Use host platform, which is currently hardcoded to be x86_64.
-			arch = "x86_64"
-		}
-	}
-	osName := key.configKey.osType.Name
-	if len(osName) == 0 || osName == "common_os" || osName == "linux_glibc" || osName == "linux_musl" {
-		// Use host OS, which is currently hardcoded to be linux.
-		osName = "linux"
-	}
-	keyString := arch + "|" + osName
-	if key.configKey.apexKey.WithinApex {
-		keyString += "|" + withinApexToString(key.configKey.apexKey.WithinApex)
-	}
-
-	if len(key.configKey.apexKey.ApexSdkVersion) > 0 {
-		keyString += "|" + key.configKey.apexKey.ApexSdkVersion
-	}
-
-	if len(key.configKey.apexKey.ApiDomain) > 0 {
-		keyString += "|" + key.configKey.apexKey.ApiDomain
-	}
-
-	return keyString
-}
-
-func GetConfigKey(ctx BaseModuleContext) configKey {
-	return configKey{
-		// use string because Arch is not a valid key in go
-		arch:   ctx.Arch().String(),
-		osType: ctx.Os(),
-	}
-}
-
-func GetConfigKeyApexVariant(ctx BaseModuleContext, apexKey *ApexConfigKey) configKey {
-	configKey := GetConfigKey(ctx)
-
-	if apexKey != nil {
-		configKey.apexKey = ApexConfigKey{
-			WithinApex:     apexKey.WithinApex,
-			ApexSdkVersion: apexKey.ApexSdkVersion,
-			ApiDomain:      apexKey.ApiDomain,
-		}
-	}
-
-	return configKey
-}
-
-func bazelDepsetName(contentHash string) string {
-	return fmt.Sprintf("bazel_depset_%s", contentHash)
-}
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
deleted file mode 100644
index 9a3c8fc..0000000
--- a/android/bazel_handler_test.go
+++ /dev/null
@@ -1,426 +0,0 @@
-package android
-
-import (
-	"encoding/json"
-	"os"
-	"path/filepath"
-	"reflect"
-	"strings"
-	"testing"
-
-	"android/soong/bazel"
-	"android/soong/bazel/cquery"
-	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
-
-	"github.com/google/blueprint/metrics"
-	"google.golang.org/protobuf/proto"
-)
-
-var testConfig = TestConfig("out", nil, "", nil)
-
-type testInvokeBazelContext struct{}
-
-type mockBazelRunner struct {
-	testHelper *testing.T
-	// Stores mock behavior. If an issueBazelCommand request is made for command
-	// k, and {k:v} is present in this map, then the mock will return v.
-	bazelCommandResults map[bazelCommand]string
-	// Requests actually made of the mockBazelRunner with issueBazelCommand,
-	// keyed by the command they represent.
-	bazelCommandRequests map[bazelCommand]bazel.CmdRequest
-}
-
-func (r *mockBazelRunner) bazelCommandForRequest(cmdRequest bazel.CmdRequest) bazelCommand {
-	for _, arg := range cmdRequest.Argv {
-		for _, cmdType := range allBazelCommands {
-			if arg == cmdType.command {
-				return cmdType
-			}
-		}
-	}
-	r.testHelper.Fatalf("Unrecognized bazel request: %s", cmdRequest)
-	return cqueryCmd
-}
-
-func (r *mockBazelRunner) issueBazelCommand(cmdRequest bazel.CmdRequest, paths *bazelPaths, eventHandler *metrics.EventHandler) (string, string, error) {
-	command := r.bazelCommandForRequest(cmdRequest)
-	r.bazelCommandRequests[command] = cmdRequest
-	return r.bazelCommandResults[command], "", nil
-}
-
-func (t *testInvokeBazelContext) GetEventHandler() *metrics.EventHandler {
-	return &metrics.EventHandler{}
-}
-
-func TestRequestResultsAfterInvokeBazel(t *testing.T) {
-	label_foo := "@//foo:foo"
-	label_bar := "@//foo:bar"
-	apexKey := ApexConfigKey{
-		WithinApex:     true,
-		ApexSdkVersion: "29",
-		ApiDomain:      "myapex",
-	}
-	cfg_foo := configKey{"arm64_armv8-a", Android, apexKey}
-	cfg_bar := configKey{arch: "arm64_armv8-a", osType: Android}
-	cmd_results := []string{
-		`@//foo:foo|arm64_armv8-a|android|within_apex|29|myapex>>out/foo/foo.txt`,
-		`@//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
-	}
-	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{cqueryCmd: strings.Join(cmd_results, "\n")})
-
-	bazelContext.QueueBazelRequest(label_foo, cquery.GetOutputFiles, cfg_foo)
-	bazelContext.QueueBazelRequest(label_bar, cquery.GetOutputFiles, cfg_bar)
-	err := bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
-	if err != nil {
-		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
-	}
-	verifyCqueryResult(t, bazelContext, label_foo, cfg_foo, "out/foo/foo.txt")
-	verifyCqueryResult(t, bazelContext, label_bar, cfg_bar, "out/foo/bar.txt")
-}
-
-func verifyCqueryResult(t *testing.T, ctx *mixedBuildBazelContext, label string, cfg configKey, result string) {
-	g, err := ctx.GetOutputFiles(label, cfg)
-	if err != nil {
-		t.Errorf("Expected cquery results after running InvokeBazel(), but got err %v", err)
-	} else if w := []string{result}; !reflect.DeepEqual(w, g) {
-		t.Errorf("Expected output %s, got %s", w, g)
-	}
-}
-
-func TestInvokeBazelWritesBazelFiles(t *testing.T) {
-	bazelContext, baseDir := testBazelContext(t, map[bazelCommand]string{})
-	err := bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
-	if err != nil {
-		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
-	}
-	if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "mixed_builds", "main.bzl")); os.IsNotExist(err) {
-		t.Errorf("Expected main.bzl to exist, but it does not")
-	} else if err != nil {
-		t.Errorf("Unexpected error stating main.bzl %s", err)
-	}
-
-	if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "mixed_builds", "BUILD.bazel")); os.IsNotExist(err) {
-		t.Errorf("Expected BUILD.bazel to exist, but it does not")
-	} else if err != nil {
-		t.Errorf("Unexpected error stating BUILD.bazel %s", err)
-	}
-
-	if _, err := os.Stat(filepath.Join(baseDir, "soong_injection", "WORKSPACE.bazel")); os.IsNotExist(err) {
-		t.Errorf("Expected WORKSPACE.bazel to exist, but it does not")
-	} else if err != nil {
-		t.Errorf("Unexpected error stating WORKSPACE.bazel %s", err)
-	}
-}
-
-func TestInvokeBazelPopulatesBuildStatements(t *testing.T) {
-	type testCase struct {
-		input   string
-		command string
-	}
-
-	var testCases = []testCase{
-		{`
-{
- "artifacts": [
-   { "id": 1, "path_fragment_id": 1 },
-   { "id": 2, "path_fragment_id": 2 }],
- "actions": [{
-   "target_Id": 1,
-   "action_Key": "x",
-   "mnemonic": "x",
-   "arguments": ["touch", "foo"],
-   "input_dep_set_ids": [1],
-   "output_Ids": [1],
-   "primary_output_id": 1
- }],
- "dep_set_of_files": [
-   { "id": 1, "direct_artifact_ids": [1, 2] }],
- "path_fragments": [
-   { "id": 1, "label": "one" },
-   { "id": 2, "label": "two" }]
-}`,
-			"cd 'test/exec_root' && rm -rf 'one' && touch foo",
-		}, {`
-{
- "artifacts": [
-   { "id": 1, "path_fragment_id": 10 },
-   { "id": 2, "path_fragment_id": 20 }],
- "actions": [{
-   "target_Id": 100,
-   "action_Key": "x",
-   "mnemonic": "x",
-   "arguments": ["bogus", "command"],
-   "output_Ids": [1, 2],
-   "primary_output_id": 1
- }],
- "path_fragments": [
-   { "id": 10, "label": "one", "parent_id": 30 },
-   { "id": 20, "label": "one.d", "parent_id": 30 },
-   { "id": 30, "label": "parent" }]
-}`,
-			`cd 'test/exec_root' && rm -rf 'parent/one' && bogus command && sed -i'' -E 's@(^|\s|")bazel-out/@\1test/bazel_out/@g' 'parent/one.d'`,
-		},
-	}
-
-	for i, testCase := range testCases {
-		data, err := JsonToActionGraphContainer(testCase.input)
-		if err != nil {
-			t.Error(err)
-		}
-		bazelContext, _ := testBazelContext(t, map[bazelCommand]string{aqueryCmd: string(data)})
-
-		err = bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
-		if err != nil {
-			t.Fatalf("testCase #%d: did not expect error invoking Bazel, but got %s", i+1, err)
-		}
-
-		got := bazelContext.BuildStatementsToRegister()
-		if want := 1; len(got) != want {
-			t.Fatalf("expected %d registered build statements, but got %#v", want, got)
-		}
-
-		cmd := RuleBuilderCommand{}
-		ctx := builderContextForTests{PathContextForTesting(TestConfig("out", nil, "", nil))}
-		createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{}, "")
-		if actual, expected := cmd.buf.String(), testCase.command; expected != actual {
-			t.Errorf("expected: [%s], actual: [%s]", expected, actual)
-		}
-	}
-}
-
-func TestMixedBuildSandboxedAction(t *testing.T) {
-	input := `{
- "artifacts": [
-   { "id": 1, "path_fragment_id": 1 },
-   { "id": 2, "path_fragment_id": 2 }],
- "actions": [{
-   "target_Id": 1,
-   "action_Key": "x",
-   "mnemonic": "x",
-   "arguments": ["touch", "foo"],
-   "input_dep_set_ids": [1],
-   "output_Ids": [1],
-   "primary_output_id": 1
- }],
- "dep_set_of_files": [
-   { "id": 1, "direct_artifact_ids": [1, 2] }],
- "path_fragments": [
-   { "id": 1, "label": "one" },
-   { "id": 2, "label": "two" }]
-}`
-	data, err := JsonToActionGraphContainer(input)
-	if err != nil {
-		t.Error(err)
-	}
-	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{aqueryCmd: string(data)})
-
-	err = bazelContext.InvokeBazel(testConfig, &testInvokeBazelContext{})
-	if err != nil {
-		t.Fatalf("TestMixedBuildSandboxedAction did not expect error invoking Bazel, but got %s", err)
-	}
-
-	statement := bazelContext.BuildStatementsToRegister()[0]
-	statement.ShouldRunInSbox = true
-
-	cmd := RuleBuilderCommand{}
-	ctx := builderContextForTests{PathContextForTesting(TestConfig("out", nil, "", nil))}
-	createCommand(&cmd, statement, "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{}, "")
-	// Assert that the output is generated in an intermediate directory
-	// fe05bcdcdc4928012781a5f1a2a77cbb5398e106 is the sha1 checksum of "one"
-	if actual, expected := cmd.outputs[0].String(), "out/soong/mixed_build_sbox_intermediates/fe05bcdcdc4928012781a5f1a2a77cbb5398e106/test/exec_root/one"; expected != actual {
-		t.Errorf("expected: [%s], actual: [%s]", expected, actual)
-	}
-
-	// Assert the actual command remains unchanged inside the sandbox
-	if actual, expected := cmd.buf.String(), "mkdir -p 'test/exec_root' && cd 'test/exec_root' && rm -rf 'one' && touch foo"; expected != actual {
-		t.Errorf("expected: [%s], actual: [%s]", expected, actual)
-	}
-}
-
-func TestCoverageFlagsAfterInvokeBazel(t *testing.T) {
-	testConfig.productVariables.ClangCoverage = boolPtr(true)
-
-	testConfig.productVariables.NativeCoveragePaths = []string{"foo1", "foo2"}
-	testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1", "bar2"}
-	verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1,+foo2,-bar1,-bar2")
-
-	testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
-	testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
-	verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1,-bar1")
-
-	testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
-	testConfig.productVariables.NativeCoverageExcludePaths = nil
-	verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+foo1")
-
-	testConfig.productVariables.NativeCoveragePaths = nil
-	testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
-	verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=-bar1")
-
-	testConfig.productVariables.NativeCoveragePaths = []string{"*"}
-	testConfig.productVariables.NativeCoverageExcludePaths = nil
-	verifyAqueryContainsFlags(t, testConfig, "--collect_code_coverage", "--instrumentation_filter=+.*")
-
-	testConfig.productVariables.ClangCoverage = boolPtr(false)
-	verifyAqueryDoesNotContainSubstrings(t, testConfig, "collect_code_coverage", "instrumentation_filter")
-}
-
-func TestBazelRequestsSorted(t *testing.T) {
-	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
-
-	cfgKeyArm64Android := configKey{arch: "arm64_armv8-a", osType: Android}
-	cfgKeyArm64Linux := configKey{arch: "arm64_armv8-a", osType: Linux}
-	cfgKeyOtherAndroid := configKey{arch: "otherarch", osType: Android}
-
-	bazelContext.QueueBazelRequest("zzz", cquery.GetOutputFiles, cfgKeyArm64Android)
-	bazelContext.QueueBazelRequest("ccc", cquery.GetApexInfo, cfgKeyArm64Android)
-	bazelContext.QueueBazelRequest("duplicate", cquery.GetOutputFiles, cfgKeyArm64Android)
-	bazelContext.QueueBazelRequest("duplicate", cquery.GetOutputFiles, cfgKeyArm64Android)
-	bazelContext.QueueBazelRequest("xxx", cquery.GetOutputFiles, cfgKeyArm64Linux)
-	bazelContext.QueueBazelRequest("aaa", cquery.GetOutputFiles, cfgKeyArm64Android)
-	bazelContext.QueueBazelRequest("aaa", cquery.GetOutputFiles, cfgKeyOtherAndroid)
-	bazelContext.QueueBazelRequest("bbb", cquery.GetOutputFiles, cfgKeyOtherAndroid)
-
-	if len(bazelContext.requests) != 7 {
-		t.Error("Expected 7 request elements, but got", len(bazelContext.requests))
-	}
-
-	lastString := ""
-	for _, val := range bazelContext.requests {
-		thisString := val.String()
-		if thisString <= lastString {
-			t.Errorf("Requests are not ordered correctly. '%s' came before '%s'", lastString, thisString)
-		}
-		lastString = thisString
-	}
-}
-
-func TestIsModuleNameAllowed(t *testing.T) {
-	libDisabled := "lib_disabled"
-	libEnabled := "lib_enabled"
-	libDclaWithinApex := "lib_dcla_within_apex"
-	libDclaNonApex := "lib_dcla_non_apex"
-	libNotConverted := "lib_not_converted"
-
-	disabledModules := map[string]bool{
-		libDisabled: true,
-	}
-	enabledModules := map[string]bool{
-		libEnabled: true,
-	}
-	dclaEnabledModules := map[string]bool{
-		libDclaWithinApex: true,
-		libDclaNonApex:    true,
-	}
-
-	bazelContext := &mixedBuildBazelContext{
-		bazelEnabledModules:     enabledModules,
-		bazelDisabledModules:    disabledModules,
-		bazelDclaEnabledModules: dclaEnabledModules,
-	}
-
-	if bazelContext.IsModuleNameAllowed(libDisabled, true) {
-		t.Fatalf("%s shouldn't be allowed for mixed build", libDisabled)
-	}
-
-	if !bazelContext.IsModuleNameAllowed(libEnabled, true) {
-		t.Fatalf("%s should be allowed for mixed build", libEnabled)
-	}
-
-	if !bazelContext.IsModuleNameAllowed(libDclaWithinApex, true) {
-		t.Fatalf("%s should be allowed for mixed build", libDclaWithinApex)
-	}
-
-	if bazelContext.IsModuleNameAllowed(libDclaNonApex, false) {
-		t.Fatalf("%s shouldn't be allowed for mixed build", libDclaNonApex)
-	}
-
-	if bazelContext.IsModuleNameAllowed(libNotConverted, true) {
-		t.Fatalf("%s shouldn't be allowed for mixed build", libNotConverted)
-	}
-}
-
-func verifyAqueryContainsFlags(t *testing.T, config Config, expected ...string) {
-	t.Helper()
-	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
-
-	err := bazelContext.InvokeBazel(config, &testInvokeBazelContext{})
-	if err != nil {
-		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
-	}
-
-	sliceContains := func(slice []string, x string) bool {
-		for _, s := range slice {
-			if s == x {
-				return true
-			}
-		}
-		return false
-	}
-
-	aqueryArgv := bazelContext.bazelRunner.(*mockBazelRunner).bazelCommandRequests[aqueryCmd].Argv
-
-	for _, expectedFlag := range expected {
-		if !sliceContains(aqueryArgv, expectedFlag) {
-			t.Errorf("aquery does not contain expected flag %#v. Argv was: %#v", expectedFlag, aqueryArgv)
-		}
-	}
-}
-
-func verifyAqueryDoesNotContainSubstrings(t *testing.T, config Config, substrings ...string) {
-	t.Helper()
-	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{})
-
-	err := bazelContext.InvokeBazel(config, &testInvokeBazelContext{})
-	if err != nil {
-		t.Fatalf("Did not expect error invoking Bazel, but got %s", err)
-	}
-
-	sliceContainsSubstring := func(slice []string, substring string) bool {
-		for _, s := range slice {
-			if strings.Contains(s, substring) {
-				return true
-			}
-		}
-		return false
-	}
-
-	aqueryArgv := bazelContext.bazelRunner.(*mockBazelRunner).bazelCommandRequests[aqueryCmd].Argv
-
-	for _, substring := range substrings {
-		if sliceContainsSubstring(aqueryArgv, substring) {
-			t.Errorf("aquery contains unexpected substring %#v. Argv was: %#v", substring, aqueryArgv)
-		}
-	}
-}
-
-func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*mixedBuildBazelContext, string) {
-	t.Helper()
-	p := bazelPaths{
-		soongOutDir:  t.TempDir(),
-		outputBase:   "outputbase",
-		workspaceDir: "workspace_dir",
-	}
-	if _, exists := bazelCommandResults[aqueryCmd]; !exists {
-		bazelCommandResults[aqueryCmd] = ""
-	}
-	runner := &mockBazelRunner{
-		testHelper:           t,
-		bazelCommandResults:  bazelCommandResults,
-		bazelCommandRequests: map[bazelCommand]bazel.CmdRequest{},
-	}
-	return &mixedBuildBazelContext{
-		bazelRunner: runner,
-		paths:       &p,
-	}, p.soongOutDir
-}
-
-// Transform the json format to ActionGraphContainer
-func JsonToActionGraphContainer(inputString string) ([]byte, error) {
-	var aqueryProtoResult analysis_v2_proto.ActionGraphContainer
-	err := json.Unmarshal([]byte(inputString), &aqueryProtoResult)
-	if err != nil {
-		return []byte(""), err
-	}
-	data, _ := proto.Marshal(&aqueryProtoResult)
-	return data, err
-}
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
deleted file mode 100644
index b08a4ca..0000000
--- a/android/bazel_paths.go
+++ /dev/null
@@ -1,599 +0,0 @@
-// Copyright 2015 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package android
-
-import (
-	"fmt"
-	"path/filepath"
-	"strings"
-
-	"android/soong/bazel"
-
-	"github.com/google/blueprint"
-	"github.com/google/blueprint/pathtools"
-)
-
-// bazel_paths contains methods to:
-//   * resolve Soong path and module references into bazel.LabelList
-//   * resolve Bazel path references into Soong-compatible paths
-//
-// There is often a similar method for Bazel as there is for Soong path handling and should be used
-// in similar circumstances
-//
-//   Bazel                                Soong
-//   ==============================================================
-//   BazelLabelForModuleSrc               PathForModuleSrc
-//   BazelLabelForModuleSrcExcludes       PathForModuleSrcExcludes
-//   BazelLabelForModuleDeps              n/a
-//   tbd                                  PathForSource
-//   tbd                                  ExistentPathsForSources
-//   PathForBazelOut                      PathForModuleOut
-//
-// Use cases:
-//  * Module contains a property (often tagged `android:"path"`) that expects paths *relative to the
-//    module directory*:
-//     * BazelLabelForModuleSrcExcludes, if the module also contains an excludes_<propname> property
-//     * BazelLabelForModuleSrc, otherwise
-//  * Converting references to other modules to Bazel Labels:
-//     BazelLabelForModuleDeps
-//  * Converting a path obtained from bazel_handler cquery results:
-//     PathForBazelOut
-//
-// NOTE: all Soong globs are expanded within Soong rather than being converted to a Bazel glob
-//       syntax. This occurs because Soong does not have a concept of crossing package boundaries,
-//       so the glob as computed by Soong may contain paths that cross package-boundaries. These
-//       would be unknowingly omitted if the glob were handled by Bazel. By expanding globs within
-//       Soong, we support identification and detection (within Bazel) use of paths that cross
-//       package boundaries.
-//
-// Path resolution:
-// * filepath/globs: resolves as itself or is converted to an absolute Bazel label (e.g.
-//   //path/to/dir:<filepath>) if path exists in a separate package or subpackage.
-// * references to other modules (using the ":name{.tag}" syntax). These resolve as a Bazel label
-//   for a target. If the Bazel target is in the local module directory, it will be returned
-//   relative to the current package (e.g.  ":<target>"). Otherwise, it will be returned as an
-//   absolute Bazel label (e.g.  "//path/to/dir:<target>"). If the reference to another module
-//   cannot be resolved,the function will panic. This is often due to the dependency not being added
-//   via an AddDependency* method.
-
-// BazelConversionContext is a minimal context interface to check if a module should be converted by bp2build,
-// with functions containing information to match against allowlists and denylists.
-// If a module is deemed to be convertible by bp2build, then it should rely on a
-// BazelConversionPathContext for more functions for dep/path features.
-type BazelConversionContext interface {
-	Config() Config
-
-	Module() Module
-	OtherModuleType(m blueprint.Module) string
-	OtherModuleName(m blueprint.Module) string
-	OtherModuleDir(m blueprint.Module) string
-	ModuleErrorf(format string, args ...interface{})
-}
-
-// A subset of the ModuleContext methods which are sufficient to resolve references to paths/deps in
-// order to form a Bazel-compatible label for conversion.
-type BazelConversionPathContext interface {
-	EarlyModulePathContext
-	BazelConversionContext
-
-	ModuleErrorf(fmt string, args ...interface{})
-	PropertyErrorf(property, fmt string, args ...interface{})
-	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
-	ModuleFromName(name string) (blueprint.Module, bool)
-	AddUnconvertedBp2buildDep(string)
-	AddMissingBp2buildDep(dep string)
-}
-
-// BazelLabelForModuleDeps expects a list of reference to other modules, ("<module>"
-// or ":<module>") and returns a Bazel-compatible label which corresponds to dependencies on the
-// module within the given ctx.
-func BazelLabelForModuleDeps(ctx BazelConversionPathContext, modules []string) bazel.LabelList {
-	return BazelLabelForModuleDepsWithFn(ctx, modules, BazelModuleLabel)
-}
-
-// BazelLabelForModuleWholeDepsExcludes expects two lists: modules (containing modules to include in
-// the list), and excludes (modules to exclude from the list). Both of these should contain
-// references to other modules, ("<module>" or ":<module>"). It returns a Bazel-compatible label
-// list which corresponds to dependencies on the module within the given ctx, and the excluded
-// dependencies.  Prebuilt dependencies will be appended with _alwayslink so they can be handled as
-// whole static libraries.
-func BazelLabelForModuleDepsExcludes(ctx BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
-	return BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, BazelModuleLabel)
-}
-
-// BazelLabelForModuleDepsWithFn expects a list of reference to other modules, ("<module>"
-// or ":<module>") and applies moduleToLabelFn to determine and return a Bazel-compatible label
-// which corresponds to dependencies on the module within the given ctx.
-func BazelLabelForModuleDepsWithFn(ctx BazelConversionPathContext, modules []string,
-	moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string) bazel.LabelList {
-	var labels bazel.LabelList
-	// In some cases, a nil string list is different than an explicitly empty list.
-	if len(modules) == 0 && modules != nil {
-		labels.Includes = []bazel.Label{}
-		return labels
-	}
-	modules = FirstUniqueStrings(modules)
-	for _, module := range modules {
-		bpText := module
-		if m := SrcIsModule(module); m == "" {
-			module = ":" + module
-		}
-		if m, t := SrcIsModuleWithTag(module); m != "" {
-			l := getOtherModuleLabel(ctx, m, t, moduleToLabelFn)
-			if l != nil {
-				l.OriginalModuleName = bpText
-				labels.Includes = append(labels.Includes, *l)
-			}
-		} else {
-			ctx.ModuleErrorf("%q, is not a module reference", module)
-		}
-	}
-	return labels
-}
-
-// BazelLabelForModuleDepsExcludesWithFn expects two lists: modules (containing modules to include in the
-// list), and excludes (modules to exclude from the list). Both of these should contain references
-// to other modules, ("<module>" or ":<module>"). It applies moduleToLabelFn to determine and return a
-// Bazel-compatible label list which corresponds to dependencies on the module within the given ctx, and
-// the excluded dependencies.
-func BazelLabelForModuleDepsExcludesWithFn(ctx BazelConversionPathContext, modules, excludes []string,
-	moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string) bazel.LabelList {
-	moduleLabels := BazelLabelForModuleDepsWithFn(ctx, RemoveListFromList(modules, excludes), moduleToLabelFn)
-	if len(excludes) == 0 {
-		return moduleLabels
-	}
-	excludeLabels := BazelLabelForModuleDepsWithFn(ctx, excludes, moduleToLabelFn)
-	return bazel.LabelList{
-		Includes: moduleLabels.Includes,
-		Excludes: excludeLabels.Includes,
-	}
-}
-
-func BazelLabelForModuleSrcSingle(ctx BazelConversionPathContext, path string) bazel.Label {
-	if srcs := BazelLabelForModuleSrcExcludes(ctx, []string{path}, []string(nil)).Includes; len(srcs) > 0 {
-		return srcs[0]
-	}
-	return bazel.Label{}
-}
-
-func BazelLabelForModuleDepSingle(ctx BazelConversionPathContext, path string) bazel.Label {
-	if srcs := BazelLabelForModuleDepsExcludes(ctx, []string{path}, []string(nil)).Includes; len(srcs) > 0 {
-		return srcs[0]
-	}
-	return bazel.Label{}
-}
-
-// BazelLabelForModuleSrc expects a list of path (relative to local module directory) and module
-// references (":<module>") and returns a bazel.LabelList{} containing the resolved references in
-// paths, relative to the local module, or Bazel-labels (absolute if in a different package or
-// relative if within the same package).
-// Properties must have been annotated with struct tag `android:"path"` so that dependencies modules
-// will have already been handled by the pathdeps mutator.
-func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) bazel.LabelList {
-	return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil))
-}
-
-// BazelLabelForModuleSrc expects lists of path and excludes (relative to local module directory)
-// and module references (":<module>") and returns a bazel.LabelList{} containing the resolved
-// references in paths, minus those in excludes, relative to the local module, or Bazel-labels
-// (absolute if in a different package or relative if within the same package).
-// Properties must have been annotated with struct tag `android:"path"` so that dependencies modules
-// will have already been handled by the pathdeps mutator.
-func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, excludes []string) bazel.LabelList {
-	excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil))
-	excluded := make([]string, 0, len(excludeLabels.Includes))
-	for _, e := range excludeLabels.Includes {
-		excluded = append(excluded, e.Label)
-	}
-	labels := expandSrcsForBazel(ctx, paths, excluded)
-	labels.Excludes = excludeLabels.Includes
-	labels = TransformSubpackagePaths(ctx.Config(), ctx.ModuleDir(), labels)
-	return labels
-}
-
-// Returns true if a prefix + components[:i] is a package boundary.
-//
-// A package boundary is determined by a BUILD file in the directory. This can happen in 2 cases:
-//
-//  1. An Android.bp exists, which bp2build will always convert to a sibling BUILD file.
-//  2. An Android.bp doesn't exist, but a checked-in BUILD/BUILD.bazel file exists, and that file
-//     is allowlisted by the bp2build configuration to be merged into the symlink forest workspace.
-func isPackageBoundary(config Config, prefix string, components []string, componentIndex int) bool {
-	prefix = filepath.Join(prefix, filepath.Join(components[:componentIndex+1]...))
-	if exists, _, _ := config.fs.Exists(filepath.Join(prefix, "Android.bp")); exists {
-		return true
-	} else if config.Bp2buildPackageConfig.ShouldKeepExistingBuildFileForDir(prefix) {
-		if exists, _, _ := config.fs.Exists(filepath.Join(prefix, "BUILD")); exists {
-			return true
-		} else if exists, _, _ := config.fs.Exists(filepath.Join(prefix, "BUILD.bazel")); exists {
-			return true
-		}
-	}
-
-	return false
-}
-
-// Transform a path (if necessary) to acknowledge package boundaries
-//
-// e.g. something like
-//
-//	async_safe/include/async_safe/CHECK.h
-//
-// might become
-//
-//	//bionic/libc/async_safe:include/async_safe/CHECK.h
-//
-// if the "async_safe" directory is actually a package and not just a directory.
-//
-// In particular, paths that extend into packages are transformed into absolute labels beginning with //.
-func transformSubpackagePath(cfg Config, dir string, path bazel.Label) bazel.Label {
-	var newPath bazel.Label
-
-	// Don't transform OriginalModuleName
-	newPath.OriginalModuleName = path.OriginalModuleName
-	// if it wasn't a module, store the original path. We may need the original path to replace
-	// references if it is actually in another package
-	if path.OriginalModuleName == "" {
-		newPath.OriginalModuleName = path.Label
-	}
-
-	if strings.HasPrefix(path.Label, "//") {
-		// Assume absolute labels are already correct (e.g. //path/to/some/package:foo.h)
-		newPath.Label = path.Label
-		return newPath
-	}
-	if strings.HasPrefix(path.Label, "./") {
-		// Drop "./" for consistent handling of paths.
-		// Specifically, to not let "." be considered a package boundary.
-		// Say `inputPath` is `x/Android.bp` and that file has some module
-		// with `srcs=["y/a.c", "z/b.c"]`.
-		// And say the directory tree is:
-		//     x
-		//     ├── Android.bp
-		//     ├── y
-		//     │   ├── a.c
-		//     │   └── Android.bp
-		//     └── z
-		//         └── b.c
-		// Then bazel equivalent labels in srcs should be:
-		//   //x/y:a.c, x/z/b.c
-		// The above should still be the case if `x/Android.bp` had
-		//   srcs=["./y/a.c", "./z/b.c"]
-		// However, if we didn't strip "./", we'd get
-		//   //x/./y:a.c, //x/.:z/b.c
-		path.Label = strings.TrimPrefix(path.Label, "./")
-	}
-	pathComponents := strings.Split(path.Label, "/")
-	newLabel := ""
-	foundPackageBoundary := false
-	// Check the deepest subdirectory first and work upwards
-	for i := len(pathComponents) - 1; i >= 0; i-- {
-		pathComponent := pathComponents[i]
-		var sep string
-		if !foundPackageBoundary && isPackageBoundary(cfg, dir, pathComponents, i) {
-			sep = ":"
-			foundPackageBoundary = true
-		} else {
-			sep = "/"
-		}
-		if newLabel == "" {
-			newLabel = pathComponent
-		} else {
-			newLabel = pathComponent + sep + newLabel
-		}
-	}
-	if foundPackageBoundary {
-		// Ensure paths end up looking like //bionic/... instead of //./bionic/...
-		moduleDir := dir
-		if strings.HasPrefix(moduleDir, ".") {
-			moduleDir = moduleDir[1:]
-		}
-		// Make the path into an absolute label (e.g. //bionic/libc/foo:bar.h instead of just foo:bar.h)
-		if moduleDir == "" {
-			newLabel = "//" + newLabel
-		} else {
-			newLabel = "//" + moduleDir + "/" + newLabel
-		}
-	}
-	newPath.Label = newLabel
-
-	return newPath
-}
-
-// Transform paths to acknowledge package boundaries
-// See transformSubpackagePath() for more information
-func TransformSubpackagePaths(cfg Config, dir string, paths bazel.LabelList) bazel.LabelList {
-	var newPaths bazel.LabelList
-	for _, include := range paths.Includes {
-		newPaths.Includes = append(newPaths.Includes, transformSubpackagePath(cfg, dir, include))
-	}
-	for _, exclude := range paths.Excludes {
-		newPaths.Excludes = append(newPaths.Excludes, transformSubpackagePath(cfg, dir, exclude))
-	}
-	return newPaths
-}
-
-// Converts root-relative Paths to a list of bazel.Label relative to the module in ctx.
-func RootToModuleRelativePaths(ctx BazelConversionPathContext, paths Paths) []bazel.Label {
-	var newPaths []bazel.Label
-	for _, path := range PathsWithModuleSrcSubDir(ctx, paths, "") {
-		s := path.Rel()
-		newPaths = append(newPaths, bazel.Label{Label: s})
-	}
-	return newPaths
-}
-
-// expandSrcsForBazel returns bazel.LabelList with paths rooted from the module's local source
-// directory and Bazel target labels, excluding those included in the excludes argument (which
-// should already be expanded to resolve references to Soong-modules). Valid elements of paths
-// include:
-//   - filepath, relative to local module directory, resolves as a filepath relative to the local
-//     source directory
-//   - glob, relative to the local module directory, resolves as filepath(s), relative to the local
-//     module directory. Because Soong does not have a concept of crossing package boundaries, the
-//     glob as computed by Soong may contain paths that cross package-boundaries that would be
-//     unknowingly omitted if the glob were handled by Bazel. To allow identification and detect
-//     (within Bazel) use of paths that cross package boundaries, we expand globs within Soong rather
-//     than converting Soong glob syntax to Bazel glob syntax. **Invalid for excludes.**
-//   - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
-//     or OutputFileProducer. These resolve as a Bazel label for a target. If the Bazel target is in
-//     the local module directory, it will be returned relative to the current package (e.g.
-//     ":<target>"). Otherwise, it will be returned as an absolute Bazel label (e.g.
-//     "//path/to/dir:<target>"). If the reference to another module cannot be resolved,the function
-//     will panic.
-//
-// Properties passed as the paths or excludes argument must have been annotated with struct tag
-// `android:"path"` so that dependencies on other modules will have already been handled by the
-// pathdeps mutator.
-func expandSrcsForBazel(ctx BazelConversionPathContext, paths, expandedExcludes []string) bazel.LabelList {
-	if paths == nil {
-		return bazel.LabelList{}
-	}
-	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, BazelModuleLabel)
-			if l != nil && !InList(l.Label, expandedExcludes) {
-				l.OriginalModuleName = fmt.Sprintf(":%s", m)
-				labels.Includes = append(labels.Includes, *l)
-			}
-		} else {
-			var expandedPaths []bazel.Label
-			if pathtools.IsGlob(p) {
-				// e.g. turn "math/*.c" in
-				// external/arm-optimized-routines to external/arm-optimized-routines/math/*.c
-				rootRelativeGlobPath := pathForModuleSrc(ctx, p).String()
-				expandedPaths = RootToModuleRelativePaths(ctx, GlobFiles(ctx, rootRelativeGlobPath, rootRelativeExpandedExcludes))
-			} else {
-				if !InList(p, expandedExcludes) {
-					expandedPaths = append(expandedPaths, bazel.Label{Label: p})
-				}
-			}
-			labels.Includes = append(labels.Includes, expandedPaths...)
-		}
-	}
-	return labels
-}
-
-// getOtherModuleLabel returns a bazel.Label for the given dependency/tag combination for the
-// module. The label will be relative to the current directory if appropriate. The dependency must
-// already be resolved by either deps mutator or path deps mutator.
-func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string,
-	labelFromModule func(BazelConversionPathContext, blueprint.Module) string) *bazel.Label {
-	m, _ := ctx.ModuleFromName(dep)
-	// The module was not found in an Android.bp file, this is often due to:
-	//		* a limited manifest
-	//		* a required module not being converted from Android.mk
-	if m == nil {
-		ctx.AddMissingBp2buildDep(dep)
-		return &bazel.Label{
-			Label: ":" + dep + "__BP2BUILD__MISSING__DEP",
-		}
-	}
-	if !convertedToBazel(ctx, m) {
-		ctx.AddUnconvertedBp2buildDep(dep)
-	}
-	label := BazelModuleLabel(ctx, ctx.Module())
-	otherLabel := labelFromModule(ctx, m)
-
-	// TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets.
-
-	if samePackage(label, otherLabel) {
-		otherLabel = bazelShortLabel(otherLabel)
-	}
-
-	return &bazel.Label{
-		Label: otherLabel,
-	}
-}
-
-func BazelModuleLabel(ctx BazelConversionPathContext, module blueprint.Module) string {
-	// TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets.
-	if !convertedToBazel(ctx, module) || isGoModule(module) {
-		return bp2buildModuleLabel(ctx, module)
-	}
-	b, _ := module.(Bazelable)
-	return b.GetBazelLabel(ctx, module)
-}
-
-func bazelShortLabel(label string) string {
-	i := strings.Index(label, ":")
-	if i == -1 {
-		panic(fmt.Errorf("Could not find the ':' character in '%s', expected a fully qualified label.", label))
-	}
-	return label[i:]
-}
-
-func bazelPackage(label string) string {
-	i := strings.Index(label, ":")
-	if i == -1 {
-		panic(fmt.Errorf("Could not find the ':' character in '%s', expected a fully qualified label.", label))
-	}
-	return label[0:i]
-}
-
-func samePackage(label1, label2 string) bool {
-	return bazelPackage(label1) == bazelPackage(label2)
-}
-
-func bp2buildModuleLabel(ctx BazelConversionContext, module blueprint.Module) string {
-	moduleName := moduleNameWithPossibleOverride(ctx, module)
-	moduleDir := moduleDirWithPossibleOverride(ctx, module)
-	if moduleDir == Bp2BuildTopLevel {
-		moduleDir = ""
-	}
-	return fmt.Sprintf("//%s:%s", moduleDir, moduleName)
-}
-
-// BazelOutPath is a Bazel output path compatible to be used for mixed builds within Soong/Ninja.
-type BazelOutPath struct {
-	OutputPath
-}
-
-// ensure BazelOutPath implements Path
-var _ Path = BazelOutPath{}
-
-// ensure BazelOutPath implements genPathProvider
-var _ genPathProvider = BazelOutPath{}
-
-// ensure BazelOutPath implements objPathProvider
-var _ objPathProvider = BazelOutPath{}
-
-func (p BazelOutPath) genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleGenPath {
-	return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
-}
-
-func (p BazelOutPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath {
-	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
-}
-
-// PathForBazelOutRelative returns a BazelOutPath representing the path under an output directory dedicated to
-// bazel-owned outputs. Calling .Rel() on the result will give the input path as relative to the given
-// relativeRoot.
-func PathForBazelOutRelative(ctx PathContext, relativeRoot string, path string) BazelOutPath {
-	validatedPath, err := validatePath(filepath.Join("execroot", "__main__", path))
-	if err != nil {
-		reportPathError(ctx, err)
-	}
-	var relativeRootPath string
-	if pathComponents := strings.SplitN(path, "/", 4); len(pathComponents) >= 3 &&
-		pathComponents[0] == "bazel-out" && pathComponents[2] == "bin" {
-		// If the path starts with something like: bazel-out/linux_x86_64-fastbuild-ST-b4ef1c4402f9/bin/
-		// make it relative to that folder. bazel-out/volatile-status.txt is an example
-		// of something that starts with bazel-out but is not relative to the bin folder
-		relativeRootPath = filepath.Join("execroot", "__main__", pathComponents[0], pathComponents[1], pathComponents[2], relativeRoot)
-	} else {
-		relativeRootPath = filepath.Join("execroot", "__main__", relativeRoot)
-	}
-
-	var relPath string
-	if relPath, err = filepath.Rel(relativeRootPath, validatedPath); err != nil || strings.HasPrefix(relPath, "../") {
-		// We failed to make this path relative to execroot/__main__, fall back to a non-relative path
-		// One case where this happens is when path is ../bazel_tools/something
-		relativeRootPath = ""
-		relPath = validatedPath
-	}
-
-	outputPath := OutputPath{
-		basePath{"", ""},
-		ctx.Config().soongOutDir,
-		ctx.Config().BazelContext.OutputBase(),
-	}
-
-	return BazelOutPath{
-		// .withRel() appends its argument onto the current path, and only the most
-		// recently appended part is returned by outputPath.rel().
-		// So outputPath.rel() will return relPath.
-		OutputPath: outputPath.withRel(relativeRootPath).withRel(relPath),
-	}
-}
-
-// PathForBazelOut returns a BazelOutPath representing the path under an output directory dedicated to
-// bazel-owned outputs.
-func PathForBazelOut(ctx PathContext, path string) BazelOutPath {
-	return PathForBazelOutRelative(ctx, "", path)
-}
-
-// PathsForBazelOut returns a list of paths representing the paths under an output directory
-// dedicated to Bazel-owned outputs.
-func PathsForBazelOut(ctx PathContext, paths []string) Paths {
-	outs := make(Paths, 0, len(paths))
-	for _, p := range paths {
-		outs = append(outs, PathForBazelOut(ctx, p))
-	}
-	return outs
-}
-
-// BazelStringOrLabelFromProp splits a Soong module property that can be
-// either a string literal, path (with android:path tag) or a module reference
-// into separate bazel string or label attributes. Bazel treats string and label
-// attributes as distinct types, so this function categorizes a string property
-// into either one of them.
-//
-// e.g. apex.private_key = "foo.pem" can either refer to:
-//
-// 1. "foo.pem" in the current directory -> file target
-// 2. "foo.pem" module -> rule target
-// 3. "foo.pem" file in a different directory, prefixed by a product variable handled
-// in a bazel macro. -> string literal
-//
-// For the first two cases, they are defined using the label attribute. For the third case,
-// it's defined with the string attribute.
-func BazelStringOrLabelFromProp(
-	ctx TopDownMutatorContext,
-	propToDistinguish *string) (bazel.LabelAttribute, bazel.StringAttribute) {
-
-	var labelAttr bazel.LabelAttribute
-	var strAttr bazel.StringAttribute
-
-	if propToDistinguish == nil {
-		// nil pointer
-		return labelAttr, strAttr
-	}
-
-	prop := String(propToDistinguish)
-	if SrcIsModule(prop) != "" {
-		// If it's a module (SrcIsModule will return the module name), set the
-		// resolved label to the label attribute.
-		labelAttr.SetValue(BazelLabelForModuleDepSingle(ctx, prop))
-	} else {
-		// Not a module name. This could be a string literal or a file target in
-		// the current dir. Check if the path exists:
-		path := ExistentPathForSource(ctx, ctx.ModuleDir(), prop)
-
-		if path.Valid() && parentDir(path.String()) == ctx.ModuleDir() {
-			// If it exists and the path is relative to the current dir, resolve the bazel label
-			// for the _file target_ and set it to the label attribute.
-			//
-			// Resolution is necessary because this could be a file in a subpackage.
-			labelAttr.SetValue(BazelLabelForModuleSrcSingle(ctx, prop))
-		} else {
-			// Otherwise, treat it as a string literal and assign to the string attribute.
-			strAttr.Value = propToDistinguish
-		}
-	}
-
-	return labelAttr, strAttr
-}
diff --git a/android/bazel_paths_test.go b/android/bazel_paths_test.go
deleted file mode 100644
index 60c0a14..0000000
--- a/android/bazel_paths_test.go
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package android
-
-import (
-	"path/filepath"
-	"testing"
-
-	"android/soong/bazel"
-	"github.com/google/blueprint"
-	"github.com/google/blueprint/pathtools"
-)
-
-type TestBazelPathContext struct{}
-
-func (*TestBazelPathContext) Config() Config {
-	cfg := NullConfig("out", "out/soong")
-	cfg.BazelContext = MockBazelContext{
-		OutputBaseDir: "out/bazel",
-	}
-	return cfg
-}
-
-func (*TestBazelPathContext) AddNinjaFileDeps(...string) {
-	panic("Unimplemented")
-}
-
-func TestPathForBazelOut(t *testing.T) {
-	ctx := &TestBazelPathContext{}
-	out := PathForBazelOut(ctx, "foo/bar/baz/boq.txt")
-	expectedPath := filepath.Join(ctx.Config().BazelContext.OutputBase(), "execroot/__main__/foo/bar/baz/boq.txt")
-	if out.String() != expectedPath {
-		t.Errorf("incorrect OutputPath: expected %q, got %q", expectedPath, out.String())
-	}
-
-	expectedRelPath := "foo/bar/baz/boq.txt"
-	if out.Rel() != expectedRelPath {
-		t.Errorf("incorrect OutputPath.Rel(): expected %q, got %q", expectedRelPath, out.Rel())
-	}
-}
-
-func TestPathForBazelOutRelative(t *testing.T) {
-	ctx := &TestBazelPathContext{}
-	out := PathForBazelOutRelative(ctx, "foo/bar", "foo/bar/baz/boq.txt")
-
-	expectedPath := filepath.Join(ctx.Config().BazelContext.OutputBase(), "execroot/__main__/foo/bar/baz/boq.txt")
-	if out.String() != expectedPath {
-		t.Errorf("incorrect OutputPath: expected %q, got %q", expectedPath, out.String())
-	}
-
-	expectedRelPath := "baz/boq.txt"
-	if out.Rel() != expectedRelPath {
-		t.Errorf("incorrect OutputPath.Rel(): expected %q, got %q", expectedRelPath, out.Rel())
-	}
-}
-
-func TestPathForBazelOutRelativeUnderBinFolder(t *testing.T) {
-	ctx := &TestBazelPathContext{}
-	out := PathForBazelOutRelative(ctx, "foo/bar", "bazel-out/linux_x86_64-fastbuild-ST-b4ef1c4402f9/bin/foo/bar/baz/boq.txt")
-
-	expectedPath := filepath.Join(ctx.Config().BazelContext.OutputBase(), "execroot/__main__/bazel-out/linux_x86_64-fastbuild-ST-b4ef1c4402f9/bin/foo/bar/baz/boq.txt")
-	if out.String() != expectedPath {
-		t.Errorf("incorrect OutputPath: expected %q, got %q", expectedPath, out.String())
-	}
-
-	expectedRelPath := "baz/boq.txt"
-	if out.Rel() != expectedRelPath {
-		t.Errorf("incorrect OutputPath.Rel(): expected %q, got %q", expectedRelPath, out.Rel())
-	}
-}
-
-func TestPathForBazelOutOutsideOfExecroot(t *testing.T) {
-	ctx := &TestBazelPathContext{}
-	out := PathForBazelOut(ctx, "../bazel_tools/linux_x86_64-fastbuild/bin/tools/android/java_base_extras.jar")
-
-	expectedPath := filepath.Join(ctx.Config().BazelContext.OutputBase(), "execroot/bazel_tools/linux_x86_64-fastbuild/bin/tools/android/java_base_extras.jar")
-	if out.String() != expectedPath {
-		t.Errorf("incorrect OutputPath: expected %q, got %q", expectedPath, out.String())
-	}
-
-	expectedRelPath := "execroot/bazel_tools/linux_x86_64-fastbuild/bin/tools/android/java_base_extras.jar"
-	if out.Rel() != expectedRelPath {
-		t.Errorf("incorrect OutputPath.Rel(): expected %q, got %q", expectedRelPath, out.Rel())
-	}
-}
-
-func TestPathForBazelOutRelativeWithParentDirectoryRoot(t *testing.T) {
-	ctx := &TestBazelPathContext{}
-	out := PathForBazelOutRelative(ctx, "../bazel_tools", "../bazel_tools/foo/bar/baz.sh")
-
-	expectedPath := filepath.Join(ctx.Config().BazelContext.OutputBase(), "execroot/bazel_tools/foo/bar/baz.sh")
-	if out.String() != expectedPath {
-		t.Errorf("incorrect OutputPath: expected %q, got %q", expectedPath, out.String())
-	}
-
-	expectedRelPath := "foo/bar/baz.sh"
-	if out.Rel() != expectedRelPath {
-		t.Errorf("incorrect OutputPath.Rel(): expected %q, got %q", expectedRelPath, out.Rel())
-	}
-}
-
-type TestBazelConversionPathContext struct {
-	TestBazelConversionContext
-	moduleDir string
-	cfg       Config
-}
-
-func (ctx *TestBazelConversionPathContext) AddNinjaFileDeps(...string) {
-	panic("Unimplemented")
-}
-
-func (ctx *TestBazelConversionPathContext) GlobWithDeps(string, []string) ([]string, error) {
-	panic("Unimplemented")
-}
-
-func (ctx *TestBazelConversionPathContext) PropertyErrorf(string, string, ...interface{}) {
-	panic("Unimplemented")
-}
-
-func (ctx *TestBazelConversionPathContext) GetDirectDep(string) (blueprint.Module, blueprint.DependencyTag) {
-	panic("Unimplemented")
-}
-
-func (ctx *TestBazelConversionPathContext) ModuleFromName(string) (blueprint.Module, bool) {
-	panic("Unimplemented")
-}
-
-func (ctx *TestBazelConversionPathContext) AddUnconvertedBp2buildDep(string) {
-	panic("Unimplemented")
-}
-
-func (ctx *TestBazelConversionPathContext) AddMissingBp2buildDep(string) {
-	panic("Unimplemented")
-}
-
-func (ctx *TestBazelConversionPathContext) Module() Module {
-	panic("Unimplemented")
-}
-
-func (ctx *TestBazelConversionPathContext) Config() Config {
-	return ctx.cfg
-}
-
-func (ctx *TestBazelConversionPathContext) ModuleDir() string {
-	return ctx.moduleDir
-}
-
-func TestTransformSubpackagePath(t *testing.T) {
-	cfg := NullConfig("out", "out/soong")
-	cfg.fs = pathtools.MockFs(map[string][]byte{
-		"x/Android.bp":   nil,
-		"x/y/Android.bp": nil,
-	})
-
-	var ctx BazelConversionPathContext = &TestBazelConversionPathContext{
-		moduleDir: "x",
-		cfg:       cfg,
-	}
-	pairs := map[string]string{
-		"y/a.c":   "//x/y:a.c",
-		"./y/a.c": "//x/y:a.c",
-		"z/b.c":   "z/b.c",
-		"./z/b.c": "z/b.c",
-	}
-	for in, out := range pairs {
-		actual := transformSubpackagePath(ctx.Config(), ctx.ModuleDir(), bazel.Label{Label: in}).Label
-		if actual != out {
-			t.Errorf("expected:\n%v\nactual:\n%v", out, actual)
-		}
-	}
-}
diff --git a/android/bazel_test.go b/android/bazel_test.go
deleted file mode 100644
index 13fd408..0000000
--- a/android/bazel_test.go
+++ /dev/null
@@ -1,585 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package android
-
-import (
-	"fmt"
-	"testing"
-
-	"android/soong/android/allowlists"
-	"android/soong/bazel"
-
-	"github.com/google/blueprint"
-	"github.com/google/blueprint/proptools"
-)
-
-func TestConvertAllModulesInPackage(t *testing.T) {
-	testCases := []struct {
-		prefixes   allowlists.Bp2BuildConfig
-		packageDir string
-	}{
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a": allowlists.Bp2BuildDefaultTrueRecursively,
-			},
-			packageDir: "a",
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a/b": allowlists.Bp2BuildDefaultTrueRecursively,
-			},
-			packageDir: "a/b",
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a/b":   allowlists.Bp2BuildDefaultTrueRecursively,
-				"a/b/c": allowlists.Bp2BuildDefaultTrueRecursively,
-			},
-			packageDir: "a/b",
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a":     allowlists.Bp2BuildDefaultTrueRecursively,
-				"d/e/f": allowlists.Bp2BuildDefaultTrueRecursively,
-			},
-			packageDir: "a/b",
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a":     allowlists.Bp2BuildDefaultFalse,
-				"a/b":   allowlists.Bp2BuildDefaultTrueRecursively,
-				"a/b/c": allowlists.Bp2BuildDefaultFalse,
-			},
-			packageDir: "a/b",
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a":     allowlists.Bp2BuildDefaultTrueRecursively,
-				"a/b":   allowlists.Bp2BuildDefaultFalse,
-				"a/b/c": allowlists.Bp2BuildDefaultTrueRecursively,
-			},
-			packageDir: "a",
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a":   allowlists.Bp2BuildDefaultFalseRecursively,
-				"a/b": allowlists.Bp2BuildDefaultTrue,
-			},
-			packageDir: "a/b",
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a":   allowlists.Bp2BuildDefaultFalseRecursively,
-				"a/b": allowlists.Bp2BuildDefaultTrueRecursively,
-			},
-			packageDir: "a/b/c",
-		},
-	}
-
-	for _, test := range testCases {
-		if ok, _ := bp2buildDefaultTrueRecursively(test.packageDir, test.prefixes); !ok {
-			t.Errorf("Expected to convert all modules in %s based on %v, but failed.", test.packageDir, test.prefixes)
-		}
-	}
-}
-
-func TestModuleOptIn(t *testing.T) {
-	testCases := []struct {
-		prefixes   allowlists.Bp2BuildConfig
-		packageDir string
-	}{
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a/b": allowlists.Bp2BuildDefaultFalse,
-			},
-			packageDir: "a/b",
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a":   allowlists.Bp2BuildDefaultFalse,
-				"a/b": allowlists.Bp2BuildDefaultTrueRecursively,
-			},
-			packageDir: "a",
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a/b": allowlists.Bp2BuildDefaultTrueRecursively,
-			},
-			packageDir: "a", // opt-in by default
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a/b/c": allowlists.Bp2BuildDefaultTrueRecursively,
-			},
-			packageDir: "a/b",
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a":     allowlists.Bp2BuildDefaultTrueRecursively,
-				"d/e/f": allowlists.Bp2BuildDefaultTrueRecursively,
-			},
-			packageDir: "foo/bar",
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a":     allowlists.Bp2BuildDefaultTrueRecursively,
-				"a/b":   allowlists.Bp2BuildDefaultFalse,
-				"a/b/c": allowlists.Bp2BuildDefaultTrueRecursively,
-			},
-			packageDir: "a/b",
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a":     allowlists.Bp2BuildDefaultFalse,
-				"a/b":   allowlists.Bp2BuildDefaultTrueRecursively,
-				"a/b/c": allowlists.Bp2BuildDefaultFalse,
-			},
-			packageDir: "a",
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a":   allowlists.Bp2BuildDefaultFalseRecursively,
-				"a/b": allowlists.Bp2BuildDefaultTrue,
-			},
-			packageDir: "a/b/c",
-		},
-		{
-			prefixes: allowlists.Bp2BuildConfig{
-				"a":   allowlists.Bp2BuildDefaultTrueRecursively,
-				"a/b": allowlists.Bp2BuildDefaultFalseRecursively,
-			},
-			packageDir: "a/b/c",
-		},
-	}
-
-	for _, test := range testCases {
-		if ok, _ := bp2buildDefaultTrueRecursively(test.packageDir, test.prefixes); ok {
-			t.Errorf("Expected to allow module opt-in in %s based on %v, but failed.", test.packageDir, test.prefixes)
-		}
-	}
-}
-
-type TestBazelModule struct {
-	bazel.TestModuleInfo
-	BazelModuleBase
-}
-
-var _ blueprint.Module = TestBazelModule{}
-
-func (m TestBazelModule) Name() string {
-	return m.TestModuleInfo.ModuleName
-}
-
-func (m TestBazelModule) GenerateBuildActions(blueprint.ModuleContext) {
-}
-
-type TestBazelConversionContext struct {
-	omc       bazel.OtherModuleTestContext
-	allowlist Bp2BuildConversionAllowlist
-	errors    []string
-}
-
-var _ bazelOtherModuleContext = &TestBazelConversionContext{}
-
-func (bcc *TestBazelConversionContext) OtherModuleType(m blueprint.Module) string {
-	return bcc.omc.OtherModuleType(m)
-}
-
-func (bcc *TestBazelConversionContext) OtherModuleName(m blueprint.Module) string {
-	return bcc.omc.OtherModuleName(m)
-}
-
-func (bcc *TestBazelConversionContext) OtherModuleDir(m blueprint.Module) string {
-	return bcc.omc.OtherModuleDir(m)
-}
-
-func (bcc *TestBazelConversionContext) ModuleErrorf(format string, args ...interface{}) {
-	bcc.errors = append(bcc.errors, fmt.Sprintf(format, args...))
-}
-
-func (bcc *TestBazelConversionContext) Config() Config {
-	return Config{
-		&config{
-			Bp2buildPackageConfig: bcc.allowlist,
-		},
-	}
-}
-
-var bazelableBazelModuleBase = BazelModuleBase{
-	bazelProperties: properties{
-		Bazel_module: BazelModuleProperties{
-			CanConvertToBazel: true,
-		},
-	},
-}
-
-func TestBp2BuildAllowlist(t *testing.T) {
-	testCases := []struct {
-		description    string
-		shouldConvert  bool
-		expectedErrors []string
-		module         TestBazelModule
-		allowlist      Bp2BuildConversionAllowlist
-	}{
-		{
-			description:   "allowlist enables module",
-			shouldConvert: true,
-			module: TestBazelModule{
-				TestModuleInfo: bazel.TestModuleInfo{
-					ModuleName: "foo",
-					Typ:        "rule1",
-					Dir:        "dir1",
-				},
-				BazelModuleBase: bazelableBazelModuleBase,
-			},
-			allowlist: Bp2BuildConversionAllowlist{
-				moduleAlwaysConvert: map[string]bool{
-					"foo": true,
-				},
-			},
-		},
-		{
-			description:    "module in name allowlist and type allowlist fails",
-			shouldConvert:  false,
-			expectedErrors: []string{"A module cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert"},
-			module: TestBazelModule{
-				TestModuleInfo: bazel.TestModuleInfo{
-					ModuleName: "foo",
-					Typ:        "rule1",
-					Dir:        "dir1",
-				},
-				BazelModuleBase: bazelableBazelModuleBase,
-			},
-			allowlist: Bp2BuildConversionAllowlist{
-				moduleAlwaysConvert: map[string]bool{
-					"foo": true,
-				},
-				moduleTypeAlwaysConvert: map[string]bool{
-					"rule1": true,
-				},
-			},
-		},
-		{
-			description:    "module in allowlist and denylist fails",
-			shouldConvert:  false,
-			expectedErrors: []string{"a module cannot be in moduleDoNotConvert and also be in moduleAlwaysConvert"},
-			module: TestBazelModule{
-				TestModuleInfo: bazel.TestModuleInfo{
-					ModuleName: "foo",
-					Typ:        "rule1",
-					Dir:        "dir1",
-				},
-				BazelModuleBase: bazelableBazelModuleBase,
-			},
-			allowlist: Bp2BuildConversionAllowlist{
-				moduleAlwaysConvert: map[string]bool{
-					"foo": true,
-				},
-				moduleDoNotConvert: map[string]bool{
-					"foo": true,
-				},
-			},
-		},
-		{
-			description:    "module allowlist and enabled directory",
-			shouldConvert:  false,
-			expectedErrors: []string{"A module cannot be in a directory marked Bp2BuildDefaultTrue or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: 'existing/build/dir' Module: 'foo'"},
-			module: TestBazelModule{
-				TestModuleInfo: bazel.TestModuleInfo{
-					ModuleName: "foo",
-					Typ:        "rule1",
-					Dir:        "existing/build/dir",
-				},
-				BazelModuleBase: bazelableBazelModuleBase,
-			},
-			allowlist: Bp2BuildConversionAllowlist{
-				moduleAlwaysConvert: map[string]bool{
-					"foo": true,
-				},
-				defaultConfig: allowlists.Bp2BuildConfig{
-					"existing/build/dir": allowlists.Bp2BuildDefaultTrue,
-				},
-			},
-		},
-		{
-			description:    "module allowlist and enabled subdirectory",
-			shouldConvert:  false,
-			expectedErrors: []string{"A module cannot be in a directory marked Bp2BuildDefaultTrue or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: 'existing/build/dir' Module: 'foo'"},
-			module: TestBazelModule{
-				TestModuleInfo: bazel.TestModuleInfo{
-					ModuleName: "foo",
-					Typ:        "rule1",
-					Dir:        "existing/build/dir/subdir",
-				},
-				BazelModuleBase: bazelableBazelModuleBase,
-			},
-			allowlist: Bp2BuildConversionAllowlist{
-				moduleAlwaysConvert: map[string]bool{
-					"foo": true,
-				},
-				defaultConfig: allowlists.Bp2BuildConfig{
-					"existing/build/dir": allowlists.Bp2BuildDefaultTrueRecursively,
-				},
-			},
-		},
-		{
-			description:   "module enabled in unit test short-circuits other allowlists",
-			shouldConvert: true,
-			module: TestBazelModule{
-				TestModuleInfo: bazel.TestModuleInfo{
-					ModuleName: "foo",
-					Typ:        "rule1",
-					Dir:        ".",
-				},
-				BazelModuleBase: BazelModuleBase{
-					bazelProperties: properties{
-						Bazel_module: BazelModuleProperties{
-							CanConvertToBazel:  true,
-							Bp2build_available: proptools.BoolPtr(true),
-						},
-					},
-				},
-			},
-			allowlist: Bp2BuildConversionAllowlist{
-				moduleAlwaysConvert: map[string]bool{
-					"foo": true,
-				},
-				moduleDoNotConvert: map[string]bool{
-					"foo": true,
-				},
-			},
-		},
-	}
-
-	for _, test := range testCases {
-		t.Run(test.description, func(t *testing.T) {
-			bcc := &TestBazelConversionContext{
-				omc: bazel.OtherModuleTestContext{
-					Modules: []bazel.TestModuleInfo{
-						test.module.TestModuleInfo,
-					},
-				},
-				allowlist: test.allowlist,
-			}
-
-			shouldConvert := test.module.shouldConvertWithBp2build(bcc, test.module.TestModuleInfo)
-			if test.shouldConvert != shouldConvert {
-				t.Errorf("Module shouldConvert expected to be: %v, but was: %v", test.shouldConvert, shouldConvert)
-			}
-
-			errorsMatch := true
-			if len(test.expectedErrors) != len(bcc.errors) {
-				errorsMatch = false
-			} else {
-				for i, err := range test.expectedErrors {
-					if err != bcc.errors[i] {
-						errorsMatch = false
-					}
-				}
-			}
-			if !errorsMatch {
-				t.Errorf("Expected errors to be: %v, but were: %v", test.expectedErrors, bcc.errors)
-			}
-		})
-	}
-}
-
-func TestBp2buildAllowList(t *testing.T) {
-	allowlist := GetBp2BuildAllowList()
-	for k, v := range allowlists.Bp2buildDefaultConfig {
-		if allowlist.defaultConfig[k] != v {
-			t.Errorf("bp2build default config of %s: expected: %v, got: %v", k, v, allowlist.defaultConfig[k])
-		}
-	}
-	for k, v := range allowlists.Bp2buildKeepExistingBuildFile {
-		if allowlist.keepExistingBuildFile[k] != v {
-			t.Errorf("bp2build keep existing build file of %s: expected: %v, got: %v", k, v, allowlist.keepExistingBuildFile[k])
-		}
-	}
-	for _, k := range allowlists.Bp2buildModuleTypeAlwaysConvertList {
-		if !allowlist.moduleTypeAlwaysConvert[k] {
-			t.Errorf("bp2build module type always convert of %s: expected: true, got: %v", k, allowlist.moduleTypeAlwaysConvert[k])
-		}
-	}
-	for _, k := range allowlists.Bp2buildModuleDoNotConvertList {
-		if !allowlist.moduleDoNotConvert[k] {
-			t.Errorf("bp2build module do not convert of %s: expected: true, got: %v", k, allowlist.moduleDoNotConvert[k])
-		}
-	}
-}
-
-func TestShouldKeepExistingBuildFileForDir(t *testing.T) {
-	allowlist := NewBp2BuildAllowlist()
-	// entry "a/b2/c2" is moot because of its parent "a/b2"
-	allowlist.SetKeepExistingBuildFile(map[string]bool{"a": false, "a/b1": false, "a/b2": true, "a/b1/c1": true, "a/b2/c2": false})
-	truths := []string{"a", "a/b1", "a/b2", "a/b1/c1", "a/b2/c", "a/b2/c2", "a/b2/c2/d"}
-	falsities := []string{"a1", "a/b", "a/b1/c"}
-	for _, dir := range truths {
-		if !allowlist.ShouldKeepExistingBuildFileForDir(dir) {
-			t.Errorf("%s expected TRUE but was FALSE", dir)
-		}
-	}
-	for _, dir := range falsities {
-		if allowlist.ShouldKeepExistingBuildFileForDir(dir) {
-			t.Errorf("%s expected FALSE but was TRUE", dir)
-		}
-	}
-}
-
-type mixedBuildModule struct {
-	ModuleBase
-	BazelModuleBase
-	props struct {
-		Deps                     []string
-		Mixed_build_incompatible *bool
-		QueuedBazelCall          bool `blueprint:"mutated"`
-	}
-}
-
-type mixedBuildModuleInfo struct {
-	QueuedBazelCall bool
-}
-
-var mixedBuildModuleProvider = blueprint.NewProvider(mixedBuildModuleInfo{})
-
-func mixedBuildModuleFactory() Module {
-	m := &mixedBuildModule{}
-	m.AddProperties(&m.props)
-	InitAndroidArchModule(m, HostAndDeviceDefault, MultilibBoth)
-	InitBazelModule(m)
-
-	return m
-}
-
-func (m *mixedBuildModule) ConvertWithBp2build(ctx TopDownMutatorContext) {
-}
-
-func (m *mixedBuildModule) DepsMutator(ctx BottomUpMutatorContext) {
-	ctx.AddDependency(ctx.Module(), installDepTag{}, m.props.Deps...)
-}
-
-func (m *mixedBuildModule) GenerateAndroidBuildActions(ctx ModuleContext) {
-}
-
-func (m *mixedBuildModule) IsMixedBuildSupported(ctx BaseModuleContext) bool {
-	return !proptools.Bool(m.props.Mixed_build_incompatible)
-}
-
-func (m *mixedBuildModule) QueueBazelCall(ctx BaseModuleContext) {
-	m.props.QueuedBazelCall = true
-}
-
-func (m *mixedBuildModule) ProcessBazelQueryResponse(ctx ModuleContext) {
-	ctx.SetProvider(mixedBuildModuleProvider, mixedBuildModuleInfo{
-		QueuedBazelCall: m.props.QueuedBazelCall,
-	})
-}
-
-var prepareForMixedBuildTests = FixtureRegisterWithContext(func(ctx RegistrationContext) {
-	ctx.RegisterModuleType("deps", mixedBuildModuleFactory)
-	RegisterMixedBuildsMutator(ctx)
-})
-
-func TestMixedBuildsEnabledForType(t *testing.T) {
-	baseBp := `
-	deps {
-		name: "foo",
-		deps: ["bar"],
-		target: { windows: { enabled: true } },
-		%s
-	}
-`
-	depBp := `
-	deps {
-		name: "bar",
-		target: {
-			windows: {
-				enabled: true,
-			},
-		},
-	}
-`
-	testCases := []struct {
-		desc               string
-		variant            *string
-		missingDeps        bool
-		extraBpInfo        string
-		mixedBuildsEnabled bool
-	}{
-		{
-			desc:               "mixed builds works",
-			mixedBuildsEnabled: true,
-			extraBpInfo:        `bazel_module: { bp2build_available: true },`,
-		},
-		{
-			desc:               "missing deps",
-			missingDeps:        true,
-			mixedBuildsEnabled: false,
-			extraBpInfo:        `bazel_module: { bp2build_available: true },`,
-		},
-		{
-			desc:               "windows no mixed builds",
-			mixedBuildsEnabled: false,
-			variant:            proptools.StringPtr("windows_x86"),
-			extraBpInfo:        `bazel_module: { bp2build_available: true },`,
-		},
-		{
-			desc:               "mixed builds disabled by type",
-			mixedBuildsEnabled: false,
-			extraBpInfo: `mixed_build_incompatible: true,
-		bazel_module: { bp2build_available: true },`,
-		},
-		{
-			desc:               "mixed builds not bp2build available",
-			mixedBuildsEnabled: false,
-			extraBpInfo:        `bazel_module: { bp2build_available: false },`,
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.desc, func(t *testing.T) {
-			handlers := GroupFixturePreparers(
-				prepareForMixedBuildTests,
-				PrepareForTestWithArchMutator,
-				FixtureModifyConfig(func(config Config) {
-					config.BazelContext = MockBazelContext{
-						OutputBaseDir: "base",
-					}
-					config.Targets[Windows] = []Target{
-						{Windows, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", true},
-						{Windows, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", true},
-					}
-				}),
-			)
-			bp := fmt.Sprintf(baseBp, tc.extraBpInfo)
-			if tc.missingDeps {
-				handlers = GroupFixturePreparers(
-					handlers,
-					PrepareForTestWithAllowMissingDependencies,
-				)
-			} else {
-				bp += depBp
-			}
-			result := handlers.RunTestWithBp(t, bp)
-
-			variant := proptools.StringDefault(tc.variant, "android_arm64_armv8-a")
-
-			m := result.ModuleForTests("foo", variant)
-			mixedBuildModuleInfo := result.TestContext.ModuleProvider(m.Module(), mixedBuildModuleProvider).(mixedBuildModuleInfo)
-			if w, g := tc.mixedBuildsEnabled, mixedBuildModuleInfo.QueuedBazelCall; w != g {
-				t.Errorf("Expected mixed builds enabled %t, got mixed builds enabled %t", w, g)
-			}
-		})
-	}
-}
diff --git a/android/buildinfo_prop.go b/android/buildinfo_prop.go
index 8e19ad5..8288fc5 100644
--- a/android/buildinfo_prop.go
+++ b/android/buildinfo_prop.go
@@ -54,6 +54,39 @@
 	return Paths{p.outputFilePath}, nil
 }
 
+func getBuildVariant(config Config) string {
+	if config.Eng() {
+		return "eng"
+	} else if config.Debuggable() {
+		return "userdebug"
+	} else {
+		return "user"
+	}
+}
+
+func getBuildFlavor(config Config) string {
+	buildFlavor := config.DeviceProduct() + "-" + getBuildVariant(config)
+	if InList("address", config.SanitizeDevice()) && !strings.Contains(buildFlavor, "_asan") {
+		buildFlavor += "_asan"
+	}
+	return buildFlavor
+}
+
+func shouldAddBuildThumbprint(config Config) bool {
+	knownOemProperties := []string{
+		"ro.product.brand",
+		"ro.product.name",
+		"ro.product.device",
+	}
+
+	for _, knownProp := range knownOemProperties {
+		if InList(knownProp, config.OemProperties()) {
+			return true
+		}
+	}
+	return false
+}
+
 func (p *buildinfoPropModule) GenerateAndroidBuildActions(ctx ModuleContext) {
 	p.outputFilePath = PathForModuleOut(ctx, p.Name()).OutputPath
 	if !ctx.Config().KatiEnabled() {
@@ -61,87 +94,66 @@
 		return
 	}
 
-	lines := make([]string, 0)
-
-	writeString := func(str string) {
-		lines = append(lines, str)
-	}
-
-	writeString("# begin build properties")
-	writeString("# autogenerated by build/soong/android/buildinfo_prop.go")
-
-	writeProp := func(key, value string) {
-		if strings.Contains(key, "=") {
-			panic(fmt.Errorf("wrong property key %q: key must not contain '='", key))
-		}
-		writeString(key + "=" + value)
-	}
+	rule := NewRuleBuilder(pctx, ctx)
 
 	config := ctx.Config()
+	buildVariant := getBuildVariant(config)
+	buildFlavor := getBuildFlavor(config)
 
-	writeProp("ro.build.version.sdk", config.PlatformSdkVersion().String())
-	writeProp("ro.build.version.preview_sdk", config.PlatformPreviewSdkVersion())
-	writeProp("ro.build.version.codename", config.PlatformSdkCodename())
-	writeProp("ro.build.version.all_codenames", strings.Join(config.PlatformVersionActiveCodenames(), ","))
-	writeProp("ro.build.version.release", config.PlatformVersionLastStable())
-	writeProp("ro.build.version.release_or_codename", config.PlatformVersionName())
-	writeProp("ro.build.version.security_patch", config.PlatformSecurityPatch())
-	writeProp("ro.build.version.base_os", config.PlatformBaseOS())
-	writeProp("ro.build.version.min_supported_target_sdk", config.PlatformMinSupportedTargetSdkVersion())
-	writeProp("ro.build.version.known_codenames", config.PlatformVersionKnownCodenames())
+	cmd := rule.Command().BuiltTool("buildinfo")
 
-	if config.Eng() {
-		writeProp("ro.build.type", "eng")
-	} else if config.Debuggable() {
-		writeProp("ro.build.type", "userdebug")
-	} else {
-		writeProp("ro.build.type", "user")
+	if config.BoardUseVbmetaDigestInFingerprint() {
+		cmd.Flag("--use-vbmeta-digest-in-fingerprint")
 	}
 
-	// Currently, only a few properties are implemented to unblock microdroid use case.
-	// TODO(b/189164487): support below properties as well and replace build/make/tools/buildinfo.sh
-	/*
-		if $BOARD_USE_VBMETA_DIGTEST_IN_FINGERPRINT {
-			writeProp("ro.build.legacy.id", config.BuildID())
-		} else {
-			writeProp("ro.build.id", config.BuildId())
-		}
-		writeProp("ro.build.display.id", $BUILD_DISPLAY_ID)
-		writeProp("ro.build.version.incremental", $BUILD_NUMBER)
-		writeProp("ro.build.version.preview_sdk_fingerprint", $PLATFORM_PREVIEW_SDK_FINGERPRINT)
-		writeProp("ro.build.version.release_or_preview_display", $PLATFORM_DISPLAY_VERSION)
-		writeProp("ro.build.date", `$DATE`)
-		writeProp("ro.build.date.utc", `$DATE +%s`)
-		writeProp("ro.build.user", $BUILD_USERNAME)
-		writeProp("ro.build.host", $BUILD_HOSTNAME)
-		writeProp("ro.build.tags", $BUILD_VERSION_TAGS)
-		writeProp("ro.build.flavor", $TARGET_BUILD_FLAVOR)
-		// These values are deprecated, use "ro.product.cpu.abilist"
-		// instead (see below).
-		writeString("# ro.product.cpu.abi and ro.product.cpu.abi2 are obsolete,")
-		writeString("# use ro.product.cpu.abilist instead.")
-		writeProp("ro.product.cpu.abi", $TARGET_CPU_ABI)
-		if [ -n "$TARGET_CPU_ABI2" ] {
-			writeProp("ro.product.cpu.abi2", $TARGET_CPU_ABI2)
-		}
+	cmd.FlagWithArg("--build-flavor=", buildFlavor)
+	cmd.FlagWithInput("--build-hostname-file=", config.BuildHostnameFile(ctx))
+	cmd.FlagWithArg("--build-id=", config.BuildId())
+	cmd.FlagWithArg("--build-keys=", config.BuildKeys())
 
-		if [ -n "$PRODUCT_DEFAULT_LOCALE" ] {
-			writeProp("ro.product.locale", $PRODUCT_DEFAULT_LOCALE)
-		}
-		writeProp("ro.wifi.channels", $PRODUCT_DEFAULT_WIFI_CHANNELS)
-		writeString("# ro.build.product is obsolete; use ro.product.device")
-		writeProp("ro.build.product", $TARGET_DEVICE)
+	// shouldn't depend on BuildNumberFile and BuildThumbprintFile to prevent from rebuilding
+	// on every incremental build.
+	cmd.FlagWithArg("--build-number-file=", config.BuildNumberFile(ctx).String())
+	if shouldAddBuildThumbprint(config) {
+		cmd.FlagWithArg("--build-thumbprint-file=", config.BuildThumbprintFile(ctx).String())
+	}
 
-		writeString("# Do not try to parse description or thumbprint")
-		writeProp("ro.build.description", $PRIVATE_BUILD_DESC)
-		if [ -n "$BUILD_THUMBPRINT" ] {
-			writeProp("ro.build.thumbprint", $BUILD_THUMBPRINT)
-		}
-	*/
+	cmd.FlagWithArg("--build-type=", config.BuildType())
+	cmd.FlagWithArg("--build-username=", config.Getenv("BUILD_USERNAME"))
+	cmd.FlagWithArg("--build-variant=", buildVariant)
+	cmd.FlagForEachArg("--cpu-abis=", config.DeviceAbi())
 
-	writeString("# end build properties")
+	// shouldn't depend on BUILD_DATETIME_FILE to prevent from rebuilding on every incremental
+	// build.
+	cmd.FlagWithArg("--date-file=", ctx.Config().Getenv("BUILD_DATETIME_FILE"))
 
-	WriteFileRule(ctx, p.outputFilePath, strings.Join(lines, "\n"))
+	if len(config.ProductLocales()) > 0 {
+		cmd.FlagWithArg("--default-locale=", config.ProductLocales()[0])
+	}
+
+	cmd.FlagForEachArg("--default-wifi-channels=", config.ProductDefaultWifiChannels())
+	cmd.FlagWithArg("--device=", config.DeviceName())
+	if config.DisplayBuildNumber() {
+		cmd.Flag("--display-build-number")
+	}
+
+	cmd.FlagWithArg("--platform-base-os=", config.PlatformBaseOS())
+	cmd.FlagWithArg("--platform-display-version=", config.PlatformDisplayVersionName())
+	cmd.FlagWithArg("--platform-min-supported-target-sdk-version=", config.PlatformMinSupportedTargetSdkVersion())
+	cmd.FlagWithInput("--platform-preview-sdk-fingerprint-file=", ApiFingerprintPath(ctx))
+	cmd.FlagWithArg("--platform-preview-sdk-version=", config.PlatformPreviewSdkVersion())
+	cmd.FlagWithArg("--platform-sdk-version=", config.PlatformSdkVersion().String())
+	cmd.FlagWithArg("--platform-security-patch=", config.PlatformSecurityPatch())
+	cmd.FlagWithArg("--platform-version=", config.PlatformVersionName())
+	cmd.FlagWithArg("--platform-version-codename=", config.PlatformSdkCodename())
+	cmd.FlagForEachArg("--platform-version-all-codenames=", config.PlatformVersionActiveCodenames())
+	cmd.FlagWithArg("--platform-version-known-codenames=", config.PlatformVersionKnownCodenames())
+	cmd.FlagWithArg("--platform-version-last-stable=", config.PlatformVersionLastStable())
+	cmd.FlagWithArg("--product=", config.DeviceProduct())
+
+	cmd.FlagWithOutput("--out=", p.outputFilePath)
+
+	rule.Build(ctx.ModuleName(), "generating buildinfo props")
 
 	if !p.installable() {
 		p.SkipInstall()
diff --git a/android/config.go b/android/config.go
index 5c8b20b..3ea9d4d 100644
--- a/android/config.go
+++ b/android/config.go
@@ -27,6 +27,9 @@
 	"strconv"
 	"strings"
 	"sync"
+	"unicode"
+
+	"android/soong/shared"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
@@ -84,23 +87,12 @@
 	SoongOutDir    string
 	SoongVariables string
 
-	SymlinkForestMarker string
-	Bp2buildMarker      string
-	BazelQueryViewDir   string
-	BazelApiBp2buildDir string
-	ModuleGraphFile     string
-	ModuleActionsFile   string
-	DocFile             string
+	BazelQueryViewDir string
+	ModuleGraphFile   string
+	ModuleActionsFile string
+	DocFile           string
 
-	MultitreeBuild bool
-
-	BazelMode                bool
-	BazelModeStaging         bool
-	BazelForceEnabledModules string
-
-	UseBazelProxy bool
-
-	BuildFromTextStub bool
+	BuildFromSourceStub bool
 
 	EnsureAllowlistIntegrity bool
 }
@@ -110,41 +102,30 @@
 	// Don't use bazel at all during module analysis.
 	AnalysisNoBazel SoongBuildMode = iota
 
-	// Symlink fores mode: merge two directory trees into a symlink forest
-	SymlinkForest
-
-	// Bp2build mode: Generate BUILD files from blueprint files and exit.
-	Bp2build
-
 	// Generate BUILD files which faithfully represent the dependency graph of
 	// blueprint modules. Individual BUILD targets will not, however, faitfhully
 	// express build semantics.
 	GenerateQueryView
 
-	// Generate BUILD files for API contributions to API surfaces
-	ApiBp2build
-
 	// Create a JSON representation of the module graph and exit.
 	GenerateModuleGraph
 
 	// Generate a documentation file for module type definitions and exit.
 	GenerateDocFile
-
-	// Use bazel during analysis of a few allowlisted build modules. The allowlist
-	// is considered "staging, as these are modules being prepared to be released
-	// into prod mode shortly after.
-	BazelStagingMode
-
-	// Use bazel during analysis of build modules from an allowlist carefully
-	// curated by the build team to be proven stable.
-	BazelProdMode
 )
 
+const testKeyDir = "build/make/target/product/security"
+
 // SoongOutDir returns the build output directory for the configuration.
 func (c Config) SoongOutDir() string {
 	return c.soongOutDir
 }
 
+// tempDir returns the path to out/soong/.temp, which is cleared at the beginning of every build.
+func (c Config) tempDir() string {
+	return shared.TempDirForOutDir(c.soongOutDir)
+}
+
 func (c Config) OutDir() string {
 	return c.outDir
 }
@@ -183,6 +164,18 @@
 			Bool(c.productVariables.Eng))
 }
 
+// DisableVerifyOverlaps returns true if verify_overlaps is skipped.
+// Mismatch in version of apexes and module SDK is required for mainline prebuilts to work in
+// trunk stable.
+// Thus, verify_overlaps is disabled when RELEASE_DEFAULT_MODULE_BUILD_FROM_SOURCE is set to false.
+// TODO(b/308174018): Re-enable verify_overlaps for both builr from source/mainline prebuilts.
+func (c Config) DisableVerifyOverlaps() bool {
+	if c.IsEnvFalse("DISABLE_VERIFY_OVERLAPS") && c.ReleaseDisableVerifyOverlaps() {
+		panic("The current release configuration does not support verify_overlaps. DISABLE_VERIFY_OVERLAPS cannot be set to false")
+	}
+	return c.IsEnvTrue("DISABLE_VERIFY_OVERLAPS") || c.ReleaseDisableVerifyOverlaps() || !c.ReleaseDefaultModuleBuildFromSource()
+}
+
 // MaxPageSizeSupported returns the max page size supported by the device. This
 // value will define the ELF segment alignment for binaries (executables and
 // shared libraries).
@@ -190,10 +183,12 @@
 	return String(c.config.productVariables.DeviceMaxPageSizeSupported)
 }
 
-// PageSizeAgnostic returns true when AOSP is page size agnostic,
-// othersise it returns false.
-func (c Config) PageSizeAgnostic() bool {
-	return Bool(c.config.productVariables.DevicePageSizeAgnostic)
+// NoBionicPageSizeMacro returns true when AOSP is page size agnostic.
+// This means that the bionic's macro PAGE_SIZE won't be defined.
+// Returns false when AOSP is NOT page size agnostic.
+// This means that bionic's macro PAGE_SIZE is defined.
+func (c Config) NoBionicPageSizeMacro() bool {
+	return Bool(c.config.productVariables.DeviceNoBionicPageSizeMacro)
 }
 
 // The release version passed to aconfig, derived from RELEASE_VERSION
@@ -201,11 +196,49 @@
 	return c.config.productVariables.ReleaseVersion
 }
 
-// The flag values files passed to aconfig, derived from RELEASE_VERSION
+// The aconfig value set passed to aconfig, derived from RELEASE_VERSION
 func (c Config) ReleaseAconfigValueSets() []string {
 	return c.config.productVariables.ReleaseAconfigValueSets
 }
 
+// The flag default permission value passed to aconfig
+// derived from RELEASE_ACONFIG_FLAG_DEFAULT_PERMISSION
+func (c Config) ReleaseAconfigFlagDefaultPermission() string {
+	return c.config.productVariables.ReleaseAconfigFlagDefaultPermission
+}
+
+// The flag indicating behavior for the tree wrt building modules or using prebuilts
+// derived from RELEASE_DEFAULT_MODULE_BUILD_FROM_SOURCE
+func (c Config) ReleaseDefaultModuleBuildFromSource() bool {
+	return c.config.productVariables.ReleaseDefaultModuleBuildFromSource == nil ||
+		Bool(c.config.productVariables.ReleaseDefaultModuleBuildFromSource)
+}
+
+func (c Config) ReleaseDisableVerifyOverlaps() bool {
+	return c.config.productVariables.GetBuildFlagBool("RELEASE_DISABLE_VERIFY_OVERLAPS_CHECK")
+}
+
+// Enables flagged apis annotated with READ_WRITE aconfig flags to be included in the stubs
+// and hiddenapi flags so that they are accessible at runtime
+func (c Config) ReleaseExportRuntimeApis() bool {
+	return Bool(c.config.productVariables.ExportRuntimeApis)
+}
+
+// Enables ABI monitoring of NDK libraries
+func (c Config) ReleaseNdkAbiMonitored() bool {
+	return c.config.productVariables.GetBuildFlagBool("RELEASE_NDK_ABI_MONITORED")
+}
+
+// Enable read flag from new storage, for C/C++
+func (c Config) ReleaseReadFromNewStorageCc() bool {
+	return c.config.productVariables.GetBuildFlagBool("RELEASE_READ_FROM_NEW_STORAGE_CC")
+}
+
+func (c Config) ReleaseHiddenApiExportableStubs() bool {
+	return c.config.productVariables.GetBuildFlagBool("RELEASE_HIDDEN_API_EXPORTABLE_STUBS") ||
+		Bool(c.config.productVariables.HiddenapiExportableStubs)
+}
+
 // A DeviceConfig object represents the configuration for a particular device
 // being built. For now there will only be one of these, but in the future there
 // may be multiple devices being built.
@@ -225,10 +258,6 @@
 	// Only available on configs created by TestConfig
 	TestProductVariables *ProductVariables
 
-	// A specialized context object for Bazel/Soong mixed builds and migration
-	// purposes.
-	BazelContext BazelContext
-
 	ProductVariablesFileName string
 
 	// BuildOS stores the OsType for the OS that the build is running on.
@@ -270,13 +299,7 @@
 	fs         pathtools.FileSystem
 	mockBpList string
 
-	BuildMode                      SoongBuildMode
-	Bp2buildPackageConfig          Bp2BuildConversionAllowlist
-	Bp2buildSoongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions
-
-	// If MultitreeBuild is true then this is one inner tree of a multitree
-	// build directed by the multitree orchestrator.
-	MultitreeBuild bool
+	BuildMode SoongBuildMode
 
 	// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
 	// in tests when a path doesn't exist.
@@ -288,32 +311,9 @@
 
 	OncePer
 
-	// These fields are only used for metrics collection. A module should be added
-	// to these maps only if its implementation supports Bazel handling in mixed
-	// builds. A module being in the "enabled" list indicates that there is a
-	// variant of that module for which bazel-handling actually took place.
-	// A module being in the "disabled" list indicates that there is a variant of
-	// that module for which bazel-handling was denied.
-	mixedBuildsLock           sync.Mutex
-	mixedBuildEnabledModules  map[string]struct{}
-	mixedBuildDisabledModules map[string]struct{}
-
-	// These are modules to be built with Bazel beyond the allowlisted/build-mode
-	// specified modules. They are passed via the command-line flag
-	// "--bazel-force-enabled-modules"
-	bazelForceEnabledModules map[string]struct{}
-
-	// Names of Bazel targets as defined by BUILD files in the source tree,
-	// keyed by the directory in which they are defined.
-	bazelTargetsByDir map[string][]string
-
-	// If true, for any requests to Bazel, communicate with a Bazel proxy using
-	// unix sockets, instead of spawning Bazel as a subprocess.
-	UseBazelProxy bool
-
-	// If buildFromTextStub is true then the Java API stubs are
-	// built from the signature text files, not the source Java files.
-	buildFromTextStub bool
+	// If buildFromSourceStub is true then the Java API stubs are
+	// built from the source Java files, not the signature text files.
+	buildFromSourceStub bool
 
 	// If ensureAllowlistIntegrity is true, then the presence of any allowlisted
 	// modules that aren't mixed-built for at least one variant will cause a build
@@ -337,6 +337,18 @@
 	return loadFromConfigFile(&config.productVariables, absolutePath(config.ProductVariablesFileName))
 }
 
+// Checks if the string is a valid go identifier. This is equivalent to blueprint's definition
+// of an identifier, so it will match the same identifiers as those that can be used in bp files.
+func isGoIdentifier(ident string) bool {
+	for i, r := range ident {
+		valid := r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) && i > 0
+		if !valid {
+			return false
+		}
+	}
+	return len(ident) > 0
+}
+
 // loadFromConfigFile loads and decodes configuration options from a JSON file
 // in the current working directory.
 func loadFromConfigFile(configurable *ProductVariables, filename string) error {
@@ -372,6 +384,20 @@
 		Bool(configurable.GcovCoverage) ||
 			Bool(configurable.ClangCoverage))
 
+	// The go scanner's definition of identifiers is c-style identifiers, but allowing unicode's
+	// definition of letters and digits. This is the same scanner that blueprint uses, so it
+	// will allow the same identifiers as are valid in bp files.
+	for namespace := range configurable.VendorVars {
+		if !isGoIdentifier(namespace) {
+			return fmt.Errorf("soong config namespaces must be valid identifiers: %q", namespace)
+		}
+		for variable := range configurable.VendorVars[namespace] {
+			if !isGoIdentifier(variable) {
+				return fmt.Errorf("soong config variables must be valid identifiers: %q", variable)
+			}
+		}
+	}
+
 	// when Platform_sdk_final is true (or PLATFORM_VERSION_CODENAME is REL), use Platform_sdk_version;
 	// if false (pre-released version, for example), use Platform_sdk_codename.
 	if Bool(configurable.Platform_sdk_final) {
@@ -521,24 +547,16 @@
 		runGoTests:        cmdArgs.RunGoTests,
 		multilibConflicts: make(map[ArchType]bool),
 
-		moduleListFile:            cmdArgs.ModuleListFile,
-		fs:                        pathtools.NewOsFs(absSrcDir),
-		mixedBuildDisabledModules: make(map[string]struct{}),
-		mixedBuildEnabledModules:  make(map[string]struct{}),
-		bazelForceEnabledModules:  make(map[string]struct{}),
+		moduleListFile: cmdArgs.ModuleListFile,
+		fs:             pathtools.NewOsFs(absSrcDir),
 
-		MultitreeBuild: cmdArgs.MultitreeBuild,
-		UseBazelProxy:  cmdArgs.UseBazelProxy,
-
-		buildFromTextStub: cmdArgs.BuildFromTextStub,
+		buildFromSourceStub: cmdArgs.BuildFromSourceStub,
 	}
 
 	config.deviceConfig = &deviceConfig{
 		config: config,
 	}
 
-	config.productVariables.Build_from_text_stub = boolPtr(config.buildFromTextStub)
-
 	// Soundness check of the build and source directories. This won't catch strange
 	// configurations with symlinks, but at least checks the obvious case.
 	absBuildDir, err := filepath.Abs(cmdArgs.SoongOutDir)
@@ -623,29 +641,9 @@
 			config.BuildMode = mode
 		}
 	}
-	setBazelMode := func(arg bool, argName string, mode SoongBuildMode) {
-		if arg {
-			if config.BuildMode != AnalysisNoBazel {
-				fmt.Fprintf(os.Stderr, "buildMode is already set, illegal argument: %s", argName)
-				os.Exit(1)
-			}
-			config.BuildMode = mode
-		}
-	}
-	setBuildMode(cmdArgs.SymlinkForestMarker, SymlinkForest)
-	setBuildMode(cmdArgs.Bp2buildMarker, Bp2build)
 	setBuildMode(cmdArgs.BazelQueryViewDir, GenerateQueryView)
-	setBuildMode(cmdArgs.BazelApiBp2buildDir, ApiBp2build)
 	setBuildMode(cmdArgs.ModuleGraphFile, GenerateModuleGraph)
 	setBuildMode(cmdArgs.DocFile, GenerateDocFile)
-	setBazelMode(cmdArgs.BazelMode, "--bazel-mode", BazelProdMode)
-	setBazelMode(cmdArgs.BazelModeStaging, "--bazel-mode-staging", BazelStagingMode)
-
-	for _, module := range getForceEnabledModulesFromFlag(cmdArgs.BazelForceEnabledModules) {
-		config.bazelForceEnabledModules[module] = struct{}{}
-	}
-	config.BazelContext, err = NewBazelContext(config)
-	config.Bp2buildPackageConfig = GetBp2BuildAllowList()
 
 	// TODO(b/276958307): Replace the hardcoded list to a sdk_library local prop.
 	config.apiLibraries = map[string]struct{}{
@@ -655,12 +653,19 @@
 		"framework-adservices":              {},
 		"framework-appsearch":               {},
 		"framework-bluetooth":               {},
+		"framework-configinfrastructure":    {},
 		"framework-connectivity":            {},
 		"framework-connectivity-t":          {},
+		"framework-devicelock":              {},
 		"framework-graphics":                {},
+		"framework-healthfitness":           {},
+		"framework-location":                {},
 		"framework-media":                   {},
 		"framework-mediaprovider":           {},
+		"framework-nfc":                     {},
 		"framework-ondevicepersonalization": {},
+		"framework-pdf":                     {},
+		"framework-pdf-v":                   {},
 		"framework-permission":              {},
 		"framework-permission-s":            {},
 		"framework-scheduling":              {},
@@ -674,14 +679,9 @@
 		"i18n.module.public.api":            {},
 	}
 
-	return Config{config}, err
-}
+	config.productVariables.Build_from_text_stub = boolPtr(config.BuildFromTextStub())
 
-func getForceEnabledModulesFromFlag(forceEnabledFlag string) []string {
-	if forceEnabledFlag == "" {
-		return []string{}
-	}
-	return strings.Split(forceEnabledFlag, ",")
+	return Config{config}, err
 }
 
 // mockFileSystem replaces all reads with accesses to the provided map of
@@ -714,41 +714,6 @@
 	c.mockBpList = blueprint.MockModuleListFile
 }
 
-// TODO(b/265062549): Add a field to our collected (and uploaded) metrics which
-// describes a reason that we fell back to non-mixed builds.
-// Returns true if "Bazel builds" is enabled. In this mode, part of build
-// analysis is handled by Bazel.
-func (c *config) IsMixedBuildsEnabled() bool {
-	globalMixedBuildsSupport := c.Once(OnceKey{"globalMixedBuildsSupport"}, func() interface{} {
-		if c.productVariables.DeviceArch != nil && *c.productVariables.DeviceArch == "riscv64" {
-			return false
-		}
-		// Disable Bazel when Kythe is running
-		if c.EmitXrefRules() {
-			return false
-		}
-		if c.IsEnvTrue("GLOBAL_THINLTO") {
-			return false
-		}
-		if len(c.productVariables.SanitizeHost) > 0 {
-			return false
-		}
-		if len(c.productVariables.SanitizeDevice) > 0 {
-			return false
-		}
-		if len(c.productVariables.SanitizeDeviceDiag) > 0 {
-			return false
-		}
-		if len(c.productVariables.SanitizeDeviceArch) > 0 {
-			return false
-		}
-		return true
-	}).(bool)
-
-	bazelModeEnabled := c.BuildMode == BazelProdMode || c.BuildMode == BazelStagingMode
-	return globalMixedBuildsSupport && bazelModeEnabled
-}
-
 func (c *config) SetAllowMissingDependencies() {
 	c.productVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
 }
@@ -764,7 +729,7 @@
 }
 
 func (c *config) HostToolPath(ctx PathContext, tool string) Path {
-	path := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "bin", false, tool)
+	path := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "bin", tool)
 	return path
 }
 
@@ -773,12 +738,12 @@
 	if runtime.GOOS == "darwin" {
 		ext = ".dylib"
 	}
-	path := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "lib64", false, lib+ext)
+	path := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "lib64", lib+ext)
 	return path
 }
 
 func (c *config) HostJavaToolPath(ctx PathContext, tool string) Path {
-	path := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "framework", false, tool)
+	path := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "framework", tool)
 	return path
 }
 
@@ -787,7 +752,7 @@
 	if ctx.Config().BuildArch.Multilib == "lib64" {
 		libDir = "lib64"
 	}
-	return pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, libDir, false, lib+".so")
+	return pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, libDir, lib+".so")
 }
 
 // PrebuiltOS returns the name of the host OS used in prebuilts directories.
@@ -875,10 +840,18 @@
 	return c.katiEnabled
 }
 
+func (c *config) ProductVariables() ProductVariables {
+	return c.productVariables
+}
+
 func (c *config) BuildId() string {
 	return String(c.productVariables.BuildId)
 }
 
+func (c *config) DisplayBuildNumber() bool {
+	return Bool(c.productVariables.DisplayBuildNumber)
+}
+
 // BuildNumberFile returns the path to a text file containing metadata
 // representing the current build's number.
 //
@@ -890,6 +863,23 @@
 	return PathForOutput(ctx, String(c.productVariables.BuildNumberFile))
 }
 
+// BuildHostnameFile returns the path to a text file containing metadata
+// representing the current build's host name.
+func (c *config) BuildHostnameFile(ctx PathContext) Path {
+	return PathForOutput(ctx, String(c.productVariables.BuildHostnameFile))
+}
+
+// BuildThumbprintFile returns the path to a text file containing metadata
+// representing the current build's thumbprint.
+//
+// Rules that want to reference the build thumbprint should read from this file
+// without depending on it. They will run whenever their other dependencies
+// require them to run and get the current build thumbprint. This ensures they
+// don't rebuild on every incremental build when the build thumbprint changes.
+func (c *config) BuildThumbprintFile(ctx PathContext) Path {
+	return PathForArbitraryOutput(ctx, "target", "product", c.DeviceName(), String(c.productVariables.BuildThumbprintFile))
+}
+
 // DeviceName returns the name of the current device target.
 // TODO: take an AndroidModuleContext to select the device name for multi-device builds
 func (c *config) DeviceName() string {
@@ -911,6 +901,10 @@
 	return c.productVariables.DeviceProduct != nil
 }
 
+func (c *config) DeviceAbi() []string {
+	return c.productVariables.DeviceAbi
+}
+
 func (c *config) DeviceResourceOverlays() []string {
 	return c.productVariables.DeviceResourceOverlays
 }
@@ -919,6 +913,10 @@
 	return c.productVariables.ProductResourceOverlays
 }
 
+func (c *config) PlatformDisplayVersionName() string {
+	return String(c.productVariables.Platform_display_version_name)
+}
+
 func (c *config) PlatformVersionName() string {
 	return String(c.productVariables.Platform_version_name)
 }
@@ -956,7 +954,11 @@
 }
 
 func (c *config) PlatformMinSupportedTargetSdkVersion() string {
-	return String(c.productVariables.Platform_min_supported_target_sdk_version)
+	var val, ok = c.productVariables.BuildFlags["RELEASE_PLATFORM_MIN_SUPPORTED_TARGET_SDK_VERSION"]
+	if !ok {
+		return ""
+	}
+	return val
 }
 
 func (c *config) PlatformBaseOS() string {
@@ -985,12 +987,18 @@
 
 func (c *config) PreviewApiLevels() []ApiLevel {
 	var levels []ApiLevel
-	for i, codename := range c.PlatformVersionActiveCodenames() {
+	i := 0
+	for _, codename := range c.PlatformVersionActiveCodenames() {
+		if codename == "REL" {
+			continue
+		}
+
 		levels = append(levels, ApiLevel{
 			value:     codename,
 			number:    i,
 			isPreview: true,
 		})
+		i++
 	}
 	return levels
 }
@@ -1014,8 +1022,6 @@
 // DefaultAppTargetSdk returns the API level that platform apps are targeting.
 // This converts a codename to the exact ApiLevel it represents.
 func (c *config) DefaultAppTargetSdk(ctx EarlyModuleContext) ApiLevel {
-	// This logic is replicated in starlark, if changing logic here update starlark code too
-	// https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/common/api.bzl;l=72;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
 	if Bool(c.productVariables.Platform_sdk_final) {
 		return c.PlatformSdkVersion()
 	}
@@ -1072,7 +1078,7 @@
 	if defaultCert != "" {
 		return PathForSource(ctx, filepath.Dir(defaultCert))
 	}
-	return PathForSource(ctx, "build/make/target/product/security")
+	return PathForSource(ctx, testKeyDir)
 }
 
 func (c *config) DefaultAppCertificate(ctx PathContext) (pem, key SourcePath) {
@@ -1084,10 +1090,18 @@
 	return defaultDir.Join(ctx, "testkey.x509.pem"), defaultDir.Join(ctx, "testkey.pk8")
 }
 
+func (c *config) BuildKeys() string {
+	defaultCert := String(c.productVariables.DefaultAppCertificate)
+	if defaultCert == "" || defaultCert == filepath.Join(testKeyDir, "testkey") {
+		return "test-keys"
+	}
+	return "dev-keys"
+}
+
 func (c *config) ApexKeyDir(ctx ModuleContext) SourcePath {
 	// TODO(b/121224311): define another variable such as TARGET_APEX_KEY_OVERRIDE
 	defaultCert := String(c.productVariables.DefaultAppCertificate)
-	if defaultCert == "" || filepath.Dir(defaultCert) == "build/make/target/product/security" {
+	if defaultCert == "" || filepath.Dir(defaultCert) == testKeyDir {
 		// When defaultCert is unset or is set to the testkeys path, use the APEX keys
 		// that is under the module dir
 		return pathForModuleSrc(ctx)
@@ -1146,6 +1160,10 @@
 	return Bool(c.productVariables.Eng)
 }
 
+func (c *config) BuildType() string {
+	return String(c.productVariables.BuildType)
+}
+
 // DevicePrimaryArchType returns the ArchType for the first configured device architecture, or
 // Common if there are no device architectures.
 func (c *config) DevicePrimaryArchType() ArchType {
@@ -1373,14 +1391,42 @@
 	return String(c.productVariables.PrebuiltHiddenApiDir)
 }
 
-func (c *config) BazelModulesForceEnabledByFlag() map[string]struct{} {
-	return c.bazelForceEnabledModules
-}
-
 func (c *config) IsVndkDeprecated() bool {
 	return !Bool(c.productVariables.KeepVndk)
 }
 
+func (c *config) VendorApiLevel() string {
+	return String(c.productVariables.VendorApiLevel)
+}
+
+func (c *config) PrevVendorApiLevel() string {
+	vendorApiLevel, err := strconv.Atoi(c.VendorApiLevel())
+	if err != nil {
+		panic(fmt.Errorf("Cannot parse vendor API level %s to an integer: %s",
+			c.VendorApiLevel(), err))
+	}
+	// The version before trunk stable is 34.
+	if vendorApiLevel == 202404 {
+		return "34"
+	}
+	if vendorApiLevel >= 1 && vendorApiLevel <= 34 {
+		return strconv.Itoa(vendorApiLevel - 1)
+	}
+	if vendorApiLevel < 202404 || vendorApiLevel%100 != 4 {
+		panic("Unknown vendor API level " + c.VendorApiLevel())
+	}
+	return strconv.Itoa(vendorApiLevel - 100)
+}
+
+func IsTrunkStableVendorApiLevel(level string) bool {
+	levelInt, err := strconv.Atoi(level)
+	return err == nil && levelInt >= 202404
+}
+
+func (c *config) VendorApiLevelFrozen() bool {
+	return c.productVariables.GetBuildFlagBool("RELEASE_BOARD_API_LEVEL_FROZEN")
+}
+
 func (c *deviceConfig) Arches() []Arch {
 	var arches []Arch
 	for _, target := range c.config.Targets[Android] {
@@ -1404,10 +1450,6 @@
 	return "vendor"
 }
 
-func (c *deviceConfig) VndkVersion() string {
-	return String(c.config.productVariables.DeviceVndkVersion)
-}
-
 func (c *deviceConfig) RecoverySnapshotVersion() string {
 	return String(c.config.productVariables.RecoverySnapshotVersion)
 }
@@ -1416,20 +1458,12 @@
 	return StringDefault(c.config.productVariables.DeviceCurrentApiLevelForVendorModules, "current")
 }
 
-func (c *deviceConfig) PlatformVndkVersion() string {
-	return String(c.config.productVariables.Platform_vndk_version)
-}
-
-func (c *deviceConfig) ProductVndkVersion() string {
-	return String(c.config.productVariables.ProductVndkVersion)
-}
-
 func (c *deviceConfig) ExtraVndkVersions() []string {
 	return c.config.productVariables.ExtraVndkVersions
 }
 
 func (c *deviceConfig) VndkUseCoreVariant() bool {
-	return Bool(c.config.productVariables.VndkUseCoreVariant)
+	return Bool(c.config.productVariables.VndkUseCoreVariant) && Bool(c.config.productVariables.KeepVndk)
 }
 
 func (c *deviceConfig) SystemSdkVersions() []string {
@@ -1538,18 +1572,18 @@
 }
 
 // AfdoProfile returns fully qualified path associated to the given module name
-func (c *deviceConfig) AfdoProfile(name string) (*string, error) {
+func (c *deviceConfig) AfdoProfile(name string) (string, error) {
 	for _, afdoProfile := range c.config.productVariables.AfdoProfiles {
 		split := strings.Split(afdoProfile, ":")
 		if len(split) != 3 {
-			return nil, fmt.Errorf("AFDO_PROFILES has invalid value: %s. "+
+			return "", fmt.Errorf("AFDO_PROFILES has invalid value: %s. "+
 				"The expected format is <module>:<fully-qualified-path-to-fdo_profile>", afdoProfile)
 		}
 		if split[0] == name {
-			return proptools.StringPtr(strings.Join([]string{split[1], split[2]}, ":")), nil
+			return strings.Join([]string{split[1], split[2]}, ":"), nil
 		}
 	}
-	return nil, nil
+	return "", nil
 }
 
 func (c *deviceConfig) VendorSepolicyDirs() []string {
@@ -1656,11 +1690,18 @@
 	return HasAnyPrefix(path, c.productVariables.MemtagHeapSyncIncludePaths) && !c.MemtagHeapDisabledForPath(path)
 }
 
+func (c *config) HWASanDisabledForPath(path string) bool {
+	if len(c.productVariables.HWASanExcludePaths) == 0 {
+		return false
+	}
+	return HasAnyPrefix(path, c.productVariables.HWASanExcludePaths)
+}
+
 func (c *config) HWASanEnabledForPath(path string) bool {
 	if len(c.productVariables.HWASanIncludePaths) == 0 {
 		return false
 	}
-	return HasAnyPrefix(path, c.productVariables.HWASanIncludePaths)
+	return HasAnyPrefix(path, c.productVariables.HWASanIncludePaths) && !c.HWASanDisabledForPath(path)
 }
 
 func (c *config) VendorConfig(name string) VendorConfig {
@@ -1771,10 +1812,6 @@
 	return String(c.config.productVariables.PlatformSepolicyVersion)
 }
 
-func (c *deviceConfig) TotSepolicyVersion() string {
-	return String(c.config.productVariables.TotSepolicyVersion)
-}
-
 func (c *deviceConfig) PlatformSepolicyCompatVersions() []string {
 	return c.config.productVariables.PlatformSepolicyCompatVersions
 }
@@ -1786,30 +1823,6 @@
 	return c.PlatformSepolicyVersion()
 }
 
-func (c *deviceConfig) BoardPlatVendorPolicy() []string {
-	return c.config.productVariables.BoardPlatVendorPolicy
-}
-
-func (c *deviceConfig) BoardReqdMaskPolicy() []string {
-	return c.config.productVariables.BoardReqdMaskPolicy
-}
-
-func (c *deviceConfig) BoardSystemExtPublicPrebuiltDirs() []string {
-	return c.config.productVariables.BoardSystemExtPublicPrebuiltDirs
-}
-
-func (c *deviceConfig) BoardSystemExtPrivatePrebuiltDirs() []string {
-	return c.config.productVariables.BoardSystemExtPrivatePrebuiltDirs
-}
-
-func (c *deviceConfig) BoardProductPublicPrebuiltDirs() []string {
-	return c.config.productVariables.BoardProductPublicPrebuiltDirs
-}
-
-func (c *deviceConfig) BoardProductPrivatePrebuiltDirs() []string {
-	return c.config.productVariables.BoardProductPrivatePrebuiltDirs
-}
-
 func (c *deviceConfig) SystemExtSepolicyPrebuiltApiDir() string {
 	return String(c.config.productVariables.SystemExtSepolicyPrebuiltApiDir)
 }
@@ -1946,6 +1959,10 @@
 	return InList(name, c.config.productVariables.BuildBrokenInputDirModules)
 }
 
+func (c *deviceConfig) BuildBrokenDontCheckSystemSdk() bool {
+	return c.config.productVariables.BuildBrokenDontCheckSystemSdk
+}
+
 func (c *config) BuildWarningBadOptionalUsesLibsAllowlist() []string {
 	return c.productVariables.BuildWarningBadOptionalUsesLibsAllowlist
 }
@@ -1978,6 +1995,10 @@
 	return c.config.productVariables.GenerateAidlNdkPlatformBackend
 }
 
+func (c *deviceConfig) AconfigContainerValidation() string {
+	return c.config.productVariables.AconfigContainerValidation
+}
+
 func (c *config) IgnorePrefer32OnDevice() bool {
 	return c.productVariables.IgnorePrefer32OnDevice
 }
@@ -2006,39 +2027,6 @@
 	return Bool(c.productVariables.HostMusl)
 }
 
-func (c *config) GetMixedBuildsEnabledModules() map[string]struct{} {
-	return c.mixedBuildEnabledModules
-}
-
-func (c *config) GetMixedBuildsDisabledModules() map[string]struct{} {
-	return c.mixedBuildDisabledModules
-}
-
-func (c *config) LogMixedBuild(ctx BaseModuleContext, useBazel bool) {
-	moduleName := ctx.Module().Name()
-	c.mixedBuildsLock.Lock()
-	defer c.mixedBuildsLock.Unlock()
-	if useBazel {
-		c.mixedBuildEnabledModules[moduleName] = struct{}{}
-	} else {
-		c.mixedBuildDisabledModules[moduleName] = struct{}{}
-	}
-}
-
-func (c *config) HasBazelBuildTargetInSource(ctx BaseModuleContext) bool {
-	moduleName := ctx.Module().Name()
-	for _, buildTarget := range c.bazelTargetsByDir[ctx.ModuleDir()] {
-		if moduleName == buildTarget {
-			return true
-		}
-	}
-	return false
-}
-
-func (c *config) SetBazelBuildFileTargets(bazelTargetsByDir map[string][]string) {
-	c.bazelTargetsByDir = bazelTargetsByDir
-}
-
 // ApiSurfaces directory returns the source path inside the api_surfaces repo
 // (relative to workspace root).
 func (c *config) ApiSurfacesDir(s ApiSurface, version string) string {
@@ -2050,21 +2038,28 @@
 		version)
 }
 
+func (c *config) JavaCoverageEnabled() bool {
+	return c.IsEnvTrue("EMMA_INSTRUMENT") || c.IsEnvTrue("EMMA_INSTRUMENT_STATIC") || c.IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK")
+}
+
+func (c *deviceConfig) BuildFromSourceStub() bool {
+	return Bool(c.config.productVariables.BuildFromSourceStub)
+}
+
 func (c *config) BuildFromTextStub() bool {
-	return c.buildFromTextStub
+	// TODO: b/302320354 - Remove the coverage build specific logic once the
+	// robust solution for handling native properties in from-text stub build
+	// is implemented.
+	return !c.buildFromSourceStub &&
+		!c.JavaCoverageEnabled() &&
+		!c.deviceConfig.BuildFromSourceStub()
 }
 
 func (c *config) SetBuildFromTextStub(b bool) {
-	c.buildFromTextStub = b
+	c.buildFromSourceStub = !b
 	c.productVariables.Build_from_text_stub = boolPtr(b)
 }
 
-func (c *config) AddForceEnabledModules(forceEnabled []string) {
-	for _, forceEnabledModule := range forceEnabled {
-		c.bazelForceEnabledModules[forceEnabledModule] = struct{}{}
-	}
-}
-
 func (c *config) SetApiLibraries(libs []string) {
 	c.apiLibraries = make(map[string]struct{})
 	for _, lib := range libs {
@@ -2075,3 +2070,85 @@
 func (c *config) GetApiLibraries() map[string]struct{} {
 	return c.apiLibraries
 }
+
+func (c *deviceConfig) CheckVendorSeappViolations() bool {
+	return Bool(c.config.productVariables.CheckVendorSeappViolations)
+}
+
+func (c *config) GetBuildFlag(name string) (string, bool) {
+	val, ok := c.productVariables.BuildFlags[name]
+	return val, ok
+}
+
+func (c *config) UseResourceProcessorByDefault() bool {
+	return c.productVariables.GetBuildFlagBool("RELEASE_USE_RESOURCE_PROCESSOR_BY_DEFAULT")
+}
+
+var (
+	mainlineApexContributionBuildFlags = []string{
+		"RELEASE_APEX_CONTRIBUTIONS_ADBD",
+		"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES",
+		"RELEASE_APEX_CONTRIBUTIONS_APPSEARCH",
+		"RELEASE_APEX_CONTRIBUTIONS_ART",
+		"RELEASE_APEX_CONTRIBUTIONS_BLUETOOTH",
+		"RELEASE_APEX_CONTRIBUTIONS_CAPTIVEPORTALLOGIN",
+		"RELEASE_APEX_CONTRIBUTIONS_CELLBROADCAST",
+		"RELEASE_APEX_CONTRIBUTIONS_CONFIGINFRASTRUCTURE",
+		"RELEASE_APEX_CONTRIBUTIONS_CONNECTIVITY",
+		"RELEASE_APEX_CONTRIBUTIONS_CONSCRYPT",
+		"RELEASE_APEX_CONTRIBUTIONS_CRASHRECOVERY",
+		"RELEASE_APEX_CONTRIBUTIONS_DEVICELOCK",
+		"RELEASE_APEX_CONTRIBUTIONS_DOCUMENTSUIGOOGLE",
+		"RELEASE_APEX_CONTRIBUTIONS_EXTSERVICES",
+		"RELEASE_APEX_CONTRIBUTIONS_HEALTHFITNESS",
+		"RELEASE_APEX_CONTRIBUTIONS_IPSEC",
+		"RELEASE_APEX_CONTRIBUTIONS_MEDIA",
+		"RELEASE_APEX_CONTRIBUTIONS_MEDIAPROVIDER",
+		"RELEASE_APEX_CONTRIBUTIONS_MODULE_METADATA",
+		"RELEASE_APEX_CONTRIBUTIONS_NETWORKSTACKGOOGLE",
+		"RELEASE_APEX_CONTRIBUTIONS_NEURALNETWORKS",
+		"RELEASE_APEX_CONTRIBUTIONS_ONDEVICEPERSONALIZATION",
+		"RELEASE_APEX_CONTRIBUTIONS_PERMISSION",
+		"RELEASE_APEX_CONTRIBUTIONS_REMOTEKEYPROVISIONING",
+		"RELEASE_APEX_CONTRIBUTIONS_RESOLV",
+		"RELEASE_APEX_CONTRIBUTIONS_SCHEDULING",
+		"RELEASE_APEX_CONTRIBUTIONS_SDKEXTENSIONS",
+		"RELEASE_APEX_CONTRIBUTIONS_SWCODEC",
+		"RELEASE_APEX_CONTRIBUTIONS_STATSD",
+		"RELEASE_APEX_CONTRIBUTIONS_TZDATA",
+		"RELEASE_APEX_CONTRIBUTIONS_UWB",
+		"RELEASE_APEX_CONTRIBUTIONS_WIFI",
+	}
+)
+
+// Returns the list of _selected_ apex_contributions
+// Each mainline module will have one entry in the list
+func (c *config) AllApexContributions() []string {
+	ret := []string{}
+	for _, f := range mainlineApexContributionBuildFlags {
+		if val, exists := c.GetBuildFlag(f); exists && val != "" {
+			ret = append(ret, val)
+		}
+	}
+	return ret
+}
+
+func (c *config) BuildIgnoreApexContributionContents() *bool {
+	return c.productVariables.BuildIgnoreApexContributionContents
+}
+
+func (c *config) ProductLocales() []string {
+	return c.productVariables.ProductLocales
+}
+
+func (c *config) ProductDefaultWifiChannels() []string {
+	return c.productVariables.ProductDefaultWifiChannels
+}
+
+func (c *config) BoardUseVbmetaDigestInFingerprint() bool {
+	return Bool(c.productVariables.BoardUseVbmetaDigestInFingerprint)
+}
+
+func (c *config) OemProperties() []string {
+	return c.productVariables.OemProperties
+}
diff --git a/android/config_bp2build.go b/android/config_bp2build.go
deleted file mode 100644
index 2beeb51..0000000
--- a/android/config_bp2build.go
+++ /dev/null
@@ -1,517 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package android
-
-import (
-	"fmt"
-	"reflect"
-	"regexp"
-	"sort"
-	"strings"
-
-	"android/soong/bazel"
-	"android/soong/starlark_fmt"
-
-	"github.com/google/blueprint"
-)
-
-// BazelVarExporter is a collection of configuration variables that can be exported for use in Bazel rules
-type BazelVarExporter interface {
-	// asBazel expands strings of configuration variables into their concrete values
-	asBazel(Config, ExportedStringVariables, ExportedStringListVariables, ExportedConfigDependingVariables) []bazelConstant
-}
-
-// ExportedVariables is a collection of interdependent configuration variables
-type ExportedVariables struct {
-	// Maps containing toolchain variables that are independent of the
-	// environment variables of the build.
-	exportedStringVars         ExportedStringVariables
-	exportedStringListVars     ExportedStringListVariables
-	exportedStringListDictVars ExportedStringListDictVariables
-
-	exportedVariableReferenceDictVars ExportedVariableReferenceDictVariables
-
-	/// Maps containing variables that are dependent on the build config.
-	exportedConfigDependingVars ExportedConfigDependingVariables
-
-	pctx PackageContext
-}
-
-// NewExportedVariables creats an empty ExportedVariables struct with non-nil maps
-func NewExportedVariables(pctx PackageContext) ExportedVariables {
-	return ExportedVariables{
-		exportedStringVars:                ExportedStringVariables{},
-		exportedStringListVars:            ExportedStringListVariables{},
-		exportedStringListDictVars:        ExportedStringListDictVariables{},
-		exportedVariableReferenceDictVars: ExportedVariableReferenceDictVariables{},
-		exportedConfigDependingVars:       ExportedConfigDependingVariables{},
-		pctx:                              pctx,
-	}
-}
-
-func (ev ExportedVariables) asBazel(config Config,
-	stringVars ExportedStringVariables, stringListVars ExportedStringListVariables, cfgDepVars ExportedConfigDependingVariables) []bazelConstant {
-	ret := []bazelConstant{}
-	ret = append(ret, ev.exportedStringVars.asBazel(config, stringVars, stringListVars, cfgDepVars)...)
-	ret = append(ret, ev.exportedStringListVars.asBazel(config, stringVars, stringListVars, cfgDepVars)...)
-	ret = append(ret, ev.exportedStringListDictVars.asBazel(config, stringVars, stringListVars, cfgDepVars)...)
-	// Note: ExportedVariableReferenceDictVars collections can only contain references to other variables and must be printed last
-	ret = append(ret, ev.exportedVariableReferenceDictVars.asBazel(config, stringVars, stringListVars, cfgDepVars)...)
-	ret = append(ret, ev.exportedConfigDependingVars.asBazel(config, stringVars, stringListVars, cfgDepVars)...)
-	return ret
-}
-
-// ExportStringStaticVariable declares a static string variable and exports it to
-// Bazel's toolchain.
-func (ev ExportedVariables) ExportStringStaticVariable(name string, value string) {
-	ev.pctx.StaticVariable(name, value)
-	ev.exportedStringVars.set(name, value)
-}
-
-// ExportStringListStaticVariable declares a static variable and exports it to
-// Bazel's toolchain.
-func (ev ExportedVariables) ExportStringListStaticVariable(name string, value []string) {
-	ev.pctx.StaticVariable(name, strings.Join(value, " "))
-	ev.exportedStringListVars.set(name, value)
-}
-
-// ExportVariableConfigMethod declares a variable whose value is evaluated at
-// runtime via a function with access to the Config and exports it to Bazel's
-// toolchain.
-func (ev ExportedVariables) ExportVariableConfigMethod(name string, method interface{}) blueprint.Variable {
-	ev.exportedConfigDependingVars.set(name, method)
-	return ev.pctx.VariableConfigMethod(name, method)
-}
-
-// ExportSourcePathVariable declares a static "source path" variable and exports
-// it to Bazel's toolchain.
-func (ev ExportedVariables) ExportSourcePathVariable(name string, value string) {
-	ev.pctx.SourcePathVariable(name, value)
-	ev.exportedStringVars.set(name, value)
-}
-
-// ExportVariableFuncVariable declares a variable whose value is evaluated at
-// runtime via a function and exports it to Bazel's toolchain.
-func (ev ExportedVariables) ExportVariableFuncVariable(name string, f func() string) {
-	ev.exportedConfigDependingVars.set(name, func(config Config) string {
-		return f()
-	})
-	ev.pctx.VariableFunc(name, func(PackageVarContext) string {
-		return f()
-	})
-}
-
-// ExportString only exports a variable to Bazel, but does not declare it in Soong
-func (ev ExportedVariables) ExportString(name string, value string) {
-	ev.exportedStringVars.set(name, value)
-}
-
-// ExportStringList only exports a variable to Bazel, but does not declare it in Soong
-func (ev ExportedVariables) ExportStringList(name string, value []string) {
-	ev.exportedStringListVars.set(name, value)
-}
-
-// ExportStringListDict only exports a variable to Bazel, but does not declare it in Soong
-func (ev ExportedVariables) ExportStringListDict(name string, value map[string][]string) {
-	ev.exportedStringListDictVars.set(name, value)
-}
-
-// ExportVariableReferenceDict only exports a variable to Bazel, but does not declare it in Soong
-func (ev ExportedVariables) ExportVariableReferenceDict(name string, value map[string]string) {
-	ev.exportedVariableReferenceDictVars.set(name, value)
-}
-
-// ExportedConfigDependingVariables is a mapping of variable names to functions
-// of type func(config Config) string which return the runtime-evaluated string
-// value of a particular variable
-type ExportedConfigDependingVariables map[string]interface{}
-
-func (m ExportedConfigDependingVariables) set(k string, v interface{}) {
-	m[k] = v
-}
-
-func (m ExportedConfigDependingVariables) asBazel(config Config,
-	stringVars ExportedStringVariables, stringListVars ExportedStringListVariables, cfgDepVars ExportedConfigDependingVariables) []bazelConstant {
-	ret := make([]bazelConstant, 0, len(m))
-	for variable, unevaluatedVar := range m {
-		evalFunc := reflect.ValueOf(unevaluatedVar)
-		validateVariableMethod(variable, evalFunc)
-		evaluatedResult := evalFunc.Call([]reflect.Value{reflect.ValueOf(config)})
-		evaluatedValue := evaluatedResult[0].Interface().(string)
-		expandedVars, err := expandVar(config, evaluatedValue, stringVars, stringListVars, cfgDepVars)
-		if err != nil {
-			panic(fmt.Errorf("error expanding config variable %s: %s", variable, err))
-		}
-		if len(expandedVars) > 1 {
-			ret = append(ret, bazelConstant{
-				variableName:       variable,
-				internalDefinition: starlark_fmt.PrintStringList(expandedVars, 0),
-			})
-		} else {
-			ret = append(ret, bazelConstant{
-				variableName:       variable,
-				internalDefinition: fmt.Sprintf(`"%s"`, validateCharacters(expandedVars[0])),
-			})
-		}
-	}
-	return ret
-}
-
-// Ensure that string s has no invalid characters to be generated into the bzl file.
-func validateCharacters(s string) string {
-	for _, c := range []string{`\n`, `"`, `\`} {
-		if strings.Contains(s, c) {
-			panic(fmt.Errorf("%s contains illegal character %s", s, c))
-		}
-	}
-	return s
-}
-
-type bazelConstant struct {
-	variableName       string
-	internalDefinition string
-	sortLast           bool
-}
-
-// ExportedStringVariables is a mapping of variable names to string values
-type ExportedStringVariables map[string]string
-
-func (m ExportedStringVariables) set(k string, v string) {
-	m[k] = v
-}
-
-func (m ExportedStringVariables) asBazel(config Config,
-	stringVars ExportedStringVariables, stringListVars ExportedStringListVariables, cfgDepVars ExportedConfigDependingVariables) []bazelConstant {
-	ret := make([]bazelConstant, 0, len(m))
-	for k, variableValue := range m {
-		expandedVar, err := expandVar(config, variableValue, stringVars, stringListVars, cfgDepVars)
-		if err != nil {
-			panic(fmt.Errorf("error expanding config variable %s: %s", k, err))
-		}
-		if len(expandedVar) > 1 {
-			panic(fmt.Errorf("%s expands to more than one string value: %s", variableValue, expandedVar))
-		}
-		ret = append(ret, bazelConstant{
-			variableName:       k,
-			internalDefinition: fmt.Sprintf(`"%s"`, validateCharacters(expandedVar[0])),
-		})
-	}
-	return ret
-}
-
-// ExportedStringListVariables is a mapping of variable names to a list of strings
-type ExportedStringListVariables map[string][]string
-
-func (m ExportedStringListVariables) set(k string, v []string) {
-	m[k] = v
-}
-
-func (m ExportedStringListVariables) asBazel(config Config,
-	stringScope ExportedStringVariables, stringListScope ExportedStringListVariables,
-	exportedVars ExportedConfigDependingVariables) []bazelConstant {
-	ret := make([]bazelConstant, 0, len(m))
-	// For each exported variable, recursively expand elements in the variableValue
-	// list to ensure that interpolated variables are expanded according to their values
-	// in the variable scope.
-	for k, variableValue := range m {
-		var expandedVars []string
-		for _, v := range variableValue {
-			expandedVar, err := expandVar(config, v, stringScope, stringListScope, exportedVars)
-			if err != nil {
-				panic(fmt.Errorf("Error expanding config variable %s=%s: %s", k, v, err))
-			}
-			expandedVars = append(expandedVars, expandedVar...)
-		}
-		// Assign the list as a bzl-private variable; this variable will be exported
-		// out through a constants struct later.
-		ret = append(ret, bazelConstant{
-			variableName:       k,
-			internalDefinition: starlark_fmt.PrintStringList(expandedVars, 0),
-		})
-	}
-	return ret
-}
-
-// ExportedStringListDictVariables is a mapping from variable names to a
-// dictionary which maps keys to lists of strings
-type ExportedStringListDictVariables map[string]map[string][]string
-
-func (m ExportedStringListDictVariables) set(k string, v map[string][]string) {
-	m[k] = v
-}
-
-// Since dictionaries are not supported in Ninja, we do not expand variables for dictionaries
-func (m ExportedStringListDictVariables) asBazel(_ Config, _ ExportedStringVariables,
-	_ ExportedStringListVariables, _ ExportedConfigDependingVariables) []bazelConstant {
-	ret := make([]bazelConstant, 0, len(m))
-	for k, dict := range m {
-		ret = append(ret, bazelConstant{
-			variableName:       k,
-			internalDefinition: starlark_fmt.PrintStringListDict(dict, 0),
-		})
-	}
-	return ret
-}
-
-// ExportedVariableReferenceDictVariables is a mapping from variable names to a
-// dictionary which references previously defined variables. This is used to
-// create a Starlark output such as:
-//
-//	string_var1 = "string1
-//	var_ref_dict_var1 = {
-//		"key1": string_var1
-//	}
-//
-// This type of variable collection must be expanded last so that it recognizes
-// previously defined variables.
-type ExportedVariableReferenceDictVariables map[string]map[string]string
-
-func (m ExportedVariableReferenceDictVariables) set(k string, v map[string]string) {
-	m[k] = v
-}
-
-func (m ExportedVariableReferenceDictVariables) asBazel(_ Config, _ ExportedStringVariables,
-	_ ExportedStringListVariables, _ ExportedConfigDependingVariables) []bazelConstant {
-	ret := make([]bazelConstant, 0, len(m))
-	for n, dict := range m {
-		for k, v := range dict {
-			matches, err := variableReference(v)
-			if err != nil {
-				panic(err)
-			} else if !matches.matches {
-				panic(fmt.Errorf("Expected a variable reference, got %q", v))
-			} else if len(matches.fullVariableReference) != len(v) {
-				panic(fmt.Errorf("Expected only a variable reference, got %q", v))
-			}
-			dict[k] = "_" + matches.variable
-		}
-		ret = append(ret, bazelConstant{
-			variableName:       n,
-			internalDefinition: starlark_fmt.PrintDict(dict, 0),
-			sortLast:           true,
-		})
-	}
-	return ret
-}
-
-// BazelToolchainVars expands an ExportedVariables collection and returns a string
-// of formatted Starlark variable definitions
-func BazelToolchainVars(config Config, exportedVars ExportedVariables) string {
-	results := exportedVars.asBazel(
-		config,
-		exportedVars.exportedStringVars,
-		exportedVars.exportedStringListVars,
-		exportedVars.exportedConfigDependingVars,
-	)
-
-	sort.Slice(results, func(i, j int) bool {
-		if results[i].sortLast != results[j].sortLast {
-			return !results[i].sortLast
-		}
-		return results[i].variableName < results[j].variableName
-	})
-
-	definitions := make([]string, 0, len(results))
-	constants := make([]string, 0, len(results))
-	for _, b := range results {
-		definitions = append(definitions,
-			fmt.Sprintf("_%s = %s", b.variableName, b.internalDefinition))
-		constants = append(constants,
-			fmt.Sprintf("%[1]s%[2]s = _%[2]s,", starlark_fmt.Indention(1), b.variableName))
-	}
-
-	// Build the exported constants struct.
-	ret := bazel.GeneratedBazelFileWarning
-	ret += "\n\n"
-	ret += strings.Join(definitions, "\n\n")
-	ret += "\n\n"
-	ret += "constants = struct(\n"
-	ret += strings.Join(constants, "\n")
-	ret += "\n)"
-
-	return ret
-}
-
-type match struct {
-	matches               bool
-	fullVariableReference string
-	variable              string
-}
-
-func variableReference(input string) (match, error) {
-	// e.g. "${ExternalCflags}"
-	r := regexp.MustCompile(`\${(?:config\.)?([a-zA-Z0-9_]+)}`)
-
-	matches := r.FindStringSubmatch(input)
-	if len(matches) == 0 {
-		return match{}, nil
-	}
-	if len(matches) != 2 {
-		return match{}, fmt.Errorf("Expected to only match 1 subexpression in %s, got %d", input, len(matches)-1)
-	}
-	return match{
-		matches:               true,
-		fullVariableReference: matches[0],
-		// Index 1 of FindStringSubmatch contains the subexpression match
-		// (variable name) of the capture group.
-		variable: matches[1],
-	}, nil
-}
-
-// expandVar recursively expand interpolated variables in the exportedVars scope.
-//
-// We're using a string slice to track the seen variables to avoid
-// stackoverflow errors with infinite recursion. it's simpler to use a
-// string slice than to handle a pass-by-referenced map, which would make it
-// quite complex to track depth-first interpolations. It's also unlikely the
-// interpolation stacks are deep (n > 1).
-func expandVar(config Config, toExpand string, stringScope ExportedStringVariables,
-	stringListScope ExportedStringListVariables, exportedVars ExportedConfigDependingVariables) ([]string, error) {
-
-	// Internal recursive function.
-	var expandVarInternal func(string, map[string]bool) (string, error)
-	expandVarInternal = func(toExpand string, seenVars map[string]bool) (string, error) {
-		var ret string
-		remainingString := toExpand
-		for len(remainingString) > 0 {
-			matches, err := variableReference(remainingString)
-			if err != nil {
-				panic(err)
-			}
-			if !matches.matches {
-				return ret + remainingString, nil
-			}
-			matchIndex := strings.Index(remainingString, matches.fullVariableReference)
-			ret += remainingString[:matchIndex]
-			remainingString = remainingString[matchIndex+len(matches.fullVariableReference):]
-
-			variable := matches.variable
-			// toExpand contains a variable.
-			if _, ok := seenVars[variable]; ok {
-				return ret, fmt.Errorf(
-					"Unbounded recursive interpolation of variable: %s", variable)
-			}
-			// A map is passed-by-reference. Create a new map for
-			// this scope to prevent variables seen in one depth-first expansion
-			// to be also treated as "seen" in other depth-first traversals.
-			newSeenVars := map[string]bool{}
-			for k := range seenVars {
-				newSeenVars[k] = true
-			}
-			newSeenVars[variable] = true
-			if unexpandedVars, ok := stringListScope[variable]; ok {
-				expandedVars := []string{}
-				for _, unexpandedVar := range unexpandedVars {
-					expandedVar, err := expandVarInternal(unexpandedVar, newSeenVars)
-					if err != nil {
-						return ret, err
-					}
-					expandedVars = append(expandedVars, expandedVar)
-				}
-				ret += strings.Join(expandedVars, " ")
-			} else if unexpandedVar, ok := stringScope[variable]; ok {
-				expandedVar, err := expandVarInternal(unexpandedVar, newSeenVars)
-				if err != nil {
-					return ret, err
-				}
-				ret += expandedVar
-			} else if unevaluatedVar, ok := exportedVars[variable]; ok {
-				evalFunc := reflect.ValueOf(unevaluatedVar)
-				validateVariableMethod(variable, evalFunc)
-				evaluatedResult := evalFunc.Call([]reflect.Value{reflect.ValueOf(config)})
-				evaluatedValue := evaluatedResult[0].Interface().(string)
-				expandedVar, err := expandVarInternal(evaluatedValue, newSeenVars)
-				if err != nil {
-					return ret, err
-				}
-				ret += expandedVar
-			} else {
-				return "", fmt.Errorf("Unbound config variable %s", variable)
-			}
-		}
-		return ret, nil
-	}
-	var ret []string
-	stringFields := splitStringKeepingQuotedSubstring(toExpand, ' ')
-	for _, v := range stringFields {
-		val, err := expandVarInternal(v, map[string]bool{})
-		if err != nil {
-			return ret, err
-		}
-		ret = append(ret, val)
-	}
-
-	return ret, nil
-}
-
-// splitStringKeepingQuotedSubstring splits a string on a provided separator,
-// but it will not split substrings inside unescaped double quotes. If the double
-// quotes are escaped, then the returned string will only include the quote, and
-// not the escape.
-func splitStringKeepingQuotedSubstring(s string, delimiter byte) []string {
-	var ret []string
-	quote := byte('"')
-
-	var substring []byte
-	quoted := false
-	escaped := false
-
-	for i := range s {
-		if !quoted && s[i] == delimiter {
-			ret = append(ret, string(substring))
-			substring = []byte{}
-			continue
-		}
-
-		characterIsEscape := i < len(s)-1 && s[i] == '\\' && s[i+1] == quote
-		if characterIsEscape {
-			escaped = true
-			continue
-		}
-
-		if s[i] == quote {
-			if !escaped {
-				quoted = !quoted
-			}
-			escaped = false
-		}
-
-		substring = append(substring, s[i])
-	}
-
-	ret = append(ret, string(substring))
-
-	return ret
-}
-
-func validateVariableMethod(name string, methodValue reflect.Value) {
-	methodType := methodValue.Type()
-	if methodType.Kind() != reflect.Func {
-		panic(fmt.Errorf("method given for variable %s is not a function",
-			name))
-	}
-	if n := methodType.NumIn(); n != 1 {
-		panic(fmt.Errorf("method for variable %s has %d inputs (should be 1)",
-			name, n))
-	}
-	if n := methodType.NumOut(); n != 1 {
-		panic(fmt.Errorf("method for variable %s has %d outputs (should be 1)",
-			name, n))
-	}
-	if kind := methodType.Out(0).Kind(); kind != reflect.String {
-		panic(fmt.Errorf("method for variable %s does not return a string",
-			name))
-	}
-}
diff --git a/android/config_bp2build_test.go b/android/config_bp2build_test.go
deleted file mode 100644
index 1a0ba7b..0000000
--- a/android/config_bp2build_test.go
+++ /dev/null
@@ -1,454 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package android
-
-import (
-	"android/soong/bazel"
-	"testing"
-)
-
-func TestExpandVars(t *testing.T) {
-	android_arm64_config := TestConfig("out", nil, "", nil)
-	android_arm64_config.BuildOS = Android
-	android_arm64_config.BuildArch = Arm64
-
-	testCases := []struct {
-		description     string
-		config          Config
-		stringScope     ExportedStringVariables
-		stringListScope ExportedStringListVariables
-		configVars      ExportedConfigDependingVariables
-		toExpand        string
-		expectedValues  []string
-	}{
-		{
-			description:    "no expansion for non-interpolated value",
-			toExpand:       "foo",
-			expectedValues: []string{"foo"},
-		},
-		{
-			description: "single level expansion for string var",
-			stringScope: ExportedStringVariables{
-				"foo": "bar",
-			},
-			toExpand:       "${foo}",
-			expectedValues: []string{"bar"},
-		},
-		{
-			description: "single level expansion with short-name for string var",
-			stringScope: ExportedStringVariables{
-				"foo": "bar",
-			},
-			toExpand:       "${config.foo}",
-			expectedValues: []string{"bar"},
-		},
-		{
-			description: "single level expansion string list var",
-			stringListScope: ExportedStringListVariables{
-				"foo": []string{"bar"},
-			},
-			toExpand:       "${foo}",
-			expectedValues: []string{"bar"},
-		},
-		{
-			description: "mixed level expansion for string list var",
-			stringScope: ExportedStringVariables{
-				"foo": "${bar}",
-				"qux": "hello",
-			},
-			stringListScope: ExportedStringListVariables{
-				"bar": []string{"baz", "${qux}"},
-			},
-			toExpand:       "${foo}",
-			expectedValues: []string{"baz hello"},
-		},
-		{
-			description: "double level expansion",
-			stringListScope: ExportedStringListVariables{
-				"foo": []string{"${bar}"},
-				"bar": []string{"baz"},
-			},
-			toExpand:       "${foo}",
-			expectedValues: []string{"baz"},
-		},
-		{
-			description: "double level expansion with a literal",
-			stringListScope: ExportedStringListVariables{
-				"a": []string{"${b}", "c"},
-				"b": []string{"d"},
-			},
-			toExpand:       "${a}",
-			expectedValues: []string{"d c"},
-		},
-		{
-			description: "double level expansion, with two variables in a string",
-			stringListScope: ExportedStringListVariables{
-				"a": []string{"${b} ${c}"},
-				"b": []string{"d"},
-				"c": []string{"e"},
-			},
-			toExpand:       "${a}",
-			expectedValues: []string{"d e"},
-		},
-		{
-			description: "triple level expansion with two variables in a string",
-			stringListScope: ExportedStringListVariables{
-				"a": []string{"${b} ${c}"},
-				"b": []string{"${c}", "${d}"},
-				"c": []string{"${d}"},
-				"d": []string{"foo"},
-			},
-			toExpand:       "${a}",
-			expectedValues: []string{"foo foo foo"},
-		},
-		{
-			description: "expansion with config depending vars",
-			configVars: ExportedConfigDependingVariables{
-				"a": func(c Config) string { return c.BuildOS.String() },
-				"b": func(c Config) string { return c.BuildArch.String() },
-			},
-			config:         android_arm64_config,
-			toExpand:       "${a}-${b}",
-			expectedValues: []string{"android-arm64"},
-		},
-		{
-			description: "double level multi type expansion",
-			stringListScope: ExportedStringListVariables{
-				"platform": []string{"${os}-${arch}"},
-				"const":    []string{"const"},
-			},
-			configVars: ExportedConfigDependingVariables{
-				"os":   func(c Config) string { return c.BuildOS.String() },
-				"arch": func(c Config) string { return c.BuildArch.String() },
-				"foo":  func(c Config) string { return "foo" },
-			},
-			config:         android_arm64_config,
-			toExpand:       "${const}/${platform}/${foo}",
-			expectedValues: []string{"const/android-arm64/foo"},
-		},
-	}
-
-	for _, testCase := range testCases {
-		t.Run(testCase.description, func(t *testing.T) {
-			output, _ := expandVar(testCase.config, testCase.toExpand, testCase.stringScope, testCase.stringListScope, testCase.configVars)
-			if len(output) != len(testCase.expectedValues) {
-				t.Errorf("Expected %d values, got %d", len(testCase.expectedValues), len(output))
-			}
-			for i, actual := range output {
-				expectedValue := testCase.expectedValues[i]
-				if actual != expectedValue {
-					t.Errorf("Actual value '%s' doesn't match expected value '%s'", actual, expectedValue)
-				}
-			}
-		})
-	}
-}
-
-func TestBazelToolchainVars(t *testing.T) {
-	testCases := []struct {
-		name        string
-		config      Config
-		vars        ExportedVariables
-		expectedOut string
-	}{
-		{
-			name: "exports strings",
-			vars: ExportedVariables{
-				exportedStringVars: ExportedStringVariables{
-					"a": "b",
-					"c": "d",
-				},
-			},
-			expectedOut: bazel.GeneratedBazelFileWarning + `
-
-_a = "b"
-
-_c = "d"
-
-constants = struct(
-    a = _a,
-    c = _c,
-)`,
-		},
-		{
-			name: "exports string lists",
-			vars: ExportedVariables{
-				exportedStringListVars: ExportedStringListVariables{
-					"a": []string{"b1", "b2"},
-					"c": []string{"d1", "d2"},
-				},
-			},
-			expectedOut: bazel.GeneratedBazelFileWarning + `
-
-_a = [
-    "b1",
-    "b2",
-]
-
-_c = [
-    "d1",
-    "d2",
-]
-
-constants = struct(
-    a = _a,
-    c = _c,
-)`,
-		},
-		{
-			name: "exports string lists dicts",
-			vars: ExportedVariables{
-				exportedStringListDictVars: ExportedStringListDictVariables{
-					"a": map[string][]string{"b1": {"b2"}},
-					"c": map[string][]string{"d1": {"d2"}},
-				},
-			},
-			expectedOut: bazel.GeneratedBazelFileWarning + `
-
-_a = {
-    "b1": ["b2"],
-}
-
-_c = {
-    "d1": ["d2"],
-}
-
-constants = struct(
-    a = _a,
-    c = _c,
-)`,
-		},
-		{
-			name: "exports dict with var refs",
-			vars: ExportedVariables{
-				exportedVariableReferenceDictVars: ExportedVariableReferenceDictVariables{
-					"a": map[string]string{"b1": "${b2}"},
-					"c": map[string]string{"d1": "${config.d2}"},
-				},
-			},
-			expectedOut: bazel.GeneratedBazelFileWarning + `
-
-_a = {
-    "b1": _b2,
-}
-
-_c = {
-    "d1": _d2,
-}
-
-constants = struct(
-    a = _a,
-    c = _c,
-)`,
-		},
-		{
-			name: "sorts across types with variable references last",
-			vars: ExportedVariables{
-				exportedStringVars: ExportedStringVariables{
-					"b": "b-val",
-					"d": "d-val",
-				},
-				exportedStringListVars: ExportedStringListVariables{
-					"c": []string{"c-val"},
-					"e": []string{"e-val"},
-				},
-				exportedStringListDictVars: ExportedStringListDictVariables{
-					"a": map[string][]string{"a1": {"a2"}},
-					"f": map[string][]string{"f1": {"f2"}},
-				},
-				exportedVariableReferenceDictVars: ExportedVariableReferenceDictVariables{
-					"aa": map[string]string{"b1": "${b}"},
-					"cc": map[string]string{"d1": "${config.d}"},
-				},
-			},
-			expectedOut: bazel.GeneratedBazelFileWarning + `
-
-_a = {
-    "a1": ["a2"],
-}
-
-_b = "b-val"
-
-_c = ["c-val"]
-
-_d = "d-val"
-
-_e = ["e-val"]
-
-_f = {
-    "f1": ["f2"],
-}
-
-_aa = {
-    "b1": _b,
-}
-
-_cc = {
-    "d1": _d,
-}
-
-constants = struct(
-    a = _a,
-    b = _b,
-    c = _c,
-    d = _d,
-    e = _e,
-    f = _f,
-    aa = _aa,
-    cc = _cc,
-)`,
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			out := BazelToolchainVars(tc.config, tc.vars)
-			if out != tc.expectedOut {
-				t.Errorf("Expected \n%s, got \n%s", tc.expectedOut, out)
-			}
-		})
-	}
-}
-
-func TestSplitStringKeepingQuotedSubstring(t *testing.T) {
-	testCases := []struct {
-		description string
-		s           string
-		delimiter   byte
-		split       []string
-	}{
-		{
-			description: "empty string returns single empty string",
-			s:           "",
-			delimiter:   ' ',
-			split: []string{
-				"",
-			},
-		},
-		{
-			description: "string with single space returns two empty strings",
-			s:           " ",
-			delimiter:   ' ',
-			split: []string{
-				"",
-				"",
-			},
-		},
-		{
-			description: "string with two spaces returns three empty strings",
-			s:           "  ",
-			delimiter:   ' ',
-			split: []string{
-				"",
-				"",
-				"",
-			},
-		},
-		{
-			description: "string with four words returns four word string",
-			s:           "hello world with words",
-			delimiter:   ' ',
-			split: []string{
-				"hello",
-				"world",
-				"with",
-				"words",
-			},
-		},
-		{
-			description: "string with words and nested quote returns word strings and quote string",
-			s:           `hello "world with" words`,
-			delimiter:   ' ',
-			split: []string{
-				"hello",
-				`"world with"`,
-				"words",
-			},
-		},
-		{
-			description: "string with escaped quote inside real quotes",
-			s:           `hello \"world "with\" words"`,
-			delimiter:   ' ',
-			split: []string{
-				"hello",
-				`"world`,
-				`"with" words"`,
-			},
-		},
-		{
-			description: "string with words and escaped quotes returns word strings",
-			s:           `hello \"world with\" words`,
-			delimiter:   ' ',
-			split: []string{
-				"hello",
-				`"world`,
-				`with"`,
-				"words",
-			},
-		},
-		{
-			description: "string which is single quoted substring returns only substring",
-			s:           `"hello world with words"`,
-			delimiter:   ' ',
-			split: []string{
-				`"hello world with words"`,
-			},
-		},
-		{
-			description: "string starting with quote returns quoted string",
-			s:           `"hello world with" words`,
-			delimiter:   ' ',
-			split: []string{
-				`"hello world with"`,
-				"words",
-			},
-		},
-		{
-			description: "string with starting quote and no ending quote returns quote to end of string",
-			s:           `hello "world with words`,
-			delimiter:   ' ',
-			split: []string{
-				"hello",
-				`"world with words`,
-			},
-		},
-		{
-			description: "quoted string is treated as a single \"word\" unless separated by delimiter",
-			s:           `hello "world"with words`,
-			delimiter:   ' ',
-			split: []string{
-				"hello",
-				`"world"with`,
-				"words",
-			},
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.description, func(t *testing.T) {
-			split := splitStringKeepingQuotedSubstring(tc.s, tc.delimiter)
-			if len(split) != len(tc.split) {
-				t.Fatalf("number of split string elements (%d) differs from expected (%d): split string (%v), expected (%v)",
-					len(split), len(tc.split), split, tc.split,
-				)
-			}
-			for i := range split {
-				if split[i] != tc.split[i] {
-					t.Errorf("split string element (%d), %v, differs from expected, %v", i, split[i], tc.split[i])
-				}
-			}
-		})
-	}
-}
diff --git a/android/deapexer.go b/android/deapexer.go
index 6a93f60..61ae64e 100644
--- a/android/deapexer.go
+++ b/android/deapexer.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"fmt"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -78,6 +79,14 @@
 	//
 	// See Prebuilt.ApexInfoMutator for more information.
 	exports map[string]WritablePath
+
+	// name of the java libraries exported from the apex
+	// e.g. core-libart
+	exportedModuleNames []string
+
+	// name of the java libraries exported from the apex that should be dexpreopt'd with the .prof
+	// file embedded in the apex
+	dexpreoptProfileGuidedExportedModuleNames []string
 }
 
 // ApexModuleName returns the name of the APEX module that provided the info.
@@ -96,21 +105,34 @@
 	return path
 }
 
+func (i DeapexerInfo) GetExportedModuleNames() []string {
+	return i.exportedModuleNames
+}
+
 // Provider that can be used from within the `GenerateAndroidBuildActions` of a module that depends
 // on a `deapexer` module to retrieve its `DeapexerInfo`.
-var DeapexerProvider = blueprint.NewProvider(DeapexerInfo{})
+var DeapexerProvider = blueprint.NewProvider[DeapexerInfo]()
 
 // NewDeapexerInfo creates and initializes a DeapexerInfo that is suitable
 // for use with a prebuilt_apex module.
 //
 // See apex/deapexer.go for more information.
-func NewDeapexerInfo(apexModuleName string, exports map[string]WritablePath) DeapexerInfo {
+func NewDeapexerInfo(apexModuleName string, exports map[string]WritablePath, moduleNames []string) DeapexerInfo {
 	return DeapexerInfo{
-		apexModuleName: apexModuleName,
-		exports:        exports,
+		apexModuleName:      apexModuleName,
+		exports:             exports,
+		exportedModuleNames: moduleNames,
 	}
 }
 
+func (i *DeapexerInfo) GetDexpreoptProfileGuidedExportedModuleNames() []string {
+	return i.dexpreoptProfileGuidedExportedModuleNames
+}
+
+func (i *DeapexerInfo) AddDexpreoptProfileGuidedExportedModuleNames(names ...string) {
+	i.dexpreoptProfileGuidedExportedModuleNames = append(i.dexpreoptProfileGuidedExportedModuleNames, names...)
+}
+
 type deapexerTagStruct struct {
 	blueprint.BaseDependencyTag
 }
@@ -133,6 +155,9 @@
 	// the path to the extracted file will be stored in the DeapexerInfo using the APEX relative file
 	// path as the key, The path can then be retrieved using the PrebuiltExportPath(key) method.
 	RequiredFilesFromPrebuiltApex(ctx BaseModuleContext) []string
+
+	// Returns true if a transitive dependency of an apex should use a .prof file to guide dexpreopt
+	UseProfileGuidedDexpreopt() bool
 }
 
 // Marker interface that identifies dependencies on modules that may require files from a prebuilt
@@ -146,11 +171,17 @@
 
 // FindDeapexerProviderForModule searches through the direct dependencies of the current context
 // module for a DeapexerTag dependency and returns its DeapexerInfo. If a single nonambiguous
-// deapexer module isn't found then errors are reported with ctx.ModuleErrorf and nil is returned.
-func FindDeapexerProviderForModule(ctx ModuleContext) *DeapexerInfo {
+// deapexer module isn't found then it returns it an error
+// clients should check the value of error and call ctx.ModuleErrof if a non nil error is received
+func FindDeapexerProviderForModule(ctx ModuleContext) (*DeapexerInfo, error) {
 	var di *DeapexerInfo
+	var err error
 	ctx.VisitDirectDepsWithTag(DeapexerTag, func(m Module) {
-		c := ctx.OtherModuleProvider(m, DeapexerProvider).(DeapexerInfo)
+		if err != nil {
+			// An err has been found. Do not visit further.
+			return
+		}
+		c, _ := OtherModuleProvider(ctx, m, DeapexerProvider)
 		p := &c
 		if di != nil {
 			// If two DeapexerInfo providers have been found then check if they are
@@ -159,17 +190,18 @@
 				di = selected
 				return
 			}
-			ctx.ModuleErrorf("Multiple installable prebuilt APEXes provide ambiguous deapexers: %s and %s",
-				di.ApexModuleName(), p.ApexModuleName())
+			err = fmt.Errorf("Multiple installable prebuilt APEXes provide ambiguous deapexers: %s and %s", di.ApexModuleName(), p.ApexModuleName())
 		}
 		di = p
 	})
-	if di != nil {
-		return di
+	if err != nil {
+		return nil, err
 	}
-	ai := ctx.Provider(ApexInfoProvider).(ApexInfo)
-	ctx.ModuleErrorf("No prebuilt APEX provides a deapexer module for APEX variant %s", ai.ApexVariationName)
-	return nil
+	if di != nil {
+		return di, nil
+	}
+	ai, _ := ModuleProvider(ctx, ApexInfoProvider)
+	return nil, fmt.Errorf("No prebuilt APEX provides a deapexer module for APEX variant %s", ai.ApexVariationName)
 }
 
 // removeCompressedApexSuffix removes the _compressed suffix from the name if present.
diff --git a/android/defaults.go b/android/defaults.go
index e0e6e5c..ff79002 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -17,7 +17,6 @@
 import (
 	"reflect"
 
-	"android/soong/ui/metrics/bp2build_metrics_proto"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -118,11 +117,6 @@
 
 type DefaultsModuleBase struct {
 	DefaultableModuleBase
-
-	// Included to support setting bazel_module.label for multiple Soong modules to the same Bazel
-	// target. This is primarily useful for modules that were architecture specific and instead are
-	// handled in Bazel as a select().
-	BazelModuleBase
 }
 
 // The common pattern for defaults modules is to register separate instances of
@@ -165,7 +159,6 @@
 type DefaultsModule interface {
 	Module
 	Defaults
-	Bazelable
 }
 
 func (d *DefaultsModuleBase) properties() []interface{} {
@@ -178,13 +171,6 @@
 
 func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {}
 
-// ConvertWithBp2build to fulfill Bazelable interface; however, at this time defaults module are
-// *NOT* converted with bp2build
-func (defaultable *DefaultsModuleBase) ConvertWithBp2build(ctx TopDownMutatorContext) {
-	// Defaults types are never convertible.
-	ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
-}
-
 func InitDefaultsModule(module DefaultsModule) {
 	commonProperties := &commonProperties{}
 
@@ -194,8 +180,6 @@
 		&ApexProperties{},
 		&distProperties{})
 
-	// Bazel module must be initialized _before_ Defaults to be included in cc_defaults module.
-	InitBazelModule(module)
 	initAndroidModuleBase(module)
 	initProductVariableModule(module)
 	initArchModule(module)
@@ -225,60 +209,10 @@
 
 var _ Defaults = (*DefaultsModuleBase)(nil)
 
-// applyNamespacedVariableDefaults only runs in bp2build mode for
-// defaultable/defaults modules. Its purpose is to merge namespaced product
-// variable props from defaults deps, even if those defaults are custom module
-// types created from soong_config_module_type, e.g. one that's wrapping a
-// cc_defaults or java_defaults.
-func applyNamespacedVariableDefaults(defaultDep Defaults, ctx TopDownMutatorContext) {
-	var dep, b Bazelable
-
-	dep, ok := defaultDep.(Bazelable)
-	if !ok {
-		if depMod, ok := defaultDep.(Module); ok {
-			// Track that this dependency hasn't been converted to bp2build yet.
-			ctx.AddUnconvertedBp2buildDep(depMod.Name())
-			return
-		} else {
-			panic("Expected default dep to be a Module.")
-		}
-	}
-
-	b, ok = ctx.Module().(Bazelable)
-	if !ok {
-		return
-	}
-
-	// namespacedVariableProps is a map from namespaces (e.g. acme, android,
-	// vendor_foo) to a slice of soong_config_variable struct pointers,
-	// containing properties for that particular module.
-	src := dep.namespacedVariableProps()
-	dst := b.namespacedVariableProps()
-	if dst == nil {
-		dst = make(namespacedVariableProperties)
-	}
-
-	// Propagate all soong_config_variable structs from the dep. We'll merge the
-	// actual property values later in variable.go.
-	for namespace := range src {
-		if dst[namespace] == nil {
-			dst[namespace] = []interface{}{}
-		}
-		for _, i := range src[namespace] {
-			dst[namespace] = append(dst[namespace], i)
-		}
-	}
-
-	b.setNamespacedVariableProps(dst)
-}
-
 func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext,
 	defaultsList []Defaults) {
 
 	for _, defaults := range defaultsList {
-		if ctx.Config().BuildMode == Bp2build {
-			applyNamespacedVariableDefaults(defaults, ctx)
-		}
 		for _, prop := range defaultable.defaultableProperties {
 			if prop == defaultable.defaultableVariableProperties {
 				defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
diff --git a/android/defaults_test.go b/android/defaults_test.go
index a7542ab..0ad0fb8 100644
--- a/android/defaults_test.go
+++ b/android/defaults_test.go
@@ -16,10 +16,13 @@
 
 import (
 	"testing"
+
+	"github.com/google/blueprint"
 )
 
 type defaultsTestProperties struct {
-	Foo []string
+	Foo       []string
+	Path_prop []string `android:"path"`
 }
 
 type defaultsTestModule struct {
@@ -130,3 +133,40 @@
 	// TODO: missing transitive defaults is currently not handled
 	_ = missingTransitiveDefaults
 }
+
+func TestDefaultsPathProperties(t *testing.T) {
+	bp := `
+		defaults {
+			name: "defaults",
+			path_prop: [":gen"],
+		}
+
+		test {
+			name: "foo",
+			defaults: ["defaults"],
+		}
+
+		test {
+			name: "gen",
+		}
+	`
+
+	result := GroupFixturePreparers(
+		prepareForDefaultsTest,
+		FixtureWithRootAndroidBp(bp),
+	).RunTest(t)
+
+	collectDeps := func(m Module) []string {
+		var deps []string
+		result.VisitDirectDeps(m, func(dep blueprint.Module) {
+			deps = append(deps, result.ModuleName(dep))
+		})
+		return deps
+	}
+
+	foo := result.Module("foo", "")
+	defaults := result.Module("defaults", "")
+
+	AssertStringListContains(t, "foo should depend on gen", collectDeps(foo), "gen")
+	AssertStringListDoesNotContain(t, "defaults should not depend on gen", collectDeps(defaults), "gen")
+}
diff --git a/android/defs.go b/android/defs.go
index 18eed2d..78cdea2 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -15,18 +15,12 @@
 package android
 
 import (
-	"fmt"
-	"strings"
-	"testing"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
-	"github.com/google/blueprint/proptools"
 )
 
 var (
-	pctx         = NewPackageContext("android/soong/android")
-	exportedVars = NewExportedVariables(pctx)
+	pctx = NewPackageContext("android/soong/android")
 
 	cpPreserveSymlinks = pctx.VariableConfigMethod("cpPreserveSymlinks",
 		Config.CpPreserveSymlinksFlags)
@@ -72,8 +66,7 @@
 			Command:     "if ! cmp -s $in $out; then cp $in $out; fi",
 			Description: "cp if changed $out",
 			Restat:      true,
-		},
-		"cpFlags")
+		})
 
 	CpExecutable = pctx.AndroidStaticRule("CpExecutable",
 		blueprint.RuleParams{
@@ -92,9 +85,8 @@
 	// A symlink rule.
 	Symlink = pctx.AndroidStaticRule("Symlink",
 		blueprint.RuleParams{
-			Command:        "rm -f $out && ln -f -s $fromPath $out",
-			Description:    "symlink $out",
-			SymlinkOutputs: []string{"$out"},
+			Command:     "rm -f $out && ln -f -s $fromPath $out",
+			Description: "symlink $out",
 		},
 		"fromPath")
 
@@ -107,20 +99,10 @@
 
 	Cat = pctx.AndroidStaticRule("Cat",
 		blueprint.RuleParams{
-			Command:     "cat $in > $out",
-			Description: "concatenate licenses $out",
+			Command:     "rm -f $out && cat $in > $out",
+			Description: "concatenate files to $out",
 		})
 
-	// ubuntu 14.04 offcially use dash for /bin/sh, and its builtin echo command
-	// doesn't support -e option. Therefore we force to use /bin/bash when writing out
-	// content to file.
-	writeFile = pctx.AndroidStaticRule("writeFile",
-		blueprint.RuleParams{
-			Command:     `/bin/bash -c 'echo -e -n "$$0" > $out' $content`,
-			Description: "writing file $out",
-		},
-		"content")
-
 	// Used only when USE_GOMA=true is set, to restrict non-goma jobs to the local parallelism value
 	localPool = blueprint.NewBuiltinPool("local_pool")
 
@@ -137,111 +119,6 @@
 	pctx.VariableFunc("RBEWrapper", func(ctx PackageVarContext) string {
 		return ctx.Config().RBEWrapper()
 	})
-
-	exportedVars.ExportStringList("NeverAllowNotInIncludeDir", neverallowNotInIncludeDir)
-	exportedVars.ExportStringList("NeverAllowNoUseIncludeDir", neverallowNoUseIncludeDir)
-}
-
-func BazelCcToolchainVars(config Config) string {
-	return BazelToolchainVars(config, exportedVars)
-}
-
-var (
-	// echoEscaper escapes a string such that passing it to "echo -e" will produce the input value.
-	echoEscaper = strings.NewReplacer(
-		`\`, `\\`, // First escape existing backslashes so they aren't interpreted by `echo -e`.
-		"\n", `\n`, // Then replace newlines with \n
-	)
-
-	// echoEscaper reverses echoEscaper.
-	echoUnescaper = strings.NewReplacer(
-		`\n`, "\n",
-		`\\`, `\`,
-	)
-
-	// shellUnescaper reverses the replacer in proptools.ShellEscape
-	shellUnescaper = strings.NewReplacer(`'\''`, `'`)
-)
-
-func buildWriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
-	content = echoEscaper.Replace(content)
-	content = proptools.NinjaEscape(proptools.ShellEscapeIncludingSpaces(content))
-	if content == "" {
-		content = "''"
-	}
-	ctx.Build(pctx, BuildParams{
-		Rule:        writeFile,
-		Output:      outputFile,
-		Description: "write " + outputFile.Base(),
-		Args: map[string]string{
-			"content": content,
-		},
-	})
-}
-
-// WriteFileRule creates a ninja rule to write contents to a file.  The contents will be escaped
-// so that the file contains exactly the contents passed to the function, plus a trailing newline.
-func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
-	WriteFileRuleVerbatim(ctx, outputFile, content+"\n")
-}
-
-// WriteFileRuleVerbatim creates a ninja rule to write contents to a file.  The contents will be
-// escaped so that the file contains exactly the contents passed to the function.
-func WriteFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
-	// This is MAX_ARG_STRLEN subtracted with some safety to account for shell escapes
-	const SHARD_SIZE = 131072 - 10000
-
-	if len(content) > SHARD_SIZE {
-		var chunks WritablePaths
-		for i, c := range ShardString(content, SHARD_SIZE) {
-			tempPath := outputFile.ReplaceExtension(ctx, fmt.Sprintf("%s.%d", outputFile.Ext(), i))
-			buildWriteFileRule(ctx, tempPath, c)
-			chunks = append(chunks, tempPath)
-		}
-		ctx.Build(pctx, BuildParams{
-			Rule:        Cat,
-			Inputs:      chunks.Paths(),
-			Output:      outputFile,
-			Description: "Merging to " + outputFile.Base(),
-		})
-		return
-	}
-	buildWriteFileRule(ctx, outputFile, content)
-}
-
-func CatFileRule(ctx BuilderContext, paths Paths, outputFile WritablePath) {
-	ctx.Build(pctx, BuildParams{
-		Rule:        Cat,
-		Inputs:      paths,
-		Output:      outputFile,
-		Description: "combine files to " + outputFile.Base(),
-	})
-}
-
-// shellUnescape reverses proptools.ShellEscape
-func shellUnescape(s string) string {
-	// Remove leading and trailing quotes if present
-	if len(s) >= 2 && s[0] == '\'' {
-		s = s[1 : len(s)-1]
-	}
-	s = shellUnescaper.Replace(s)
-	return s
-}
-
-// ContentFromFileRuleForTests returns the content that was passed to a WriteFileRule for use
-// in tests.
-func ContentFromFileRuleForTests(t *testing.T, params TestingBuildParams) string {
-	t.Helper()
-	if g, w := params.Rule, writeFile; g != w {
-		t.Errorf("expected params.Rule to be %q, was %q", w, g)
-		return ""
-	}
-
-	content := params.Args["content"]
-	content = shellUnescape(content)
-	content = echoUnescaper.Replace(content)
-
-	return content
 }
 
 // GlobToListFileRule creates a rule that writes a list of files matching a pattern to a file.
diff --git a/android/deptag.go b/android/deptag.go
index a15443b..c7ba4d3 100644
--- a/android/deptag.go
+++ b/android/deptag.go
@@ -43,3 +43,15 @@
 	}
 	return false
 }
+
+type PropagateAconfigValidationDependencyTag interface {
+	PropagateAconfigValidation() bool
+}
+
+type AlwaysPropagateAconfigValidationDependencyTag struct{}
+
+func (p AlwaysPropagateAconfigValidationDependencyTag) PropagateAconfigValidation() bool {
+	return true
+}
+
+var _ PropagateAconfigValidationDependencyTag = AlwaysPropagateAconfigValidationDependencyTag{}
diff --git a/android/early_module_context.go b/android/early_module_context.go
new file mode 100644
index 0000000..cf1b5fc
--- /dev/null
+++ b/android/early_module_context.go
@@ -0,0 +1,177 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"os"
+	"text/scanner"
+
+	"github.com/google/blueprint"
+)
+
+// EarlyModuleContext provides methods that can be called early, as soon as the properties have
+// been parsed into the module and before any mutators have run.
+type EarlyModuleContext interface {
+	// Module returns the current module as a Module.  It should rarely be necessary, as the module already has a
+	// reference to itself.
+	Module() Module
+
+	// ModuleName returns the name of the module.  This is generally the value that was returned by Module.Name() when
+	// the module was created, but may have been modified by calls to BaseMutatorContext.Rename.
+	ModuleName() string
+
+	// ModuleDir returns the path to the directory that contains the definition of the module.
+	ModuleDir() string
+
+	// ModuleType returns the name of the module type that was used to create the module, as specified in
+	// RegisterModuleType.
+	ModuleType() string
+
+	// BlueprintFile returns the name of the blueprint file that contains the definition of this
+	// module.
+	BlueprintsFile() string
+
+	// ContainsProperty returns true if the specified property name was set in the module definition.
+	ContainsProperty(name string) bool
+
+	// Errorf reports an error at the specified position of the module definition file.
+	Errorf(pos scanner.Position, fmt string, args ...interface{})
+
+	// ModuleErrorf reports an error at the line number of the module type in the module definition.
+	ModuleErrorf(fmt string, args ...interface{})
+
+	// PropertyErrorf reports an error at the line number of a property in the module definition.
+	PropertyErrorf(property, fmt string, args ...interface{})
+
+	// OtherModulePropertyErrorf reports an error at the line number of a property in the given module definition.
+	OtherModulePropertyErrorf(module Module, property, fmt string, args ...interface{})
+
+	// Failed returns true if any errors have been reported.  In most cases the module can continue with generating
+	// build rules after an error, allowing it to report additional errors in a single run, but in cases where the error
+	// has prevented the module from creating necessary data it can return early when Failed returns true.
+	Failed() bool
+
+	// AddNinjaFileDeps adds dependencies on the specified files to the rule that creates the ninja manifest.  The
+	// primary builder will be rerun whenever the specified files are modified.
+	AddNinjaFileDeps(deps ...string)
+
+	DeviceSpecific() bool
+	SocSpecific() bool
+	ProductSpecific() bool
+	SystemExtSpecific() bool
+	Platform() bool
+
+	Config() Config
+	DeviceConfig() DeviceConfig
+
+	// Deprecated: use Config()
+	AConfig() Config
+
+	// GlobWithDeps returns a list of files that match the specified pattern but do not match any
+	// of the patterns in excludes.  It also adds efficient dependencies to rerun the primary
+	// builder whenever a file matching the pattern as added or removed, without rerunning if a
+	// file that does not match the pattern is added to a searched directory.
+	GlobWithDeps(pattern string, excludes []string) ([]string, error)
+
+	Glob(globPattern string, excludes []string) Paths
+	GlobFiles(globPattern string, excludes []string) Paths
+	IsSymlink(path Path) bool
+	Readlink(path Path) string
+
+	// Namespace returns the Namespace object provided by the NameInterface set by Context.SetNameInterface, or the
+	// default SimpleNameInterface if Context.SetNameInterface was not called.
+	Namespace() *Namespace
+}
+
+// Deprecated: use EarlyModuleContext instead
+type BaseContext interface {
+	EarlyModuleContext
+}
+
+type earlyModuleContext struct {
+	blueprint.EarlyModuleContext
+
+	kind   moduleKind
+	config Config
+}
+
+func (e *earlyModuleContext) Glob(globPattern string, excludes []string) Paths {
+	return Glob(e, globPattern, excludes)
+}
+
+func (e *earlyModuleContext) GlobFiles(globPattern string, excludes []string) Paths {
+	return GlobFiles(e, globPattern, excludes)
+}
+
+func (e *earlyModuleContext) IsSymlink(path Path) bool {
+	fileInfo, err := e.config.fs.Lstat(path.String())
+	if err != nil {
+		e.ModuleErrorf("os.Lstat(%q) failed: %s", path.String(), err)
+	}
+	return fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink
+}
+
+func (e *earlyModuleContext) Readlink(path Path) string {
+	dest, err := e.config.fs.Readlink(path.String())
+	if err != nil {
+		e.ModuleErrorf("os.Readlink(%q) failed: %s", path.String(), err)
+	}
+	return dest
+}
+
+func (e *earlyModuleContext) Module() Module {
+	module, _ := e.EarlyModuleContext.Module().(Module)
+	return module
+}
+
+func (e *earlyModuleContext) Config() Config {
+	return e.EarlyModuleContext.Config().(Config)
+}
+
+func (e *earlyModuleContext) AConfig() Config {
+	return e.config
+}
+
+func (e *earlyModuleContext) DeviceConfig() DeviceConfig {
+	return DeviceConfig{e.config.deviceConfig}
+}
+
+func (e *earlyModuleContext) Platform() bool {
+	return e.kind == platformModule
+}
+
+func (e *earlyModuleContext) DeviceSpecific() bool {
+	return e.kind == deviceSpecificModule
+}
+
+func (e *earlyModuleContext) SocSpecific() bool {
+	return e.kind == socSpecificModule
+}
+
+func (e *earlyModuleContext) ProductSpecific() bool {
+	return e.kind == productSpecificModule
+}
+
+func (e *earlyModuleContext) SystemExtSpecific() bool {
+	return e.kind == systemExtSpecificModule
+}
+
+func (e *earlyModuleContext) Namespace() *Namespace {
+	return e.EarlyModuleContext.Namespace().(*Namespace)
+}
+
+func (e *earlyModuleContext) OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{}) {
+	e.EarlyModuleContext.OtherModulePropertyErrorf(module, property, fmt, args)
+}
diff --git a/android/filegroup.go b/android/filegroup.go
index 6cc9232..86d7b4b 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -15,16 +15,10 @@
 package android
 
 import (
-	"path/filepath"
-	"regexp"
+	"maps"
 	"strings"
 
-	"android/soong/bazel"
-	"android/soong/bazel/cquery"
-	"android/soong/ui/metrics/bp2build_metrics_proto"
-
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/proptools"
 )
 
 func init() {
@@ -40,185 +34,6 @@
 	ctx.RegisterModuleType("filegroup_defaults", FileGroupDefaultsFactory)
 }
 
-var convertedProtoLibrarySuffix = "_bp2build_converted"
-
-// IsFilegroup checks that a module is a filegroup type
-func IsFilegroup(ctx bazel.OtherModuleContext, m blueprint.Module) bool {
-	return ctx.OtherModuleType(m) == "filegroup"
-}
-
-var (
-	// ignoring case, checks for proto or protos as an independent word in the name, whether at the
-	// beginning, end, or middle. e.g. "proto.foo", "bar-protos", "baz_proto_srcs" would all match
-	filegroupLikelyProtoPattern = regexp.MustCompile("(?i)(^|[^a-z])proto(s)?([^a-z]|$)")
-	filegroupLikelyAidlPattern  = regexp.MustCompile("(?i)(^|[^a-z])aidl([^a-z]|$)")
-
-	ProtoSrcLabelPartition = bazel.LabelPartition{
-		Extensions:  []string{".proto"},
-		LabelMapper: isFilegroupWithPattern(filegroupLikelyProtoPattern),
-	}
-	AidlSrcLabelPartition = bazel.LabelPartition{
-		Extensions:  []string{".aidl"},
-		LabelMapper: isFilegroupWithPattern(filegroupLikelyAidlPattern),
-	}
-)
-
-func isFilegroupWithPattern(pattern *regexp.Regexp) bazel.LabelMapper {
-	return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
-		m, exists := ctx.ModuleFromName(label.OriginalModuleName)
-		labelStr := label.Label
-		if !exists || !IsFilegroup(ctx, m) {
-			return labelStr, false
-		}
-		likelyMatched := pattern.MatchString(label.OriginalModuleName)
-		return labelStr, likelyMatched
-	}
-}
-
-// https://docs.bazel.build/versions/master/be/general.html#filegroup
-type bazelFilegroupAttributes struct {
-	Srcs                bazel.LabelListAttribute
-	Applicable_licenses bazel.LabelListAttribute
-}
-
-type bazelAidlLibraryAttributes struct {
-	Srcs                bazel.LabelListAttribute
-	Strip_import_prefix *string
-}
-
-// api srcs can be contained in filegroups.
-// this should be generated in api_bp2build workspace as well.
-func (fg *fileGroup) ConvertWithApiBp2build(ctx TopDownMutatorContext) {
-	fg.ConvertWithBp2build(ctx)
-}
-
-// ConvertWithBp2build performs bp2build conversion of filegroup
-func (fg *fileGroup) ConvertWithBp2build(ctx TopDownMutatorContext) {
-	srcs := bazel.MakeLabelListAttribute(
-		BazelLabelForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs))
-
-	// For Bazel compatibility, don't generate the filegroup if there is only 1
-	// source file, and that the source file is named the same as the module
-	// itself. In Bazel, eponymous filegroups like this would be an error.
-	//
-	// Instead, dependents on this single-file filegroup can just depend
-	// on the file target, instead of rule target, directly.
-	//
-	// You may ask: what if a filegroup has multiple files, and one of them
-	// shares the name? The answer: we haven't seen that in the wild, and
-	// should lock Soong itself down to prevent the behavior. For now,
-	// we raise an error if bp2build sees this problem.
-	for _, f := range srcs.Value.Includes {
-		if f.Label == fg.Name() {
-			if len(srcs.Value.Includes) > 1 {
-				ctx.ModuleErrorf("filegroup '%s' cannot contain a file with the same name", fg.Name())
-			}
-			ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_SRC_NAME_COLLISION, "")
-			return
-		}
-	}
-
-	// Convert module that has only AIDL files to aidl_library
-	// If the module has a mixed bag of AIDL and non-AIDL files, split the filegroup manually
-	// and then convert
-	if fg.ShouldConvertToAidlLibrary(ctx) {
-		tags := []string{"apex_available=//apex_available:anyapex"}
-		attrs := &bazelAidlLibraryAttributes{
-			Srcs:                srcs,
-			Strip_import_prefix: fg.properties.Path,
-		}
-
-		props := bazel.BazelTargetModuleProperties{
-			Rule_class:        "aidl_library",
-			Bzl_load_location: "//build/bazel/rules/aidl:aidl_library.bzl",
-		}
-
-		ctx.CreateBazelTargetModule(
-			props,
-			CommonAttributes{
-				Name: fg.Name(),
-				Tags: bazel.MakeStringListAttribute(tags),
-			},
-			attrs)
-	} else {
-		if fg.ShouldConvertToProtoLibrary(ctx) {
-			pkgToSrcs := partitionSrcsByPackage(ctx.ModuleDir(), bazel.MakeLabelList(srcs.Value.Includes))
-			if len(pkgToSrcs) > 1 {
-				ctx.ModuleErrorf("TODO: Add bp2build support for multiple package .protosrcs in filegroup")
-				return
-			}
-			pkg := SortedKeys(pkgToSrcs)[0]
-			attrs := &ProtoAttrs{
-				Srcs:                bazel.MakeLabelListAttribute(pkgToSrcs[pkg]),
-				Strip_import_prefix: fg.properties.Path,
-			}
-
-			tags := []string{
-				"apex_available=//apex_available:anyapex",
-				// TODO(b/246997908): we can remove this tag if we could figure out a solution for this bug.
-				"manual",
-			}
-			if pkg != ctx.ModuleDir() {
-				// Since we are creating the proto_library in a subpackage, create an import_prefix relative to the current package
-				if rel, err := filepath.Rel(ctx.ModuleDir(), pkg); err != nil {
-					ctx.ModuleErrorf("Could not get relative path for %v %v", pkg, err)
-				} else if rel != "." {
-					attrs.Import_prefix = &rel
-					// Strip the package prefix
-					attrs.Strip_import_prefix = proptools.StringPtr("")
-				}
-			}
-
-			ctx.CreateBazelTargetModule(
-				bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
-				CommonAttributes{
-					Name: fg.Name() + "_proto",
-					Dir:  proptools.StringPtr(pkg),
-					Tags: bazel.MakeStringListAttribute(tags),
-				},
-				attrs)
-
-			// Create an alias in the current dir. The actual target might exist in a different package, but rdeps
-			// can reliabily use this alias
-			ctx.CreateBazelTargetModule(
-				bazel.BazelTargetModuleProperties{Rule_class: "alias"},
-				CommonAttributes{
-					Name: fg.Name() + convertedProtoLibrarySuffix,
-					// TODO(b/246997908): we can remove this tag if we could figure out a solution for this bug.
-					Tags: bazel.MakeStringListAttribute(tags),
-				},
-				&bazelAliasAttributes{
-					Actual: bazel.MakeLabelAttribute("//" + pkg + ":" + fg.Name() + "_proto"),
-				},
-			)
-		}
-
-		// TODO(b/242847534): Still convert to a filegroup because other unconverted
-		// modules may depend on the filegroup
-		attrs := &bazelFilegroupAttributes{
-			Srcs: srcs,
-		}
-
-		props := bazel.BazelTargetModuleProperties{
-			Rule_class:        "filegroup",
-			Bzl_load_location: "//build/bazel/rules:filegroup.bzl",
-		}
-
-		ctx.CreateBazelTargetModule(props, CommonAttributes{Name: fg.Name()}, attrs)
-	}
-}
-
-type FileGroupPath interface {
-	GetPath(ctx TopDownMutatorContext) string
-}
-
-func (fg *fileGroup) GetPath(ctx TopDownMutatorContext) string {
-	if fg.properties.Path != nil {
-		return *fg.properties.Path
-	}
-	return ""
-}
-
 type fileGroupProperties struct {
 	// srcs lists files that will be included in this filegroup
 	Srcs []string `android:"path"`
@@ -238,18 +53,15 @@
 
 type fileGroup struct {
 	ModuleBase
-	BazelModuleBase
 	DefaultableModuleBase
-	FileGroupAsLibrary
-	FileGroupPath
 	properties fileGroupProperties
 	srcs       Paths
+
+	// Aconfig files for all transitive deps.  Also exposed via TransitiveDeclarationsInfo
+	mergedAconfigFiles map[string]Paths
 }
 
-var _ MixedBuildBuildable = (*fileGroup)(nil)
 var _ SourceFileProducer = (*fileGroup)(nil)
-var _ FileGroupAsLibrary = (*fileGroup)(nil)
-var _ FileGroupPath = (*fileGroup)(nil)
 
 // filegroup contains a list of files that are referenced by other modules
 // properties (such as "srcs") using the syntax ":<name>". filegroup are
@@ -258,7 +70,6 @@
 	module := &fileGroup{}
 	module.AddProperties(&module.properties)
 	InitAndroidModule(module)
-	InitBazelModule(module)
 	InitDefaultableModule(module)
 	return module
 }
@@ -285,6 +96,27 @@
 	if fg.properties.Path != nil {
 		fg.srcs = PathsWithModuleSrcSubDir(ctx, fg.srcs, String(fg.properties.Path))
 	}
+	SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: fg.srcs.Strings()})
+	CollectDependencyAconfigFiles(ctx, &fg.mergedAconfigFiles)
+
+	var aconfigDeclarations []string
+	var intermediateCacheOutputPaths Paths
+	var srcjars Paths
+	modeInfos := make(map[string]ModeInfo)
+	ctx.VisitDirectDeps(func(module Module) {
+		if dep, ok := OtherModuleProvider(ctx, module, CodegenInfoProvider); ok {
+			aconfigDeclarations = append(aconfigDeclarations, dep.AconfigDeclarations...)
+			intermediateCacheOutputPaths = append(intermediateCacheOutputPaths, dep.IntermediateCacheOutputPaths...)
+			srcjars = append(srcjars, dep.Srcjars...)
+			maps.Copy(modeInfos, dep.ModeInfos)
+		}
+	})
+	SetProvider(ctx, CodegenInfoProvider, CodegenInfo{
+		AconfigDeclarations:          aconfigDeclarations,
+		IntermediateCacheOutputPaths: intermediateCacheOutputPaths,
+		Srcjars:                      srcjars,
+		ModeInfos:                    modeInfos,
+	})
 }
 
 func (fg *fileGroup) Srcs() Paths {
@@ -297,101 +129,6 @@
 	}
 }
 
-func (fg *fileGroup) QueueBazelCall(ctx BaseModuleContext) {
-	bazelCtx := ctx.Config().BazelContext
-
-	bazelCtx.QueueBazelRequest(
-		fg.GetBazelLabel(ctx, fg),
-		cquery.GetOutputFiles,
-		configKey{arch: Common.String(), osType: CommonOS})
-}
-
-func (fg *fileGroup) IsMixedBuildSupported(ctx BaseModuleContext) bool {
-	// TODO(b/247782695), TODO(b/242847534) Fix mixed builds for filegroups
-	return false
-}
-
-func (fg *fileGroup) ProcessBazelQueryResponse(ctx ModuleContext) {
-	bazelCtx := ctx.Config().BazelContext
-	// This is a short-term solution because we rely on info from Android.bp to handle
-	// a converted module. This will block when we want to remove Android.bp for all
-	// converted modules at some point.
-	// TODO(b/242847534): Implement a long-term solution in which we don't need to rely
-	// on info form Android.bp for modules that are already converted to Bazel
-	relativeRoot := ctx.ModuleDir()
-	if fg.properties.Path != nil {
-		relativeRoot = filepath.Join(relativeRoot, *fg.properties.Path)
-	}
-
-	filePaths, err := bazelCtx.GetOutputFiles(fg.GetBazelLabel(ctx, fg), configKey{arch: Common.String(), osType: CommonOS})
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-		return
-	}
-
-	bazelOuts := make(Paths, 0, len(filePaths))
-	for _, p := range filePaths {
-		bazelOuts = append(bazelOuts, PathForBazelOutRelative(ctx, relativeRoot, p))
-	}
-	fg.srcs = bazelOuts
-}
-
-func (fg *fileGroup) ShouldConvertToAidlLibrary(ctx BazelConversionPathContext) bool {
-	return fg.shouldConvertToLibrary(ctx, ".aidl")
-}
-
-func (fg *fileGroup) ShouldConvertToProtoLibrary(ctx BazelConversionPathContext) bool {
-	return fg.shouldConvertToLibrary(ctx, ".proto")
-}
-
-func (fg *fileGroup) shouldConvertToLibrary(ctx BazelConversionPathContext, suffix string) bool {
-	if len(fg.properties.Srcs) == 0 || !fg.ShouldConvertWithBp2build(ctx) {
-		return false
-	}
-	for _, src := range fg.properties.Srcs {
-		if !strings.HasSuffix(src, suffix) {
-			return false
-		}
-	}
-	return true
-}
-
-func (fg *fileGroup) GetAidlLibraryLabel(ctx BazelConversionPathContext) string {
-	return fg.getFileGroupAsLibraryLabel(ctx)
-}
-
-func (fg *fileGroup) GetProtoLibraryLabel(ctx BazelConversionPathContext) string {
-	return fg.getFileGroupAsLibraryLabel(ctx) + convertedProtoLibrarySuffix
-}
-
-func (fg *fileGroup) getFileGroupAsLibraryLabel(ctx BazelConversionPathContext) string {
-	if ctx.OtherModuleDir(fg.module) == ctx.ModuleDir() {
-		return ":" + fg.Name()
-	} else {
-		return fg.GetBazelLabel(ctx, fg)
-	}
-}
-
-// Given a name in srcs prop, check to see if the name references a filegroup
-// and the filegroup is converted to aidl_library
-func IsConvertedToAidlLibrary(ctx BazelConversionPathContext, name string) bool {
-	if fg, ok := ToFileGroupAsLibrary(ctx, name); ok {
-		return fg.ShouldConvertToAidlLibrary(ctx)
-	}
-	return false
-}
-
-func ToFileGroupAsLibrary(ctx BazelConversionPathContext, name string) (FileGroupAsLibrary, bool) {
-	if module, ok := ctx.ModuleFromName(name); ok {
-		if IsFilegroup(ctx, module) {
-			if fg, ok := module.(FileGroupAsLibrary); ok {
-				return fg, true
-			}
-		}
-	}
-	return nil, false
-}
-
 // Defaults
 type FileGroupDefaults struct {
 	ModuleBase
diff --git a/android/filegroup_test.go b/android/filegroup_test.go
index 893da57..14e9368 100644
--- a/android/filegroup_test.go
+++ b/android/filegroup_test.go
@@ -40,17 +40,8 @@
 	}
 
 	for _, testCase := range testCases {
-		outBaseDir := "outputbase"
 		result := GroupFixturePreparers(
 			PrepareForTestWithFilegroup,
-			FixtureModifyConfig(func(config Config) {
-				config.BazelContext = MockBazelContext{
-					OutputBaseDir: outBaseDir,
-					LabelToOutputFiles: map[string][]string{
-						"//:baz": []string{"a/b/c/d/test.aidl"},
-					},
-				}
-			}),
 		).RunTestWithBp(t, testCase.bp)
 
 		fg := result.Module("baz", "").(*fileGroup)
diff --git a/android/fixture.go b/android/fixture.go
index 6660afd..5ad47e8 100644
--- a/android/fixture.go
+++ b/android/fixture.go
@@ -275,6 +275,15 @@
 	})
 }
 
+// Sync the mock filesystem with the current config, then modify the context,
+// This allows context modification that requires filesystem access.
+func FixtureModifyContextWithMockFs(mutator func(ctx *TestContext)) FixturePreparer {
+	return newSimpleFixturePreparer(func(f *fixture) {
+		f.config.mockFileSystem("", f.mockFS)
+		mutator(f.ctx)
+	})
+}
+
 func FixtureRegisterWithContext(registeringFunc func(ctx RegistrationContext)) FixturePreparer {
 	return FixtureModifyContext(func(ctx *TestContext) { registeringFunc(ctx) })
 }
diff --git a/android/license.go b/android/license.go
index a09422b..5bffc25 100644
--- a/android/license.go
+++ b/android/license.go
@@ -15,12 +15,7 @@
 package android
 
 import (
-	"fmt"
-	"os"
-
 	"github.com/google/blueprint"
-
-	"android/soong/bazel"
 )
 
 type licenseKindDependencyTag struct {
@@ -53,54 +48,13 @@
 	Visibility []string
 }
 
-var _ Bazelable = &licenseModule{}
-
 type licenseModule struct {
 	ModuleBase
 	DefaultableModuleBase
-	BazelModuleBase
 
 	properties licenseProperties
 }
 
-type bazelLicenseAttributes struct {
-	License_kinds    []string
-	Copyright_notice *string
-	License_text     bazel.LabelAttribute
-	Package_name     *string
-	Visibility       []string
-}
-
-func (m *licenseModule) ConvertWithBp2build(ctx TopDownMutatorContext) {
-	attrs := &bazelLicenseAttributes{
-		License_kinds:    m.properties.License_kinds,
-		Copyright_notice: m.properties.Copyright_notice,
-		Package_name:     m.properties.Package_name,
-		Visibility:       m.properties.Visibility,
-	}
-
-	// TODO(asmundak): Soong supports multiple license texts while Bazel's license
-	// rule does not. Have android_license create a genrule to concatenate multiple
-	// license texts.
-	if len(m.properties.License_text) > 1 && ctx.Config().IsEnvTrue("BP2BUILD_VERBOSE") {
-		fmt.Fprintf(os.Stderr, "warning: using only the first license_text item from //%s:%s\n",
-			ctx.ModuleDir(), m.Name())
-	}
-	if len(m.properties.License_text) >= 1 {
-		attrs.License_text.SetValue(BazelLabelForModuleSrcSingle(ctx, m.properties.License_text[0]))
-	}
-
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "android_license",
-			Bzl_load_location: "//build/bazel/rules/license:license.bzl",
-		},
-		CommonAttributes{
-			Name: m.Name(),
-		},
-		attrs)
-}
-
 func (m *licenseModule) DepsMutator(ctx BottomUpMutatorContext) {
 	for i, license := range m.properties.License_kinds {
 		for j := i + 1; j < len(m.properties.License_kinds); j++ {
@@ -131,14 +85,13 @@
 	module := &licenseModule{}
 
 	base := module.base()
-	module.AddProperties(&base.nameProperties, &module.properties, &base.commonProperties.BazelConversionStatus)
+	module.AddProperties(&base.nameProperties, &module.properties)
 
 	// The visibility property needs to be checked and parsed by the visibility module.
 	setPrimaryVisibilityProperty(module, "visibility", &module.properties.Visibility)
 
 	initAndroidModuleBase(module)
 	InitDefaultableModule(module)
-	InitBazelModule(module)
 
 	return module
 }
diff --git a/android/license_kind.go b/android/license_kind.go
index 24b91e4..838dedd 100644
--- a/android/license_kind.go
+++ b/android/license_kind.go
@@ -14,8 +14,6 @@
 
 package android
 
-import "android/soong/bazel"
-
 func init() {
 	RegisterLicenseKindBuildComponents(InitRegistrationContext)
 }
@@ -34,39 +32,13 @@
 	Visibility []string
 }
 
-var _ Bazelable = &licenseKindModule{}
-
 type licenseKindModule struct {
 	ModuleBase
 	DefaultableModuleBase
-	BazelModuleBase
 
 	properties licenseKindProperties
 }
 
-type bazelLicenseKindAttributes struct {
-	Conditions []string
-	Url        string
-	Visibility []string
-}
-
-func (m *licenseKindModule) ConvertWithBp2build(ctx TopDownMutatorContext) {
-	attrs := &bazelLicenseKindAttributes{
-		Conditions: m.properties.Conditions,
-		Url:        m.properties.Url,
-		Visibility: m.properties.Visibility,
-	}
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "license_kind",
-			Bzl_load_location: "@rules_license//rules:license_kind.bzl",
-		},
-		CommonAttributes{
-			Name: m.Name(),
-		},
-		attrs)
-}
-
 func (m *licenseKindModule) DepsMutator(ctx BottomUpMutatorContext) {
 	// Nothing to do.
 }
@@ -79,14 +51,13 @@
 	module := &licenseKindModule{}
 
 	base := module.base()
-	module.AddProperties(&base.nameProperties, &module.properties, &base.commonProperties.BazelConversionStatus)
+	module.AddProperties(&base.nameProperties, &module.properties)
 
 	// The visibility property needs to be checked and parsed by the visibility module.
 	setPrimaryVisibilityProperty(module, "visibility", &module.properties.Visibility)
 
 	initAndroidModuleBase(module)
 	InitDefaultableModule(module)
-	InitBazelModule(module)
 
 	return module
 }
diff --git a/android/license_metadata.go b/android/license_metadata.go
index 8933bd5..eabb1b1 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -50,7 +50,14 @@
 		outputFiles = PathsIfNonNil(outputFiles...)
 	}
 
-	isContainer := isContainerFromFileExtensions(base.installFiles, outputFiles)
+	// Only pass the last installed file to isContainerFromFileExtensions so a *.zip file in test data
+	// doesn't mark the whole module as a container.
+	var installFiles InstallPaths
+	if len(base.installFiles) > 0 {
+		installFiles = InstallPaths{base.installFiles[len(base.installFiles)-1]}
+	}
+
+	isContainer := isContainerFromFileExtensions(installFiles, outputFiles)
 
 	var allDepMetadataFiles Paths
 	var allDepMetadataArgs []string
@@ -70,9 +77,13 @@
 		if ctx.OtherModuleDependencyTag(dep) == DefaultsDepTag {
 			return
 		}
+		// The required dependencies just say modules A and B should be installed together.
+		// It doesn't mean that one is built using the other.
+		if ctx.OtherModuleDependencyTag(dep) == RequiredDepTag {
+			return
+		}
 
-		if ctx.OtherModuleHasProvider(dep, LicenseMetadataProvider) {
-			info := ctx.OtherModuleProvider(dep, LicenseMetadataProvider).(*LicenseMetadataInfo)
+		if info, ok := OtherModuleProvider(ctx, dep, LicenseMetadataProvider); ok {
 			allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath)
 			if isContainer || isInstallDepNeeded(dep, ctx.OtherModuleDependencyTag(dep)) {
 				allDepMetadataDepSets = append(allDepMetadataDepSets, info.LicenseMetadataDepSet)
@@ -168,7 +179,7 @@
 		},
 	})
 
-	ctx.SetProvider(LicenseMetadataProvider, &LicenseMetadataInfo{
+	SetProvider(ctx, LicenseMetadataProvider, &LicenseMetadataInfo{
 		LicenseMetadataPath:   licenseMetadataFile,
 		LicenseMetadataDepSet: NewDepSet(TOPOLOGICAL, Paths{licenseMetadataFile}, allDepMetadataDepSets),
 	})
@@ -193,7 +204,7 @@
 }
 
 // LicenseMetadataProvider is used to propagate license metadata paths between modules.
-var LicenseMetadataProvider = blueprint.NewProvider(&LicenseMetadataInfo{})
+var LicenseMetadataProvider = blueprint.NewProvider[*LicenseMetadataInfo]()
 
 // LicenseMetadataInfo stores the license metadata path for a module.
 type LicenseMetadataInfo struct {
diff --git a/android/licenses.go b/android/licenses.go
index c6b3243..be1eede 100644
--- a/android/licenses.go
+++ b/android/licenses.go
@@ -230,7 +230,7 @@
 	licenseInfo := LicenseInfo{
 		Licenses: licenses,
 	}
-	ctx.SetProvider(LicenseInfoProvider, licenseInfo)
+	SetProvider(ctx, LicenseInfoProvider, licenseInfo)
 }
 
 // Update a property string array with a distinct union of its values and a list of new values.
@@ -322,7 +322,7 @@
 	Licenses []string
 }
 
-var LicenseInfoProvider = blueprint.NewProvider(LicenseInfo{})
+var LicenseInfoProvider = blueprint.NewProvider[LicenseInfo]()
 
 func init() {
 	RegisterMakeVarsProvider(pctx, licensesMakeVarsProvider)
diff --git a/android/makevars.go b/android/makevars.go
index 0800190..4039e7e 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -16,9 +16,11 @@
 
 import (
 	"bytes"
+	"cmp"
 	"fmt"
 	"path/filepath"
 	"runtime"
+	"slices"
 	"sort"
 	"strings"
 
@@ -92,7 +94,7 @@
 	ModuleDir(module blueprint.Module) string
 	ModuleSubDir(module blueprint.Module) string
 	ModuleType(module blueprint.Module) string
-	ModuleProvider(module blueprint.Module, key blueprint.ProviderKey) interface{}
+	moduleProvider(module blueprint.Module, key blueprint.AnyProviderKey) (any, bool)
 	BlueprintFile(module blueprint.Module) string
 
 	ModuleErrorf(module blueprint.Module, format string, args ...interface{})
@@ -242,6 +244,8 @@
 	var dists []dist
 	var phonies []phony
 	var katiInstalls []katiInstall
+	var katiInitRcInstalls []katiInstall
+	var katiVintfManifestInstalls []katiInstall
 	var katiSymlinks []katiInstall
 
 	providers := append([]makeVarsProvider(nil), makeVarsInitProviders...)
@@ -275,10 +279,33 @@
 
 		if m.ExportedToMake() {
 			katiInstalls = append(katiInstalls, m.base().katiInstalls...)
+			katiInitRcInstalls = append(katiInitRcInstalls, m.base().katiInitRcInstalls...)
+			katiVintfManifestInstalls = append(katiVintfManifestInstalls, m.base().katiVintfInstalls...)
 			katiSymlinks = append(katiSymlinks, m.base().katiSymlinks...)
 		}
 	})
 
+	compareKatiInstalls := func(a, b katiInstall) int {
+		aTo, bTo := a.to.String(), b.to.String()
+		if cmpTo := cmp.Compare(aTo, bTo); cmpTo != 0 {
+			return cmpTo
+		}
+
+		aFrom, bFrom := a.from.String(), b.from.String()
+		return cmp.Compare(aFrom, bFrom)
+	}
+
+	slices.SortFunc(katiInitRcInstalls, compareKatiInstalls)
+	katiInitRcInstalls = slices.CompactFunc(katiInitRcInstalls, func(a, b katiInstall) bool {
+		return compareKatiInstalls(a, b) == 0
+	})
+	katiInstalls = append(katiInstalls, katiInitRcInstalls...)
+
+	slices.SortFunc(katiVintfManifestInstalls, compareKatiInstalls)
+	katiVintfManifestInstalls = slices.CompactFunc(katiVintfManifestInstalls, func(a, b katiInstall) bool {
+		return compareKatiInstalls(a, b) == 0
+	})
+
 	if ctx.Failed() {
 		return
 	}
@@ -316,7 +343,7 @@
 		ctx.Errorf(err.Error())
 	}
 
-	installsBytes := s.writeInstalls(katiInstalls, katiSymlinks)
+	installsBytes := s.writeInstalls(katiInstalls, katiSymlinks, katiVintfManifestInstalls)
 	if err := pathtools.WriteFileIfChanged(installsFile, installsBytes, 0666); err != nil {
 		ctx.Errorf(err.Error())
 	}
@@ -438,7 +465,7 @@
 // writeInstalls writes the list of install rules generated by Soong to a makefile.  The rules
 // are exported to Make instead of written directly to the ninja file so that main.mk can add
 // the dependencies from the `required` property that are hard to resolve in Soong.
-func (s *makeVarsSingleton) writeInstalls(installs, symlinks []katiInstall) []byte {
+func (s *makeVarsSingleton) writeInstalls(installs, symlinks, katiVintfManifestInstalls []katiInstall) []byte {
 	buf := &bytes.Buffer{}
 
 	fmt.Fprint(buf, `# Autogenerated file
@@ -486,9 +513,9 @@
 	for _, symlink := range symlinks {
 		fmt.Fprintf(buf, "%s:", symlink.to.String())
 		if symlink.from != nil {
-			// The symlink doesn't need updating when the target is modified, but we sometimes
-			// have a dependency on a symlink to a binary instead of to the binary directly, and
-			// the mtime of the symlink must be updated when the binary is modified, so use a
+			// The katiVintfManifestInstall doesn't need updating when the target is modified, but we sometimes
+			// have a dependency on a katiVintfManifestInstall to a binary instead of to the binary directly, and
+			// the mtime of the katiVintfManifestInstall must be updated when the binary is modified, so use a
 			// normal dependency here instead of an order-only dependency.
 			fmt.Fprintf(buf, " %s", symlink.from.String())
 		}
@@ -507,7 +534,7 @@
 		if symlink.from != nil {
 			rel, err := filepath.Rel(filepath.Dir(symlink.to.String()), symlink.from.String())
 			if err != nil {
-				panic(fmt.Errorf("failed to find relative path for symlink from %q to %q: %w",
+				panic(fmt.Errorf("failed to find relative path for katiVintfManifestInstall from %q to %q: %w",
 					symlink.from.String(), symlink.to.String(), err))
 			}
 			fromStr = rel
@@ -521,6 +548,19 @@
 		fmt.Fprintln(buf)
 	}
 
+	for _, install := range katiVintfManifestInstalls {
+		// Write a rule for each vintf install request that calls the copy-vintf-manifest-chedk make function.
+		fmt.Fprintf(buf, "$(eval $(call copy-vintf-manifest-checked, %s, %s))\n", install.from.String(), install.to.String())
+
+		if len(install.implicitDeps) > 0 {
+			panic(fmt.Errorf("unsupported implicitDeps %q in vintf install rule %q", install.implicitDeps, install.to))
+		}
+		if len(install.orderOnlyDeps) > 0 {
+			panic(fmt.Errorf("unsupported orderOnlyDeps %q in vintf install rule %q", install.orderOnlyDeps, install.to))
+		}
+
+		fmt.Fprintln(buf)
+	}
 	return buf.Bytes()
 }
 
diff --git a/android/metrics.go b/android/metrics.go
index 63c72cd..6834b1b 100644
--- a/android/metrics.go
+++ b/android/metrics.go
@@ -15,9 +15,12 @@
 package android
 
 import (
+	"bytes"
 	"io/ioutil"
+	"os"
 	"runtime"
-	"sort"
+	"strconv"
+	"time"
 
 	"github.com/google/blueprint/metrics"
 	"google.golang.org/protobuf/proto"
@@ -27,18 +30,21 @@
 
 var soongMetricsOnceKey = NewOnceKey("soong metrics")
 
-type SoongMetrics struct {
-	Modules  int
-	Variants int
+type soongMetrics struct {
+	modules       int
+	variants      int
+	perfCollector perfCollector
 }
 
-func readSoongMetrics(config Config) (SoongMetrics, bool) {
-	soongMetrics, ok := config.Peek(soongMetricsOnceKey)
-	if ok {
-		return soongMetrics.(SoongMetrics), true
-	} else {
-		return SoongMetrics{}, false
-	}
+type perfCollector struct {
+	events []*soong_metrics_proto.PerfCounters
+	stop   chan<- bool
+}
+
+func getSoongMetrics(config Config) *soongMetrics {
+	return config.Once(soongMetricsOnceKey, func() interface{} {
+		return &soongMetrics{}
+	}).(*soongMetrics)
 }
 
 func init() {
@@ -50,27 +56,27 @@
 type soongMetricsSingleton struct{}
 
 func (soongMetricsSingleton) GenerateBuildActions(ctx SingletonContext) {
-	metrics := SoongMetrics{}
+	metrics := getSoongMetrics(ctx.Config())
 	ctx.VisitAllModules(func(m Module) {
 		if ctx.PrimaryModule(m) == m {
-			metrics.Modules++
+			metrics.modules++
 		}
-		metrics.Variants++
-	})
-	ctx.Config().Once(soongMetricsOnceKey, func() interface{} {
-		return metrics
+		metrics.variants++
 	})
 }
 
 func collectMetrics(config Config, eventHandler *metrics.EventHandler) *soong_metrics_proto.SoongBuildMetrics {
 	metrics := &soong_metrics_proto.SoongBuildMetrics{}
 
-	soongMetrics, ok := readSoongMetrics(config)
-	if ok {
-		metrics.Modules = proto.Uint32(uint32(soongMetrics.Modules))
-		metrics.Variants = proto.Uint32(uint32(soongMetrics.Variants))
+	soongMetrics := getSoongMetrics(config)
+	if soongMetrics.modules > 0 {
+		metrics.Modules = proto.Uint32(uint32(soongMetrics.modules))
+		metrics.Variants = proto.Uint32(uint32(soongMetrics.variants))
 	}
 
+	soongMetrics.perfCollector.stop <- true
+	metrics.PerfCounters = soongMetrics.perfCollector.events
+
 	memStats := runtime.MemStats{}
 	runtime.ReadMemStats(&memStats)
 	metrics.MaxHeapSize = proto.Uint64(memStats.HeapSys)
@@ -86,27 +92,117 @@
 		}
 		metrics.Events = append(metrics.Events, &perfInfo)
 	}
-	mixedBuildsInfo := soong_metrics_proto.MixedBuildsInfo{}
-	mixedBuildEnabledModules := make([]string, 0, len(config.mixedBuildEnabledModules))
-	for module, _ := range config.mixedBuildEnabledModules {
-		mixedBuildEnabledModules = append(mixedBuildEnabledModules, module)
-	}
-
-	mixedBuildDisabledModules := make([]string, 0, len(config.mixedBuildDisabledModules))
-	for module, _ := range config.mixedBuildDisabledModules {
-		mixedBuildDisabledModules = append(mixedBuildDisabledModules, module)
-	}
-	// Sorted for deterministic output.
-	sort.Strings(mixedBuildEnabledModules)
-	sort.Strings(mixedBuildDisabledModules)
-
-	mixedBuildsInfo.MixedBuildEnabledModules = mixedBuildEnabledModules
-	mixedBuildsInfo.MixedBuildDisabledModules = mixedBuildDisabledModules
-	metrics.MixedBuildsInfo = &mixedBuildsInfo
 
 	return metrics
 }
 
+func StartBackgroundMetrics(config Config) {
+	perfCollector := &getSoongMetrics(config).perfCollector
+	stop := make(chan bool)
+	perfCollector.stop = stop
+
+	previousTime := time.Now()
+	previousCpuTime := readCpuTime()
+
+	ticker := time.NewTicker(time.Second)
+
+	go func() {
+		for {
+			select {
+			case <-stop:
+				ticker.Stop()
+				return
+			case <-ticker.C:
+				// carry on
+			}
+
+			currentTime := time.Now()
+
+			var memStats runtime.MemStats
+			runtime.ReadMemStats(&memStats)
+
+			currentCpuTime := readCpuTime()
+
+			interval := currentTime.Sub(previousTime)
+			intervalCpuTime := currentCpuTime - previousCpuTime
+			intervalCpuPercent := intervalCpuTime * 100 / interval
+
+			// heapAlloc is the memory that has been allocated on the heap but not yet GC'd.  It may be referenced,
+			// or unrefenced but not yet GC'd.
+			heapAlloc := memStats.HeapAlloc
+			// heapUnused is the memory that was previously used by the heap, but is currently not used.  It does not
+			// count memory that was used and then returned to the OS.
+			heapUnused := memStats.HeapIdle - memStats.HeapReleased
+			// heapOverhead is the memory used by the allocator and GC
+			heapOverhead := memStats.MSpanSys + memStats.MCacheSys + memStats.GCSys
+			// otherMem is the memory used outside of the heap.
+			otherMem := memStats.Sys - memStats.HeapSys - heapOverhead
+
+			perfCollector.events = append(perfCollector.events, &soong_metrics_proto.PerfCounters{
+				Time: proto.Uint64(uint64(currentTime.UnixNano())),
+				Groups: []*soong_metrics_proto.PerfCounterGroup{
+					{
+						Name: proto.String("cpu"),
+						Counters: []*soong_metrics_proto.PerfCounter{
+							{Name: proto.String("cpu_percent"), Value: proto.Int64(int64(intervalCpuPercent))},
+						},
+					}, {
+						Name: proto.String("memory"),
+						Counters: []*soong_metrics_proto.PerfCounter{
+							{Name: proto.String("heap_alloc"), Value: proto.Int64(int64(heapAlloc))},
+							{Name: proto.String("heap_unused"), Value: proto.Int64(int64(heapUnused))},
+							{Name: proto.String("heap_overhead"), Value: proto.Int64(int64(heapOverhead))},
+							{Name: proto.String("other"), Value: proto.Int64(int64(otherMem))},
+						},
+					},
+				},
+			})
+
+			previousTime = currentTime
+			previousCpuTime = currentCpuTime
+		}
+	}()
+}
+
+func readCpuTime() time.Duration {
+	if runtime.GOOS != "linux" {
+		return 0
+	}
+
+	stat, err := os.ReadFile("/proc/self/stat")
+	if err != nil {
+		return 0
+	}
+
+	endOfComm := bytes.LastIndexByte(stat, ')')
+	if endOfComm < 0 || endOfComm > len(stat)-2 {
+		return 0
+	}
+
+	stat = stat[endOfComm+2:]
+
+	statFields := bytes.Split(stat, []byte{' '})
+	// This should come from sysconf(_SC_CLK_TCK), but there's no way to call that from Go.  Assume it's 100,
+	// which is the value for all platforms we support.
+	const HZ = 100
+	const MS_PER_HZ = 1e3 / HZ * time.Millisecond
+
+	const STAT_UTIME_FIELD = 14 - 2
+	const STAT_STIME_FIELD = 15 - 2
+	if len(statFields) < STAT_STIME_FIELD {
+		return 0
+	}
+	userCpuTicks, err := strconv.ParseUint(string(statFields[STAT_UTIME_FIELD]), 10, 64)
+	if err != nil {
+		return 0
+	}
+	kernelCpuTicks, _ := strconv.ParseUint(string(statFields[STAT_STIME_FIELD]), 10, 64)
+	if err != nil {
+		return 0
+	}
+	return time.Duration(userCpuTicks+kernelCpuTicks) * MS_PER_HZ
+}
+
 func WriteMetrics(config Config, eventHandler *metrics.EventHandler, metricsFile string) error {
 	metrics := collectMetrics(config, eventHandler)
 
diff --git a/android/module.go b/android/module.go
index 19502ba..effca03 100644
--- a/android/module.go
+++ b/android/module.go
@@ -20,17 +20,13 @@
 	"encoding/json"
 	"fmt"
 	"net/url"
-	"os"
-	"path"
 	"path/filepath"
 	"reflect"
-	"regexp"
+	"slices"
 	"sort"
 	"strings"
-	"text/scanner"
 
 	"android/soong/bazel"
-	"android/soong/ui/metrics/bp2build_metrics_proto"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -39,472 +35,9 @@
 var (
 	DeviceSharedLibrary = "shared_library"
 	DeviceStaticLibrary = "static_library"
+	jarJarPrefixHandler func(ctx ModuleContext)
 )
 
-// BuildParameters describes the set of potential parameters to build a Ninja rule.
-// In general, these correspond to a Ninja concept.
-type BuildParams struct {
-	// A Ninja Rule that will be written to the Ninja file. This allows factoring out common code
-	// among multiple modules to reduce repetition in the Ninja file of action requirements. A rule
-	// can contain variables that should be provided in Args.
-	Rule blueprint.Rule
-	// Deps represents the depfile format. When using RuleBuilder, this defaults to GCC when depfiles
-	// are used.
-	Deps blueprint.Deps
-	// Depfile is a writeable path that allows correct incremental builds when the inputs have not
-	// been fully specified by the Ninja rule. Ninja supports a subset of the Makefile depfile syntax.
-	Depfile WritablePath
-	// A description of the build action.
-	Description string
-	// Output is an output file of the action. When using this field, references to $out in the Ninja
-	// command will refer to this file.
-	Output WritablePath
-	// Outputs is a slice of output file of the action. When using this field, references to $out in
-	// the Ninja command will refer to these files.
-	Outputs WritablePaths
-	// SymlinkOutput is an output file specifically that is a symlink.
-	SymlinkOutput WritablePath
-	// SymlinkOutputs is a slice of output files specifically that is a symlink.
-	SymlinkOutputs WritablePaths
-	// ImplicitOutput is an output file generated by the action. Note: references to `$out` in the
-	// Ninja command will NOT include references to this file.
-	ImplicitOutput WritablePath
-	// ImplicitOutputs is a slice of output files generated by the action. Note: references to `$out`
-	// in the Ninja command will NOT include references to these files.
-	ImplicitOutputs WritablePaths
-	// Input is an input file to the Ninja action. When using this field, references to $in in the
-	// Ninja command will refer to this file.
-	Input Path
-	// Inputs is a slice of input files to the Ninja action. When using this field, references to $in
-	// in the Ninja command will refer to these files.
-	Inputs Paths
-	// Implicit is an input file to the Ninja action. Note: references to `$in` in the Ninja command
-	// will NOT include references to this file.
-	Implicit Path
-	// Implicits is a slice of input files to the Ninja action. Note: references to `$in` in the Ninja
-	// command will NOT include references to these files.
-	Implicits Paths
-	// OrderOnly are Ninja order-only inputs to the action. When these are out of date, the output is
-	// not rebuilt until they are built, but changes in order-only dependencies alone do not cause the
-	// output to be rebuilt.
-	OrderOnly Paths
-	// Validation is an output path for a validation action. Validation outputs imply lower
-	// non-blocking priority to building non-validation outputs.
-	Validation Path
-	// Validations is a slice of output path for a validation action. Validation outputs imply lower
-	// non-blocking priority to building non-validation outputs.
-	Validations Paths
-	// Whether to skip outputting a default target statement which will be built by Ninja when no
-	// targets are specified on Ninja's command line.
-	Default bool
-	// Args is a key value mapping for replacements of variables within the Rule
-	Args map[string]string
-}
-
-type ModuleBuildParams BuildParams
-
-// EarlyModuleContext provides methods that can be called early, as soon as the properties have
-// been parsed into the module and before any mutators have run.
-type EarlyModuleContext interface {
-	// Module returns the current module as a Module.  It should rarely be necessary, as the module already has a
-	// reference to itself.
-	Module() Module
-
-	// ModuleName returns the name of the module.  This is generally the value that was returned by Module.Name() when
-	// the module was created, but may have been modified by calls to BaseMutatorContext.Rename.
-	ModuleName() string
-
-	// ModuleDir returns the path to the directory that contains the definition of the module.
-	ModuleDir() string
-
-	// ModuleType returns the name of the module type that was used to create the module, as specified in
-	// RegisterModuleType.
-	ModuleType() string
-
-	// BlueprintFile returns the name of the blueprint file that contains the definition of this
-	// module.
-	BlueprintsFile() string
-
-	// ContainsProperty returns true if the specified property name was set in the module definition.
-	ContainsProperty(name string) bool
-
-	// Errorf reports an error at the specified position of the module definition file.
-	Errorf(pos scanner.Position, fmt string, args ...interface{})
-
-	// ModuleErrorf reports an error at the line number of the module type in the module definition.
-	ModuleErrorf(fmt string, args ...interface{})
-
-	// PropertyErrorf reports an error at the line number of a property in the module definition.
-	PropertyErrorf(property, fmt string, args ...interface{})
-
-	// Failed returns true if any errors have been reported.  In most cases the module can continue with generating
-	// build rules after an error, allowing it to report additional errors in a single run, but in cases where the error
-	// has prevented the module from creating necessary data it can return early when Failed returns true.
-	Failed() bool
-
-	// AddNinjaFileDeps adds dependencies on the specified files to the rule that creates the ninja manifest.  The
-	// primary builder will be rerun whenever the specified files are modified.
-	AddNinjaFileDeps(deps ...string)
-
-	DeviceSpecific() bool
-	SocSpecific() bool
-	ProductSpecific() bool
-	SystemExtSpecific() bool
-	Platform() bool
-
-	Config() Config
-	DeviceConfig() DeviceConfig
-
-	// Deprecated: use Config()
-	AConfig() Config
-
-	// GlobWithDeps returns a list of files that match the specified pattern but do not match any
-	// of the patterns in excludes.  It also adds efficient dependencies to rerun the primary
-	// builder whenever a file matching the pattern as added or removed, without rerunning if a
-	// file that does not match the pattern is added to a searched directory.
-	GlobWithDeps(pattern string, excludes []string) ([]string, error)
-
-	Glob(globPattern string, excludes []string) Paths
-	GlobFiles(globPattern string, excludes []string) Paths
-	IsSymlink(path Path) bool
-	Readlink(path Path) string
-
-	// Namespace returns the Namespace object provided by the NameInterface set by Context.SetNameInterface, or the
-	// default SimpleNameInterface if Context.SetNameInterface was not called.
-	Namespace() *Namespace
-}
-
-// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns
-// a Config instead of an interface{}, and some methods have been wrapped to use an android.Module
-// instead of a blueprint.Module, plus some extra methods that return Android-specific information
-// about the current module.
-type BaseModuleContext interface {
-	EarlyModuleContext
-
-	blueprintBaseModuleContext() blueprint.BaseModuleContext
-
-	// OtherModuleName returns the name of another Module.  See BaseModuleContext.ModuleName for more information.
-	// It is intended for use inside the visit functions of Visit* and WalkDeps.
-	OtherModuleName(m blueprint.Module) string
-
-	// OtherModuleDir returns the directory of another Module.  See BaseModuleContext.ModuleDir for more information.
-	// It is intended for use inside the visit functions of Visit* and WalkDeps.
-	OtherModuleDir(m blueprint.Module) string
-
-	// OtherModuleErrorf reports an error on another Module.  See BaseModuleContext.ModuleErrorf for more information.
-	// It is intended for use inside the visit functions of Visit* and WalkDeps.
-	OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
-
-	// OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency
-	// on the module.  When called inside a Visit* method with current module being visited, and there are multiple
-	// dependencies on the module being visited, it returns the dependency tag used for the current dependency.
-	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
-
-	// OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface
-	// passed to Context.SetNameInterface, or SimpleNameInterface if it was not called.
-	OtherModuleExists(name string) bool
-
-	// OtherModuleDependencyVariantExists returns true if a module with the
-	// specified name and variant exists. The variant must match the given
-	// variations. It must also match all the non-local variations of the current
-	// module. In other words, it checks for the module that AddVariationDependencies
-	// would add a dependency on with the same arguments.
-	OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool
-
-	// OtherModuleFarDependencyVariantExists returns true if a module with the
-	// specified name and variant exists. The variant must match the given
-	// variations, but not the non-local variations of the current module. In
-	// other words, it checks for the module that AddFarVariationDependencies
-	// would add a dependency on with the same arguments.
-	OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool
-
-	// OtherModuleReverseDependencyVariantExists returns true if a module with the
-	// specified name exists with the same variations as the current module. In
-	// other words, it checks for the module that AddReverseDependency would add a
-	// dependency on with the same argument.
-	OtherModuleReverseDependencyVariantExists(name string) bool
-
-	// OtherModuleType returns the type of another Module.  See BaseModuleContext.ModuleType for more information.
-	// It is intended for use inside the visit functions of Visit* and WalkDeps.
-	OtherModuleType(m blueprint.Module) string
-
-	// OtherModuleProvider returns the value for a provider for the given module.  If the value is
-	// not set it returns the zero value of the type of the provider, so the return value can always
-	// be type asserted to the type of the provider.  The value returned may be a deep copy of the
-	// value originally passed to SetProvider.
-	OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{}
-
-	// OtherModuleHasProvider returns true if the provider for the given module has been set.
-	OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool
-
-	// Provider returns the value for a provider for the current module.  If the value is
-	// not set it returns the zero value of the type of the provider, so the return value can always
-	// be type asserted to the type of the provider.  It panics if called before the appropriate
-	// mutator or GenerateBuildActions pass for the provider.  The value returned may be a deep
-	// copy of the value originally passed to SetProvider.
-	Provider(provider blueprint.ProviderKey) interface{}
-
-	// HasProvider returns true if the provider for the current module has been set.
-	HasProvider(provider blueprint.ProviderKey) bool
-
-	// SetProvider sets the value for a provider for the current module.  It panics if not called
-	// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value
-	// is not of the appropriate type, or if the value has already been set.  The value should not
-	// be modified after being passed to SetProvider.
-	SetProvider(provider blueprint.ProviderKey, value interface{})
-
-	GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
-
-	// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if
-	// none exists.  It panics if the dependency does not have the specified tag.  It skips any
-	// dependencies that are not an android.Module.
-	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.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.
-	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
-
-	ModuleFromName(name string) (blueprint.Module, bool)
-
-	// VisitDirectDepsBlueprint calls visit for each direct dependency.  If there are multiple
-	// direct dependencies on the same module visit will be called multiple times on that module
-	// and OtherModuleDependencyTag will return a different tag for each.
-	//
-	// The Module passed to the visit function should not be retained outside of the visit
-	// function, it may be invalidated by future mutators.
-	VisitDirectDepsBlueprint(visit func(blueprint.Module))
-
-	// VisitDirectDeps calls visit for each direct dependency.  If there are multiple
-	// direct dependencies on the same module visit will be called multiple times on that module
-	// and OtherModuleDependencyTag will return a different tag for each.  It raises an error if any of the
-	// dependencies are not an android.Module.
-	//
-	// The Module passed to the visit function should not be retained outside of the visit
-	// function, it may be invalidated by future mutators.
-	VisitDirectDeps(visit func(Module))
-
-	VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
-
-	// VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit.  If there are
-	// multiple direct dependencies on the same module pred and visit will be called multiple times on that module and
-	// OtherModuleDependencyTag will return a different tag for each.  It skips any
-	// dependencies that are not an android.Module.
-	//
-	// The Module passed to the visit function should not be retained outside of the visit function, it may be
-	// invalidated by future mutators.
-	VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
-	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
-	VisitDepsDepthFirst(visit func(Module))
-	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
-	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
-
-	// WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order.  visit may
-	// be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the
-	// child and parent with different tags.  OtherModuleDependencyTag will return the tag for the currently visited
-	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down to child.  It skips
-	// any dependencies that are not an android.Module.
-	//
-	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
-	// invalidated by future mutators.
-	WalkDeps(visit func(child, parent Module) bool)
-
-	// WalkDepsBlueprint calls visit for each transitive dependency, traversing the dependency
-	// tree in top down order.  visit may be called multiple times for the same (child, parent)
-	// pair if there are multiple direct dependencies between the child and parent with different
-	// tags.  OtherModuleDependencyTag will return the tag for the currently visited
-	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down
-	// to child.
-	//
-	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
-	// invalidated by future mutators.
-	WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool)
-
-	// GetWalkPath is supposed to be called in visit function passed in WalkDeps()
-	// and returns a top-down dependency path from a start module to current child module.
-	GetWalkPath() []Module
-
-	// PrimaryModule returns the first variant of the current module.  Variants of a module are always visited in
-	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the
-	// Module returned by PrimaryModule without data races.  This can be used to perform singleton actions that are
-	// only done once for all variants of a module.
-	PrimaryModule() Module
-
-	// FinalModule returns the last variant of the current module.  Variants of a module are always visited in
-	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all
-	// variants using VisitAllModuleVariants if the current module == FinalModule().  This can be used to perform
-	// singleton actions that are only done once for all variants of a module.
-	FinalModule() Module
-
-	// VisitAllModuleVariants calls visit for each variant of the current module.  Variants of a module are always
-	// visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read
-	// from all variants if the current module == FinalModule().  Otherwise, care must be taken to not access any
-	// data modified by the current mutator.
-	VisitAllModuleVariants(visit func(Module))
-
-	// GetTagPath is supposed to be called in visit function passed in WalkDeps()
-	// and returns a top-down dependency tags path from a start module to current child module.
-	// It has one less entry than GetWalkPath() as it contains the dependency tags that
-	// exist between each adjacent pair of modules in the GetWalkPath().
-	// GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1]
-	GetTagPath() []blueprint.DependencyTag
-
-	// GetPathString is supposed to be called in visit function passed in WalkDeps()
-	// and returns a multi-line string showing the modules and dependency tags
-	// among them along the top-down dependency path from a start module to current child module.
-	// skipFirst when set to true, the output doesn't include the start module,
-	// which is already printed when this function is used along with ModuleErrorf().
-	GetPathString(skipFirst bool) string
-
-	AddMissingDependencies(missingDeps []string)
-
-	// getMissingDependencies returns the list of missing dependencies.
-	// Calling this function prevents adding new dependencies.
-	getMissingDependencies() []string
-
-	// AddUnconvertedBp2buildDep stores module name of a direct dependency that was not converted via bp2build
-	AddUnconvertedBp2buildDep(dep string)
-
-	// AddMissingBp2buildDep stores the module name of a direct dependency that was not found.
-	AddMissingBp2buildDep(dep string)
-
-	Target() Target
-	TargetPrimary() bool
-
-	// The additional arch specific targets (e.g. 32/64 bit) that this module variant is
-	// responsible for creating.
-	MultiTargets() []Target
-	Arch() Arch
-	Os() OsType
-	Host() bool
-	Device() bool
-	Darwin() bool
-	Windows() bool
-	Debug() bool
-	PrimaryArch() bool
-}
-
-// Deprecated: use EarlyModuleContext instead
-type BaseContext interface {
-	EarlyModuleContext
-}
-
-type ModuleContext interface {
-	BaseModuleContext
-
-	blueprintModuleContext() blueprint.ModuleContext
-
-	// Deprecated: use ModuleContext.Build instead.
-	ModuleBuild(pctx PackageContext, params ModuleBuildParams)
-
-	// Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must
-	// be tagged with `android:"path" to support automatic source module dependency resolution.
-	//
-	// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
-	ExpandSources(srcFiles, excludes []string) Paths
-
-	// Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must
-	// be tagged with `android:"path" to support automatic source module dependency resolution.
-	//
-	// Deprecated: use PathForModuleSrc instead.
-	ExpandSource(srcFile, prop string) Path
-
-	ExpandOptionalSource(srcFile *string, prop string) OptionalPath
-
-	// InstallExecutable creates a rule to copy srcPath to name in the installPath directory,
-	// with the given additional dependencies.  The file is marked executable after copying.
-	//
-	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
-	// installed file will be returned by PackagingSpecs() on this module or by
-	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
-	// for which IsInstallDepNeeded returns true.
-	InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
-
-	// InstallFile creates a rule to copy srcPath to name in the installPath directory,
-	// with the given additional dependencies.
-	//
-	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
-	// installed file will be returned by PackagingSpecs() on this module or by
-	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
-	// for which IsInstallDepNeeded returns true.
-	InstallFile(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
-
-	// InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath
-	// directory, and also unzip a zip file containing extra files to install into the same
-	// directory.
-	//
-	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
-	// installed file will be returned by PackagingSpecs() on this module or by
-	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
-	// for which IsInstallDepNeeded returns true.
-	InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...Path) InstallPath
-
-	// InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath
-	// directory.
-	//
-	// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
-	// installed file will be returned by PackagingSpecs() on this module or by
-	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
-	// for which IsInstallDepNeeded returns true.
-	InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath
-
-	// InstallAbsoluteSymlink creates a rule to create an absolute symlink from src srcPath to name
-	// in the installPath directory.
-	//
-	// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
-	// installed file will be returned by PackagingSpecs() on this module or by
-	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
-	// for which IsInstallDepNeeded returns true.
-	InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath
-
-	// PackageFile creates a PackagingSpec as if InstallFile was called, but without creating
-	// the rule to copy the file.  This is useful to define how a module would be packaged
-	// without installing it into the global installation directories.
-	//
-	// The created PackagingSpec for the will be returned by PackagingSpecs() on this module or by
-	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
-	// for which IsInstallDepNeeded returns true.
-	PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec
-
-	CheckbuildFile(srcPath Path)
-
-	InstallInData() bool
-	InstallInTestcases() bool
-	InstallInSanitizerDir() bool
-	InstallInRamdisk() bool
-	InstallInVendorRamdisk() bool
-	InstallInDebugRamdisk() bool
-	InstallInRecovery() bool
-	InstallInRoot() bool
-	InstallInVendor() bool
-	InstallForceOS() (*OsType, *ArchType)
-
-	RequiredModuleNames() []string
-	HostRequiredModuleNames() []string
-	TargetRequiredModuleNames() []string
-
-	ModuleSubDir() string
-	SoongConfigTraceHash() string
-
-	Variable(pctx PackageContext, name, value string)
-	Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
-	// Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string,
-	// and performs more verification.
-	Build(pctx PackageContext, params BuildParams)
-	// Phony creates a Make-style phony rule, a rule with no commands that can depend on other
-	// phony rules or real files.  Phony can be called on the same name multiple times to add
-	// additional dependencies.
-	Phony(phony string, deps ...Path)
-
-	// GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods,
-	// but do not exist.
-	GetMissingDependencies() []string
-
-	// LicenseMetadataFile returns the path where the license metadata for this module will be
-	// generated.
-	LicenseMetadataFile() Path
-}
-
 type Module interface {
 	blueprint.Module
 
@@ -547,6 +80,8 @@
 	InstallInDebugRamdisk() bool
 	InstallInRecovery() bool
 	InstallInRoot() bool
+	InstallInOdm() bool
+	InstallInProduct() bool
 	InstallInVendor() bool
 	InstallForceOS() (*OsType, *ArchType)
 	PartitionTag(DeviceConfig) string
@@ -565,15 +100,6 @@
 	AddProperties(props ...interface{})
 	GetProperties() []interface{}
 
-	// IsConvertedByBp2build returns whether this module was converted via bp2build
-	IsConvertedByBp2build() bool
-	GetUnconvertedReason() *UnconvertedReason
-
-	// Bp2buildTargets returns the target(s) generated for Bazel via bp2build for this module
-	Bp2buildTargets() []bp2buildInfo
-	GetUnconvertedBp2buildDeps() []string
-	GetMissingBp2buildDeps() []string
-
 	BuildParamsForTests() []BuildParams
 	RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams
 	VariablesForTests() map[string]string
@@ -597,6 +123,8 @@
 	// TransitivePackagingSpecs returns the PackagingSpecs for this module and any transitive
 	// dependencies with dependency tags for which IsInstallDepNeeded() returns true.
 	TransitivePackagingSpecs() []PackagingSpec
+
+	ConfigurableEvaluator(ctx ConfigAndErrorContext) proptools.ConfigurableEvaluator
 }
 
 // Qualified id for a module
@@ -802,7 +330,7 @@
 	// defaults module, use the `defaults_visibility` property on the defaults module;
 	// not to be confused with the `default_visibility` property on the package module.
 	//
-	// See https://android.googlesource.com/platform/build/soong/+/master/README.md#visibility for
+	// See https://android.googlesource.com/platform/build/soong/+/main/README.md#visibility for
 	// more details.
 	Visibility []string
 
@@ -907,6 +435,10 @@
 	// Set by osMutator
 	CompileOS OsType `blueprint:"mutated"`
 
+	// Set to true after the arch mutator has run on this module and set CompileTarget,
+	// CompileMultiTargets, and CompilePrimary
+	ArchReady bool `blueprint:"mutated"`
+
 	// The Target of artifacts that this module variant is responsible for creating.
 	//
 	// Set by archMutator
@@ -988,9 +520,6 @@
 	// constants in image.go, but can also be set to a custom value by individual module types.
 	ImageVariation string `blueprint:"mutated"`
 
-	// Bazel conversion status
-	BazelConversionStatus BazelConversionStatus `blueprint:"mutated"`
-
 	// SoongConfigTrace records accesses to VendorVars (soong_config). The trace will be hashed
 	// and used as a subdir of PathForModuleOut.  Note that we mainly focus on incremental
 	// builds among similar products (e.g. aosp_cf_x86_64_phone and aosp_cf_x86_64_foldable),
@@ -998,41 +527,9 @@
 	// trace, but influence modules among products.
 	SoongConfigTrace     soongConfigTrace `blueprint:"mutated"`
 	SoongConfigTraceHash string           `blueprint:"mutated"`
-}
 
-// CommonAttributes represents the common Bazel attributes from which properties
-// in `commonProperties` are translated/mapped; such properties are annotated in
-// a list their corresponding attribute. It is embedded within `bp2buildInfo`.
-type CommonAttributes struct {
-	// Soong nameProperties -> Bazel name
-	Name string
-
-	// Data mapped from: Required
-	Data bazel.LabelListAttribute
-
-	// SkipData is neither a Soong nor Bazel target attribute
-	// If true, this will not fill the data attribute automatically
-	// This is useful for Soong modules that have 1:many Bazel targets
-	// Some of the generated Bazel targets might not have a data attribute
-	SkipData *bool
-
-	Tags bazel.StringListAttribute
-
-	Applicable_licenses bazel.LabelListAttribute
-
-	Testonly *bool
-
-	// Dir is neither a Soong nor Bazel target attribute
-	// If set, the bazel target will be created in this directory
-	// If unset, the bazel target will default to be created in the directory of the visited soong module
-	Dir *string
-}
-
-// constraintAttributes represents Bazel attributes pertaining to build constraints,
-// which make restrict building a Bazel target for some set of platforms.
-type constraintAttributes struct {
-	// Constraint values this target can be built for.
-	Target_compatible_with bazel.LabelListAttribute
+	// The team (defined by the owner/vendor) who owns the property.
+	Team *string `android:"path"`
 }
 
 type distProperties struct {
@@ -1045,6 +542,21 @@
 	Dists []Dist `android:"arch_variant"`
 }
 
+type TeamDepTagType struct {
+	blueprint.BaseDependencyTag
+}
+
+var teamDepTag = TeamDepTagType{}
+
+// Dependency tag for required, host_required, and target_required modules.
+var RequiredDepTag = struct {
+	blueprint.BaseDependencyTag
+	InstallAlwaysNeededDependencyTag
+	// Requiring disabled module has been supported (as a side effect of this being implemented
+	// in Make). We may want to make it an error, but for now, let's keep the existing behavior.
+	AlwaysAllowDisabledModuleDependencyTag
+}{}
+
 // CommonTestOptions represents the common `test_options` properties in
 // Android.bp.
 type CommonTestOptions struct {
@@ -1272,189 +784,6 @@
 	m.base().commonProperties.CreateCommonOSVariant = true
 }
 
-func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutatorContext,
-	enabledPropertyOverrides bazel.BoolAttribute) constraintAttributes {
-
-	mod := ctx.Module().base()
-	// Assert passed-in attributes include Name
-	if len(attrs.Name) == 0 {
-		if ctx.ModuleType() != "package" {
-			ctx.ModuleErrorf("CommonAttributes in fillCommonBp2BuildModuleAttrs expects a `.Name`!")
-		}
-	}
-
-	depsToLabelList := func(deps []string) bazel.LabelListAttribute {
-		return bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, deps))
-	}
-
-	var enabledProperty bazel.BoolAttribute
-
-	onlyAndroid := false
-	neitherHostNorDevice := false
-
-	osSupport := map[string]bool{}
-
-	// if the target is enabled and supports arch variance, determine the defaults based on the module
-	// type's host or device property and host_supported/device_supported properties
-	if mod.commonProperties.ArchSpecific {
-		moduleSupportsDevice := mod.DeviceSupported()
-		moduleSupportsHost := mod.HostSupported()
-		if moduleSupportsHost && !moduleSupportsDevice {
-			// for host only, we specify as unsupported on android rather than listing all host osSupport
-			// TODO(b/220874839): consider replacing this with a constraint that covers all host osSupport
-			// instead
-			enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, Android.Name, proptools.BoolPtr(false))
-		} else if moduleSupportsDevice && !moduleSupportsHost {
-			enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, Android.Name, proptools.BoolPtr(true))
-			// specify as a positive to ensure any target-specific enabled can be resolved
-			// also save that a target is only android, as if there is only the positive restriction on
-			// android, it'll be dropped, so we may need to add it back later
-			onlyAndroid = true
-		} else if !moduleSupportsHost && !moduleSupportsDevice {
-			neitherHostNorDevice = true
-		}
-
-		for _, osType := range OsTypeList() {
-			if osType.Class == Host {
-				osSupport[osType.Name] = moduleSupportsHost
-			} else if osType.Class == Device {
-				osSupport[osType.Name] = moduleSupportsDevice
-			}
-		}
-	}
-
-	if neitherHostNorDevice {
-		// we can't build this, disable
-		enabledProperty.Value = proptools.BoolPtr(false)
-	} else if mod.commonProperties.Enabled != nil {
-		enabledProperty.SetValue(mod.commonProperties.Enabled)
-		if !*mod.commonProperties.Enabled {
-			for oss, enabled := range osSupport {
-				if val := enabledProperty.SelectValue(bazel.OsConfigurationAxis, oss); enabled && val != nil && *val {
-					// if this should be disabled by default, clear out any enabling we've done
-					enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, oss, nil)
-				}
-			}
-		}
-	}
-
-	attrs.Applicable_licenses = bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, mod.commonProperties.Licenses))
-
-	// The required property can contain the module itself. This causes a cycle
-	// when generated as the 'data' label list attribute in Bazel. Remove it if
-	// it exists. See b/247985196.
-	_, requiredWithoutCycles := RemoveFromList(ctx.ModuleName(), mod.commonProperties.Required)
-	requiredWithoutCycles = FirstUniqueStrings(requiredWithoutCycles)
-	required := depsToLabelList(requiredWithoutCycles)
-	archVariantProps := mod.GetArchVariantProperties(ctx, &commonProperties{})
-	for axis, configToProps := range archVariantProps {
-		for config, _props := range configToProps {
-			if archProps, ok := _props.(*commonProperties); ok {
-				_, requiredWithoutCycles := RemoveFromList(ctx.ModuleName(), archProps.Required)
-				requiredWithoutCycles = FirstUniqueStrings(requiredWithoutCycles)
-				required.SetSelectValue(axis, config, depsToLabelList(requiredWithoutCycles).Value)
-				if !neitherHostNorDevice {
-					if archProps.Enabled != nil {
-						if axis != bazel.OsConfigurationAxis || osSupport[config] {
-							enabledProperty.SetSelectValue(axis, config, archProps.Enabled)
-						}
-					}
-				}
-			}
-		}
-	}
-
-	if !neitherHostNorDevice {
-		if enabledPropertyOverrides.Value != nil {
-			enabledProperty.Value = enabledPropertyOverrides.Value
-		}
-		for _, axis := range enabledPropertyOverrides.SortedConfigurationAxes() {
-			configToBools := enabledPropertyOverrides.ConfigurableValues[axis]
-			for cfg, val := range configToBools {
-				if axis != bazel.OsConfigurationAxis || osSupport[cfg] {
-					enabledProperty.SetSelectValue(axis, cfg, &val)
-				}
-			}
-		}
-	}
-
-	productConfigEnabledAttribute := bazel.LabelListAttribute{}
-	// TODO(b/234497586): Soong config variables and product variables have different overriding behavior, we
-	// should handle it correctly
-	if !proptools.BoolDefault(enabledProperty.Value, true) && !neitherHostNorDevice {
-		// If the module is not enabled by default, then we can check if a
-		// product variable enables it
-		productConfigEnabledAttribute = productVariableConfigEnableAttribute(ctx)
-
-		if len(productConfigEnabledAttribute.ConfigurableValues) > 0 {
-			// In this case, an existing product variable configuration overrides any
-			// module-level `enable: false` definition
-			newValue := true
-			enabledProperty.Value = &newValue
-		}
-	}
-
-	platformEnabledAttribute, err := enabledProperty.ToLabelListAttribute(
-		bazel.LabelList{[]bazel.Label{{Label: "@platforms//:incompatible"}}, nil},
-		bazel.LabelList{[]bazel.Label{}, nil})
-	if err != nil {
-		ctx.ModuleErrorf("Error processing platform enabled attribute: %s", err)
-	}
-
-	// if android is the only arch/os enabled, then add a restriction to only be compatible with android
-	if platformEnabledAttribute.IsNil() && onlyAndroid {
-		l := bazel.LabelAttribute{}
-		l.SetValue(bazel.Label{Label: bazel.OsConfigurationAxis.SelectKey(Android.Name)})
-		platformEnabledAttribute.Add(&l)
-	}
-
-	if !proptools.Bool(attrs.SkipData) {
-		attrs.Data.Append(required)
-	}
-	// SkipData is not an attribute of any Bazel target
-	// Set this to nil so that it does not appear in the generated build file
-	attrs.SkipData = nil
-
-	moduleEnableConstraints := bazel.LabelListAttribute{}
-	moduleEnableConstraints.Append(platformEnabledAttribute)
-	moduleEnableConstraints.Append(productConfigEnabledAttribute)
-
-	return constraintAttributes{Target_compatible_with: moduleEnableConstraints}
-}
-
-// Check product variables for `enabled: true` flag override.
-// Returns a list of the constraint_value targets who enable this override.
-func productVariableConfigEnableAttribute(ctx *topDownMutatorContext) bazel.LabelListAttribute {
-	result := bazel.LabelListAttribute{}
-	productVariableProps := ProductVariableProperties(ctx, ctx.Module())
-	if productConfigProps, exists := productVariableProps["Enabled"]; exists {
-		for productConfigProp, prop := range productConfigProps {
-			flag, ok := prop.(*bool)
-			if !ok {
-				ctx.ModuleErrorf("Could not convert product variable enabled property")
-			}
-
-			if flag == nil {
-				// soong config var is not used to set `enabled`. nothing to do.
-				continue
-			} else if *flag {
-				axis := productConfigProp.ConfigurationAxis()
-				result.SetSelectValue(axis, bazel.ConditionsDefaultConfigKey, bazel.MakeLabelList([]bazel.Label{{Label: "@platforms//:incompatible"}}))
-				result.SetSelectValue(axis, productConfigProp.SelectKey(), bazel.LabelList{Includes: []bazel.Label{}})
-			} else if scp, isSoongConfigProperty := productConfigProp.(SoongConfigProperty); isSoongConfigProperty && scp.value == bazel.ConditionsDefaultConfigKey {
-				// productVariableConfigEnableAttribute runs only if `enabled: false` is set at the top-level outside soong_config_variables
-				// conditions_default { enabled: false} is a no-op in this case
-				continue
-			} else {
-				// TODO(b/210546943): handle negative case where `enabled: false`
-				ctx.ModuleErrorf("`enabled: false` is not currently supported for configuration variables. See b/210546943")
-			}
-		}
-	}
-
-	return result
-}
-
 // A ModuleBase object contains the properties that are common to all Android
 // modules.  It should be included as an anonymous field in every module
 // struct definition.  InitAndroidModule should then be called from the module's
@@ -1537,7 +866,12 @@
 	// katiInstalls tracks the install rules that were created by Soong but are being exported
 	// to Make to convert to ninja rules so that Make can add additional dependencies.
 	katiInstalls katiInstalls
-	katiSymlinks katiInstalls
+	// katiInitRcInstalls and katiVintfInstalls track the install rules created by Soong that are
+	// allowed to have duplicates across modules and variants.
+	katiInitRcInstalls katiInstalls
+	katiVintfInstalls  katiInstalls
+	katiSymlinks       katiInstalls
+	testData           []DataPath
 
 	// The files to copy to the dist as explicitly specified in the .bp file.
 	distFiles TaggedDistFiles
@@ -1560,101 +894,19 @@
 	initRcPaths         Paths
 	vintfFragmentsPaths Paths
 
+	installedInitRcPaths         InstallPaths
+	installedVintfFragmentsPaths InstallPaths
+
 	// set of dependency module:location mappings used to populate the license metadata for
 	// apex containers.
 	licenseInstallMap []string
 
 	// The path to the generated license metadata file for the module.
 	licenseMetadataFile WritablePath
-}
 
-// A struct containing all relevant information about a Bazel target converted via bp2build.
-type bp2buildInfo struct {
-	Dir             string
-	BazelProps      bazel.BazelTargetModuleProperties
-	CommonAttrs     CommonAttributes
-	ConstraintAttrs constraintAttributes
-	Attrs           interface{}
-}
-
-// TargetName returns the Bazel target name of a bp2build converted target.
-func (b bp2buildInfo) TargetName() string {
-	return b.CommonAttrs.Name
-}
-
-// TargetPackage returns the Bazel package of a bp2build converted target.
-func (b bp2buildInfo) TargetPackage() string {
-	return b.Dir
-}
-
-// BazelRuleClass returns the Bazel rule class of a bp2build converted target.
-func (b bp2buildInfo) BazelRuleClass() string {
-	return b.BazelProps.Rule_class
-}
-
-// BazelRuleLoadLocation returns the location of the  Bazel rule of a bp2build converted target.
-// This may be empty as native Bazel rules do not need to be loaded.
-func (b bp2buildInfo) BazelRuleLoadLocation() string {
-	return b.BazelProps.Bzl_load_location
-}
-
-// BazelAttributes returns the Bazel attributes of a bp2build converted target.
-func (b bp2buildInfo) BazelAttributes() []interface{} {
-	return []interface{}{&b.CommonAttrs, &b.ConstraintAttrs, b.Attrs}
-}
-
-func (m *ModuleBase) addBp2buildInfo(info bp2buildInfo) {
-	if m.commonProperties.BazelConversionStatus.UnconvertedReason != nil {
-		panic(fmt.Errorf("bp2build: module '%s' marked unconvertible and also is converted", m.Name()))
-	}
-	m.commonProperties.BazelConversionStatus.Bp2buildInfo = append(m.commonProperties.BazelConversionStatus.Bp2buildInfo, info)
-}
-
-func (m *ModuleBase) setBp2buildUnconvertible(reasonType bp2build_metrics_proto.UnconvertedReasonType, detail string) {
-	if len(m.commonProperties.BazelConversionStatus.Bp2buildInfo) > 0 {
-		panic(fmt.Errorf("bp2build: module '%s' marked unconvertible and also is converted", m.Name()))
-	}
-	m.commonProperties.BazelConversionStatus.UnconvertedReason = &UnconvertedReason{
-		ReasonType: int(reasonType),
-		Detail:     detail,
-	}
-}
-
-// IsConvertedByBp2build returns whether this module was converted via bp2build.
-func (m *ModuleBase) IsConvertedByBp2build() bool {
-	return len(m.commonProperties.BazelConversionStatus.Bp2buildInfo) > 0
-}
-
-func (m *ModuleBase) GetUnconvertedReason() *UnconvertedReason {
-	return m.commonProperties.BazelConversionStatus.UnconvertedReason
-}
-
-// Bp2buildTargets returns the Bazel targets bp2build generated for this module.
-func (m *ModuleBase) Bp2buildTargets() []bp2buildInfo {
-	return m.commonProperties.BazelConversionStatus.Bp2buildInfo
-}
-
-// AddUnconvertedBp2buildDep stores module name of a dependency that was not converted to Bazel.
-func (b *baseModuleContext) AddUnconvertedBp2buildDep(dep string) {
-	unconvertedDeps := &b.Module().base().commonProperties.BazelConversionStatus.UnconvertedDeps
-	*unconvertedDeps = append(*unconvertedDeps, dep)
-}
-
-// AddMissingBp2buildDep stores module name of a dependency that was not found in a Android.bp file.
-func (b *baseModuleContext) AddMissingBp2buildDep(dep string) {
-	missingDeps := &b.Module().base().commonProperties.BazelConversionStatus.MissingDeps
-	*missingDeps = append(*missingDeps, dep)
-}
-
-// GetUnconvertedBp2buildDeps returns the list of module names of this module's direct dependencies that
-// were not converted to Bazel.
-func (m *ModuleBase) GetUnconvertedBp2buildDeps() []string {
-	return FirstUniqueStrings(m.commonProperties.BazelConversionStatus.UnconvertedDeps)
-}
-
-// GetMissingBp2buildDeps returns the list of module names that were not found in Android.bp files.
-func (m *ModuleBase) GetMissingBp2buildDeps() []string {
-	return FirstUniqueStrings(m.commonProperties.BazelConversionStatus.MissingDeps)
+	// moduleInfoJSON can be filled out by GenerateAndroidBuildActions to write a JSON file that will
+	// be included in the final module-info.json produced by Make.
+	moduleInfoJSON *ModuleInfoJSON
 }
 
 func (m *ModuleBase) AddJSONData(d *map[string]interface{}) {
@@ -1766,6 +1018,101 @@
 
 func (m *ModuleBase) DepsMutator(BottomUpMutatorContext) {}
 
+func (m *ModuleBase) baseDepsMutator(ctx BottomUpMutatorContext) {
+	if m.Team() != "" {
+		ctx.AddDependency(ctx.Module(), teamDepTag, m.Team())
+	}
+
+	// TODO(jiyong): remove below case. This is to work around build errors happening
+	// on branches with reduced manifest like aosp_kernel-build-tools.
+	// In the branch, a build error occurs as follows.
+	// 1. aosp_kernel-build-tools is a reduced manifest branch. It doesn't have some git
+	// projects like external/bouncycastle
+	// 2. `boot_signer` is `required` by modules like `build_image` which is explicitly list as
+	// the top-level build goal (in the shell file that invokes Soong).
+	// 3. `boot_signer` depends on `bouncycastle-unbundled` which is in the missing git project.
+	// 4. aosp_kernel-build-tools invokes soong with `--skip-make`. Therefore, the absence of
+	// ALLOW_MISSING_DEPENDENCIES didn't cause a problem.
+	// 5. Now, since Soong understands `required` deps, it tries to build `boot_signer` and the
+	// absence of external/bouncycastle fails the build.
+	//
+	// Unfortunately, there's no way for Soong to correctly determine if it's running in a
+	// reduced manifest branch. Instead, here, we use the absence of DeviceArch or DeviceName as
+	// a strong signal, because that's very common across reduced manifest branches.
+	pv := ctx.Config().productVariables
+	fullManifest := pv.DeviceArch != nil && pv.DeviceName != nil
+	if fullManifest {
+		addRequiredDeps(ctx)
+	}
+}
+
+// addRequiredDeps adds required, target_required, and host_required as dependencies.
+func addRequiredDeps(ctx BottomUpMutatorContext) {
+	addDep := func(target Target, depName string) {
+		if !ctx.OtherModuleExists(depName) {
+			if ctx.Config().AllowMissingDependencies() {
+				return
+			}
+		}
+
+		// If Android native module requires another Android native module, ensure that
+		// they have the same bitness. This mimics the policy in select-bitness-of-required-modules
+		// in build/make/core/main.mk.
+		// TODO(jiyong): the Make-side does this only when the required module is a shared
+		// library or a native test.
+		bothInAndroid := ctx.Device() && target.Os.Class == Device
+		nativeArch := InList(ctx.Arch().ArchType.Multilib, []string{"lib32", "lib64"})
+		sameBitness := ctx.Arch().ArchType.Multilib == target.Arch.ArchType.Multilib
+		if bothInAndroid && nativeArch && !sameBitness {
+			return
+		}
+
+		variation := target.Variations()
+		if ctx.OtherModuleFarDependencyVariantExists(variation, depName) {
+			ctx.AddFarVariationDependencies(variation, RequiredDepTag, depName)
+		}
+	}
+
+	var deviceTargets []Target
+	deviceTargets = append(deviceTargets, ctx.Config().Targets[Android]...)
+	deviceTargets = append(deviceTargets, ctx.Config().AndroidCommonTarget)
+
+	var hostTargets []Target
+	hostTargets = append(hostTargets, ctx.Config().Targets[ctx.Config().BuildOS]...)
+	hostTargets = append(hostTargets, ctx.Config().BuildOSCommonTarget)
+
+	if ctx.Device() {
+		for _, depName := range ctx.Module().RequiredModuleNames() {
+			for _, target := range deviceTargets {
+				addDep(target, depName)
+			}
+		}
+		for _, depName := range ctx.Module().HostRequiredModuleNames() {
+			for _, target := range hostTargets {
+				addDep(target, depName)
+			}
+		}
+	}
+
+	if ctx.Host() {
+		for _, depName := range ctx.Module().RequiredModuleNames() {
+			for _, target := range hostTargets {
+				// When a host module requires another host module, don't make a
+				// dependency if they have different OSes (i.e. hostcross).
+				if ctx.Target().HostCross != target.HostCross {
+					continue
+				}
+				addDep(target, depName)
+			}
+		}
+		for _, depName := range ctx.Module().TargetRequiredModuleNames() {
+			for _, target := range deviceTargets {
+				addDep(target, depName)
+			}
+		}
+	}
+}
+
 // AddProperties "registers" the provided props
 // each value in props MUST be a pointer to a struct
 func (m *ModuleBase) AddProperties(props ...interface{}) {
@@ -1893,6 +1240,10 @@
 	return distFiles
 }
 
+func (m *ModuleBase) ArchReady() bool {
+	return m.commonProperties.ArchReady
+}
+
 func (m *ModuleBase) Target() Target {
 	return m.commonProperties.CompileTarget
 }
@@ -2187,6 +1538,14 @@
 	return Bool(m.commonProperties.Recovery)
 }
 
+func (m *ModuleBase) InstallInOdm() bool {
+	return false
+}
+
+func (m *ModuleBase) InstallInProduct() bool {
+	return false
+}
+
 func (m *ModuleBase) InstallInVendor() bool {
 	return Bool(m.commonProperties.Vendor) || Bool(m.commonProperties.Soc_specific) || Bool(m.commonProperties.Proprietary)
 }
@@ -2203,6 +1562,10 @@
 	return String(m.commonProperties.Owner)
 }
 
+func (m *ModuleBase) Team() string {
+	return String(m.commonProperties.Team)
+}
+
 func (m *ModuleBase) setImageVariation(variant string) {
 	m.commonProperties.ImageVariation = variant
 }
@@ -2388,14 +1751,32 @@
 func (m *ModuleBase) baseModuleContextFactory(ctx blueprint.BaseModuleContext) baseModuleContext {
 	return baseModuleContext{
 		bp:                 ctx,
+		archModuleContext:  m.archModuleContextFactory(ctx),
 		earlyModuleContext: m.earlyModuleContextFactory(ctx),
-		os:                 m.commonProperties.CompileOS,
-		target:             m.commonProperties.CompileTarget,
-		targetPrimary:      m.commonProperties.CompilePrimary,
-		multiTargets:       m.commonProperties.CompileMultiTargets,
 	}
 }
 
+func (m *ModuleBase) archModuleContextFactory(ctx blueprint.IncomingTransitionContext) archModuleContext {
+	config := ctx.Config().(Config)
+	target := m.Target()
+	primaryArch := false
+	if len(config.Targets[target.Os]) <= 1 {
+		primaryArch = true
+	} else {
+		primaryArch = target.Arch.ArchType == config.Targets[target.Os][0].Arch.ArchType
+	}
+
+	return archModuleContext{
+		ready:         m.commonProperties.ArchReady,
+		os:            m.commonProperties.CompileOS,
+		target:        m.commonProperties.CompileTarget,
+		targetPrimary: m.commonProperties.CompilePrimary,
+		multiTargets:  m.commonProperties.CompileMultiTargets,
+		primaryArch:   primaryArch,
+	}
+
+}
+
 func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) {
 	ctx := &moduleContext{
 		module:            m.module,
@@ -2436,7 +1817,7 @@
 	if !ctx.PrimaryArch() {
 		suffix = append(suffix, ctx.Arch().ArchType.String())
 	}
-	if apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo); !apexInfo.IsForPlatform() {
+	if apexInfo, _ := ModuleProvider(ctx, ApexInfoProvider); !apexInfo.IsForPlatform() {
 		suffix = append(suffix, apexInfo.ApexVariationName)
 	}
 
@@ -2458,34 +1839,65 @@
 		// ensure all direct android.Module deps are enabled
 		ctx.VisitDirectDepsBlueprint(func(bm blueprint.Module) {
 			if m, ok := bm.(Module); ok {
-				ctx.validateAndroidModule(bm, ctx.OtherModuleDependencyTag(m), ctx.baseModuleContext.strictVisitDeps)
+				ctx.validateAndroidModule(bm, ctx.OtherModuleDependencyTag(m), ctx.baseModuleContext.strictVisitDeps, false)
 			}
 		})
 
+		if m.Device() {
+			// Handle any init.rc and vintf fragment files requested by the module.  All files installed by this
+			// module will automatically have a dependency on the installed init.rc or vintf fragment file.
+			// The same init.rc or vintf fragment file may be requested by multiple modules or variants,
+			// so instead of installing them now just compute the install path and store it for later.
+			// The full list of all init.rc and vintf fragment install rules will be deduplicated later
+			// so only a single rule is created for each init.rc or vintf fragment file.
+
+			if !m.InVendorRamdisk() {
+				m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
+				rcDir := PathForModuleInstall(ctx, "etc", "init")
+				for _, src := range m.initRcPaths {
+					installedInitRc := rcDir.Join(ctx, src.Base())
+					m.katiInitRcInstalls = append(m.katiInitRcInstalls, katiInstall{
+						from: src,
+						to:   installedInitRc,
+					})
+					ctx.PackageFile(rcDir, src.Base(), src)
+					m.installedInitRcPaths = append(m.installedInitRcPaths, installedInitRc)
+				}
+			}
+
+			m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments)
+			vintfDir := PathForModuleInstall(ctx, "etc", "vintf", "manifest")
+			for _, src := range m.vintfFragmentsPaths {
+				installedVintfFragment := vintfDir.Join(ctx, src.Base())
+				m.katiVintfInstalls = append(m.katiVintfInstalls, katiInstall{
+					from: src,
+					to:   installedVintfFragment,
+				})
+				ctx.PackageFile(vintfDir, src.Base(), src)
+				m.installedVintfFragmentsPaths = append(m.installedVintfFragmentsPaths, installedVintfFragment)
+			}
+		}
+
 		licensesPropertyFlattener(ctx)
 		if ctx.Failed() {
 			return
 		}
 
-		if mixedBuildMod, handled := m.isHandledByBazel(ctx); handled {
-			mixedBuildMod.ProcessBazelQueryResponse(ctx)
-		} else {
-			m.module.GenerateAndroidBuildActions(ctx)
+		if jarJarPrefixHandler != nil {
+			jarJarPrefixHandler(ctx)
+			if ctx.Failed() {
+				return
+			}
 		}
+
+		m.module.GenerateAndroidBuildActions(ctx)
 		if ctx.Failed() {
 			return
 		}
 
-		m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
-		rcDir := PathForModuleInstall(ctx, "etc", "init")
-		for _, src := range m.initRcPaths {
-			ctx.PackageFile(rcDir, filepath.Base(src.String()), src)
-		}
-
-		m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments)
-		vintfDir := PathForModuleInstall(ctx, "etc", "vintf", "manifest")
-		for _, src := range m.vintfFragmentsPaths {
-			ctx.PackageFile(vintfDir, filepath.Base(src.String()), src)
+		aconfigUpdateAndroidBuildActions(ctx)
+		if ctx.Failed() {
+			return
 		}
 
 		// Create the set of tagged dist files after calling GenerateAndroidBuildActions
@@ -2502,6 +1914,7 @@
 		m.packagingSpecs = append(m.packagingSpecs, ctx.packagingSpecs...)
 		m.katiInstalls = append(m.katiInstalls, ctx.katiInstalls...)
 		m.katiSymlinks = append(m.katiSymlinks, ctx.katiSymlinks...)
+		m.testData = append(m.testData, ctx.testData...)
 	} else if ctx.Config().AllowMissingDependencies() {
 		// If the module is not enabled it will not create any build rules, nothing will call
 		// ctx.GetMissingDependencies(), and blueprint will consider the missing dependencies to be unhandled
@@ -2522,18 +1935,95 @@
 
 	buildLicenseMetadata(ctx, m.licenseMetadataFile)
 
+	if m.moduleInfoJSON != nil {
+		var installed InstallPaths
+		installed = append(installed, m.katiInstalls.InstallPaths()...)
+		installed = append(installed, m.katiSymlinks.InstallPaths()...)
+		installed = append(installed, m.katiInitRcInstalls.InstallPaths()...)
+		installed = append(installed, m.katiVintfInstalls.InstallPaths()...)
+		installedStrings := installed.Strings()
+
+		var targetRequired, hostRequired []string
+		if ctx.Host() {
+			targetRequired = m.commonProperties.Target_required
+		} else {
+			hostRequired = m.commonProperties.Host_required
+		}
+
+		var data []string
+		for _, d := range m.testData {
+			data = append(data, d.ToRelativeInstallPath())
+		}
+
+		if m.moduleInfoJSON.Uninstallable {
+			installedStrings = nil
+			if len(m.moduleInfoJSON.CompatibilitySuites) == 1 && m.moduleInfoJSON.CompatibilitySuites[0] == "null-suite" {
+				m.moduleInfoJSON.CompatibilitySuites = nil
+				m.moduleInfoJSON.TestConfig = nil
+				m.moduleInfoJSON.AutoTestConfig = nil
+				data = nil
+			}
+		}
+
+		m.moduleInfoJSON.core = CoreModuleInfoJSON{
+			RegisterName:       m.moduleInfoRegisterName(ctx, m.moduleInfoJSON.SubName),
+			Path:               []string{ctx.ModuleDir()},
+			Installed:          installedStrings,
+			ModuleName:         m.BaseModuleName() + m.moduleInfoJSON.SubName,
+			SupportedVariants:  []string{m.moduleInfoVariant(ctx)},
+			TargetDependencies: targetRequired,
+			HostDependencies:   hostRequired,
+			Data:               data,
+		}
+		SetProvider(ctx, ModuleInfoJSONProvider, m.moduleInfoJSON)
+	}
+
 	m.buildParams = ctx.buildParams
 	m.ruleParams = ctx.ruleParams
 	m.variables = ctx.variables
 }
 
-func (m *ModuleBase) isHandledByBazel(ctx ModuleContext) (MixedBuildBuildable, bool) {
-	if mixedBuildMod, ok := m.module.(MixedBuildBuildable); ok {
-		if mixedBuildMod.IsMixedBuildSupported(ctx) && (MixedBuildsEnabled(ctx) == MixedBuildEnabled) {
-			return mixedBuildMod, true
+func SetJarJarPrefixHandler(handler func(ModuleContext)) {
+	if jarJarPrefixHandler != nil {
+		panic("jarJarPrefixHandler already set")
+	}
+	jarJarPrefixHandler = handler
+}
+
+func (m *ModuleBase) moduleInfoRegisterName(ctx ModuleContext, subName string) string {
+	name := m.BaseModuleName()
+
+	prefix := ""
+	if ctx.Host() {
+		if ctx.Os() != ctx.Config().BuildOS {
+			prefix = "host_cross_"
 		}
 	}
-	return nil, false
+	suffix := ""
+	arches := slices.Clone(ctx.Config().Targets[ctx.Os()])
+	arches = slices.DeleteFunc(arches, func(target Target) bool {
+		return target.NativeBridge != ctx.Target().NativeBridge
+	})
+	if len(arches) > 0 && ctx.Arch().ArchType != arches[0].Arch.ArchType {
+		if ctx.Arch().ArchType.Multilib == "lib32" {
+			suffix = "_32"
+		} else {
+			suffix = "_64"
+		}
+	}
+	return prefix + name + subName + suffix
+}
+
+func (m *ModuleBase) moduleInfoVariant(ctx ModuleContext) string {
+	variant := "DEVICE"
+	if ctx.Host() {
+		if ctx.Os() != ctx.Config().BuildOS {
+			variant = "HOST_CROSS"
+		} else {
+			variant = "HOST"
+		}
+	}
+	return variant
 }
 
 // Check the supplied dist structure to make sure that it is valid.
@@ -2562,163 +2052,6 @@
 
 }
 
-type earlyModuleContext struct {
-	blueprint.EarlyModuleContext
-
-	kind   moduleKind
-	config Config
-}
-
-func (e *earlyModuleContext) Glob(globPattern string, excludes []string) Paths {
-	return Glob(e, globPattern, excludes)
-}
-
-func (e *earlyModuleContext) GlobFiles(globPattern string, excludes []string) Paths {
-	return GlobFiles(e, globPattern, excludes)
-}
-
-func (e *earlyModuleContext) IsSymlink(path Path) bool {
-	fileInfo, err := e.config.fs.Lstat(path.String())
-	if err != nil {
-		e.ModuleErrorf("os.Lstat(%q) failed: %s", path.String(), err)
-	}
-	return fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink
-}
-
-func (e *earlyModuleContext) Readlink(path Path) string {
-	dest, err := e.config.fs.Readlink(path.String())
-	if err != nil {
-		e.ModuleErrorf("os.Readlink(%q) failed: %s", path.String(), err)
-	}
-	return dest
-}
-
-func (e *earlyModuleContext) Module() Module {
-	module, _ := e.EarlyModuleContext.Module().(Module)
-	return module
-}
-
-func (e *earlyModuleContext) Config() Config {
-	return e.EarlyModuleContext.Config().(Config)
-}
-
-func (e *earlyModuleContext) AConfig() Config {
-	return e.config
-}
-
-func (e *earlyModuleContext) DeviceConfig() DeviceConfig {
-	return DeviceConfig{e.config.deviceConfig}
-}
-
-func (e *earlyModuleContext) Platform() bool {
-	return e.kind == platformModule
-}
-
-func (e *earlyModuleContext) DeviceSpecific() bool {
-	return e.kind == deviceSpecificModule
-}
-
-func (e *earlyModuleContext) SocSpecific() bool {
-	return e.kind == socSpecificModule
-}
-
-func (e *earlyModuleContext) ProductSpecific() bool {
-	return e.kind == productSpecificModule
-}
-
-func (e *earlyModuleContext) SystemExtSpecific() bool {
-	return e.kind == systemExtSpecificModule
-}
-
-func (e *earlyModuleContext) Namespace() *Namespace {
-	return e.EarlyModuleContext.Namespace().(*Namespace)
-}
-
-type baseModuleContext struct {
-	bp blueprint.BaseModuleContext
-	earlyModuleContext
-	os            OsType
-	target        Target
-	multiTargets  []Target
-	targetPrimary bool
-	debug         bool
-
-	walkPath []Module
-	tagPath  []blueprint.DependencyTag
-
-	strictVisitDeps bool // If true, enforce that all dependencies are enabled
-
-	bazelConversionMode bool
-}
-
-func (b *baseModuleContext) isBazelConversionMode() bool {
-	return b.bazelConversionMode
-}
-func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string {
-	return b.bp.OtherModuleName(m)
-}
-func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string { return b.bp.OtherModuleDir(m) }
-func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) {
-	b.bp.OtherModuleErrorf(m, fmt, args...)
-}
-func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag {
-	return b.bp.OtherModuleDependencyTag(m)
-}
-func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) }
-func (b *baseModuleContext) OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool {
-	return b.bp.OtherModuleDependencyVariantExists(variations, name)
-}
-func (b *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool {
-	return b.bp.OtherModuleFarDependencyVariantExists(variations, name)
-}
-func (b *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool {
-	return b.bp.OtherModuleReverseDependencyVariantExists(name)
-}
-func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string {
-	return b.bp.OtherModuleType(m)
-}
-func (b *baseModuleContext) OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{} {
-	return b.bp.OtherModuleProvider(m, provider)
-}
-func (b *baseModuleContext) OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool {
-	return b.bp.OtherModuleHasProvider(m, provider)
-}
-func (b *baseModuleContext) Provider(provider blueprint.ProviderKey) interface{} {
-	return b.bp.Provider(provider)
-}
-func (b *baseModuleContext) HasProvider(provider blueprint.ProviderKey) bool {
-	return b.bp.HasProvider(provider)
-}
-func (b *baseModuleContext) SetProvider(provider blueprint.ProviderKey, value interface{}) {
-	b.bp.SetProvider(provider, value)
-}
-
-func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
-	return b.bp.GetDirectDepWithTag(name, tag)
-}
-
-func (b *baseModuleContext) blueprintBaseModuleContext() blueprint.BaseModuleContext {
-	return b.bp
-}
-
-type moduleContext struct {
-	bp blueprint.ModuleContext
-	baseModuleContext
-	packagingSpecs  []PackagingSpec
-	installFiles    InstallPaths
-	checkbuildFiles Paths
-	module          Module
-	phonies         map[string]Paths
-
-	katiInstalls []katiInstall
-	katiSymlinks []katiInstall
-
-	// For tests
-	buildParams []BuildParams
-	ruleParams  map[blueprint.Rule]blueprint.RuleParams
-	variables   map[string]string
-}
-
 // katiInstall stores a request from Soong to Make to create an install rule.
 type katiInstall struct {
 	from          Path
@@ -2762,517 +2095,6 @@
 	return paths
 }
 
-func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContext, BuildParams) {
-	return pctx, BuildParams{
-		Rule:            ErrorRule,
-		Description:     params.Description,
-		Output:          params.Output,
-		Outputs:         params.Outputs,
-		ImplicitOutput:  params.ImplicitOutput,
-		ImplicitOutputs: params.ImplicitOutputs,
-		Args: map[string]string{
-			"error": err.Error(),
-		},
-	}
-}
-
-func (m *moduleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) {
-	m.Build(pctx, BuildParams(params))
-}
-
-func validateBuildParams(params blueprint.BuildParams) error {
-	// Validate that the symlink outputs are declared outputs or implicit outputs
-	allOutputs := map[string]bool{}
-	for _, output := range params.Outputs {
-		allOutputs[output] = true
-	}
-	for _, output := range params.ImplicitOutputs {
-		allOutputs[output] = true
-	}
-	for _, symlinkOutput := range params.SymlinkOutputs {
-		if !allOutputs[symlinkOutput] {
-			return fmt.Errorf(
-				"Symlink output %s is not a declared output or implicit output",
-				symlinkOutput)
-		}
-	}
-	return nil
-}
-
-// Convert build parameters from their concrete Android types into their string representations,
-// and combine the singular and plural fields of the same type (e.g. Output and Outputs).
-func convertBuildParams(params BuildParams) blueprint.BuildParams {
-	bparams := blueprint.BuildParams{
-		Rule:            params.Rule,
-		Description:     params.Description,
-		Deps:            params.Deps,
-		Outputs:         params.Outputs.Strings(),
-		ImplicitOutputs: params.ImplicitOutputs.Strings(),
-		SymlinkOutputs:  params.SymlinkOutputs.Strings(),
-		Inputs:          params.Inputs.Strings(),
-		Implicits:       params.Implicits.Strings(),
-		OrderOnly:       params.OrderOnly.Strings(),
-		Validations:     params.Validations.Strings(),
-		Args:            params.Args,
-		Optional:        !params.Default,
-	}
-
-	if params.Depfile != nil {
-		bparams.Depfile = params.Depfile.String()
-	}
-	if params.Output != nil {
-		bparams.Outputs = append(bparams.Outputs, params.Output.String())
-	}
-	if params.SymlinkOutput != nil {
-		bparams.SymlinkOutputs = append(bparams.SymlinkOutputs, params.SymlinkOutput.String())
-	}
-	if params.ImplicitOutput != nil {
-		bparams.ImplicitOutputs = append(bparams.ImplicitOutputs, params.ImplicitOutput.String())
-	}
-	if params.Input != nil {
-		bparams.Inputs = append(bparams.Inputs, params.Input.String())
-	}
-	if params.Implicit != nil {
-		bparams.Implicits = append(bparams.Implicits, params.Implicit.String())
-	}
-	if params.Validation != nil {
-		bparams.Validations = append(bparams.Validations, params.Validation.String())
-	}
-
-	bparams.Outputs = proptools.NinjaEscapeList(bparams.Outputs)
-	bparams.ImplicitOutputs = proptools.NinjaEscapeList(bparams.ImplicitOutputs)
-	bparams.SymlinkOutputs = proptools.NinjaEscapeList(bparams.SymlinkOutputs)
-	bparams.Inputs = proptools.NinjaEscapeList(bparams.Inputs)
-	bparams.Implicits = proptools.NinjaEscapeList(bparams.Implicits)
-	bparams.OrderOnly = proptools.NinjaEscapeList(bparams.OrderOnly)
-	bparams.Validations = proptools.NinjaEscapeList(bparams.Validations)
-	bparams.Depfile = proptools.NinjaEscape(bparams.Depfile)
-
-	return bparams
-}
-
-func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
-	if m.config.captureBuild {
-		m.variables[name] = value
-	}
-
-	m.bp.Variable(pctx.PackageContext, name, value)
-}
-
-func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
-	argNames ...string) blueprint.Rule {
-
-	if m.config.UseRemoteBuild() {
-		if params.Pool == nil {
-			// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
-			// jobs to the local parallelism value
-			params.Pool = localPool
-		} else if params.Pool == remotePool {
-			// remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
-			// pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
-			// parallelism.
-			params.Pool = nil
-		}
-	}
-
-	rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...)
-
-	if m.config.captureBuild {
-		m.ruleParams[rule] = params
-	}
-
-	return rule
-}
-
-func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
-	if params.Description != "" {
-		params.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}"
-	}
-
-	if missingDeps := m.GetMissingDependencies(); len(missingDeps) > 0 {
-		pctx, params = m.ninjaError(params, fmt.Errorf("module %s missing dependencies: %s\n",
-			m.ModuleName(), strings.Join(missingDeps, ", ")))
-	}
-
-	if m.config.captureBuild {
-		m.buildParams = append(m.buildParams, params)
-	}
-
-	bparams := convertBuildParams(params)
-	err := validateBuildParams(bparams)
-	if err != nil {
-		m.ModuleErrorf(
-			"%s: build parameter validation failed: %s",
-			m.ModuleName(),
-			err.Error())
-	}
-	m.bp.Build(pctx.PackageContext, bparams)
-}
-
-func (m *moduleContext) Phony(name string, deps ...Path) {
-	addPhony(m.config, name, deps...)
-}
-
-func (m *moduleContext) GetMissingDependencies() []string {
-	var missingDeps []string
-	missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...)
-	missingDeps = append(missingDeps, m.bp.GetMissingDependencies()...)
-	missingDeps = FirstUniqueStrings(missingDeps)
-	return missingDeps
-}
-
-func (b *baseModuleContext) AddMissingDependencies(deps []string) {
-	if deps != nil {
-		missingDeps := &b.Module().base().commonProperties.MissingDeps
-		*missingDeps = append(*missingDeps, deps...)
-		*missingDeps = FirstUniqueStrings(*missingDeps)
-	}
-}
-
-func (b *baseModuleContext) checkedMissingDeps() bool {
-	return b.Module().base().commonProperties.CheckedMissingDeps
-}
-
-func (b *baseModuleContext) getMissingDependencies() []string {
-	checked := &b.Module().base().commonProperties.CheckedMissingDeps
-	*checked = true
-	var missingDeps []string
-	missingDeps = append(missingDeps, b.Module().base().commonProperties.MissingDeps...)
-	missingDeps = append(missingDeps, b.bp.EarlyGetMissingDependencies()...)
-	missingDeps = FirstUniqueStrings(missingDeps)
-	return missingDeps
-}
-
-type AllowDisabledModuleDependency interface {
-	blueprint.DependencyTag
-	AllowDisabledModuleDependency(target Module) bool
-}
-
-func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool) Module {
-	aModule, _ := module.(Module)
-
-	if !strict {
-		return aModule
-	}
-
-	if aModule == nil {
-		b.ModuleErrorf("module %q (%#v) not an android module", b.OtherModuleName(module), tag)
-		return nil
-	}
-
-	if !aModule.Enabled() {
-		if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependency(aModule) {
-			if b.Config().AllowMissingDependencies() {
-				b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
-			} else {
-				b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
-			}
-		}
-		return nil
-	}
-	return aModule
-}
-
-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 {
-			if aModule.base().BaseModuleName() == name {
-				returnedTag := b.bp.OtherModuleDependencyTag(aModule)
-				if tag == nil || returnedTag == tag {
-					deps = append(deps, dep{aModule, returnedTag})
-				}
-			}
-		} else if b.bp.OtherModuleName(module) == name {
-			returnedTag := b.bp.OtherModuleDependencyTag(module)
-			if tag == nil || returnedTag == tag {
-				deps = append(deps, dep{module, returnedTag})
-			}
-		}
-	})
-	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 {
-		panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
-			name, b.ModuleName()))
-	} else {
-		return nil, nil
-	}
-}
-
-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) {
-		if aModule, _ := module.(Module); aModule != nil {
-			if b.bp.OtherModuleDependencyTag(aModule) == tag {
-				deps = append(deps, aModule)
-			}
-		}
-	})
-	return deps
-}
-
-func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
-	module, _ := m.getDirectDepInternal(name, tag)
-	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.getDirectDepFirstTag(name)
-}
-
-func (b *baseModuleContext) ModuleFromName(name string) (blueprint.Module, bool) {
-	if !b.isBazelConversionMode() {
-		panic("cannot call ModuleFromName if not in bazel conversion mode")
-	}
-	if moduleName, _ := SrcIsModuleWithTag(name); moduleName != "" {
-		return b.bp.ModuleFromName(moduleName)
-	} else {
-		return b.bp.ModuleFromName(name)
-	}
-}
-
-func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) {
-	b.bp.VisitDirectDeps(visit)
-}
-
-func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) {
-	b.bp.VisitDirectDeps(func(module blueprint.Module) {
-		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
-			visit(aModule)
-		}
-	})
-}
-
-func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
-	b.bp.VisitDirectDeps(func(module blueprint.Module) {
-		if b.bp.OtherModuleDependencyTag(module) == tag {
-			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
-				visit(aModule)
-			}
-		}
-	})
-}
-
-func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
-	b.bp.VisitDirectDepsIf(
-		// pred
-		func(module blueprint.Module) bool {
-			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
-				return pred(aModule)
-			} else {
-				return false
-			}
-		},
-		// visit
-		func(module blueprint.Module) {
-			visit(module.(Module))
-		})
-}
-
-func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
-	b.bp.VisitDepsDepthFirst(func(module blueprint.Module) {
-		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
-			visit(aModule)
-		}
-	})
-}
-
-func (b *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) {
-	b.bp.VisitDepsDepthFirstIf(
-		// pred
-		func(module blueprint.Module) bool {
-			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
-				return pred(aModule)
-			} else {
-				return false
-			}
-		},
-		// visit
-		func(module blueprint.Module) {
-			visit(module.(Module))
-		})
-}
-
-func (b *baseModuleContext) WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) {
-	b.bp.WalkDeps(visit)
-}
-
-func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
-	b.walkPath = []Module{b.Module()}
-	b.tagPath = []blueprint.DependencyTag{}
-	b.bp.WalkDeps(func(child, parent blueprint.Module) bool {
-		childAndroidModule, _ := child.(Module)
-		parentAndroidModule, _ := parent.(Module)
-		if childAndroidModule != nil && parentAndroidModule != nil {
-			// record walkPath before visit
-			for b.walkPath[len(b.walkPath)-1] != parentAndroidModule {
-				b.walkPath = b.walkPath[0 : len(b.walkPath)-1]
-				b.tagPath = b.tagPath[0 : len(b.tagPath)-1]
-			}
-			b.walkPath = append(b.walkPath, childAndroidModule)
-			b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule))
-			return visit(childAndroidModule, parentAndroidModule)
-		} else {
-			return false
-		}
-	})
-}
-
-func (b *baseModuleContext) GetWalkPath() []Module {
-	return b.walkPath
-}
-
-func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag {
-	return b.tagPath
-}
-
-func (b *baseModuleContext) VisitAllModuleVariants(visit func(Module)) {
-	b.bp.VisitAllModuleVariants(func(module blueprint.Module) {
-		visit(module.(Module))
-	})
-}
-
-func (b *baseModuleContext) PrimaryModule() Module {
-	return b.bp.PrimaryModule().(Module)
-}
-
-func (b *baseModuleContext) FinalModule() Module {
-	return b.bp.FinalModule().(Module)
-}
-
-// IsMetaDependencyTag returns true for cross-cutting metadata dependencies.
-func IsMetaDependencyTag(tag blueprint.DependencyTag) bool {
-	if tag == licenseKindTag {
-		return true
-	} else if tag == licensesTag {
-		return true
-	}
-	return false
-}
-
-// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
-// a dependency tag.
-var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:{}\E(, )?`)
-
-// PrettyPrintTag returns string representation of the tag, but prefers
-// custom String() method if available.
-func PrettyPrintTag(tag blueprint.DependencyTag) string {
-	// Use tag's custom String() method if available.
-	if stringer, ok := tag.(fmt.Stringer); ok {
-		return stringer.String()
-	}
-
-	// Otherwise, get a default string representation of the tag's struct.
-	tagString := fmt.Sprintf("%T: %+v", tag, tag)
-
-	// Remove the boilerplate from BaseDependencyTag as it adds no value.
-	tagString = tagCleaner.ReplaceAllString(tagString, "")
-	return tagString
-}
-
-func (b *baseModuleContext) GetPathString(skipFirst bool) string {
-	sb := strings.Builder{}
-	tagPath := b.GetTagPath()
-	walkPath := b.GetWalkPath()
-	if !skipFirst {
-		sb.WriteString(walkPath[0].String())
-	}
-	for i, m := range walkPath[1:] {
-		sb.WriteString("\n")
-		sb.WriteString(fmt.Sprintf("           via tag %s\n", PrettyPrintTag(tagPath[i])))
-		sb.WriteString(fmt.Sprintf("    -> %s", m.String()))
-	}
-	return sb.String()
-}
-
-func (m *moduleContext) ModuleSubDir() string {
-	return m.bp.ModuleSubDir()
-}
-
-func (m *moduleContext) SoongConfigTraceHash() string {
-	return m.module.base().commonProperties.SoongConfigTraceHash
-}
-
-func (b *baseModuleContext) Target() Target {
-	return b.target
-}
-
-func (b *baseModuleContext) TargetPrimary() bool {
-	return b.targetPrimary
-}
-
-func (b *baseModuleContext) MultiTargets() []Target {
-	return b.multiTargets
-}
-
-func (b *baseModuleContext) Arch() Arch {
-	return b.target.Arch
-}
-
-func (b *baseModuleContext) Os() OsType {
-	return b.os
-}
-
-func (b *baseModuleContext) Host() bool {
-	return b.os.Class == Host
-}
-
-func (b *baseModuleContext) Device() bool {
-	return b.os.Class == Device
-}
-
-func (b *baseModuleContext) Darwin() bool {
-	return b.os == Darwin
-}
-
-func (b *baseModuleContext) Windows() bool {
-	return b.os == Windows
-}
-
-func (b *baseModuleContext) Debug() bool {
-	return b.debug
-}
-
-func (b *baseModuleContext) PrimaryArch() bool {
-	if len(b.config.Targets[b.target.Os]) <= 1 {
-		return true
-	}
-	return b.target.Arch.ArchType == b.config.Targets[b.target.Os][0].Arch.ArchType
-}
-
 // Makes this module a platform module, i.e. not specific to soc, device,
 // product, or system_ext.
 func (m *ModuleBase) MakeAsPlatform() {
@@ -3296,272 +2118,116 @@
 	return proptools.Bool(m.commonProperties.Native_bridge_supported)
 }
 
-func (m *moduleContext) InstallInData() bool {
-	return m.module.InstallInData()
+type ConfigAndErrorContext interface {
+	Config() Config
+	OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{})
 }
 
-func (m *moduleContext) InstallInTestcases() bool {
-	return m.module.InstallInTestcases()
+type configurationEvalutor struct {
+	ctx ConfigAndErrorContext
+	m   Module
 }
 
-func (m *moduleContext) InstallInSanitizerDir() bool {
-	return m.module.InstallInSanitizerDir()
-}
-
-func (m *moduleContext) InstallInRamdisk() bool {
-	return m.module.InstallInRamdisk()
-}
-
-func (m *moduleContext) InstallInVendorRamdisk() bool {
-	return m.module.InstallInVendorRamdisk()
-}
-
-func (m *moduleContext) InstallInDebugRamdisk() bool {
-	return m.module.InstallInDebugRamdisk()
-}
-
-func (m *moduleContext) InstallInRecovery() bool {
-	return m.module.InstallInRecovery()
-}
-
-func (m *moduleContext) InstallInRoot() bool {
-	return m.module.InstallInRoot()
-}
-
-func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) {
-	return m.module.InstallForceOS()
-}
-
-func (m *moduleContext) InstallInVendor() bool {
-	return m.module.InstallInVendor()
-}
-
-func (m *moduleContext) skipInstall() bool {
-	if m.module.base().commonProperties.SkipInstall {
-		return true
+func (m *ModuleBase) ConfigurableEvaluator(ctx ConfigAndErrorContext) proptools.ConfigurableEvaluator {
+	return configurationEvalutor{
+		ctx: ctx,
+		m:   m.module,
 	}
-
-	if m.module.base().commonProperties.HideFromMake {
-		return true
-	}
-
-	// We'll need a solution for choosing which of modules with the same name in different
-	// namespaces to install.  For now, reuse the list of namespaces exported to Make as the
-	// list of namespaces to install in a Soong-only build.
-	if !m.module.base().commonProperties.NamespaceExportedToMake {
-		return true
-	}
-
-	return false
 }
 
-func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path,
-	deps ...Path) InstallPath {
-	return m.installFile(installPath, name, srcPath, deps, false, nil)
+func (e configurationEvalutor) PropertyErrorf(property string, fmt string, args ...interface{}) {
+	e.ctx.OtherModulePropertyErrorf(e.m, property, fmt, args)
 }
 
-func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path,
-	deps ...Path) InstallPath {
-	return m.installFile(installPath, name, srcPath, deps, true, nil)
-}
-
-func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path,
-	extraZip Path, deps ...Path) InstallPath {
-	return m.installFile(installPath, name, srcPath, deps, false, &extraFilesZip{
-		zip: extraZip,
-		dir: installPath,
-	})
-}
-
-func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec {
-	fullInstallPath := installPath.Join(m, name)
-	return m.packageFile(fullInstallPath, srcPath, false)
-}
-
-func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec {
-	licenseFiles := m.Module().EffectiveLicenseFiles()
-	spec := PackagingSpec{
-		relPathInPackage:      Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
-		srcPath:               srcPath,
-		symlinkTarget:         "",
-		executable:            executable,
-		effectiveLicenseFiles: &licenseFiles,
-		partition:             fullInstallPath.partition,
-	}
-	m.packagingSpecs = append(m.packagingSpecs, spec)
-	return spec
-}
-
-func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []Path,
-	executable bool, extraZip *extraFilesZip) InstallPath {
-
-	fullInstallPath := installPath.Join(m, name)
-	m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false)
-
-	if !m.skipInstall() {
-		deps = append(deps, InstallPaths(m.module.base().installFilesDepSet.ToList()).Paths()...)
-
-		var implicitDeps, orderOnlyDeps Paths
-
-		if m.Host() {
-			// Installed host modules might be used during the build, depend directly on their
-			// dependencies so their timestamp is updated whenever their dependency is updated
-			implicitDeps = deps
-		} else {
-			orderOnlyDeps = deps
+func (e configurationEvalutor) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue {
+	ctx := e.ctx
+	m := e.m
+	switch condition.FunctionName() {
+	case "release_variable":
+		if condition.NumArgs() != 1 {
+			ctx.OtherModulePropertyErrorf(m, property, "release_variable requires 1 argument, found %d", condition.NumArgs())
+			return proptools.ConfigurableValueUndefined()
 		}
-
-		if m.Config().KatiEnabled() {
-			// When creating the install rule in Soong but embedding in Make, write the rule to a
-			// makefile instead of directly to the ninja file so that main.mk can add the
-			// dependencies from the `required` property that are hard to resolve in Soong.
-			m.katiInstalls = append(m.katiInstalls, katiInstall{
-				from:          srcPath,
-				to:            fullInstallPath,
-				implicitDeps:  implicitDeps,
-				orderOnlyDeps: orderOnlyDeps,
-				executable:    executable,
-				extraFiles:    extraZip,
-			})
-		} else {
-			rule := Cp
-			if executable {
-				rule = CpExecutable
+		if v, ok := ctx.Config().productVariables.BuildFlags[condition.Arg(0)]; ok {
+			return proptools.ConfigurableValueString(v)
+		}
+		return proptools.ConfigurableValueUndefined()
+	case "product_variable":
+		// TODO(b/323382414): Might add these on a case-by-case basis
+		ctx.OtherModulePropertyErrorf(m, property, "TODO(b/323382414): Product variables are not yet supported in selects")
+		return proptools.ConfigurableValueUndefined()
+	case "soong_config_variable":
+		if condition.NumArgs() != 2 {
+			ctx.OtherModulePropertyErrorf(m, property, "soong_config_variable requires 2 arguments, found %d", condition.NumArgs())
+			return proptools.ConfigurableValueUndefined()
+		}
+		namespace := condition.Arg(0)
+		variable := condition.Arg(1)
+		if n, ok := ctx.Config().productVariables.VendorVars[namespace]; ok {
+			if v, ok := n[variable]; ok {
+				return proptools.ConfigurableValueString(v)
 			}
+		}
+		return proptools.ConfigurableValueUndefined()
+	case "arch":
+		if condition.NumArgs() != 0 {
+			ctx.OtherModulePropertyErrorf(m, property, "arch requires no arguments, found %d", condition.NumArgs())
+			return proptools.ConfigurableValueUndefined()
+		}
+		if !m.base().ArchReady() {
+			ctx.OtherModulePropertyErrorf(m, property, "A select on arch was attempted before the arch mutator ran")
+			return proptools.ConfigurableValueUndefined()
+		}
+		return proptools.ConfigurableValueString(m.base().Arch().ArchType.Name)
+	case "os":
+		if condition.NumArgs() != 0 {
+			ctx.OtherModulePropertyErrorf(m, property, "os requires no arguments, found %d", condition.NumArgs())
+			return proptools.ConfigurableValueUndefined()
+		}
+		// the arch mutator runs after the os mutator, we can just use this to enforce that os is ready.
+		if !m.base().ArchReady() {
+			ctx.OtherModulePropertyErrorf(m, property, "A select on os was attempted before the arch mutator ran (arch runs after os, we use it to lazily detect that os is ready)")
+			return proptools.ConfigurableValueUndefined()
+		}
+		return proptools.ConfigurableValueString(m.base().Os().Name)
+	case "boolean_var_for_testing":
+		// We currently don't have any other boolean variables (we should add support for typing
+		// the soong config variables), so add this fake one for testing the boolean select
+		// functionality.
+		if condition.NumArgs() != 0 {
+			ctx.OtherModulePropertyErrorf(m, property, "boolean_var_for_testing requires 0 arguments, found %d", condition.NumArgs())
+			return proptools.ConfigurableValueUndefined()
+		}
 
-			extraCmds := ""
-			if extraZip != nil {
-				extraCmds += fmt.Sprintf(" && ( unzip -qDD -d '%s' '%s' 2>&1 | grep -v \"zipfile is empty\"; exit $${PIPESTATUS[0]} )",
-					extraZip.dir.String(), extraZip.zip.String())
-				extraCmds += " || ( code=$$?; if [ $$code -ne 0 -a $$code -ne 1 ]; then exit $$code; fi )"
-				implicitDeps = append(implicitDeps, extraZip.zip)
+		if n, ok := ctx.Config().productVariables.VendorVars["boolean_var"]; ok {
+			if v, ok := n["for_testing"]; ok {
+				switch v {
+				case "true":
+					return proptools.ConfigurableValueBool(true)
+				case "false":
+					return proptools.ConfigurableValueBool(false)
+				default:
+					ctx.OtherModulePropertyErrorf(m, property, "testing:my_boolean_var can only be true or false, found %q", v)
+				}
 			}
-
-			m.Build(pctx, BuildParams{
-				Rule:        rule,
-				Description: "install " + fullInstallPath.Base(),
-				Output:      fullInstallPath,
-				Input:       srcPath,
-				Implicits:   implicitDeps,
-				OrderOnly:   orderOnlyDeps,
-				Default:     !m.Config().KatiEnabled(),
-				Args: map[string]string{
-					"extraCmds": extraCmds,
-				},
-			})
 		}
-
-		m.installFiles = append(m.installFiles, fullInstallPath)
+		return proptools.ConfigurableValueUndefined()
+	default:
+		ctx.OtherModulePropertyErrorf(m, property, "Unknown select condition %s", condition.FunctionName)
+		return proptools.ConfigurableValueUndefined()
 	}
-
-	m.packageFile(fullInstallPath, srcPath, executable)
-
-	m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
-
-	return fullInstallPath
 }
 
-func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath {
-	fullInstallPath := installPath.Join(m, name)
-	m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, true)
-
-	relPath, err := filepath.Rel(path.Dir(fullInstallPath.String()), srcPath.String())
-	if err != nil {
-		panic(fmt.Sprintf("Unable to generate symlink between %q and %q: %s", fullInstallPath.Base(), srcPath.Base(), err))
-	}
-	if !m.skipInstall() {
-
-		if m.Config().KatiEnabled() {
-			// When creating the symlink rule in Soong but embedding in Make, write the rule to a
-			// makefile instead of directly to the ninja file so that main.mk can add the
-			// dependencies from the `required` property that are hard to resolve in Soong.
-			m.katiSymlinks = append(m.katiSymlinks, katiInstall{
-				from: srcPath,
-				to:   fullInstallPath,
-			})
-		} else {
-			// The symlink doesn't need updating when the target is modified, but we sometimes
-			// have a dependency on a symlink to a binary instead of to the binary directly, and
-			// the mtime of the symlink must be updated when the binary is modified, so use a
-			// normal dependency here instead of an order-only dependency.
-			m.Build(pctx, BuildParams{
-				Rule:        Symlink,
-				Description: "install symlink " + fullInstallPath.Base(),
-				Output:      fullInstallPath,
-				Input:       srcPath,
-				Default:     !m.Config().KatiEnabled(),
-				Args: map[string]string{
-					"fromPath": relPath,
-				},
-			})
+// ModuleNameWithPossibleOverride returns the name of the OverrideModule that overrides the current
+// variant of this OverridableModule, or ctx.ModuleName() if this module is not an OverridableModule
+// or if this variant is not overridden.
+func ModuleNameWithPossibleOverride(ctx BaseModuleContext) string {
+	if overridable, ok := ctx.Module().(OverridableModule); ok {
+		if o := overridable.GetOverriddenBy(); o != "" {
+			return o
 		}
-
-		m.installFiles = append(m.installFiles, fullInstallPath)
-		m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
 	}
-
-	m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
-		relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
-		srcPath:          nil,
-		symlinkTarget:    relPath,
-		executable:       false,
-		partition:        fullInstallPath.partition,
-	})
-
-	return fullInstallPath
-}
-
-// installPath/name -> absPath where absPath might be a path that is available only at runtime
-// (e.g. /apex/...)
-func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath {
-	fullInstallPath := installPath.Join(m, name)
-	m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true)
-
-	if !m.skipInstall() {
-		if m.Config().KatiEnabled() {
-			// When creating the symlink rule in Soong but embedding in Make, write the rule to a
-			// makefile instead of directly to the ninja file so that main.mk can add the
-			// dependencies from the `required` property that are hard to resolve in Soong.
-			m.katiSymlinks = append(m.katiSymlinks, katiInstall{
-				absFrom: absPath,
-				to:      fullInstallPath,
-			})
-		} else {
-			m.Build(pctx, BuildParams{
-				Rule:        Symlink,
-				Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath,
-				Output:      fullInstallPath,
-				Default:     !m.Config().KatiEnabled(),
-				Args: map[string]string{
-					"fromPath": absPath,
-				},
-			})
-		}
-
-		m.installFiles = append(m.installFiles, fullInstallPath)
-	}
-
-	m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
-		relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
-		srcPath:          nil,
-		symlinkTarget:    absPath,
-		executable:       false,
-		partition:        fullInstallPath.partition,
-	})
-
-	return fullInstallPath
-}
-
-func (m *moduleContext) CheckbuildFile(srcPath Path) {
-	m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
-}
-
-func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext {
-	return m.bp
-}
-
-func (m *moduleContext) LicenseMetadataFile() Path {
-	return m.module.base().licenseMetadataFile
+	return ctx.ModuleName()
 }
 
 // SrcIsModule decodes module references in the format ":unqualified-name" or "//namespace:name"
@@ -3631,6 +2297,7 @@
 // caused by prebuilt_ prefix, or fully qualified module names.
 type sourceOrOutputDependencyTag struct {
 	blueprint.BaseDependencyTag
+	AlwaysPropagateAconfigValidationDependencyTag
 
 	// The name of the module.
 	moduleName string
@@ -3770,44 +2437,6 @@
 	HostToolPath() OptionalPath
 }
 
-// Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must
-// be tagged with `android:"path" to support automatic source module dependency resolution.
-//
-// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
-func (m *moduleContext) ExpandSources(srcFiles, excludes []string) Paths {
-	return PathsForModuleSrcExcludes(m, srcFiles, excludes)
-}
-
-// Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must
-// be tagged with `android:"path" to support automatic source module dependency resolution.
-//
-// Deprecated: use PathForModuleSrc instead.
-func (m *moduleContext) ExpandSource(srcFile, _ string) Path {
-	return PathForModuleSrc(m, srcFile)
-}
-
-// Returns an optional single path expanded from globs and modules referenced using ":module" syntax if
-// the srcFile is non-nil.  The property must be tagged with `android:"path" to support automatic source module
-// dependency resolution.
-func (m *moduleContext) ExpandOptionalSource(srcFile *string, _ string) OptionalPath {
-	if srcFile != nil {
-		return OptionalPathForPath(PathForModuleSrc(m, *srcFile))
-	}
-	return OptionalPath{}
-}
-
-func (m *moduleContext) RequiredModuleNames() []string {
-	return m.module.RequiredModuleNames()
-}
-
-func (m *moduleContext) HostRequiredModuleNames() []string {
-	return m.module.HostRequiredModuleNames()
-}
-
-func (m *moduleContext) TargetRequiredModuleNames() []string {
-	return m.module.TargetRequiredModuleNames()
-}
-
 func init() {
 	RegisterParallelSingletonType("buildtarget", BuildTargetSingleton)
 	RegisterParallelSingletonType("soongconfigtrace", soongConfigTraceSingletonFunc)
@@ -4024,36 +2653,3 @@
 	WriteFileRule(ctx, outFile, string(j))
 	ctx.Phony("soong_config_trace", outFile)
 }
-
-// Interface implemented by xsd_config which has 1:many mappings in bp2build workspace
-// This interface exists because we want to
-// 1. Determine the name of the additional targets generated by the primary soong module
-// 2. Enable distinguishing an xsd_config module from other Soong modules using type assertion
-type XsdConfigBp2buildTargets interface {
-	CppBp2buildTargetName() string
-	JavaBp2buildTargetName() string
-}
-
-// XsdModuleToTargetName is a function that takes an XsdConfigBp2buildTarget
-type XsdModuleToTargetName func(xsd XsdConfigBp2buildTargets) string
-
-// XsdLabelMapper returns a bazel.LabelMapper for partitioning XSD sources/headers given an
-// XsdModuleToTargetName function.
-func XsdLabelMapper(targetName XsdModuleToTargetName) bazel.LabelMapper {
-	return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
-		mod, exists := ctx.ModuleFromName(label.OriginalModuleName)
-		if !exists {
-			return label.Label, false
-		}
-		xsdMod, isXsd := mod.(XsdConfigBp2buildTargets)
-		if !isXsd {
-			return label.Label, false
-		}
-
-		// Remove the base module name
-		ret := strings.TrimSuffix(label.Label, mod.Name())
-		// Append the language specific target name
-		ret += targetName(xsdMod)
-		return ret, true
-	}
-}
diff --git a/android/module_context.go b/android/module_context.go
new file mode 100644
index 0000000..dea22ba
--- /dev/null
+++ b/android/module_context.go
@@ -0,0 +1,721 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"fmt"
+	"path"
+	"path/filepath"
+	"strings"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+// BuildParameters describes the set of potential parameters to build a Ninja rule.
+// In general, these correspond to a Ninja concept.
+type BuildParams struct {
+	// A Ninja Rule that will be written to the Ninja file. This allows factoring out common code
+	// among multiple modules to reduce repetition in the Ninja file of action requirements. A rule
+	// can contain variables that should be provided in Args.
+	Rule blueprint.Rule
+	// Deps represents the depfile format. When using RuleBuilder, this defaults to GCC when depfiles
+	// are used.
+	Deps blueprint.Deps
+	// Depfile is a writeable path that allows correct incremental builds when the inputs have not
+	// been fully specified by the Ninja rule. Ninja supports a subset of the Makefile depfile syntax.
+	Depfile WritablePath
+	// A description of the build action.
+	Description string
+	// Output is an output file of the action. When using this field, references to $out in the Ninja
+	// command will refer to this file.
+	Output WritablePath
+	// Outputs is a slice of output file of the action. When using this field, references to $out in
+	// the Ninja command will refer to these files.
+	Outputs WritablePaths
+	// ImplicitOutput is an output file generated by the action. Note: references to `$out` in the
+	// Ninja command will NOT include references to this file.
+	ImplicitOutput WritablePath
+	// ImplicitOutputs is a slice of output files generated by the action. Note: references to `$out`
+	// in the Ninja command will NOT include references to these files.
+	ImplicitOutputs WritablePaths
+	// Input is an input file to the Ninja action. When using this field, references to $in in the
+	// Ninja command will refer to this file.
+	Input Path
+	// Inputs is a slice of input files to the Ninja action. When using this field, references to $in
+	// in the Ninja command will refer to these files.
+	Inputs Paths
+	// Implicit is an input file to the Ninja action. Note: references to `$in` in the Ninja command
+	// will NOT include references to this file.
+	Implicit Path
+	// Implicits is a slice of input files to the Ninja action. Note: references to `$in` in the Ninja
+	// command will NOT include references to these files.
+	Implicits Paths
+	// OrderOnly are Ninja order-only inputs to the action. When these are out of date, the output is
+	// not rebuilt until they are built, but changes in order-only dependencies alone do not cause the
+	// output to be rebuilt.
+	OrderOnly Paths
+	// Validation is an output path for a validation action. Validation outputs imply lower
+	// non-blocking priority to building non-validation outputs.
+	Validation Path
+	// Validations is a slice of output path for a validation action. Validation outputs imply lower
+	// non-blocking priority to building non-validation outputs.
+	Validations Paths
+	// Whether to skip outputting a default target statement which will be built by Ninja when no
+	// targets are specified on Ninja's command line.
+	Default bool
+	// Args is a key value mapping for replacements of variables within the Rule
+	Args map[string]string
+}
+
+type ModuleBuildParams BuildParams
+
+type ModuleContext interface {
+	BaseModuleContext
+
+	blueprintModuleContext() blueprint.ModuleContext
+
+	// Deprecated: use ModuleContext.Build instead.
+	ModuleBuild(pctx PackageContext, params ModuleBuildParams)
+
+	// Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must
+	// be tagged with `android:"path" to support automatic source module dependency resolution.
+	//
+	// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
+	ExpandSources(srcFiles, excludes []string) Paths
+
+	// Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must
+	// be tagged with `android:"path" to support automatic source module dependency resolution.
+	//
+	// Deprecated: use PathForModuleSrc instead.
+	ExpandSource(srcFile, prop string) Path
+
+	ExpandOptionalSource(srcFile *string, prop string) OptionalPath
+
+	// InstallExecutable creates a rule to copy srcPath to name in the installPath directory,
+	// with the given additional dependencies.  The file is marked executable after copying.
+	//
+	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
+
+	// InstallFile creates a rule to copy srcPath to name in the installPath directory,
+	// with the given additional dependencies.
+	//
+	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	InstallFile(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
+
+	// InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath
+	// directory, and also unzip a zip file containing extra files to install into the same
+	// directory.
+	//
+	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...InstallPath) InstallPath
+
+	// InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath
+	// directory.
+	//
+	// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath
+
+	// InstallAbsoluteSymlink creates a rule to create an absolute symlink from src srcPath to name
+	// in the installPath directory.
+	//
+	// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath
+
+	// InstallTestData creates rules to install test data (e.g. data files used during a test) into
+	// the installPath directory.
+	//
+	// The installed files will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed files will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	InstallTestData(installPath InstallPath, data []DataPath) InstallPaths
+
+	// PackageFile creates a PackagingSpec as if InstallFile was called, but without creating
+	// the rule to copy the file.  This is useful to define how a module would be packaged
+	// without installing it into the global installation directories.
+	//
+	// The created PackagingSpec for the will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec
+
+	CheckbuildFile(srcPath Path)
+
+	InstallInData() bool
+	InstallInTestcases() bool
+	InstallInSanitizerDir() bool
+	InstallInRamdisk() bool
+	InstallInVendorRamdisk() bool
+	InstallInDebugRamdisk() bool
+	InstallInRecovery() bool
+	InstallInRoot() bool
+	InstallInOdm() bool
+	InstallInProduct() bool
+	InstallInVendor() bool
+	InstallForceOS() (*OsType, *ArchType)
+
+	RequiredModuleNames() []string
+	HostRequiredModuleNames() []string
+	TargetRequiredModuleNames() []string
+
+	ModuleSubDir() string
+	SoongConfigTraceHash() string
+
+	Variable(pctx PackageContext, name, value string)
+	Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
+	// Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string,
+	// and performs more verification.
+	Build(pctx PackageContext, params BuildParams)
+	// Phony creates a Make-style phony rule, a rule with no commands that can depend on other
+	// phony rules or real files.  Phony can be called on the same name multiple times to add
+	// additional dependencies.
+	Phony(phony string, deps ...Path)
+
+	// GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods,
+	// but do not exist.
+	GetMissingDependencies() []string
+
+	// LicenseMetadataFile returns the path where the license metadata for this module will be
+	// generated.
+	LicenseMetadataFile() Path
+
+	// ModuleInfoJSON returns a pointer to the ModuleInfoJSON struct that can be filled out by
+	// GenerateAndroidBuildActions.  If it is called then the struct will be written out and included in
+	// the module-info.json generated by Make, and Make will not generate its own data for this module.
+	ModuleInfoJSON() *ModuleInfoJSON
+}
+
+type moduleContext struct {
+	bp blueprint.ModuleContext
+	baseModuleContext
+	packagingSpecs  []PackagingSpec
+	installFiles    InstallPaths
+	checkbuildFiles Paths
+	module          Module
+	phonies         map[string]Paths
+
+	katiInstalls []katiInstall
+	katiSymlinks []katiInstall
+
+	testData []DataPath
+
+	// For tests
+	buildParams []BuildParams
+	ruleParams  map[blueprint.Rule]blueprint.RuleParams
+	variables   map[string]string
+}
+
+var _ ModuleContext = &moduleContext{}
+
+func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContext, BuildParams) {
+	return pctx, BuildParams{
+		Rule:            ErrorRule,
+		Description:     params.Description,
+		Output:          params.Output,
+		Outputs:         params.Outputs,
+		ImplicitOutput:  params.ImplicitOutput,
+		ImplicitOutputs: params.ImplicitOutputs,
+		Args: map[string]string{
+			"error": err.Error(),
+		},
+	}
+}
+
+func (m *moduleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) {
+	m.Build(pctx, BuildParams(params))
+}
+
+// Convert build parameters from their concrete Android types into their string representations,
+// and combine the singular and plural fields of the same type (e.g. Output and Outputs).
+func convertBuildParams(params BuildParams) blueprint.BuildParams {
+	bparams := blueprint.BuildParams{
+		Rule:            params.Rule,
+		Description:     params.Description,
+		Deps:            params.Deps,
+		Outputs:         params.Outputs.Strings(),
+		ImplicitOutputs: params.ImplicitOutputs.Strings(),
+		Inputs:          params.Inputs.Strings(),
+		Implicits:       params.Implicits.Strings(),
+		OrderOnly:       params.OrderOnly.Strings(),
+		Validations:     params.Validations.Strings(),
+		Args:            params.Args,
+		Optional:        !params.Default,
+	}
+
+	if params.Depfile != nil {
+		bparams.Depfile = params.Depfile.String()
+	}
+	if params.Output != nil {
+		bparams.Outputs = append(bparams.Outputs, params.Output.String())
+	}
+	if params.ImplicitOutput != nil {
+		bparams.ImplicitOutputs = append(bparams.ImplicitOutputs, params.ImplicitOutput.String())
+	}
+	if params.Input != nil {
+		bparams.Inputs = append(bparams.Inputs, params.Input.String())
+	}
+	if params.Implicit != nil {
+		bparams.Implicits = append(bparams.Implicits, params.Implicit.String())
+	}
+	if params.Validation != nil {
+		bparams.Validations = append(bparams.Validations, params.Validation.String())
+	}
+
+	bparams.Outputs = proptools.NinjaEscapeList(bparams.Outputs)
+	bparams.ImplicitOutputs = proptools.NinjaEscapeList(bparams.ImplicitOutputs)
+	bparams.Inputs = proptools.NinjaEscapeList(bparams.Inputs)
+	bparams.Implicits = proptools.NinjaEscapeList(bparams.Implicits)
+	bparams.OrderOnly = proptools.NinjaEscapeList(bparams.OrderOnly)
+	bparams.Validations = proptools.NinjaEscapeList(bparams.Validations)
+	bparams.Depfile = proptools.NinjaEscape(bparams.Depfile)
+
+	return bparams
+}
+
+func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
+	if m.config.captureBuild {
+		m.variables[name] = value
+	}
+
+	m.bp.Variable(pctx.PackageContext, name, value)
+}
+
+func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
+	argNames ...string) blueprint.Rule {
+
+	if m.config.UseRemoteBuild() {
+		if params.Pool == nil {
+			// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
+			// jobs to the local parallelism value
+			params.Pool = localPool
+		} else if params.Pool == remotePool {
+			// remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
+			// pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
+			// parallelism.
+			params.Pool = nil
+		}
+	}
+
+	rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...)
+
+	if m.config.captureBuild {
+		m.ruleParams[rule] = params
+	}
+
+	return rule
+}
+
+func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
+	if params.Description != "" {
+		params.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}"
+	}
+
+	if missingDeps := m.GetMissingDependencies(); len(missingDeps) > 0 {
+		pctx, params = m.ninjaError(params, fmt.Errorf("module %s missing dependencies: %s\n",
+			m.ModuleName(), strings.Join(missingDeps, ", ")))
+	}
+
+	if m.config.captureBuild {
+		m.buildParams = append(m.buildParams, params)
+	}
+
+	bparams := convertBuildParams(params)
+	m.bp.Build(pctx.PackageContext, bparams)
+}
+
+func (m *moduleContext) Phony(name string, deps ...Path) {
+	addPhony(m.config, name, deps...)
+}
+
+func (m *moduleContext) GetMissingDependencies() []string {
+	var missingDeps []string
+	missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...)
+	missingDeps = append(missingDeps, m.bp.GetMissingDependencies()...)
+	missingDeps = FirstUniqueStrings(missingDeps)
+	return missingDeps
+}
+
+func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
+	module, _ := m.getDirectDepInternal(name, tag)
+	return module
+}
+
+func (m *moduleContext) ModuleSubDir() string {
+	return m.bp.ModuleSubDir()
+}
+
+func (m *moduleContext) SoongConfigTraceHash() string {
+	return m.module.base().commonProperties.SoongConfigTraceHash
+}
+
+func (m *moduleContext) InstallInData() bool {
+	return m.module.InstallInData()
+}
+
+func (m *moduleContext) InstallInTestcases() bool {
+	return m.module.InstallInTestcases()
+}
+
+func (m *moduleContext) InstallInSanitizerDir() bool {
+	return m.module.InstallInSanitizerDir()
+}
+
+func (m *moduleContext) InstallInRamdisk() bool {
+	return m.module.InstallInRamdisk()
+}
+
+func (m *moduleContext) InstallInVendorRamdisk() bool {
+	return m.module.InstallInVendorRamdisk()
+}
+
+func (m *moduleContext) InstallInDebugRamdisk() bool {
+	return m.module.InstallInDebugRamdisk()
+}
+
+func (m *moduleContext) InstallInRecovery() bool {
+	return m.module.InstallInRecovery()
+}
+
+func (m *moduleContext) InstallInRoot() bool {
+	return m.module.InstallInRoot()
+}
+
+func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) {
+	return m.module.InstallForceOS()
+}
+
+func (m *moduleContext) InstallInOdm() bool {
+	return m.module.InstallInOdm()
+}
+
+func (m *moduleContext) InstallInProduct() bool {
+	return m.module.InstallInProduct()
+}
+
+func (m *moduleContext) InstallInVendor() bool {
+	return m.module.InstallInVendor()
+}
+
+func (m *moduleContext) skipInstall() bool {
+	if m.module.base().commonProperties.SkipInstall {
+		return true
+	}
+
+	if m.module.base().commonProperties.HideFromMake {
+		return true
+	}
+
+	// We'll need a solution for choosing which of modules with the same name in different
+	// namespaces to install.  For now, reuse the list of namespaces exported to Make as the
+	// list of namespaces to install in a Soong-only build.
+	if !m.module.base().commonProperties.NamespaceExportedToMake {
+		return true
+	}
+
+	return false
+}
+
+func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path,
+	deps ...InstallPath) InstallPath {
+	return m.installFile(installPath, name, srcPath, deps, false, true, nil)
+}
+
+func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path,
+	deps ...InstallPath) InstallPath {
+	return m.installFile(installPath, name, srcPath, deps, true, true, nil)
+}
+
+func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path,
+	extraZip Path, deps ...InstallPath) InstallPath {
+	return m.installFile(installPath, name, srcPath, deps, false, true, &extraFilesZip{
+		zip: extraZip,
+		dir: installPath,
+	})
+}
+
+func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec {
+	fullInstallPath := installPath.Join(m, name)
+	return m.packageFile(fullInstallPath, srcPath, false)
+}
+
+func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec {
+	licenseFiles := m.Module().EffectiveLicenseFiles()
+	spec := PackagingSpec{
+		relPathInPackage:      Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
+		srcPath:               srcPath,
+		symlinkTarget:         "",
+		executable:            executable,
+		effectiveLicenseFiles: &licenseFiles,
+		partition:             fullInstallPath.partition,
+		skipInstall:           m.skipInstall(),
+	}
+	m.packagingSpecs = append(m.packagingSpecs, spec)
+	return spec
+}
+
+func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []InstallPath,
+	executable bool, hooks bool, extraZip *extraFilesZip) InstallPath {
+
+	fullInstallPath := installPath.Join(m, name)
+	if hooks {
+		m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false)
+	}
+
+	if !m.skipInstall() {
+		deps = append(deps, InstallPaths(m.module.base().installFilesDepSet.ToList())...)
+		deps = append(deps, m.module.base().installedInitRcPaths...)
+		deps = append(deps, m.module.base().installedVintfFragmentsPaths...)
+
+		var implicitDeps, orderOnlyDeps Paths
+
+		if m.Host() {
+			// Installed host modules might be used during the build, depend directly on their
+			// dependencies so their timestamp is updated whenever their dependency is updated
+			implicitDeps = InstallPaths(deps).Paths()
+		} else {
+			orderOnlyDeps = InstallPaths(deps).Paths()
+		}
+
+		if m.Config().KatiEnabled() {
+			// When creating the install rule in Soong but embedding in Make, write the rule to a
+			// makefile instead of directly to the ninja file so that main.mk can add the
+			// dependencies from the `required` property that are hard to resolve in Soong.
+			m.katiInstalls = append(m.katiInstalls, katiInstall{
+				from:          srcPath,
+				to:            fullInstallPath,
+				implicitDeps:  implicitDeps,
+				orderOnlyDeps: orderOnlyDeps,
+				executable:    executable,
+				extraFiles:    extraZip,
+			})
+		} else {
+			rule := Cp
+			if executable {
+				rule = CpExecutable
+			}
+
+			extraCmds := ""
+			if extraZip != nil {
+				extraCmds += fmt.Sprintf(" && ( unzip -qDD -d '%s' '%s' 2>&1 | grep -v \"zipfile is empty\"; exit $${PIPESTATUS[0]} )",
+					extraZip.dir.String(), extraZip.zip.String())
+				extraCmds += " || ( code=$$?; if [ $$code -ne 0 -a $$code -ne 1 ]; then exit $$code; fi )"
+				implicitDeps = append(implicitDeps, extraZip.zip)
+			}
+
+			m.Build(pctx, BuildParams{
+				Rule:        rule,
+				Description: "install " + fullInstallPath.Base(),
+				Output:      fullInstallPath,
+				Input:       srcPath,
+				Implicits:   implicitDeps,
+				OrderOnly:   orderOnlyDeps,
+				Default:     !m.Config().KatiEnabled(),
+				Args: map[string]string{
+					"extraCmds": extraCmds,
+				},
+			})
+		}
+
+		m.installFiles = append(m.installFiles, fullInstallPath)
+	}
+
+	m.packageFile(fullInstallPath, srcPath, executable)
+
+	m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
+
+	return fullInstallPath
+}
+
+func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath {
+	fullInstallPath := installPath.Join(m, name)
+	m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, true)
+
+	relPath, err := filepath.Rel(path.Dir(fullInstallPath.String()), srcPath.String())
+	if err != nil {
+		panic(fmt.Sprintf("Unable to generate symlink between %q and %q: %s", fullInstallPath.Base(), srcPath.Base(), err))
+	}
+	if !m.skipInstall() {
+
+		if m.Config().KatiEnabled() {
+			// When creating the symlink rule in Soong but embedding in Make, write the rule to a
+			// makefile instead of directly to the ninja file so that main.mk can add the
+			// dependencies from the `required` property that are hard to resolve in Soong.
+			m.katiSymlinks = append(m.katiSymlinks, katiInstall{
+				from: srcPath,
+				to:   fullInstallPath,
+			})
+		} else {
+			// The symlink doesn't need updating when the target is modified, but we sometimes
+			// have a dependency on a symlink to a binary instead of to the binary directly, and
+			// the mtime of the symlink must be updated when the binary is modified, so use a
+			// normal dependency here instead of an order-only dependency.
+			m.Build(pctx, BuildParams{
+				Rule:        Symlink,
+				Description: "install symlink " + fullInstallPath.Base(),
+				Output:      fullInstallPath,
+				Input:       srcPath,
+				Default:     !m.Config().KatiEnabled(),
+				Args: map[string]string{
+					"fromPath": relPath,
+				},
+			})
+		}
+
+		m.installFiles = append(m.installFiles, fullInstallPath)
+		m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
+	}
+
+	m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
+		relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
+		srcPath:          nil,
+		symlinkTarget:    relPath,
+		executable:       false,
+		partition:        fullInstallPath.partition,
+		skipInstall:      m.skipInstall(),
+	})
+
+	return fullInstallPath
+}
+
+// installPath/name -> absPath where absPath might be a path that is available only at runtime
+// (e.g. /apex/...)
+func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath {
+	fullInstallPath := installPath.Join(m, name)
+	m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true)
+
+	if !m.skipInstall() {
+		if m.Config().KatiEnabled() {
+			// When creating the symlink rule in Soong but embedding in Make, write the rule to a
+			// makefile instead of directly to the ninja file so that main.mk can add the
+			// dependencies from the `required` property that are hard to resolve in Soong.
+			m.katiSymlinks = append(m.katiSymlinks, katiInstall{
+				absFrom: absPath,
+				to:      fullInstallPath,
+			})
+		} else {
+			m.Build(pctx, BuildParams{
+				Rule:        Symlink,
+				Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath,
+				Output:      fullInstallPath,
+				Default:     !m.Config().KatiEnabled(),
+				Args: map[string]string{
+					"fromPath": absPath,
+				},
+			})
+		}
+
+		m.installFiles = append(m.installFiles, fullInstallPath)
+	}
+
+	m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
+		relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
+		srcPath:          nil,
+		symlinkTarget:    absPath,
+		executable:       false,
+		partition:        fullInstallPath.partition,
+		skipInstall:      m.skipInstall(),
+	})
+
+	return fullInstallPath
+}
+
+func (m *moduleContext) InstallTestData(installPath InstallPath, data []DataPath) InstallPaths {
+	m.testData = append(m.testData, data...)
+
+	ret := make(InstallPaths, 0, len(data))
+	for _, d := range data {
+		relPath := d.ToRelativeInstallPath()
+		installed := m.installFile(installPath, relPath, d.SrcPath, nil, false, false, nil)
+		ret = append(ret, installed)
+	}
+
+	return ret
+}
+
+func (m *moduleContext) CheckbuildFile(srcPath Path) {
+	m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
+}
+
+func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext {
+	return m.bp
+}
+
+func (m *moduleContext) LicenseMetadataFile() Path {
+	return m.module.base().licenseMetadataFile
+}
+
+func (m *moduleContext) ModuleInfoJSON() *ModuleInfoJSON {
+	if moduleInfoJSON := m.module.base().moduleInfoJSON; moduleInfoJSON != nil {
+		return moduleInfoJSON
+	}
+	moduleInfoJSON := &ModuleInfoJSON{}
+	m.module.base().moduleInfoJSON = moduleInfoJSON
+	return moduleInfoJSON
+}
+
+// Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must
+// be tagged with `android:"path" to support automatic source module dependency resolution.
+//
+// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
+func (m *moduleContext) ExpandSources(srcFiles, excludes []string) Paths {
+	return PathsForModuleSrcExcludes(m, srcFiles, excludes)
+}
+
+// Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must
+// be tagged with `android:"path" to support automatic source module dependency resolution.
+//
+// Deprecated: use PathForModuleSrc instead.
+func (m *moduleContext) ExpandSource(srcFile, _ string) Path {
+	return PathForModuleSrc(m, srcFile)
+}
+
+// Returns an optional single path expanded from globs and modules referenced using ":module" syntax if
+// the srcFile is non-nil.  The property must be tagged with `android:"path" to support automatic source module
+// dependency resolution.
+func (m *moduleContext) ExpandOptionalSource(srcFile *string, _ string) OptionalPath {
+	if srcFile != nil {
+		return OptionalPathForPath(PathForModuleSrc(m, *srcFile))
+	}
+	return OptionalPath{}
+}
+
+func (m *moduleContext) RequiredModuleNames() []string {
+	return m.module.RequiredModuleNames()
+}
+
+func (m *moduleContext) HostRequiredModuleNames() []string {
+	return m.module.HostRequiredModuleNames()
+}
+
+func (m *moduleContext) TargetRequiredModuleNames() []string {
+	return m.module.TargetRequiredModuleNames()
+}
diff --git a/android/module_info_json.go b/android/module_info_json.go
new file mode 100644
index 0000000..1c0a38e
--- /dev/null
+++ b/android/module_info_json.go
@@ -0,0 +1,103 @@
+package android
+
+import (
+	"encoding/json"
+	"io"
+	"slices"
+
+	"github.com/google/blueprint"
+)
+
+type CoreModuleInfoJSON struct {
+	RegisterName       string   `json:"-"`
+	Path               []string `json:"path,omitempty"`                // $(sort $(ALL_MODULES.$(m).PATH))
+	Installed          []string `json:"installed,omitempty"`           // $(sort $(ALL_MODULES.$(m).INSTALLED))
+	ModuleName         string   `json:"module_name,omitempty"`         // $(ALL_MODULES.$(m).MODULE_NAME)
+	SupportedVariants  []string `json:"supported_variants,omitempty"`  // $(sort $(ALL_MODULES.$(m).SUPPORTED_VARIANTS))
+	HostDependencies   []string `json:"host_dependencies,omitempty"`   // $(sort $(ALL_MODULES.$(m).HOST_REQUIRED_FROM_TARGET))
+	TargetDependencies []string `json:"target_dependencies,omitempty"` // $(sort $(ALL_MODULES.$(m).TARGET_REQUIRED_FROM_HOST))
+	Data               []string `json:"data,omitempty"`                // $(sort $(ALL_MODULES.$(m).TEST_DATA))
+}
+
+type ModuleInfoJSON struct {
+	core                CoreModuleInfoJSON
+	SubName             string   `json:"-"`
+	Uninstallable       bool     `json:"-"`
+	Class               []string `json:"class,omitempty"`                 // $(sort $(ALL_MODULES.$(m).CLASS))
+	Tags                []string `json:"tags,omitempty"`                  // $(sort $(ALL_MODULES.$(m).TAGS))
+	Dependencies        []string `json:"dependencies,omitempty"`          // $(sort $(ALL_DEPS.$(m).ALL_DEPS))
+	SharedLibs          []string `json:"shared_libs,omitempty"`           // $(sort $(ALL_MODULES.$(m).SHARED_LIBS))
+	StaticLibs          []string `json:"static_libs,omitempty"`           // $(sort $(ALL_MODULES.$(m).STATIC_LIBS))
+	SystemSharedLibs    []string `json:"system_shared_libs,omitempty"`    // $(sort $(ALL_MODULES.$(m).SYSTEM_SHARED_LIBS))
+	Srcs                []string `json:"srcs,omitempty"`                  // $(sort $(ALL_MODULES.$(m).SRCS))
+	SrcJars             []string `json:"srcjars,omitempty"`               // $(sort $(ALL_MODULES.$(m).SRCJARS))
+	ClassesJar          []string `json:"classes_jar,omitempty"`           // $(sort $(ALL_MODULES.$(m).CLASSES_JAR))
+	TestMainlineModules []string `json:"test_mainline_modules,omitempty"` // $(sort $(ALL_MODULES.$(m).TEST_MAINLINE_MODULES))
+	IsUnitTest          bool     `json:"is_unit_test,omitempty"`          // $(ALL_MODULES.$(m).IS_UNIT_TEST)
+	TestOptionsTags     []string `json:"test_options_tags,omitempty"`     // $(sort $(ALL_MODULES.$(m).TEST_OPTIONS_TAGS))
+	RuntimeDependencies []string `json:"runtime_dependencies,omitempty"`  // $(sort $(ALL_MODULES.$(m).LOCAL_RUNTIME_LIBRARIES))
+	StaticDependencies  []string `json:"static_dependencies,omitempty"`   // $(sort $(ALL_MODULES.$(m).LOCAL_STATIC_LIBRARIES))
+	DataDependencies    []string `json:"data_dependencies,omitempty"`     // $(sort $(ALL_MODULES.$(m).TEST_DATA_BINS))
+
+	CompatibilitySuites []string `json:"compatibility_suites,omitempty"` // $(sort $(ALL_MODULES.$(m).COMPATIBILITY_SUITES))
+	AutoTestConfig      []string `json:"auto_test_config,omitempty"`     // $(ALL_MODULES.$(m).auto_test_config)
+	TestConfig          []string `json:"test_config,omitempty"`          // $(strip $(ALL_MODULES.$(m).TEST_CONFIG) $(ALL_MODULES.$(m).EXTRA_TEST_CONFIGS)
+}
+
+//ALL_DEPS.$(LOCAL_MODULE).ALL_DEPS := $(sort \
+//$(ALL_DEPS.$(LOCAL_MODULE).ALL_DEPS) \
+//$(LOCAL_STATIC_LIBRARIES) \
+//$(LOCAL_WHOLE_STATIC_LIBRARIES) \
+//$(LOCAL_SHARED_LIBRARIES) \
+//$(LOCAL_DYLIB_LIBRARIES) \
+//$(LOCAL_RLIB_LIBRARIES) \
+//$(LOCAL_PROC_MACRO_LIBRARIES) \
+//$(LOCAL_HEADER_LIBRARIES) \
+//$(LOCAL_STATIC_JAVA_LIBRARIES) \
+//$(LOCAL_JAVA_LIBRARIES) \
+//$(LOCAL_JNI_SHARED_LIBRARIES))
+
+type combinedModuleInfoJSON struct {
+	*CoreModuleInfoJSON
+	*ModuleInfoJSON
+}
+
+func encodeModuleInfoJSON(w io.Writer, moduleInfoJSON *ModuleInfoJSON) error {
+	moduleInfoJSONCopy := *moduleInfoJSON
+
+	sortAndUnique := func(s *[]string) {
+		*s = slices.Clone(*s)
+		slices.Sort(*s)
+		*s = slices.Compact(*s)
+	}
+
+	sortAndUnique(&moduleInfoJSONCopy.core.Path)
+	sortAndUnique(&moduleInfoJSONCopy.core.Installed)
+	sortAndUnique(&moduleInfoJSONCopy.core.SupportedVariants)
+	sortAndUnique(&moduleInfoJSONCopy.core.HostDependencies)
+	sortAndUnique(&moduleInfoJSONCopy.core.TargetDependencies)
+	sortAndUnique(&moduleInfoJSONCopy.core.Data)
+
+	sortAndUnique(&moduleInfoJSONCopy.Class)
+	sortAndUnique(&moduleInfoJSONCopy.Tags)
+	sortAndUnique(&moduleInfoJSONCopy.Dependencies)
+	sortAndUnique(&moduleInfoJSONCopy.SharedLibs)
+	sortAndUnique(&moduleInfoJSONCopy.StaticLibs)
+	sortAndUnique(&moduleInfoJSONCopy.SystemSharedLibs)
+	sortAndUnique(&moduleInfoJSONCopy.Srcs)
+	sortAndUnique(&moduleInfoJSONCopy.SrcJars)
+	sortAndUnique(&moduleInfoJSONCopy.ClassesJar)
+	sortAndUnique(&moduleInfoJSONCopy.TestMainlineModules)
+	sortAndUnique(&moduleInfoJSONCopy.TestOptionsTags)
+	sortAndUnique(&moduleInfoJSONCopy.RuntimeDependencies)
+	sortAndUnique(&moduleInfoJSONCopy.StaticDependencies)
+	sortAndUnique(&moduleInfoJSONCopy.DataDependencies)
+	sortAndUnique(&moduleInfoJSONCopy.CompatibilitySuites)
+	sortAndUnique(&moduleInfoJSONCopy.AutoTestConfig)
+	sortAndUnique(&moduleInfoJSONCopy.TestConfig)
+
+	encoder := json.NewEncoder(w)
+	return encoder.Encode(combinedModuleInfoJSON{&moduleInfoJSONCopy.core, &moduleInfoJSONCopy})
+}
+
+var ModuleInfoJSONProvider = blueprint.NewProvider[*ModuleInfoJSON]()
diff --git a/android/module_test.go b/android/module_test.go
index 1ca7422..1f3db5c 100644
--- a/android/module_test.go
+++ b/android/module_test.go
@@ -15,10 +15,11 @@
 package android
 
 import (
-	"github.com/google/blueprint"
 	"path/filepath"
 	"runtime"
 	"testing"
+
+	"github.com/google/blueprint"
 )
 
 func TestSrcIsModule(t *testing.T) {
@@ -244,52 +245,6 @@
 		RunTestWithBp(t, bp)
 }
 
-func TestValidateCorrectBuildParams(t *testing.T) {
-	config := TestConfig(t.TempDir(), nil, "", nil)
-	pathContext := PathContextForTesting(config)
-	bparams := convertBuildParams(BuildParams{
-		// Test with Output
-		Output:        PathForOutput(pathContext, "undeclared_symlink"),
-		SymlinkOutput: PathForOutput(pathContext, "undeclared_symlink"),
-	})
-
-	err := validateBuildParams(bparams)
-	if err != nil {
-		t.Error(err)
-	}
-
-	bparams = convertBuildParams(BuildParams{
-		// Test with ImplicitOutput
-		ImplicitOutput: PathForOutput(pathContext, "undeclared_symlink"),
-		SymlinkOutput:  PathForOutput(pathContext, "undeclared_symlink"),
-	})
-
-	err = validateBuildParams(bparams)
-	if err != nil {
-		t.Error(err)
-	}
-}
-
-func TestValidateIncorrectBuildParams(t *testing.T) {
-	config := TestConfig(t.TempDir(), nil, "", nil)
-	pathContext := PathContextForTesting(config)
-	params := BuildParams{
-		Output:          PathForOutput(pathContext, "regular_output"),
-		Outputs:         PathsForOutput(pathContext, []string{"out1", "out2"}),
-		ImplicitOutput:  PathForOutput(pathContext, "implicit_output"),
-		ImplicitOutputs: PathsForOutput(pathContext, []string{"i_out1", "_out2"}),
-		SymlinkOutput:   PathForOutput(pathContext, "undeclared_symlink"),
-	}
-
-	bparams := convertBuildParams(params)
-	err := validateBuildParams(bparams)
-	if err != nil {
-		FailIfNoMatchingErrors(t, "undeclared_symlink is not a declared output or implicit output", []error{err})
-	} else {
-		t.Errorf("Expected build params to fail validation: %+v", bparams)
-	}
-}
-
 func TestDistErrorChecking(t *testing.T) {
 	bp := `
 		deps {
diff --git a/android/mutator.go b/android/mutator.go
index 6bcac93..75ba650 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -15,9 +15,7 @@
 package android
 
 import (
-	"android/soong/bazel"
-	"android/soong/ui/metrics/bp2build_metrics_proto"
-	"path/filepath"
+	"sync"
 
 	"github.com/google/blueprint"
 )
@@ -31,46 +29,9 @@
 //   run FinalDeps mutators (CreateVariations disallowed in this phase)
 //   continue on to GenerateAndroidBuildActions
 
-// RegisterMutatorsForBazelConversion is a alternate registration pipeline for bp2build. Exported for testing.
-func RegisterMutatorsForBazelConversion(ctx *Context, preArchMutators []RegisterMutatorFunc) {
-	bp2buildMutators := append(preArchMutators, registerBp2buildConversionMutator)
-	registerMutatorsForBazelConversion(ctx, bp2buildMutators)
-}
-
-// RegisterMutatorsForApiBazelConversion is an alternate registration pipeline for api_bp2build
-// This pipeline restricts generation of Bazel targets to Soong modules that contribute APIs
-func RegisterMutatorsForApiBazelConversion(ctx *Context, preArchMutators []RegisterMutatorFunc) {
-	bp2buildMutators := append(preArchMutators, registerApiBp2buildConversionMutator)
-	registerMutatorsForBazelConversion(ctx, bp2buildMutators)
-}
-
-func registerMutatorsForBazelConversion(ctx *Context, bp2buildMutators []RegisterMutatorFunc) {
-	mctx := &registerMutatorsContext{
-		bazelConversionMode: true,
-	}
-
-	allMutators := append([]RegisterMutatorFunc{
-		RegisterNamespaceMutator,
-		RegisterDefaultsPreArchMutators,
-		// TODO(b/165114590): this is required to resolve deps that are only prebuilts, but we should
-		// evaluate the impact on conversion.
-		RegisterPrebuiltsPreArchMutators,
-	},
-		bp2buildMutators...)
-
-	// Register bp2build mutators
-	for _, f := range allMutators {
-		f(mctx)
-	}
-
-	mctx.mutators.registerAll(ctx)
-}
-
 // collateGloballyRegisteredMutators constructs the list of mutators that have been registered
 // with the InitRegistrationContext and will be used at runtime.
 func collateGloballyRegisteredMutators() sortableComponents {
-	// ensure mixed builds mutator is the last mutator
-	finalDeps = append(finalDeps, registerMixedBuildsMutator)
 	return collateRegisteredMutators(preArch, preDeps, postDeps, finalDeps)
 }
 
@@ -99,9 +60,8 @@
 }
 
 type registerMutatorsContext struct {
-	mutators            sortableComponents
-	finalPhase          bool
-	bazelConversionMode bool
+	mutators   sortableComponents
+	finalPhase bool
 }
 
 type RegisterMutatorsContext interface {
@@ -224,21 +184,6 @@
 	finalDeps = append(finalDeps, f)
 }
 
-var bp2buildPreArchMutators = []RegisterMutatorFunc{}
-
-// A minimal context for Bp2build conversion
-type Bp2buildMutatorContext interface {
-	BazelConversionPathContext
-
-	CreateBazelTargetModule(bazel.BazelTargetModuleProperties, CommonAttributes, interface{})
-}
-
-// PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules
-// into Bazel BUILD targets that should run prior to deps and conversion.
-func PreArchBp2BuildMutators(f RegisterMutatorFunc) {
-	bp2buildPreArchMutators = append(bp2buildPreArchMutators, f)
-}
-
 type BaseMutatorContext interface {
 	BaseModuleContext
 
@@ -258,35 +203,6 @@
 	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
 	// the specified property structs to it as if the properties were set in a blueprint file.
 	CreateModule(ModuleFactory, ...interface{}) Module
-
-	// CreateBazelTargetModule creates a BazelTargetModule by calling the
-	// factory method, just like in CreateModule, but also requires
-	// BazelTargetModuleProperties containing additional metadata for the
-	// bp2build codegenerator.
-	CreateBazelTargetModule(bazel.BazelTargetModuleProperties, CommonAttributes, interface{})
-
-	// CreateBazelTargetModuleWithRestrictions creates a BazelTargetModule by calling the
-	// factory method, just like in CreateModule, but also requires
-	// BazelTargetModuleProperties containing additional metadata for the
-	// bp2build codegenerator. The generated target is restricted to only be buildable for certain
-	// platforms, as dictated by a given bool attribute: the target will not be buildable in
-	// any platform for which this bool attribute is false.
-	CreateBazelTargetModuleWithRestrictions(bazel.BazelTargetModuleProperties, CommonAttributes, interface{}, bazel.BoolAttribute)
-
-	// MarkBp2buildUnconvertible registers the current module as "unconvertible to bp2build" for the
-	// given reason.
-	MarkBp2buildUnconvertible(reasonType bp2build_metrics_proto.UnconvertedReasonType, detail string)
-
-	// CreateBazelTargetAliasInDir creates an alias definition in `dir` directory.
-	// This function can be used to create alias definitions in a directory that is different
-	// from the directory of the visited Soong module.
-	CreateBazelTargetAliasInDir(dir string, name string, actual bazel.Label)
-
-	// CreateBazelConfigSetting creates a config_setting in <dir>/BUILD.bazel
-	// build/bazel has several static config_setting(s) that are used in Bazel builds.
-	// This function can be used to createa additional config_setting(s) based on the build graph
-	// (e.g. a config_setting specific to an apex variant)
-	CreateBazelConfigSetting(csa bazel.ConfigSettingAttributes, ca CommonAttributes, dir string)
 }
 
 type topDownMutatorContext struct {
@@ -411,34 +327,55 @@
 	// if the value is not of the appropriate type, or if the module is not a newly created
 	// variant of the current module.  The value should not be modified after being passed to
 	// SetVariationProvider.
-	SetVariationProvider(module blueprint.Module, provider blueprint.ProviderKey, value interface{})
+	SetVariationProvider(module blueprint.Module, provider blueprint.AnyProviderKey, value interface{})
 }
 
+// An outgoingTransitionContextImpl and incomingTransitionContextImpl is created for every dependency of every module
+// for each transition mutator.  bottomUpMutatorContext and topDownMutatorContext are created once for every module
+// for every BottomUp or TopDown mutator.  Use a global pool for each to avoid reallocating every time.
+var (
+	outgoingTransitionContextPool = sync.Pool{
+		New: func() any { return &outgoingTransitionContextImpl{} },
+	}
+	incomingTransitionContextPool = sync.Pool{
+		New: func() any { return &incomingTransitionContextImpl{} },
+	}
+	bottomUpMutatorContextPool = sync.Pool{
+		New: func() any { return &bottomUpMutatorContext{} },
+	}
+
+	topDownMutatorContextPool = sync.Pool{
+		New: func() any { return &topDownMutatorContext{} },
+	}
+)
+
 type bottomUpMutatorContext struct {
 	bp blueprint.BottomUpMutatorContext
 	baseModuleContext
 	finalPhase bool
 }
 
+// callers must immediately follow the call to this function with defer bottomUpMutatorContextPool.Put(mctx).
 func bottomUpMutatorContextFactory(ctx blueprint.BottomUpMutatorContext, a Module,
-	finalPhase, bazelConversionMode bool) BottomUpMutatorContext {
+	finalPhase bool) BottomUpMutatorContext {
 
 	moduleContext := a.base().baseModuleContextFactory(ctx)
-	moduleContext.bazelConversionMode = bazelConversionMode
-
-	return &bottomUpMutatorContext{
+	mctx := bottomUpMutatorContextPool.Get().(*bottomUpMutatorContext)
+	*mctx = bottomUpMutatorContext{
 		bp:                ctx,
 		baseModuleContext: moduleContext,
 		finalPhase:        finalPhase,
 	}
+	return mctx
 }
 
 func (x *registerMutatorsContext) BottomUp(name string, m BottomUpMutator) MutatorHandle {
 	finalPhase := x.finalPhase
-	bazelConversionMode := x.bazelConversionMode
 	f := func(ctx blueprint.BottomUpMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
-			m(bottomUpMutatorContextFactory(ctx, a, finalPhase, bazelConversionMode))
+			mctx := bottomUpMutatorContextFactory(ctx, a, finalPhase)
+			defer bottomUpMutatorContextPool.Put(mctx)
+			m(mctx)
 		}
 	}
 	mutator := &mutator{name: x.mutatorName(name), bottomUpMutator: f}
@@ -453,15 +390,23 @@
 }
 
 type IncomingTransitionContext interface {
+	ArchModuleContext
+	ModuleProviderContext
+
 	// Module returns the target of the dependency edge for which the transition
 	// is being computed
 	Module() Module
 
 	// Config returns the configuration for the build.
 	Config() Config
+
+	DeviceConfig() DeviceConfig
 }
 
 type OutgoingTransitionContext interface {
+	ArchModuleContext
+	ModuleProviderContext
+
 	// Module returns the target of the dependency edge for which the transition
 	// is being computed
 	Module() Module
@@ -469,9 +414,14 @@
 	// DepTag() Returns the dependency tag through which this dependency is
 	// reached
 	DepTag() blueprint.DependencyTag
+
+	// Config returns the configuration for the build.
+	Config() Config
+
+	DeviceConfig() DeviceConfig
 }
 
-// Transition mutators implement a top-down mechanism where a module tells its
+// TransitionMutator implements a top-down mechanism where a module tells its
 // direct dependencies what variation they should be built in but the dependency
 // has the final say.
 //
@@ -536,18 +486,18 @@
 	// called on.
 	Split(ctx BaseModuleContext) []string
 
-	// Called on a module to determine which variation it wants from its direct
-	// dependencies. The dependency itself can override this decision. This method
-	// should not mutate the module itself.
+	// OutgoingTransition is called on a module to determine which variation it wants
+	// from its direct dependencies. The dependency itself can override this decision.
+	// This method should not mutate the module itself.
 	OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string
 
-	// Called on a module to determine which variation it should be in based on
-	// the variation modules that depend on it want. This gives the module a final
-	// say about its own variations. This method should not mutate the module
+	// IncomingTransition is called on a module to determine which variation it should
+	// be in based on the variation modules that depend on it want. This gives the module
+	// a final say about its own variations. This method should not mutate the module
 	// itself.
 	IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string
 
-	// Called after a module was split into multiple variations on each variation.
+	// Mutate is called after a module was split into multiple variations on each variation.
 	// It should not split the module any further but adding new dependencies is
 	// fine. Unlike all the other methods on TransitionMutator, this method is
 	// allowed to mutate the module.
@@ -555,15 +505,14 @@
 }
 
 type androidTransitionMutator struct {
-	finalPhase          bool
-	bazelConversionMode bool
-	mutator             TransitionMutator
+	finalPhase bool
+	mutator    TransitionMutator
+	name       string
 }
 
 func (a *androidTransitionMutator) Split(ctx blueprint.BaseModuleContext) []string {
 	if m, ok := ctx.Module().(Module); ok {
 		moduleContext := m.base().baseModuleContextFactory(ctx)
-		moduleContext.bazelConversionMode = a.bazelConversionMode
 		return a.mutator.Split(&moduleContext)
 	} else {
 		return []string{""}
@@ -571,6 +520,7 @@
 }
 
 type outgoingTransitionContextImpl struct {
+	archModuleContext
 	bp blueprint.OutgoingTransitionContext
 }
 
@@ -582,15 +532,34 @@
 	return c.bp.DepTag()
 }
 
-func (a *androidTransitionMutator) OutgoingTransition(ctx blueprint.OutgoingTransitionContext, sourceVariation string) string {
-	if _, ok := ctx.Module().(Module); ok {
-		return a.mutator.OutgoingTransition(&outgoingTransitionContextImpl{bp: ctx}, sourceVariation)
+func (c *outgoingTransitionContextImpl) Config() Config {
+	return c.bp.Config().(Config)
+}
+
+func (c *outgoingTransitionContextImpl) DeviceConfig() DeviceConfig {
+	return DeviceConfig{c.bp.Config().(Config).deviceConfig}
+}
+
+func (c *outgoingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) {
+	return c.bp.Provider(provider)
+}
+
+func (a *androidTransitionMutator) OutgoingTransition(bpctx blueprint.OutgoingTransitionContext, sourceVariation string) string {
+	if m, ok := bpctx.Module().(Module); ok {
+		ctx := outgoingTransitionContextPool.Get().(*outgoingTransitionContextImpl)
+		defer outgoingTransitionContextPool.Put(ctx)
+		*ctx = outgoingTransitionContextImpl{
+			archModuleContext: m.base().archModuleContextFactory(bpctx),
+			bp:                bpctx,
+		}
+		return a.mutator.OutgoingTransition(ctx, sourceVariation)
 	} else {
 		return ""
 	}
 }
 
 type incomingTransitionContextImpl struct {
+	archModuleContext
 	bp blueprint.IncomingTransitionContext
 }
 
@@ -602,9 +571,23 @@
 	return c.bp.Config().(Config)
 }
 
-func (a *androidTransitionMutator) IncomingTransition(ctx blueprint.IncomingTransitionContext, incomingVariation string) string {
-	if _, ok := ctx.Module().(Module); ok {
-		return a.mutator.IncomingTransition(&incomingTransitionContextImpl{bp: ctx}, incomingVariation)
+func (c *incomingTransitionContextImpl) DeviceConfig() DeviceConfig {
+	return DeviceConfig{c.bp.Config().(Config).deviceConfig}
+}
+
+func (c *incomingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) {
+	return c.bp.Provider(provider)
+}
+
+func (a *androidTransitionMutator) IncomingTransition(bpctx blueprint.IncomingTransitionContext, incomingVariation string) string {
+	if m, ok := bpctx.Module().(Module); ok {
+		ctx := incomingTransitionContextPool.Get().(*incomingTransitionContextImpl)
+		defer incomingTransitionContextPool.Put(ctx)
+		*ctx = incomingTransitionContextImpl{
+			archModuleContext: m.base().archModuleContextFactory(bpctx),
+			bp:                bpctx,
+		}
+		return a.mutator.IncomingTransition(ctx, incomingVariation)
 	} else {
 		return ""
 	}
@@ -612,15 +595,20 @@
 
 func (a *androidTransitionMutator) Mutate(ctx blueprint.BottomUpMutatorContext, variation string) {
 	if am, ok := ctx.Module().(Module); ok {
-		a.mutator.Mutate(bottomUpMutatorContextFactory(ctx, am, a.finalPhase, a.bazelConversionMode), variation)
+		mctx := bottomUpMutatorContextFactory(ctx, am, a.finalPhase)
+		defer bottomUpMutatorContextPool.Put(mctx)
+		base := am.base()
+		base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, a.name)
+		base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variation)
+		a.mutator.Mutate(mctx, variation)
 	}
 }
 
 func (x *registerMutatorsContext) Transition(name string, m TransitionMutator) {
 	atm := &androidTransitionMutator{
-		finalPhase:          x.finalPhase,
-		bazelConversionMode: x.bazelConversionMode,
-		mutator:             m,
+		finalPhase: x.finalPhase,
+		mutator:    m,
+		name:       name,
 	}
 	mutator := &mutator{
 		name:              name,
@@ -629,9 +617,6 @@
 }
 
 func (x *registerMutatorsContext) mutatorName(name string) string {
-	if x.bazelConversionMode {
-		return name + "_bp2build"
-	}
 	return name
 }
 
@@ -639,8 +624,9 @@
 	f := func(ctx blueprint.TopDownMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
 			moduleContext := a.base().baseModuleContextFactory(ctx)
-			moduleContext.bazelConversionMode = x.bazelConversionMode
-			actx := &topDownMutatorContext{
+			actx := topDownMutatorContextPool.Get().(*topDownMutatorContext)
+			defer topDownMutatorContextPool.Put(actx)
+			*actx = topDownMutatorContext{
 				bp:                ctx,
 				baseModuleContext: moduleContext,
 			}
@@ -695,6 +681,7 @@
 
 func depsMutator(ctx BottomUpMutatorContext) {
 	if m := ctx.Module(); m.Enabled() {
+		m.base().baseDepsMutator(ctx)
 		m.DepsMutator(ctx)
 	}
 }
@@ -703,185 +690,6 @@
 	ctx.BottomUp("deps", depsMutator).Parallel()
 }
 
-func registerDepsMutatorBp2Build(ctx RegisterMutatorsContext) {
-	// TODO(b/179313531): Consider a separate mutator that only runs depsMutator for modules that are
-	// being converted to build targets.
-	ctx.BottomUp("deps", depsMutator).Parallel()
-}
-
-func (t *topDownMutatorContext) CreateBazelTargetModule(
-	bazelProps bazel.BazelTargetModuleProperties,
-	commonAttrs CommonAttributes,
-	attrs interface{}) {
-	t.createBazelTargetModule(bazelProps, commonAttrs, attrs, bazel.BoolAttribute{})
-}
-
-func (t *topDownMutatorContext) CreateBazelTargetModuleWithRestrictions(
-	bazelProps bazel.BazelTargetModuleProperties,
-	commonAttrs CommonAttributes,
-	attrs interface{},
-	enabledProperty bazel.BoolAttribute) {
-	t.createBazelTargetModule(bazelProps, commonAttrs, attrs, enabledProperty)
-}
-
-func (t *topDownMutatorContext) MarkBp2buildUnconvertible(
-	reasonType bp2build_metrics_proto.UnconvertedReasonType, detail string) {
-	mod := t.Module()
-	mod.base().setBp2buildUnconvertible(reasonType, detail)
-}
-
-var (
-	bazelAliasModuleProperties = bazel.BazelTargetModuleProperties{
-		Rule_class: "alias",
-	}
-)
-
-type bazelAliasAttributes struct {
-	Actual *bazel.LabelAttribute
-}
-
-func (t *topDownMutatorContext) CreateBazelTargetAliasInDir(
-	dir string,
-	name string,
-	actual bazel.Label) {
-	mod := t.Module()
-	attrs := &bazelAliasAttributes{
-		Actual: bazel.MakeLabelAttribute(actual.Label),
-	}
-	info := bp2buildInfo{
-		Dir:             dir,
-		BazelProps:      bazelAliasModuleProperties,
-		CommonAttrs:     CommonAttributes{Name: name},
-		ConstraintAttrs: constraintAttributes{},
-		Attrs:           attrs,
-	}
-	mod.base().addBp2buildInfo(info)
-}
-
-// Returns the directory in which the bazel target will be generated
-// If ca.Dir is not nil, use that
-// Otherwise default to the directory of the soong module
-func dirForBazelTargetGeneration(t *topDownMutatorContext, ca *CommonAttributes) string {
-	dir := t.OtherModuleDir(t.Module())
-	if ca.Dir != nil {
-		dir = *ca.Dir
-		// Restrict its use to dirs that contain an Android.bp file.
-		// There are several places in bp2build where we use the existence of Android.bp/BUILD on the filesystem
-		// to curate a compatible label for src files (e.g. headers for cc).
-		// If we arbritrarily create BUILD files, then it might render those curated labels incompatible.
-		if exists, _, _ := t.Config().fs.Exists(filepath.Join(dir, "Android.bp")); !exists {
-			t.ModuleErrorf("Cannot use ca.Dir to create a BazelTarget in dir: %v since it does not contain an Android.bp file", dir)
-		}
-
-		// Set ca.Dir to nil so that it does not get emitted to the BUILD files
-		ca.Dir = nil
-	}
-	return dir
-}
-
-func (t *topDownMutatorContext) CreateBazelConfigSetting(
-	csa bazel.ConfigSettingAttributes,
-	ca CommonAttributes,
-	dir string) {
-	mod := t.Module()
-	info := bp2buildInfo{
-		Dir: dir,
-		BazelProps: bazel.BazelTargetModuleProperties{
-			Rule_class: "config_setting",
-		},
-		CommonAttrs:     ca,
-		ConstraintAttrs: constraintAttributes{},
-		Attrs:           &csa,
-	}
-	mod.base().addBp2buildInfo(info)
-}
-
-// ApexAvailableTags converts the apex_available property value of an ApexModule
-// module and returns it as a list of keyed tags.
-func ApexAvailableTags(mod Module) bazel.StringListAttribute {
-	attr := bazel.StringListAttribute{}
-	// Transform specific attributes into tags.
-	if am, ok := mod.(ApexModule); ok {
-		// TODO(b/218841706): hidl_interface has the apex_available prop, but it's
-		// defined directly as a prop and not via ApexModule, so this doesn't
-		// pick those props up.
-		apexAvailable := am.apexModuleBase().ApexAvailable()
-		// If a user does not specify apex_available in Android.bp, then soong provides a default.
-		// To avoid verbosity of BUILD files, remove this default from user-facing BUILD files.
-		if len(am.apexModuleBase().ApexProperties.Apex_available) == 0 {
-			apexAvailable = []string{}
-		}
-		attr.Value = ConvertApexAvailableToTags(apexAvailable)
-	}
-	return attr
-}
-
-func ApexAvailableTagsWithoutTestApexes(ctx BaseModuleContext, mod Module) bazel.StringListAttribute {
-	attr := bazel.StringListAttribute{}
-	if am, ok := mod.(ApexModule); ok {
-		apexAvailableWithoutTestApexes := removeTestApexes(ctx, am.apexModuleBase().ApexAvailable())
-		// If a user does not specify apex_available in Android.bp, then soong provides a default.
-		// To avoid verbosity of BUILD files, remove this default from user-facing BUILD files.
-		if len(am.apexModuleBase().ApexProperties.Apex_available) == 0 {
-			apexAvailableWithoutTestApexes = []string{}
-		}
-		attr.Value = ConvertApexAvailableToTags(apexAvailableWithoutTestApexes)
-	}
-	return attr
-}
-
-func removeTestApexes(ctx BaseModuleContext, apex_available []string) []string {
-	testApexes := []string{}
-	for _, aa := range apex_available {
-		// ignore the wildcards
-		if InList(aa, AvailableToRecognziedWildcards) {
-			continue
-		}
-		mod, _ := ctx.ModuleFromName(aa)
-		if apex, ok := mod.(ApexTestInterface); ok && apex.IsTestApex() {
-			testApexes = append(testApexes, aa)
-		}
-	}
-	return RemoveListFromList(CopyOf(apex_available), testApexes)
-}
-
-func ConvertApexAvailableToTags(apexAvailable []string) []string {
-	if len(apexAvailable) == 0 {
-		// We need nil specifically to make bp2build not add the tags property at all,
-		// instead of adding it with an empty list
-		return nil
-	}
-	result := make([]string, 0, len(apexAvailable))
-	for _, a := range apexAvailable {
-		result = append(result, "apex_available="+a)
-	}
-	return result
-}
-
-// ConvertApexAvailableToTagsWithoutTestApexes converts a list of apex names to a list of bazel tags
-// This function drops any test apexes from the input.
-func ConvertApexAvailableToTagsWithoutTestApexes(ctx BaseModuleContext, apexAvailable []string) []string {
-	noTestApexes := removeTestApexes(ctx, apexAvailable)
-	return ConvertApexAvailableToTags(noTestApexes)
-}
-
-func (t *topDownMutatorContext) createBazelTargetModule(
-	bazelProps bazel.BazelTargetModuleProperties,
-	commonAttrs CommonAttributes,
-	attrs interface{},
-	enabledProperty bazel.BoolAttribute) {
-	constraintAttributes := commonAttrs.fillCommonBp2BuildModuleAttrs(t, enabledProperty)
-	mod := t.Module()
-	info := bp2buildInfo{
-		Dir:             dirForBazelTargetGeneration(t, &commonAttrs),
-		BazelProps:      bazelProps,
-		CommonAttrs:     commonAttrs,
-		ConstraintAttrs: constraintAttributes,
-		Attrs:           attrs,
-	}
-	mod.base().addBp2buildInfo(info)
-}
-
 // android.topDownMutatorContext either has to embed blueprint.TopDownMutatorContext, in which case every method that
 // has an overridden version in android.BaseModuleContext has to be manually forwarded to BaseModuleContext to avoid
 // ambiguous method errors, or it has to store a blueprint.TopDownMutatorContext non-embedded, in which case every
@@ -1020,6 +828,6 @@
 	b.bp.CreateAliasVariation(fromVariationName, toVariationName)
 }
 
-func (b *bottomUpMutatorContext) SetVariationProvider(module blueprint.Module, provider blueprint.ProviderKey, value interface{}) {
+func (b *bottomUpMutatorContext) SetVariationProvider(module blueprint.Module, provider blueprint.AnyProviderKey, value interface{}) {
 	b.bp.SetVariationProvider(module, provider, value)
 }
diff --git a/android/mutator_test.go b/android/mutator_test.go
index dbdfa33..21eebd2 100644
--- a/android/mutator_test.go
+++ b/android/mutator_test.go
@@ -16,7 +16,6 @@
 
 import (
 	"fmt"
-	"reflect"
 	"strings"
 	"testing"
 
@@ -268,22 +267,3 @@
 		FixtureWithRootAndroidBp(`test {name: "foo"}`),
 	).RunTest(t)
 }
-
-func TestConvertApexAvailableToTags(t *testing.T) {
-	input := []string{
-		"com.android.adbd",
-		"//apex_available:platform",
-	}
-	actual := ConvertApexAvailableToTags(input)
-	expected := []string{
-		"apex_available=com.android.adbd",
-		"apex_available=//apex_available:platform",
-	}
-	if !reflect.DeepEqual(actual, expected) {
-		t.Errorf("Expected: %v, actual: %v", expected, actual)
-	}
-
-	if ConvertApexAvailableToTags(nil) != nil {
-		t.Errorf("Expected providing nil to return nil")
-	}
-}
diff --git a/android/neverallow.go b/android/neverallow.go
index 24031ba..62c5e59 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -57,9 +57,9 @@
 	AddNeverAllowRules(createUncompressDexRules()...)
 	AddNeverAllowRules(createInitFirstStageRules()...)
 	AddNeverAllowRules(createProhibitFrameworkAccessRules()...)
-	AddNeverAllowRules(createBp2BuildRule())
 	AddNeverAllowRules(createCcStubsRule())
 	AddNeverAllowRules(createJavaExcludeStaticLibsRule())
+	AddNeverAllowRules(createProhibitHeaderOnlyRule())
 }
 
 // Add a NeverAllow rule to the set of rules to apply.
@@ -67,14 +67,6 @@
 	neverallows = append(neverallows, rules...)
 }
 
-func createBp2BuildRule() Rule {
-	return NeverAllow().
-		With("bazel_module.bp2build_available", "true").
-		NotIn("soong_tests"). // only used in tests
-		Because("setting bp2build_available in Android.bp is not " +
-			"supported for custom conversion, use allowlists.go instead.")
-}
-
 var (
 	neverallowNotInIncludeDir = []string{
 		"art",
@@ -168,6 +160,8 @@
 		"external/kotlinx.coroutines",
 		"external/robolectric-shadows",
 		"external/robolectric",
+		"frameworks/base/ravenwood",
+		"frameworks/base/tools/hoststubgen",
 		"frameworks/layoutlib",
 	}
 
@@ -264,6 +258,13 @@
 		Because("exclude_static_libs property is only allowed for java modules defined in build/soong, libcore, and frameworks/base/api")
 }
 
+func createProhibitHeaderOnlyRule() Rule {
+	return NeverAllow().
+		Without("name", "framework-minus-apex-headers").
+		With("headers_only", "true").
+		Because("headers_only can only be used for generating framework-minus-apex headers for non-updatable modules")
+}
+
 func neverallowMutator(ctx BottomUpMutatorContext) {
 	m, ok := ctx.Module().(Module)
 	if !ok {
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 2a938b8..b2620ef 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -361,6 +361,21 @@
 			`exclude_static_libs property is only allowed for java modules defined in build/soong, libcore, and frameworks/base/api`,
 		},
 	},
+	// Test for only allowing headers_only for framework-minus-apex-headers
+	{
+		name: `"headers_only" outside framework-minus-apex-headers modules`,
+		fs: map[string][]byte{
+			"a/b/Android.bp": []byte(`
+				java_library {
+					name: "baz",
+					headers_only: true,
+				}
+			`),
+		},
+		expectedErrors: []string{
+			`headers_only can only be used for generating framework-minus-apex headers for non-updatable modules`,
+		},
+	},
 }
 
 var prepareForNeverAllowTest = GroupFixturePreparers(
@@ -451,6 +466,7 @@
 	Sdk_version         *string
 	Uncompress_dex      *bool
 	Exclude_static_libs []string
+	Headers_only        *bool
 }
 
 type mockJavaLibraryModule struct {
diff --git a/android/ninja_deps.go b/android/ninja_deps.go
index 1d50a47..bdf465e 100644
--- a/android/ninja_deps.go
+++ b/android/ninja_deps.go
@@ -15,7 +15,6 @@
 package android
 
 import (
-	"android/soong/starlark_import"
 	"sort"
 )
 
@@ -43,11 +42,4 @@
 
 func (ninjaDepsSingleton) GenerateBuildActions(ctx SingletonContext) {
 	ctx.AddNinjaFileDeps(ctx.Config().ninjaFileDeps()...)
-
-	deps, err := starlark_import.GetNinjaDeps()
-	if err != nil {
-		ctx.Errorf("Error running starlark code: %s", err)
-	} else {
-		ctx.AddNinjaFileDeps(deps...)
-	}
 }
diff --git a/android/override_module.go b/android/override_module.go
index a4b7431..1341f53 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -214,17 +214,6 @@
 	}
 	b.overridableModuleProperties.OverriddenBy = o.Name()
 	b.overridableModuleProperties.OverriddenByModuleDir = o.ModuleDir()
-
-	if oBazelable, ok := o.base().module.(Bazelable); ok {
-		if bBazelable, ok := m.(Bazelable); ok {
-			oProps := oBazelable.bazelProps()
-			bProps := bBazelable.bazelProps()
-			bProps.Bazel_module.Bp2build_available = oProps.Bazel_module.Bp2build_available
-			bProps.Bazel_module.Label = oProps.Bazel_module.Label
-		} else {
-			ctx.ModuleErrorf("Override type cannot be Bazelable if original module type is not Bazelable %v %v.", o.Name(), m.Name())
-		}
-	}
 }
 
 // GetOverriddenBy returns the name of the override module that has overridden this module.
@@ -348,31 +337,3 @@
 		}
 	}
 }
-
-// ModuleNameWithPossibleOverride returns the name of the OverrideModule that overrides the current
-// variant of this OverridableModule, or ctx.ModuleName() if this module is not an OverridableModule
-// or if this variant is not overridden.
-func ModuleNameWithPossibleOverride(ctx BazelConversionContext) string {
-	return moduleNameWithPossibleOverride(ctx, ctx.Module())
-}
-
-func moduleNameWithPossibleOverride(ctx bazelOtherModuleContext, module blueprint.Module) string {
-	if overridable, ok := module.(OverridableModule); ok {
-		if o := overridable.GetOverriddenBy(); o != "" {
-			return o
-		}
-	}
-	return ctx.OtherModuleName(module)
-}
-
-// moduleDirWithPossibleOverride returns the dir of the OverrideModule that overrides the current
-// variant of the given OverridableModule, or ctx.OtherModuleName() if the module is not an
-// OverridableModule or if the variant is not overridden.
-func moduleDirWithPossibleOverride(ctx bazelOtherModuleContext, module blueprint.Module) string {
-	if overridable, ok := module.(OverridableModule); ok {
-		if o := overridable.GetOverriddenByModuleDir(); o != "" {
-			return o
-		}
-	}
-	return ctx.OtherModuleDir(module)
-}
diff --git a/android/package.go b/android/package.go
index 7fbc700..eb76751 100644
--- a/android/package.go
+++ b/android/package.go
@@ -15,9 +15,6 @@
 package android
 
 import (
-	"path/filepath"
-
-	"android/soong/bazel"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -38,58 +35,26 @@
 	Default_visibility []string
 	// Specifies the default license terms for all modules defined in this package.
 	Default_applicable_licenses []string
-}
-
-type bazelPackageAttributes struct {
-	Default_visibility       []string
-	Default_package_metadata bazel.LabelListAttribute
+	Default_team                *string `android:"path"`
 }
 
 type packageModule struct {
 	ModuleBase
-	BazelModuleBase
 
 	properties packageProperties
 }
 
-var _ Bazelable = &packageModule{}
-
-func (p *packageModule) ConvertWithBp2build(ctx TopDownMutatorContext) {
-	defaultPackageMetadata := bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, p.properties.Default_applicable_licenses))
-	// If METADATA file exists in the package, add it to package(default_package_metadata=) using a
-	// filegroup(name="default_metadata_file") which can be accessed later on each module in Bazel
-	// using attribute "applicable_licenses".
-	// Attribute applicable_licenses of filegroup "default_metadata_file" has to be set to [],
-	// otherwise Bazel reports cyclic reference error.
-	if existed, _, _ := ctx.Config().fs.Exists(filepath.Join(ctx.ModuleDir(), "METADATA")); existed {
-		ctx.CreateBazelTargetModule(
-			bazel.BazelTargetModuleProperties{
-				Rule_class: "filegroup",
-			},
-			CommonAttributes{Name: "default_metadata_file"},
-			&bazelFilegroupAttributes{
-				Srcs:                bazel.MakeLabelListAttribute(BazelLabelForModuleSrc(ctx, []string{"METADATA"})),
-				Applicable_licenses: bazel.LabelListAttribute{Value: bazel.LabelList{Includes: []bazel.Label{}}, EmitEmptyList: true},
-			})
-		defaultPackageMetadata.Value.Add(&bazel.Label{Label: ":default_metadata_file"})
-	}
-
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class: "package",
-		},
-		CommonAttributes{},
-		&bazelPackageAttributes{
-			Default_package_metadata: defaultPackageMetadata,
-			// FIXME(asmundak): once b/221436821 is resolved
-			Default_visibility: []string{"//visibility:public"},
-		})
-}
-
 func (p *packageModule) GenerateAndroidBuildActions(ModuleContext) {
 	// Nothing to do.
 }
 
+func (p *packageModule) DepsMutator(ctx BottomUpMutatorContext) {
+	// Add the dependency to do a validity check
+	if p.properties.Default_team != nil {
+		ctx.AddDependency(ctx.Module(), nil, *p.properties.Default_team)
+	}
+}
+
 func (p *packageModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
 	// Nothing to do.
 }
@@ -102,7 +67,7 @@
 func PackageFactory() Module {
 	module := &packageModule{}
 
-	module.AddProperties(&module.properties, &module.commonProperties.BazelConversionStatus)
+	module.AddProperties(&module.properties)
 
 	// The name is the relative path from build root to the directory containing this
 	// module. Set that name at the earliest possible moment that information is available
@@ -119,7 +84,5 @@
 	// its checking and parsing phases so make it the primary licenses property.
 	setPrimaryLicensesProperty(module, "default_applicable_licenses", &module.properties.Default_applicable_licenses)
 
-	InitBazelModule(module)
-
 	return module
 }
diff --git a/android/packaging.go b/android/packaging.go
index 503bb97..6677218 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"path/filepath"
+	"strings"
 
 	"github.com/google/blueprint"
 )
@@ -42,6 +43,11 @@
 	effectiveLicenseFiles *Paths
 
 	partition string
+
+	// Whether this packaging spec represents an installation of the srcPath (i.e. this struct
+	// is created via InstallFile or InstallSymlink) or a simple packaging (i.e. created via
+	// PackageFile).
+	skipInstall bool
 }
 
 // Get file name of installed package
@@ -73,6 +79,10 @@
 	return p.partition
 }
 
+func (p *PackagingSpec) SkipInstall() bool {
+	return p.skipInstall
+}
+
 type PackageModule interface {
 	Module
 	packagingBase() *PackagingBase
@@ -84,6 +94,7 @@
 
 	// GatherPackagingSpecs gathers PackagingSpecs of transitive dependencies.
 	GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec
+	GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec
 
 	// CopyDepsToZip zips the built artifacts of the dependencies into the given zip file and
 	// returns zip entries in it. This is expected to be called in GenerateAndroidBuildActions,
@@ -220,14 +231,18 @@
 	}
 }
 
-// See PackageModule.GatherPackagingSpecs
-func (p *PackagingBase) GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec {
+func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec {
 	m := make(map[string]PackagingSpec)
 	ctx.VisitDirectDeps(func(child Module) {
 		if pi, ok := ctx.OtherModuleDependencyTag(child).(PackagingItem); !ok || !pi.IsPackagingItem() {
 			return
 		}
 		for _, ps := range child.TransitivePackagingSpecs() {
+			if filter != nil {
+				if !filter(ps) {
+					continue
+				}
+			}
 			if _, ok := m[ps.relPathInPackage]; !ok {
 				m[ps.relPathInPackage] = ps
 			}
@@ -236,10 +251,22 @@
 	return m
 }
 
+// See PackageModule.GatherPackagingSpecs
+func (p *PackagingBase) GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec {
+	return p.GatherPackagingSpecsWithFilter(ctx, nil)
+}
+
 // CopySpecsToDir is a helper that will add commands to the rule builder to copy the PackagingSpec
 // entries into the specified directory.
 func (p *PackagingBase) CopySpecsToDir(ctx ModuleContext, builder *RuleBuilder, specs map[string]PackagingSpec, dir WritablePath) (entries []string) {
+	if len(specs) == 0 {
+		return entries
+	}
 	seenDir := make(map[string]bool)
+	preparerPath := PathForModuleOut(ctx, "preparer.sh")
+	cmd := builder.Command().Tool(preparerPath)
+	var sb strings.Builder
+	sb.WriteString("set -e\n")
 	for _, k := range SortedKeys(specs) {
 		ps := specs[k]
 		destPath := filepath.Join(dir.String(), ps.relPathInPackage)
@@ -247,18 +274,21 @@
 		entries = append(entries, ps.relPathInPackage)
 		if _, ok := seenDir[destDir]; !ok {
 			seenDir[destDir] = true
-			builder.Command().Text("mkdir").Flag("-p").Text(destDir)
+			sb.WriteString(fmt.Sprintf("mkdir -p %s\n", destDir))
 		}
 		if ps.symlinkTarget == "" {
-			builder.Command().Text("cp").Input(ps.srcPath).Text(destPath)
+			cmd.Implicit(ps.srcPath)
+			sb.WriteString(fmt.Sprintf("cp %s %s\n", ps.srcPath, destPath))
 		} else {
-			builder.Command().Text("ln").Flag("-sf").Text(ps.symlinkTarget).Text(destPath)
+			sb.WriteString(fmt.Sprintf("ln -sf %s %s\n", ps.symlinkTarget, destPath))
 		}
 		if ps.executable {
-			builder.Command().Text("chmod").Flag("a+x").Text(destPath)
+			sb.WriteString(fmt.Sprintf("chmod a+x %s\n", destPath))
 		}
 	}
 
+	WriteExecutableFileRuleVerbatim(ctx, preparerPath, sb.String())
+
 	return entries
 }
 
diff --git a/android/path_properties.go b/android/path_properties.go
index fdc4d91..6210aee 100644
--- a/android/path_properties.go
+++ b/android/path_properties.go
@@ -33,6 +33,11 @@
 // The pathDepsMutator automatically adds dependencies on any module that is listed with the
 // ":module" module reference syntax in a property that is tagged with `android:"path"`.
 func pathDepsMutator(ctx BottomUpMutatorContext) {
+	if _, ok := ctx.Module().(DefaultsModule); ok {
+		// Defaults modules shouldn't have dependencies added for path properties, they have already been
+		// squashed into the real modules.
+		return
+	}
 	props := ctx.Module().base().GetProperties()
 	addPathDepsForProps(ctx, props)
 }
@@ -42,7 +47,7 @@
 	// tagged with `android:"path"`.
 	var pathProperties []string
 	for _, ps := range props {
-		pathProperties = append(pathProperties, pathPropertiesForPropertyStruct(ps)...)
+		pathProperties = append(pathProperties, pathPropertiesForPropertyStruct(ctx, ps)...)
 	}
 
 	// Remove duplicates to avoid multiple dependencies.
@@ -59,7 +64,7 @@
 // pathPropertiesForPropertyStruct uses the indexes of properties that are tagged with
 // android:"path" to extract all their values from a property struct, returning them as a single
 // slice of strings.
-func pathPropertiesForPropertyStruct(ps interface{}) []string {
+func pathPropertiesForPropertyStruct(ctx BottomUpMutatorContext, ps interface{}) []string {
 	v := reflect.ValueOf(ps)
 	if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
 		panic(fmt.Errorf("type %s is not a pointer to a struct", v.Type()))
@@ -101,6 +106,16 @@
 				ret = append(ret, sv.String())
 			case reflect.Slice:
 				ret = append(ret, sv.Interface().([]string)...)
+			case reflect.Struct:
+				intf := sv.Interface()
+				if configurable, ok := intf.(proptools.Configurable[string]); ok {
+					ret = append(ret, configurable.GetOrDefault(ctx, ""))
+				} else if configurable, ok := intf.(proptools.Configurable[[]string]); ok {
+					ret = append(ret, configurable.GetOrDefault(ctx, nil)...)
+				} else {
+					panic(fmt.Errorf(`field %s in type %s has tag android:"path" but is not a string or slice of strings, it is a %s`,
+						v.Type().FieldByIndex(i).Name, v.Type(), sv.Type()))
+				}
 			default:
 				panic(fmt.Errorf(`field %s in type %s has tag android:"path" but is not a string or slice of strings, it is a %s`,
 					v.Type().FieldByIndex(i).Name, v.Type(), sv.Type()))
diff --git a/android/paths.go b/android/paths.go
index 325a953..2b33f67 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -111,11 +111,68 @@
 	InstallInDebugRamdisk() bool
 	InstallInRecovery() bool
 	InstallInRoot() bool
+	InstallInOdm() bool
+	InstallInProduct() bool
+	InstallInVendor() bool
 	InstallForceOS() (*OsType, *ArchType)
 }
 
 var _ ModuleInstallPathContext = ModuleContext(nil)
 
+type baseModuleContextToModuleInstallPathContext struct {
+	BaseModuleContext
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInData() bool {
+	return ctx.Module().InstallInData()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInTestcases() bool {
+	return ctx.Module().InstallInTestcases()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInSanitizerDir() bool {
+	return ctx.Module().InstallInSanitizerDir()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInRamdisk() bool {
+	return ctx.Module().InstallInRamdisk()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInVendorRamdisk() bool {
+	return ctx.Module().InstallInVendorRamdisk()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInDebugRamdisk() bool {
+	return ctx.Module().InstallInDebugRamdisk()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInRecovery() bool {
+	return ctx.Module().InstallInRecovery()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInRoot() bool {
+	return ctx.Module().InstallInRoot()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInOdm() bool {
+	return ctx.Module().InstallInOdm()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInProduct() bool {
+	return ctx.Module().InstallInProduct()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallInVendor() bool {
+	return ctx.Module().InstallInVendor()
+}
+
+func (ctx *baseModuleContextToModuleInstallPathContext) InstallForceOS() (*OsType, *ArchType) {
+	return ctx.Module().InstallForceOS()
+}
+
+var _ ModuleInstallPathContext = (*baseModuleContextToModuleInstallPathContext)(nil)
+
 // errorfContext is the interface containing the Errorf method matching the
 // Errorf method in blueprint.SingletonContext.
 type errorfContext interface {
@@ -124,13 +181,13 @@
 
 var _ errorfContext = blueprint.SingletonContext(nil)
 
-// moduleErrorf is the interface containing the ModuleErrorf method matching
+// ModuleErrorfContext is the interface containing the ModuleErrorf method matching
 // the ModuleErrorf method in blueprint.ModuleContext.
-type moduleErrorf interface {
+type ModuleErrorfContext interface {
 	ModuleErrorf(format string, args ...interface{})
 }
 
-var _ moduleErrorf = blueprint.ModuleContext(nil)
+var _ ModuleErrorfContext = blueprint.ModuleContext(nil)
 
 // reportPathError will register an error with the attached context. It
 // attempts ctx.ModuleErrorf for a better error message first, then falls
@@ -143,7 +200,7 @@
 // attempts ctx.ModuleErrorf for a better error message first, then falls
 // back to ctx.Errorf.
 func ReportPathErrorf(ctx PathContext, format string, args ...interface{}) {
-	if mctx, ok := ctx.(moduleErrorf); ok {
+	if mctx, ok := ctx.(ModuleErrorfContext); ok {
 		mctx.ModuleErrorf(format, args...)
 	} else if ectx, ok := ctx.(errorfContext); ok {
 		ectx.Errorf(format, args...)
@@ -480,7 +537,7 @@
 
 // PathForGoBinary returns the path to the installed location of a bootstrap_go_binary module.
 func PathForGoBinary(ctx PathContext, goBinary bootstrap.GoBinaryTool) Path {
-	goBinaryInstallDir := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "bin", false)
+	goBinaryInstallDir := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "bin")
 	rel := Rel(ctx, goBinaryInstallDir.String(), goBinary.InstallPath())
 	return goBinaryInstallDir.Join(ctx, rel)
 }
@@ -616,7 +673,8 @@
 		expandedSrcFiles = append(expandedSrcFiles, srcFiles...)
 	}
 
-	return expandedSrcFiles, append(missingDeps, missingExcludeDeps...)
+	// TODO: b/334169722 - Replace with an error instead of implicitly removing duplicates.
+	return FirstUniquePaths(expandedSrcFiles), append(missingDeps, missingExcludeDeps...)
 }
 
 type missingDependencyError struct {
@@ -1604,6 +1662,8 @@
 
 	// makePath indicates whether this path is for Soong (false) or Make (true).
 	makePath bool
+
+	fullPath string
 }
 
 // Will panic if called from outside a test environment.
@@ -1616,7 +1676,12 @@
 
 func (p InstallPath) RelativeToTop() Path {
 	ensureTestOnly()
-	p.soongOutDir = OutSoongDir
+	if p.makePath {
+		p.soongOutDir = OutDir
+	} else {
+		p.soongOutDir = OutSoongDir
+	}
+	p.fullPath = filepath.Join(p.soongOutDir, p.path)
 	return p
 }
 
@@ -1634,12 +1699,7 @@
 func (p InstallPath) writablePath() {}
 
 func (p InstallPath) String() string {
-	if p.makePath {
-		// Make path starts with out/ instead of out/soong.
-		return filepath.Join(p.soongOutDir, "../", p.path)
-	} else {
-		return filepath.Join(p.soongOutDir, p.path)
-	}
+	return p.fullPath
 }
 
 // PartitionDir returns the path to the partition where the install path is rooted at. It is
@@ -1669,6 +1729,7 @@
 
 func (p InstallPath) withRel(rel string) InstallPath {
 	p.basePath = p.basePath.withRel(rel)
+	p.fullPath = filepath.Join(p.fullPath, rel)
 	return p
 }
 
@@ -1683,20 +1744,20 @@
 // module appended with paths...
 func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
 	os, arch := osAndArch(ctx)
-	partition := modulePartition(ctx, os)
-	return makePathForInstall(ctx, os, arch, partition, ctx.Debug(), pathComponents...)
+	partition := modulePartition(ctx, os.Class == Device)
+	return pathForInstall(ctx, os, arch, partition, pathComponents...)
 }
 
 // PathForHostDexInstall returns an InstallPath representing the install path for the
 // module appended with paths...
 func PathForHostDexInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
-	return makePathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "", ctx.Debug(), pathComponents...)
+	return pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "", pathComponents...)
 }
 
 // PathForModuleInPartitionInstall is similar to PathForModuleInstall but partition is provided by the caller
 func PathForModuleInPartitionInstall(ctx ModuleInstallPathContext, partition string, pathComponents ...string) InstallPath {
 	os, arch := osAndArch(ctx)
-	return makePathForInstall(ctx, os, arch, partition, ctx.Debug(), pathComponents...)
+	return pathForInstall(ctx, os, arch, partition, pathComponents...)
 }
 
 func osAndArch(ctx ModuleInstallPathContext) (OsType, ArchType) {
@@ -1712,12 +1773,26 @@
 	return os, arch
 }
 
-func makePathForInstall(ctx ModuleInstallPathContext, os OsType, arch ArchType, partition string, debug bool, pathComponents ...string) InstallPath {
-	ret := pathForInstall(ctx, os, arch, partition, debug, pathComponents...)
-	return ret
+func pathForPartitionInstallDir(ctx PathContext, partition, partitionPath string, makePath bool) InstallPath {
+	fullPath := ctx.Config().SoongOutDir()
+	if makePath {
+		// Make path starts with out/ instead of out/soong.
+		fullPath = filepath.Join(fullPath, "../", partitionPath)
+	} else {
+		fullPath = filepath.Join(fullPath, partitionPath)
+	}
+
+	return InstallPath{
+		basePath:     basePath{partitionPath, ""},
+		soongOutDir:  ctx.Config().soongOutDir,
+		partitionDir: partitionPath,
+		partition:    partition,
+		makePath:     makePath,
+		fullPath:     fullPath,
+	}
 }
 
-func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string, debug bool,
+func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string,
 	pathComponents ...string) InstallPath {
 
 	var partitionPaths []string
@@ -1747,45 +1822,23 @@
 		}
 		partitionPaths = []string{"host", osName + "-" + archName, partition}
 	}
-	if debug {
-		partitionPaths = append([]string{"debug"}, partitionPaths...)
-	}
 
 	partitionPath, err := validatePath(partitionPaths...)
 	if err != nil {
 		reportPathError(ctx, err)
 	}
 
-	base := InstallPath{
-		basePath:     basePath{partitionPath, ""},
-		soongOutDir:  ctx.Config().soongOutDir,
-		partitionDir: partitionPath,
-		partition:    partition,
-	}
-
-	if ctx.Config().KatiEnabled() {
-		base.makePath = true
-	}
-
+	base := pathForPartitionInstallDir(ctx, partition, partitionPath, ctx.Config().KatiEnabled())
 	return base.Join(ctx, pathComponents...)
 }
 
-func pathForNdkOrSdkInstall(ctx PathContext, prefix string, paths []string) InstallPath {
-	base := InstallPath{
-		basePath:     basePath{prefix, ""},
-		soongOutDir:  ctx.Config().soongOutDir,
-		partitionDir: prefix,
-		makePath:     false,
-	}
-	return base.Join(ctx, paths...)
-}
-
-func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
-	return pathForNdkOrSdkInstall(ctx, "ndk", paths)
+func PathForNdkInstall(ctx PathContext, paths ...string) OutputPath {
+	return PathForOutput(ctx, append([]string{"ndk"}, paths...)...)
 }
 
 func PathForMainlineSdksInstall(ctx PathContext, paths ...string) InstallPath {
-	return pathForNdkOrSdkInstall(ctx, "mainline-sdks", paths)
+	base := pathForPartitionInstallDir(ctx, "", "mainline-sdks", false)
+	return base.Join(ctx, paths...)
 }
 
 func InstallPathToOnDevicePath(ctx PathContext, path InstallPath) string {
@@ -1793,12 +1846,12 @@
 	return "/" + rel
 }
 
-func modulePartition(ctx ModuleInstallPathContext, os OsType) string {
+func modulePartition(ctx ModuleInstallPathContext, device bool) string {
 	var partition string
 	if ctx.InstallInTestcases() {
 		// "testcases" install directory can be used for host or device modules.
 		partition = "testcases"
-	} else if os.Class == Device {
+	} else if device {
 		if ctx.InstallInData() {
 			partition = "data"
 		} else if ctx.InstallInRamdisk() {
@@ -1832,11 +1885,11 @@
 				// the layout of recovery partion is the same as that of system partition
 				partition = "recovery/root/system"
 			}
-		} else if ctx.SocSpecific() {
+		} else if ctx.SocSpecific() || ctx.InstallInVendor() {
 			partition = ctx.DeviceConfig().VendorPath()
-		} else if ctx.DeviceSpecific() {
+		} else if ctx.DeviceSpecific() || ctx.InstallInOdm() {
 			partition = ctx.DeviceConfig().OdmPath()
-		} else if ctx.ProductSpecific() {
+		} else if ctx.ProductSpecific() || ctx.InstallInProduct() {
 			partition = ctx.DeviceConfig().ProductPath()
 		} else if ctx.SystemExtSpecific() {
 			partition = ctx.DeviceConfig().SystemExtPath()
@@ -1881,7 +1934,9 @@
 // validatePathInternal ensures that a path does not leave its component, and
 // optionally doesn't contain Ninja variables.
 func validatePathInternal(allowNinjaVariables bool, pathComponents ...string) (string, error) {
-	for _, path := range pathComponents {
+	initialEmpty := 0
+	finalEmpty := 0
+	for i, path := range pathComponents {
 		if !allowNinjaVariables && strings.Contains(path, "$") {
 			return "", fmt.Errorf("Path contains invalid character($): %s", path)
 		}
@@ -1890,11 +1945,25 @@
 		if path == ".." || strings.HasPrefix(path, "../") || strings.HasPrefix(path, "/") {
 			return "", fmt.Errorf("Path is outside directory: %s", path)
 		}
+
+		if i == initialEmpty && pathComponents[i] == "" {
+			initialEmpty++
+		}
+		if i == finalEmpty && pathComponents[len(pathComponents)-1-i] == "" {
+			finalEmpty++
+		}
 	}
+	// Optimization: filepath.Join("foo", "") returns a newly allocated copy
+	// of "foo", while filepath.Join("foo") does not.  Strip out any empty
+	// path components.
+	if initialEmpty == len(pathComponents) {
+		return "", nil
+	}
+	nonEmptyPathComponents := pathComponents[initialEmpty : len(pathComponents)-finalEmpty]
 	// TODO: filepath.Join isn't necessarily correct with embedded ninja
 	// variables. '..' may remove the entire ninja variable, even if it
 	// will be expanded to multiple nested directories.
-	return filepath.Join(pathComponents...), nil
+	return filepath.Join(nonEmptyPathComponents...), nil
 }
 
 // validateSafePath validates a path that we trust (may contain ninja
@@ -2016,6 +2085,9 @@
 	inDebugRamdisk  bool
 	inRecovery      bool
 	inRoot          bool
+	inOdm           bool
+	inProduct       bool
+	inVendor        bool
 	forceOS         *OsType
 	forceArch       *ArchType
 }
@@ -2058,6 +2130,18 @@
 	return m.inRoot
 }
 
+func (m testModuleInstallPathContext) InstallInOdm() bool {
+	return m.inOdm
+}
+
+func (m testModuleInstallPathContext) InstallInProduct() bool {
+	return m.inProduct
+}
+
+func (m testModuleInstallPathContext) InstallInVendor() bool {
+	return m.inVendor
+}
+
 func (m testModuleInstallPathContext) InstallForceOS() (*OsType, *ArchType) {
 	return m.forceOS, m.forceArch
 }
@@ -2158,6 +2242,19 @@
 	SrcPath Path
 	// The install path of the data file, relative to the install root.
 	RelativeInstallPath string
+	// If WithoutRel is true, use SrcPath.Base() instead of SrcPath.Rel() as the filename.
+	WithoutRel bool
+}
+
+func (d *DataPath) ToRelativeInstallPath() string {
+	relPath := d.SrcPath.Rel()
+	if d.WithoutRel {
+		relPath = d.SrcPath.Base()
+	}
+	if d.RelativeInstallPath != "" {
+		relPath = filepath.Join(d.RelativeInstallPath, relPath)
+	}
+	return relPath
 }
 
 // PathsIfNonNil returns a Paths containing only the non-nil input arguments.
diff --git a/android/paths_test.go b/android/paths_test.go
index 2f87977..93b9b9a 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -37,6 +37,22 @@
 		out: "",
 	},
 	{
+		in:  []string{"", ""},
+		out: "",
+	},
+	{
+		in:  []string{"a", ""},
+		out: "a",
+	},
+	{
+		in:  []string{"", "a"},
+		out: "a",
+	},
+	{
+		in:  []string{"", "a", ""},
+		out: "a",
+	},
+	{
 		in:  []string{"a/b"},
 		out: "a/b",
 	},
@@ -252,8 +268,10 @@
 			name: "host binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     hostTarget.Os,
-					target: hostTarget,
+					archModuleContext: archModuleContext{
+						os:     hostTarget.Os,
+						target: hostTarget,
+					},
 				},
 			},
 			in:           []string{"bin", "my_test"},
@@ -265,8 +283,10 @@
 			name: "system binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 			},
 			in:           []string{"bin", "my_test"},
@@ -277,8 +297,10 @@
 			name: "vendor binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: socSpecificModule,
 					},
@@ -292,8 +314,10 @@
 			name: "odm binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: deviceSpecificModule,
 					},
@@ -307,8 +331,10 @@
 			name: "product binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: productSpecificModule,
 					},
@@ -322,8 +348,10 @@
 			name: "system_ext binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: systemExtSpecificModule,
 					},
@@ -337,8 +365,10 @@
 			name: "root binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inRoot: true,
 			},
@@ -350,8 +380,10 @@
 			name: "recovery binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inRecovery: true,
 			},
@@ -363,8 +395,10 @@
 			name: "recovery root binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inRecovery: true,
 				inRoot:     true,
@@ -378,8 +412,10 @@
 			name: "ramdisk binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inRamdisk: true,
 			},
@@ -391,8 +427,10 @@
 			name: "ramdisk root binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inRamdisk: true,
 				inRoot:    true,
@@ -405,8 +443,10 @@
 			name: "vendor_ramdisk binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inVendorRamdisk: true,
 			},
@@ -418,8 +458,10 @@
 			name: "vendor_ramdisk root binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inVendorRamdisk: true,
 				inRoot:          true,
@@ -432,8 +474,10 @@
 			name: "debug_ramdisk binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inDebugRamdisk: true,
 			},
@@ -445,8 +489,10 @@
 			name: "system native test binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inData: true,
 			},
@@ -458,8 +504,10 @@
 			name: "vendor native test binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: socSpecificModule,
 					},
@@ -474,8 +522,10 @@
 			name: "odm native test binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: deviceSpecificModule,
 					},
@@ -490,8 +540,10 @@
 			name: "product native test binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: productSpecificModule,
 					},
@@ -507,8 +559,10 @@
 			name: "system_ext native test binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: systemExtSpecificModule,
 					},
@@ -524,8 +578,10 @@
 			name: "sanitized system binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inSanitizerDir: true,
 			},
@@ -537,8 +593,10 @@
 			name: "sanitized vendor binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: socSpecificModule,
 					},
@@ -553,8 +611,10 @@
 			name: "sanitized odm binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: deviceSpecificModule,
 					},
@@ -569,8 +629,10 @@
 			name: "sanitized product binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: productSpecificModule,
 					},
@@ -586,8 +648,10 @@
 			name: "sanitized system_ext binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: systemExtSpecificModule,
 					},
@@ -603,8 +667,10 @@
 			name: "sanitized system native test binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inData:         true,
 				inSanitizerDir: true,
@@ -617,8 +683,10 @@
 			name: "sanitized vendor native test binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: socSpecificModule,
 					},
@@ -634,8 +702,10 @@
 			name: "sanitized odm native test binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: deviceSpecificModule,
 					},
@@ -651,8 +721,10 @@
 			name: "sanitized product native test binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: productSpecificModule,
 					},
@@ -668,8 +740,10 @@
 			name: "sanitized system_ext native test binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 					earlyModuleContext: earlyModuleContext{
 						kind: systemExtSpecificModule,
 					},
@@ -684,8 +758,10 @@
 			name: "device testcases",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inTestcases: true,
 			},
@@ -696,8 +772,10 @@
 			name: "host testcases",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     hostTarget.Os,
-					target: hostTarget,
+					archModuleContext: archModuleContext{
+						os:     hostTarget.Os,
+						target: hostTarget,
+					},
 				},
 				inTestcases: true,
 			},
@@ -708,8 +786,10 @@
 			name: "forced host testcases",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inTestcases: true,
 				forceOS:     &Linux,
@@ -755,8 +835,10 @@
 			name: "ramdisk binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inRamdisk: true,
 				inRoot:    true,
@@ -770,8 +852,10 @@
 			name: "vendor_ramdisk binary",
 			ctx: &testModuleInstallPathContext{
 				baseModuleContext: baseModuleContext{
-					os:     deviceTarget.Os,
-					target: deviceTarget,
+					archModuleContext: archModuleContext{
+						os:     deviceTarget.Os,
+						target: deviceTarget,
+					},
 				},
 				inVendorRamdisk: true,
 				inRoot:          true,
@@ -805,8 +889,10 @@
 
 	ctx := &testModuleInstallPathContext{
 		baseModuleContext: baseModuleContext{
-			os:     deviceTarget.Os,
-			target: deviceTarget,
+			archModuleContext: archModuleContext{
+				os:     deviceTarget.Os,
+				target: deviceTarget,
+			},
 		},
 	}
 	ctx.baseModuleContext.config = testConfig
@@ -1475,8 +1561,10 @@
 
 	ctx := &testModuleInstallPathContext{
 		baseModuleContext: baseModuleContext{
-			os:     deviceTarget.Os,
-			target: deviceTarget,
+			archModuleContext: archModuleContext{
+				os:     deviceTarget.Os,
+				target: deviceTarget,
+			},
 		},
 	}
 	ctx.baseModuleContext.config = testConfig
diff --git a/android/plugin.go b/android/plugin.go
index 4672453..d62fc94 100644
--- a/android/plugin.go
+++ b/android/plugin.go
@@ -16,8 +16,6 @@
 
 import (
 	"encoding/json"
-	"fmt"
-	"io/ioutil"
 	"os"
 	"strings"
 
@@ -72,28 +70,30 @@
 	"xsdc-soong-rules":                       true,
 }
 
-const (
-	internalPluginsPath = "vendor/google/build/soong/internal_plugins.json"
-)
+var internalPluginsPaths = []string{
+	"vendor/google/build/soong/internal_plugins.json",
+}
 
 type pluginProvider interface {
 	IsPluginFor(string) bool
 }
 
 func maybeAddInternalPluginsToAllowlist(ctx SingletonContext) {
-	if path := ExistentPathForSource(ctx, internalPluginsPath); path.Valid() {
-		ctx.AddNinjaFileDeps(path.String())
-		absPath := absolutePath(path.String())
-		var moreAllowed map[string]bool
-		data, err := ioutil.ReadFile(absPath)
-		if err != nil {
-			ctx.Errorf("Failed to open internal plugins path %q %q", internalPluginsPath, err)
-		}
-		if err := json.Unmarshal(data, &moreAllowed); err != nil {
-			fmt.Fprintf(os.Stderr, "Internal plugins file %q did not parse correctly: %q", data, err)
-		}
-		for k, v := range moreAllowed {
-			allowedPluginsByName[k] = v
+	for _, internalPluginsPath := range internalPluginsPaths {
+		if path := ExistentPathForSource(ctx, internalPluginsPath); path.Valid() {
+			ctx.AddNinjaFileDeps(path.String())
+			absPath := absolutePath(path.String())
+			var moreAllowed map[string]bool
+			data, err := os.ReadFile(absPath)
+			if err != nil {
+				ctx.Errorf("Failed to open internal plugins path %q %q", internalPluginsPath, err)
+			}
+			if err := json.Unmarshal(data, &moreAllowed); err != nil {
+				ctx.Errorf("Internal plugins file %q did not parse correctly: %q", data, err)
+			}
+			for k, v := range moreAllowed {
+				allowedPluginsByName[k] = v
+			}
 		}
 	}
 }
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 95b772d..2b7b55b 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -71,6 +71,9 @@
 	//
 	// If specified then the prefer property is ignored in favor of the value of the Soong config
 	// variable.
+	//
+	// DEPRECATED: This property is being deprecated b/308188211.
+	// Use RELEASE_APEX_CONTRIBUTIONS build flags to select prebuilts of mainline modules.
 	Use_source_config_var *ConfigVarProperties
 }
 
@@ -277,6 +280,9 @@
 		}
 		value := srcPropsValue.FieldByIndex(srcFieldIndex)
 		if value.Kind() == reflect.Ptr {
+			if value.IsNil() {
+				return nil
+			}
 			value = value.Elem()
 		}
 		if value.Kind() != reflect.String {
@@ -387,16 +393,23 @@
 
 func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) {
 	ctx.BottomUp("prebuilt_source", PrebuiltSourceDepsMutator).Parallel()
-	ctx.TopDown("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
+	ctx.BottomUp("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
 	ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).Parallel()
 }
 
+// Returns the name of the source module corresponding to a prebuilt module
+// For source modules, it returns its own name
+type baseModuleName interface {
+	BaseModuleName() string
+}
+
 // PrebuiltRenameMutator ensures that there always is a module with an
 // undecorated name.
 func PrebuiltRenameMutator(ctx BottomUpMutatorContext) {
 	m := ctx.Module()
 	if p := GetEmbeddedPrebuilt(m); p != nil {
-		name := m.base().BaseModuleName()
+		bmn, _ := m.(baseModuleName)
+		name := bmn.BaseModuleName()
 		if !ctx.OtherModuleExists(name) {
 			ctx.Rename(name)
 			p.properties.PrebuiltRenamedToSource = true
@@ -406,16 +419,27 @@
 
 // PrebuiltSourceDepsMutator adds dependencies to the prebuilt module from the
 // corresponding source module, if one exists for the same variant.
+// Add a dependency from the prebuilt to `all_apex_contributions`
+// The metadata will be used for source vs prebuilts selection
 func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) {
 	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()
+		bmn, _ := m.(baseModuleName)
+		name := bmn.BaseModuleName()
 		if ctx.OtherModuleReverseDependencyVariantExists(name) {
 			ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
 			p.properties.SourceExists = true
 		}
+		// Add a dependency from the prebuilt to the `all_apex_contributions`
+		// metadata module
+		// TODO: When all branches contain this singleton module, make this strict
+		// TODO: Add this dependency only for mainline prebuilts and not every prebuilt module
+		if ctx.OtherModuleExists("all_apex_contributions") {
+			ctx.AddDependency(m, acDepTag, "all_apex_contributions")
+		}
+
 	}
 }
 
@@ -435,7 +459,11 @@
 
 // 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 the visited module is the metadata module `all_apex_contributions`, it sets a
+// provider containing metadata about whether source or prebuilt of mainline modules should be used.
+// This logic was added here to prevent the overhead of creating a new mutator.
+func PrebuiltSelectModuleMutator(ctx BottomUpMutatorContext) {
 	m := ctx.Module()
 	if p := GetEmbeddedPrebuilt(m); p != nil {
 		if p.srcsSupplier == nil && p.srcsPropertyName == "" {
@@ -444,7 +472,21 @@
 		if !p.properties.SourceExists {
 			p.properties.UsePrebuilt = p.usePrebuilt(ctx, nil, m)
 		}
+		// Propagate the provider received from `all_apex_contributions`
+		// to the source module
+		ctx.VisitDirectDepsWithTag(acDepTag, func(am Module) {
+			psi, _ := OtherModuleProvider(ctx, am, PrebuiltSelectionInfoProvider)
+			SetProvider(ctx, PrebuiltSelectionInfoProvider, psi)
+		})
+
 	} else if s, ok := ctx.Module().(Module); ok {
+		// Use `all_apex_contributions` for source vs prebuilt selection.
+		psi := PrebuiltSelectionInfoMap{}
+		ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(am Module) {
+			// The value of psi gets overwritten with the provider from the last visited prebuilt.
+			// But all prebuilts have the same value of the provider, so this should be idempontent.
+			psi, _ = OtherModuleProvider(ctx, am, PrebuiltSelectionInfoProvider)
+		})
 		ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(prebuiltModule Module) {
 			p := GetEmbeddedPrebuilt(prebuiltModule)
 			if p.usePrebuilt(ctx, s, prebuiltModule) {
@@ -454,6 +496,78 @@
 				s.ReplacedByPrebuilt()
 			}
 		})
+
+		// If any module in this mainline module family has been flagged using apex_contributions, disable every other module in that family
+		// Add source
+		allModules := []Module{s}
+		// Add each prebuilt
+		ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(prebuiltModule Module) {
+			allModules = append(allModules, prebuiltModule)
+		})
+		hideUnflaggedModules(ctx, psi, allModules)
+
+	}
+
+	// If this is `all_apex_contributions`, set a provider containing
+	// metadata about source vs prebuilts selection
+	if am, ok := m.(*allApexContributions); ok {
+		am.SetPrebuiltSelectionInfoProvider(ctx)
+	}
+}
+
+// If any module in this mainline module family has been flagged using apex_contributions, disable every other module in that family
+func hideUnflaggedModules(ctx BottomUpMutatorContext, psi PrebuiltSelectionInfoMap, allModulesInFamily []Module) {
+	var selectedModuleInFamily Module
+	// query all_apex_contributions to see if any module in this family has been selected
+	for _, moduleInFamily := range allModulesInFamily {
+		// validate that are no duplicates
+		if isSelected(psi, moduleInFamily) {
+			if selectedModuleInFamily == nil {
+				// Store this so we can validate that there are no duplicates
+				selectedModuleInFamily = moduleInFamily
+			} else {
+				// There are duplicate modules from the same mainline module family
+				ctx.ModuleErrorf("Found duplicate variations of the same module in apex_contributions: %s and %s. Please remove one of these.\n", selectedModuleInFamily.Name(), moduleInFamily.Name())
+			}
+		}
+	}
+
+	// If a module has been selected, hide all other modules
+	if selectedModuleInFamily != nil {
+		for _, moduleInFamily := range allModulesInFamily {
+			if moduleInFamily.Name() != selectedModuleInFamily.Name() {
+				moduleInFamily.HideFromMake()
+				// If this is a prebuilt module, unset properties.UsePrebuilt
+				// properties.UsePrebuilt might evaluate to true via soong config var fallback mechanism
+				// Set it to false explicitly so that the following mutator does not replace rdeps to this unselected prebuilt
+				if p := GetEmbeddedPrebuilt(moduleInFamily); p != nil {
+					p.properties.UsePrebuilt = false
+				}
+			}
+		}
+	}
+	// Do a validation pass to make sure that multiple prebuilts of a specific module are not selected.
+	// This might happen if the prebuilts share the same soong config var namespace.
+	// This should be an error, unless one of the prebuilts has been explicitly declared in apex_contributions
+	var selectedPrebuilt Module
+	for _, moduleInFamily := range allModulesInFamily {
+		// Skip if this module is in a different namespace
+		if !moduleInFamily.ExportedToMake() {
+			continue
+		}
+		// Skip for the top-level java_sdk_library_(_import). This has some special cases that need to be addressed first.
+		// This does not run into non-determinism because PrebuiltPostDepsMutator also has the special case
+		if sdkLibrary, ok := moduleInFamily.(interface{ SdkLibraryName() *string }); ok && sdkLibrary.SdkLibraryName() != nil {
+			continue
+		}
+		if p := GetEmbeddedPrebuilt(moduleInFamily); p != nil && p.properties.UsePrebuilt {
+			if selectedPrebuilt == nil {
+				selectedPrebuilt = moduleInFamily
+			} else {
+				ctx.ModuleErrorf("Multiple prebuilt modules %v and %v have been marked as preferred for this source module. "+
+					"Please add the appropriate prebuilt module to apex_contributions for this release config.", selectedPrebuilt.Name(), moduleInFamily.Name())
+			}
+		}
 	}
 }
 
@@ -463,14 +577,31 @@
 func PrebuiltPostDepsMutator(ctx BottomUpMutatorContext) {
 	m := ctx.Module()
 	if p := GetEmbeddedPrebuilt(m); p != nil {
-		name := m.base().BaseModuleName()
+		bmn, _ := m.(baseModuleName)
+		name := bmn.BaseModuleName()
+		psi := PrebuiltSelectionInfoMap{}
+		ctx.VisitDirectDepsWithTag(acDepTag, func(am Module) {
+			psi, _ = OtherModuleProvider(ctx, am, PrebuiltSelectionInfoProvider)
+		})
+
 		if p.properties.UsePrebuilt {
 			if p.properties.SourceExists {
 				ctx.ReplaceDependenciesIf(name, func(from blueprint.Module, tag blueprint.DependencyTag, to blueprint.Module) bool {
+					if sdkLibrary, ok := m.(interface{ SdkLibraryName() *string }); ok && sdkLibrary.SdkLibraryName() != nil {
+						// Do not replace deps to the top-level prebuilt java_sdk_library hook.
+						// This hook has been special-cased in #isSelected to be _always_ active, even in next builds
+						// for dexpreopt and hiddenapi processing.
+						// If we do not special-case this here, rdeps referring to a java_sdk_library in next builds via libs
+						// will get prebuilt stubs
+						// TODO (b/308187268): Remove this after the apexes have been added to apex_contributions
+						if psi.IsSelected(name) {
+							return false
+						}
+					}
+
 					if t, ok := tag.(ReplaceSourceWithPrebuilt); ok {
 						return t.ReplaceSourceWithPrebuilt()
 					}
-
 					return true
 				})
 			}
@@ -480,10 +611,86 @@
 	}
 }
 
+// A wrapper around PrebuiltSelectionInfoMap.IsSelected with special handling for java_sdk_library
+// java_sdk_library is a macro that creates
+// 1. top-level impl library
+// 2. stub libraries (suffixed with .stubs...)
+//
+// java_sdk_library_import is a macro that creates
+// 1. top-level "impl" library
+// 2. stub libraries (suffixed with .stubs...)
+//
+// the impl of java_sdk_library_import is a "hook" for hiddenapi and dexpreopt processing. It does not have an impl jar, but acts as a shim
+// to provide the jar deapxed from the prebuilt apex
+//
+// isSelected uses `all_apex_contributions` to supersede source vs prebuilts selection of the stub libraries. It does not supersede the
+// selection of the top-level "impl" library so that this hook can work
+//
+// TODO (b/308174306) - Fix this when we need to support multiple prebuilts in main
+func isSelected(psi PrebuiltSelectionInfoMap, m Module) bool {
+	if sdkLibrary, ok := m.(interface{ SdkLibraryName() *string }); ok && sdkLibrary.SdkLibraryName() != nil {
+		sln := proptools.String(sdkLibrary.SdkLibraryName())
+
+		// This is the top-level library
+		// Do not supersede the existing prebuilts vs source selection mechanisms
+		// TODO (b/308187268): Remove this after the apexes have been added to apex_contributions
+		if bmn, ok := m.(baseModuleName); ok && sln == bmn.BaseModuleName() {
+			return false
+		}
+
+		// Stub library created by java_sdk_library_import
+		// java_sdk_library creates several child modules (java_import + prebuilt_stubs_sources) dynamically.
+		// This code block ensures that these child modules are selected if the top-level java_sdk_library_import is listed
+		// in the selected apex_contributions.
+		if javaImport, ok := m.(createdByJavaSdkLibraryName); ok && javaImport.CreatedByJavaSdkLibraryName() != nil {
+			return psi.IsSelected(PrebuiltNameFromSource(proptools.String(javaImport.CreatedByJavaSdkLibraryName())))
+		}
+
+		// Stub library created by java_sdk_library
+		return psi.IsSelected(sln)
+	}
+	return psi.IsSelected(m.Name())
+}
+
+// implemented by child modules of java_sdk_library_import
+type createdByJavaSdkLibraryName interface {
+	CreatedByJavaSdkLibraryName() *string
+}
+
+// Returns true if the prebuilt variant is disabled
+// e.g. for a cc_prebuilt_library_shared, this will return
+// - true for the static variant of the module
+// - false for the shared variant of the module
+//
+// Even though this is a cc_prebuilt_library_shared, we create both the variants today
+// https://source.corp.google.com/h/googleplex-android/platform/build/soong/+/e08e32b45a18a77bc3c3e751f730539b1b374f1b:cc/library.go;l=2113-2116;drc=2c4a9779cd1921d0397a12b3d3521f4c9b30d747;bpv=1;bpt=0
+func (p *Prebuilt) variantIsDisabled(ctx BaseMutatorContext, prebuilt Module) bool {
+	return p.srcsSupplier != nil && len(p.srcsSupplier(ctx, prebuilt)) == 0
+}
+
 // usePrebuilt returns true if a prebuilt should be used instead of the source module.  The prebuilt
 // will be used if it is marked "prefer" or if the source module is disabled.
-func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module, prebuilt Module) bool {
-	if p.srcsSupplier != nil && len(p.srcsSupplier(ctx, prebuilt)) == 0 {
+func (p *Prebuilt) usePrebuilt(ctx BaseMutatorContext, source Module, prebuilt Module) bool {
+	// Use `all_apex_contributions` for source vs prebuilt selection.
+	psi := PrebuiltSelectionInfoMap{}
+	ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(am Module) {
+		psi, _ = OtherModuleProvider(ctx, am, PrebuiltSelectionInfoProvider)
+	})
+
+	// If the source module is explicitly listed in the metadata module, use that
+	if source != nil && isSelected(psi, source) {
+		return false
+	}
+	// If the prebuilt module is explicitly listed in the metadata module, use that
+	if isSelected(psi, prebuilt) && !p.variantIsDisabled(ctx, prebuilt) {
+		return true
+	}
+
+	// If the baseModuleName could not be found in the metadata module,
+	// fall back to the existing source vs prebuilt selection.
+	// TODO: Drop the fallback mechanisms
+
+	if p.variantIsDisabled(ctx, prebuilt) {
 		return false
 	}
 
@@ -499,11 +706,6 @@
 		return true
 	}
 
-	// If the use_source_config_var property is set then it overrides the prefer property setting.
-	if configVar := p.properties.Use_source_config_var; configVar != nil {
-		return !ctx.Config().VendorConfig(proptools.String(configVar.Config_namespace)).Bool(proptools.String(configVar.Var_name))
-	}
-
 	// TODO: use p.Properties.Name and ctx.ModuleDir to override preference
 	return Bool(p.properties.Prefer)
 }
diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go
index aeae20f..17b3230 100644
--- a/android/prebuilt_build_tool.go
+++ b/android/prebuilt_build_tool.go
@@ -17,7 +17,7 @@
 import "path/filepath"
 
 func init() {
-	RegisterModuleType("prebuilt_build_tool", prebuiltBuildToolFactory)
+	RegisterModuleType("prebuilt_build_tool", NewPrebuiltBuildTool)
 }
 
 type prebuiltBuildToolProperties struct {
@@ -101,10 +101,6 @@
 
 // prebuilt_build_tool is to declare prebuilts to be used during the build, particularly for use
 // in genrules with the "tools" property.
-func prebuiltBuildToolFactory() Module {
-	return NewPrebuiltBuildTool()
-}
-
 func NewPrebuiltBuildTool() Module {
 	module := &prebuiltBuildTool{}
 	module.AddProperties(&module.properties)
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index fc47cfd..575b926 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -295,86 +295,6 @@
 				}`,
 			prebuilt: []OsType{Android, buildOS},
 		},
-		{
-			name: "prebuilt use_source_config_var={acme, use_source} - no var specified",
-			modules: `
-				source {
-					name: "bar",
-				}
-
-				prebuilt {
-					name: "bar",
-					use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
-					srcs: ["prebuilt_file"],
-				}`,
-			// When use_source_env is specified then it will use the prebuilt by default if the environment
-			// variable is not set.
-			prebuilt: []OsType{Android, buildOS},
-		},
-		{
-			name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=false",
-			modules: `
-				source {
-					name: "bar",
-				}
-
-				prebuilt {
-					name: "bar",
-					use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
-					srcs: ["prebuilt_file"],
-				}`,
-			preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
-				variables.VendorVars = map[string]map[string]string{
-					"acme": {
-						"use_source": "false",
-					},
-				}
-			}),
-			// Setting the environment variable named in use_source_env to false will cause the prebuilt to
-			// be used.
-			prebuilt: []OsType{Android, buildOS},
-		},
-		{
-			name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=true",
-			modules: `
-				source {
-					name: "bar",
-				}
-
-				prebuilt {
-					name: "bar",
-					use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
-					srcs: ["prebuilt_file"],
-				}`,
-			preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
-				variables.VendorVars = map[string]map[string]string{
-					"acme": {
-						"use_source": "true",
-					},
-				}
-			}),
-			// Setting the environment variable named in use_source_env to true will cause the source to be
-			// used.
-			prebuilt: nil,
-		},
-		{
-			name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=true, no source",
-			modules: `
-				prebuilt {
-					name: "bar",
-					use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
-					srcs: ["prebuilt_file"],
-				}`,
-			preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
-				variables.VendorVars = map[string]map[string]string{
-					"acme": {
-						"use_source": "true",
-					},
-				}
-			}),
-			// Although the environment variable says to use source there is no source available.
-			prebuilt: []OsType{Android, buildOS},
-		},
 	}
 
 	fs := MockFS{
@@ -497,7 +417,7 @@
 	}
 }
 
-func testPrebuiltError(t *testing.T, expectedError, bp string) {
+func testPrebuiltErrorWithFixture(t *testing.T, expectedError, bp string, fixture FixturePreparer) {
 	t.Helper()
 	fs := MockFS{
 		"prebuilt_file": nil,
@@ -508,9 +428,15 @@
 		PrepareForTestWithOverrides,
 		fs.AddToFixture(),
 		FixtureRegisterWithContext(registerTestPrebuiltModules),
+		OptionalFixturePreparer(fixture),
 	).
 		ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(expectedError)).
 		RunTestWithBp(t, bp)
+
+}
+
+func testPrebuiltError(t *testing.T, expectedError, bp string) {
+	testPrebuiltErrorWithFixture(t, expectedError, bp, nil)
 }
 
 func TestPrebuiltShouldNotChangePartition(t *testing.T) {
@@ -559,6 +485,7 @@
 	ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
 	ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
 	ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
+	RegisterApexContributionsBuildComponents(ctx)
 }
 
 type prebuiltModule struct {
@@ -653,3 +580,33 @@
 	InitOverrideModule(m)
 	return m
 }
+
+func TestPrebuiltErrorCannotListBothSourceAndPrebuiltInContributions(t *testing.T) {
+	selectMainlineModuleContritbutions := GroupFixturePreparers(
+		FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_apex_contributions",
+			}
+		}),
+	)
+	testPrebuiltErrorWithFixture(t, `Found duplicate variations of the same module in apex_contributions: foo and prebuilt_foo. Please remove one of these`, `
+		source {
+			name: "foo",
+		}
+		prebuilt {
+			name: "foo",
+			srcs: ["prebuilt_file"],
+		}
+		apex_contributions {
+			name: "my_apex_contributions",
+			api_domain: "my_mainline_module",
+			contents: [
+			  "foo",
+			  "prebuilt_foo",
+			],
+		}
+		all_apex_contributions {
+			name: "all_apex_contributions",
+		}
+		`, selectMainlineModuleContritbutions)
+}
diff --git a/android/proto.go b/android/proto.go
index 49b3733..0d8e097 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -15,11 +15,8 @@
 package android
 
 import (
-	"path/filepath"
 	"strings"
 
-	"android/soong/bazel"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -153,155 +150,3 @@
 	rule.Command().
 		BuiltTool("dep_fixer").Flag(depFile.String())
 }
-
-// Bp2buildProtoInfo contains information necessary to pass on to language specific conversion.
-type Bp2buildProtoInfo struct {
-	Type       *string
-	Proto_libs bazel.LabelList
-}
-
-type ProtoAttrs struct {
-	Srcs                bazel.LabelListAttribute
-	Import_prefix       *string
-	Strip_import_prefix *string
-	Deps                bazel.LabelListAttribute
-}
-
-// For each package in the include_dirs property a proto_library target should
-// be added to the BUILD file in that package and a mapping should be added here
-var includeDirsToProtoDeps = map[string]string{
-	"external/protobuf/src": "//external/protobuf:libprotobuf-proto",
-}
-
-// Partitions srcs by the pkg it is in
-// srcs has been created using `TransformSubpackagePaths`
-// This function uses existence of Android.bp/BUILD files to create a label that is compatible with the package structure of bp2build workspace
-func partitionSrcsByPackage(currentDir string, srcs bazel.LabelList) map[string]bazel.LabelList {
-	getPackageFromLabel := func(label string) string {
-		// Remove any preceding //
-		label = strings.TrimPrefix(label, "//")
-		split := strings.Split(label, ":")
-		if len(split) == 1 {
-			// e.g. foo.proto
-			return currentDir
-		} else if split[0] == "" {
-			// e.g. :foo.proto
-			return currentDir
-		} else {
-			return split[0]
-		}
-	}
-
-	pkgToSrcs := map[string]bazel.LabelList{}
-	for _, src := range srcs.Includes {
-		pkg := getPackageFromLabel(src.Label)
-		list := pkgToSrcs[pkg]
-		list.Add(&src)
-		pkgToSrcs[pkg] = list
-	}
-	return pkgToSrcs
-}
-
-// Bp2buildProtoProperties converts proto properties, creating a proto_library and returning the
-// information necessary for language-specific handling.
-func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) {
-	var info Bp2buildProtoInfo
-	if srcs.IsEmpty() {
-		return info, false
-	}
-
-	var protoLibraries bazel.LabelList
-	var directProtoSrcs bazel.LabelList
-
-	// For filegroups that should be converted to proto_library just collect the
-	// labels of converted proto_library targets.
-	for _, protoSrc := range srcs.Value.Includes {
-		src := protoSrc.OriginalModuleName
-		if fg, ok := ToFileGroupAsLibrary(ctx, src); ok &&
-			fg.ShouldConvertToProtoLibrary(ctx) {
-			protoLibraries.Add(&bazel.Label{
-				Label: fg.GetProtoLibraryLabel(ctx),
-			})
-		} else {
-			directProtoSrcs.Add(&protoSrc)
-		}
-	}
-
-	name := m.Name() + "_proto"
-
-	depsFromFilegroup := protoLibraries
-	var canonicalPathFromRoot bool
-
-	if len(directProtoSrcs.Includes) > 0 {
-		pkgToSrcs := partitionSrcsByPackage(ctx.ModuleDir(), directProtoSrcs)
-		for _, pkg := range SortedStringKeys(pkgToSrcs) {
-			srcs := pkgToSrcs[pkg]
-			attrs := ProtoAttrs{
-				Srcs: bazel.MakeLabelListAttribute(srcs),
-			}
-			attrs.Deps.Append(bazel.MakeLabelListAttribute(depsFromFilegroup))
-
-			for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) {
-				for _, rawProps := range configToProps {
-					var props *ProtoProperties
-					var ok bool
-					if props, ok = rawProps.(*ProtoProperties); !ok {
-						ctx.ModuleErrorf("Could not cast ProtoProperties to expected type")
-					}
-					if axis == bazel.NoConfigAxis {
-						info.Type = props.Proto.Type
-
-						canonicalPathFromRoot = proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault)
-						if !canonicalPathFromRoot {
-							// an empty string indicates to strips the package path
-							path := ""
-							attrs.Strip_import_prefix = &path
-						}
-
-						for _, dir := range props.Proto.Include_dirs {
-							if dep, ok := includeDirsToProtoDeps[dir]; ok {
-								attrs.Deps.Add(bazel.MakeLabelAttribute(dep))
-							} else {
-								ctx.PropertyErrorf("Could not find the proto_library target for include dir", dir)
-							}
-						}
-					} else if props.Proto.Type != info.Type && props.Proto.Type != nil {
-						ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.")
-					}
-				}
-			}
-
-			tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
-
-			moduleDir := ctx.ModuleDir()
-			if !canonicalPathFromRoot {
-				// Since we are creating the proto_library in a subpackage, set the import_prefix relative to the current package
-				if rel, err := filepath.Rel(moduleDir, pkg); err != nil {
-					ctx.ModuleErrorf("Could not get relative path for %v %v", pkg, err)
-				} else if rel != "." {
-					attrs.Import_prefix = &rel
-				}
-			}
-
-			ctx.CreateBazelTargetModule(
-				bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
-				CommonAttributes{Name: name, Dir: proptools.StringPtr(pkg), Tags: tags},
-				&attrs,
-			)
-
-			l := ""
-			if pkg == moduleDir { // same package that the original module lives in
-				l = ":" + name
-			} else {
-				l = "//" + pkg + ":" + name
-			}
-			protoLibraries.Add(&bazel.Label{
-				Label: l,
-			})
-		}
-	}
-
-	info.Proto_libs = protoLibraries
-
-	return info, true
-}
diff --git a/android/provider.go b/android/provider.go
new file mode 100644
index 0000000..3b9c5d2
--- /dev/null
+++ b/android/provider.go
@@ -0,0 +1,120 @@
+package android
+
+import (
+	"github.com/google/blueprint"
+)
+
+// OtherModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or
+// TopDownMutatorContext for use in OtherModuleProvider.
+type OtherModuleProviderContext interface {
+	otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
+}
+
+var _ OtherModuleProviderContext = BaseModuleContext(nil)
+var _ OtherModuleProviderContext = ModuleContext(nil)
+var _ OtherModuleProviderContext = BottomUpMutatorContext(nil)
+var _ OtherModuleProviderContext = TopDownMutatorContext(nil)
+
+// OtherModuleProvider reads the provider for the given module.  If the provider has been set the value is
+// returned and the boolean is true.  If it has not been set the zero value of the provider's type  is returned
+// and the boolean is false.  The value returned may be a deep copy of the value originally passed to SetProvider.
+//
+// OtherModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or
+// TopDownMutatorContext.
+func OtherModuleProvider[K any](ctx OtherModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) (K, bool) {
+	value, ok := ctx.otherModuleProvider(module, provider)
+	if !ok {
+		var k K
+		return k, false
+	}
+	return value.(K), ok
+}
+
+// ModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or
+// TopDownMutatorContext for use in ModuleProvider.
+type ModuleProviderContext interface {
+	provider(provider blueprint.AnyProviderKey) (any, bool)
+}
+
+var _ ModuleProviderContext = BaseModuleContext(nil)
+var _ ModuleProviderContext = ModuleContext(nil)
+var _ ModuleProviderContext = BottomUpMutatorContext(nil)
+var _ ModuleProviderContext = TopDownMutatorContext(nil)
+
+// ModuleProvider reads the provider for the current module.  If the provider has been set the value is
+// returned and the boolean is true.  If it has not been set the zero value of the provider's type  is returned
+// and the boolean is false.  The value returned may be a deep copy of the value originally passed to SetProvider.
+//
+// ModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or
+// TopDownMutatorContext.
+func ModuleProvider[K any](ctx ModuleProviderContext, provider blueprint.ProviderKey[K]) (K, bool) {
+	value, ok := ctx.provider(provider)
+	if !ok {
+		var k K
+		return k, false
+	}
+	return value.(K), ok
+}
+
+type SingletonModuleProviderContext interface {
+	moduleProvider(blueprint.Module, blueprint.AnyProviderKey) (any, bool)
+}
+
+var _ SingletonModuleProviderContext = SingletonContext(nil)
+var _ SingletonModuleProviderContext = (*TestContext)(nil)
+
+// SingletonModuleProvider wraps blueprint.SingletonModuleProvider to provide a type-safe method to retrieve the value
+// of the given provider from a module using a SingletonContext.  If the provider has not been set the first return
+// value will be the zero value of the provider's type, and the second return value will be false.  If the provider has
+// been set the second return value will be true.
+func SingletonModuleProvider[K any](ctx SingletonModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) (K, bool) {
+	value, ok := ctx.moduleProvider(module, provider)
+	if !ok {
+		var k K
+		return k, false
+	}
+	return value.(K), ok
+}
+
+// SetProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or
+// TopDownMutatorContext for use in SetProvider.
+type SetProviderContext interface {
+	setProvider(provider blueprint.AnyProviderKey, value any)
+}
+
+var _ SetProviderContext = BaseModuleContext(nil)
+var _ SetProviderContext = ModuleContext(nil)
+var _ SetProviderContext = BottomUpMutatorContext(nil)
+var _ SetProviderContext = TopDownMutatorContext(nil)
+
+// SetProvider sets the value for a provider for the current module.  It panics if not called
+// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value
+// is not of the appropriate type, or if the value has already been set.  The value should not
+// be modified after being passed to SetProvider.
+//
+// SetProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or
+// TopDownMutatorContext.
+func SetProvider[K any](ctx SetProviderContext, provider blueprint.ProviderKey[K], value K) {
+	ctx.setProvider(provider, value)
+}
+
+var _ OtherModuleProviderContext = (*otherModuleProviderAdaptor)(nil)
+
+// An OtherModuleProviderFunc can be passed to NewOtherModuleProviderAdaptor to create an OtherModuleProviderContext
+// for use in tests.
+type OtherModuleProviderFunc func(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
+
+type otherModuleProviderAdaptor struct {
+	otherModuleProviderFunc OtherModuleProviderFunc
+}
+
+func (p *otherModuleProviderAdaptor) otherModuleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
+	return p.otherModuleProviderFunc(module, provider)
+}
+
+// NewOtherModuleProviderAdaptor returns an OtherModuleProviderContext that proxies calls to otherModuleProvider to
+// the provided OtherModuleProviderFunc.  It can be used in tests to unit test methods that need to call
+// android.OtherModuleProvider.
+func NewOtherModuleProviderAdaptor(otherModuleProviderFunc OtherModuleProviderFunc) OtherModuleProviderContext {
+	return &otherModuleProviderAdaptor{otherModuleProviderFunc}
+}
diff --git a/android/raw_files.go b/android/raw_files.go
new file mode 100644
index 0000000..9d7f5e8
--- /dev/null
+++ b/android/raw_files.go
@@ -0,0 +1,279 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"crypto/sha1"
+	"encoding/hex"
+	"fmt"
+	"github.com/google/blueprint"
+	"io"
+	"io/fs"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/google/blueprint/proptools"
+)
+
+// WriteFileRule creates a ninja rule to write contents to a file by immediately writing the
+// contents, plus a trailing newline, to a file in out/soong/raw-${TARGET_PRODUCT}, and then creating
+// a ninja rule to copy the file into place.
+func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
+	writeFileRule(ctx, outputFile, content, true, false)
+}
+
+// WriteFileRuleVerbatim creates a ninja rule to write contents to a file by immediately writing the
+// contents to a file in out/soong/raw-${TARGET_PRODUCT}, and then creating a ninja rule to copy the file into place.
+func WriteFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
+	writeFileRule(ctx, outputFile, content, false, false)
+}
+
+// WriteExecutableFileRuleVerbatim is the same as WriteFileRuleVerbatim, but runs chmod +x on the result
+func WriteExecutableFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
+	writeFileRule(ctx, outputFile, content, false, true)
+}
+
+// tempFile provides a testable wrapper around a file in out/soong/.temp.  It writes to a temporary file when
+// not in tests, but writes to a buffer in memory when used in tests.
+type tempFile struct {
+	// tempFile contains wraps an io.Writer, which will be file if testMode is false, or testBuf if it is true.
+	io.Writer
+
+	file    *os.File
+	testBuf *strings.Builder
+}
+
+func newTempFile(ctx BuilderContext, pattern string, testMode bool) *tempFile {
+	if testMode {
+		testBuf := &strings.Builder{}
+		return &tempFile{
+			Writer:  testBuf,
+			testBuf: testBuf,
+		}
+	} else {
+		f, err := os.CreateTemp(absolutePath(ctx.Config().tempDir()), pattern)
+		if err != nil {
+			panic(fmt.Errorf("failed to open temporary raw file: %w", err))
+		}
+		return &tempFile{
+			Writer: f,
+			file:   f,
+		}
+	}
+}
+
+func (t *tempFile) close() error {
+	if t.file != nil {
+		return t.file.Close()
+	}
+	return nil
+}
+
+func (t *tempFile) name() string {
+	if t.file != nil {
+		return t.file.Name()
+	}
+	return "temp_file_in_test"
+}
+
+func (t *tempFile) rename(to string) {
+	if t.file != nil {
+		os.MkdirAll(filepath.Dir(to), 0777)
+		err := os.Rename(t.file.Name(), to)
+		if err != nil {
+			panic(fmt.Errorf("failed to rename %s to %s: %w", t.file.Name(), to, err))
+		}
+	}
+}
+
+func (t *tempFile) remove() error {
+	if t.file != nil {
+		return os.Remove(t.file.Name())
+	}
+	return nil
+}
+
+func writeContentToTempFileAndHash(ctx BuilderContext, content string, newline bool) (*tempFile, string) {
+	tempFile := newTempFile(ctx, "raw", ctx.Config().captureBuild)
+	defer tempFile.close()
+
+	hash := sha1.New()
+	w := io.MultiWriter(tempFile, hash)
+
+	_, err := io.WriteString(w, content)
+	if err == nil && newline {
+		_, err = io.WriteString(w, "\n")
+	}
+	if err != nil {
+		panic(fmt.Errorf("failed to write to temporary raw file %s: %w", tempFile.name(), err))
+	}
+	return tempFile, hex.EncodeToString(hash.Sum(nil))
+}
+
+func writeFileRule(ctx BuilderContext, outputFile WritablePath, content string, newline bool, executable bool) {
+	// Write the contents to a temporary file while computing its hash.
+	tempFile, hash := writeContentToTempFileAndHash(ctx, content, newline)
+
+	// Shard the final location of the raw file into a subdirectory based on the first two characters of the
+	// hash to avoid making the raw directory too large and slowing down accesses.
+	relPath := filepath.Join(hash[0:2], hash)
+
+	// These files are written during soong_build.  If something outside the build deleted them there would be no
+	// trigger to rerun soong_build, and the build would break with dependencies on missing files.  Writing them
+	// to their final locations would risk having them deleted when cleaning a module, and would also pollute the
+	// output directory with files for modules that have never been built.
+	// Instead, the files are written to a separate "raw" directory next to the build.ninja file, and a ninja
+	// rule is created to copy the files into their final location as needed.
+	// Obsolete files written by previous runs of soong_build must be cleaned up to avoid continually growing
+	// disk usage as the hashes of the files change over time.  The cleanup must not remove files that were
+	// created by previous runs of soong_build for other products, as the build.ninja files for those products
+	// may still exist and still reference those files.  The raw files from different products are kept
+	// separate by appending the Make_suffix to the directory name.
+	rawPath := PathForOutput(ctx, "raw"+proptools.String(ctx.Config().productVariables.Make_suffix), relPath)
+
+	rawFileInfo := rawFileInfo{
+		relPath: relPath,
+	}
+
+	if ctx.Config().captureBuild {
+		// When running tests tempFile won't write to disk, instead store the contents for later retrieval by
+		// ContentFromFileRuleForTests.
+		rawFileInfo.contentForTests = tempFile.testBuf.String()
+	}
+
+	rawFileSet := getRawFileSet(ctx.Config())
+	if _, exists := rawFileSet.LoadOrStore(hash, rawFileInfo); exists {
+		// If a raw file with this hash has already been created delete the temporary file.
+		tempFile.remove()
+	} else {
+		// If this is the first time this hash has been seen then move it from the temporary directory
+		// to the raw directory.  If the file already exists in the raw directory assume it has the correct
+		// contents.
+		absRawPath := absolutePath(rawPath.String())
+		_, err := os.Stat(absRawPath)
+		if os.IsNotExist(err) {
+			tempFile.rename(absRawPath)
+		} else if err != nil {
+			panic(fmt.Errorf("failed to stat %q: %w", absRawPath, err))
+		} else {
+			tempFile.remove()
+		}
+	}
+
+	// Emit a rule to copy the file from raw directory to the final requested location in the output tree.
+	// Restat is used to ensure that two different products that produce identical files copied from their
+	// own raw directories they don't cause everything downstream to rebuild.
+	rule := rawFileCopy
+	if executable {
+		rule = rawFileCopyExecutable
+	}
+	ctx.Build(pctx, BuildParams{
+		Rule:        rule,
+		Input:       rawPath,
+		Output:      outputFile,
+		Description: "raw " + outputFile.Base(),
+	})
+}
+
+var (
+	rawFileCopy = pctx.AndroidStaticRule("rawFileCopy",
+		blueprint.RuleParams{
+			Command:     "if ! cmp -s $in $out; then cp $in $out; fi",
+			Description: "copy raw file $out",
+			Restat:      true,
+		})
+	rawFileCopyExecutable = pctx.AndroidStaticRule("rawFileCopyExecutable",
+		blueprint.RuleParams{
+			Command:     "if ! cmp -s $in $out; then cp $in $out; fi && chmod +x $out",
+			Description: "copy raw exectuable file $out",
+			Restat:      true,
+		})
+)
+
+type rawFileInfo struct {
+	relPath         string
+	contentForTests string
+}
+
+var rawFileSetKey OnceKey = NewOnceKey("raw file set")
+
+func getRawFileSet(config Config) *SyncMap[string, rawFileInfo] {
+	return config.Once(rawFileSetKey, func() any {
+		return &SyncMap[string, rawFileInfo]{}
+	}).(*SyncMap[string, rawFileInfo])
+}
+
+// ContentFromFileRuleForTests returns the content that was passed to a WriteFileRule for use
+// in tests.
+func ContentFromFileRuleForTests(t *testing.T, ctx *TestContext, params TestingBuildParams) string {
+	t.Helper()
+	if params.Rule != rawFileCopy && params.Rule != rawFileCopyExecutable {
+		t.Errorf("expected params.Rule to be rawFileCopy or rawFileCopyExecutable, was %q", params.Rule)
+		return ""
+	}
+
+	key := filepath.Base(params.Input.String())
+	rawFileSet := getRawFileSet(ctx.Config())
+	rawFileInfo, _ := rawFileSet.Load(key)
+
+	return rawFileInfo.contentForTests
+}
+
+func rawFilesSingletonFactory() Singleton {
+	return &rawFilesSingleton{}
+}
+
+type rawFilesSingleton struct{}
+
+func (rawFilesSingleton) GenerateBuildActions(ctx SingletonContext) {
+	if ctx.Config().captureBuild {
+		// Nothing to do when running in tests, no temporary files were created.
+		return
+	}
+	rawFileSet := getRawFileSet(ctx.Config())
+	rawFilesDir := PathForOutput(ctx, "raw"+proptools.String(ctx.Config().productVariables.Make_suffix)).String()
+	absRawFilesDir := absolutePath(rawFilesDir)
+	err := filepath.WalkDir(absRawFilesDir, func(path string, d fs.DirEntry, err error) error {
+		if err != nil {
+			return err
+		}
+		if d.IsDir() {
+			// Ignore obsolete directories for now.
+			return nil
+		}
+
+		// Assume the basename of the file is a hash
+		key := filepath.Base(path)
+		relPath, err := filepath.Rel(absRawFilesDir, path)
+		if err != nil {
+			return err
+		}
+
+		// Check if a file with the same hash was written by this run of soong_build.  If the file was not written,
+		// or if a file with the same hash was written but to a different path in the raw directory, then delete it.
+		// Checking that the path matches allows changing the structure of the raw directory, for example to increase
+		// the sharding.
+		rawFileInfo, written := rawFileSet.Load(key)
+		if !written || rawFileInfo.relPath != relPath {
+			os.Remove(path)
+		}
+		return nil
+	})
+	if err != nil {
+		panic(fmt.Errorf("failed to clean %q: %w", rawFilesDir, err))
+	}
+}
diff --git a/android/register.go b/android/register.go
index 64b0207..d00c15f 100644
--- a/android/register.go
+++ b/android/register.go
@@ -16,9 +16,8 @@
 
 import (
 	"fmt"
-	"reflect"
-
 	"github.com/google/blueprint"
+	"reflect"
 )
 
 // A sortable component is one whose registration order affects the order in which it is executed
@@ -62,9 +61,6 @@
 var moduleTypeByFactory = map[reflect.Value]string{}
 
 type singleton struct {
-	// True if this should be registered as a pre-singleton, false otherwise.
-	pre bool
-
 	// True if this should be registered as a parallel singleton.
 	parallel bool
 
@@ -73,11 +69,7 @@
 }
 
 func newSingleton(name string, factory SingletonFactory, parallel bool) singleton {
-	return singleton{pre: false, parallel: parallel, name: name, factory: factory}
-}
-
-func newPreSingleton(name string, factory SingletonFactory) singleton {
-	return singleton{pre: true, parallel: false, name: name, factory: factory}
+	return singleton{parallel: parallel, name: name, factory: factory}
 }
 
 func (s singleton) componentName() string {
@@ -86,17 +78,12 @@
 
 func (s singleton) register(ctx *Context) {
 	adaptor := SingletonFactoryAdaptor(ctx, s.factory)
-	if s.pre {
-		ctx.RegisterPreSingletonType(s.name, adaptor)
-	} else {
-		ctx.RegisterSingletonType(s.name, adaptor, s.parallel)
-	}
+	ctx.RegisterSingletonType(s.name, adaptor, s.parallel)
 }
 
 var _ sortableComponent = singleton{}
 
 var singletons sortableComponents
-var preSingletons sortableComponents
 
 type mutator struct {
 	name              string
@@ -160,10 +147,6 @@
 	registerSingletonType(name, factory, true)
 }
 
-func RegisterPreSingletonType(name string, factory SingletonFactory) {
-	preSingletons = append(preSingletons, newPreSingleton(name, factory))
-}
-
 type Context struct {
 	*blueprint.Context
 	config Config
@@ -177,38 +160,9 @@
 	return ctx
 }
 
-// Helper function to register the module types used in bp2build and
-// api_bp2build.
-func registerModuleTypes(ctx *Context) {
-	for _, t := range moduleTypes {
-		t.register(ctx)
-	}
-	// Required for SingletonModule types, even though we are not using them.
-	for _, t := range singletons {
-		t.register(ctx)
-	}
-}
-
-// RegisterForBazelConversion registers an alternate shadow pipeline of
-// singletons, module types and mutators to register for converting Blueprint
-// files to semantically equivalent BUILD files.
-func (ctx *Context) RegisterForBazelConversion() {
-	registerModuleTypes(ctx)
-	RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators)
-}
-
-// RegisterForApiBazelConversion is similar to RegisterForBazelConversion except that
-// it only generates API targets in the generated  workspace
-func (ctx *Context) RegisterForApiBazelConversion() {
-	registerModuleTypes(ctx)
-	RegisterMutatorsForApiBazelConversion(ctx, bp2buildPreArchMutators)
-}
-
 // Register the pipeline of singletons, module types, and mutators for
 // generating build.ninja and other files for Kati, from Android.bp files.
 func (ctx *Context) Register() {
-	preSingletons.registerAll(ctx)
-
 	for _, t := range moduleTypes {
 		t.register(ctx)
 	}
@@ -231,17 +185,16 @@
 func collateGloballyRegisteredSingletons() sortableComponents {
 	allSingletons := append(sortableComponents(nil), singletons...)
 	allSingletons = append(allSingletons,
-		singleton{pre: false, parallel: true, name: "bazeldeps", factory: BazelSingleton},
-
 		// Register phony just before makevars so it can write out its phony rules as Make rules
-		singleton{pre: false, parallel: false, name: "phony", factory: phonySingletonFactory},
+		singleton{parallel: false, name: "phony", factory: phonySingletonFactory},
 
 		// Register makevars after other singletons so they can export values through makevars
-		singleton{pre: false, parallel: false, name: "makevars", factory: makeVarsSingletonFunc},
+		singleton{parallel: false, name: "makevars", factory: makeVarsSingletonFunc},
 
-		// Register env and ninjadeps last so that they can track all used environment variables and
+		// Register rawfiles and ninjadeps last so that they can track all used environment variables and
 		// Ninja file dependencies stored in the config.
-		singleton{pre: false, parallel: false, name: "ninjadeps", factory: ninjaDepsSingletonFactory},
+		singleton{parallel: false, name: "rawfiles", factory: rawFilesSingletonFactory},
+		singleton{parallel: false, name: "ninjadeps", factory: ninjaDepsSingletonFactory},
 	)
 
 	return allSingletons
@@ -271,7 +224,6 @@
 	RegisterModuleType(name string, factory ModuleFactory)
 	RegisterSingletonModuleType(name string, factory SingletonModuleFactory)
 	RegisterParallelSingletonModuleType(name string, factory SingletonModuleFactory)
-	RegisterPreSingletonType(name string, factory SingletonFactory)
 	RegisterParallelSingletonType(name string, factory SingletonFactory)
 	RegisterSingletonType(name string, factory SingletonFactory)
 	PreArchMutators(f RegisterMutatorFunc)
@@ -303,9 +255,8 @@
 //	ctx := android.NewTestContext(config)
 //	RegisterBuildComponents(ctx)
 var InitRegistrationContext RegistrationContext = &initRegistrationContext{
-	moduleTypes:       make(map[string]ModuleFactory),
-	singletonTypes:    make(map[string]SingletonFactory),
-	preSingletonTypes: make(map[string]SingletonFactory),
+	moduleTypes:    make(map[string]ModuleFactory),
+	singletonTypes: make(map[string]SingletonFactory),
 }
 
 // Make sure the TestContext implements RegistrationContext.
@@ -314,7 +265,6 @@
 type initRegistrationContext struct {
 	moduleTypes        map[string]ModuleFactory
 	singletonTypes     map[string]SingletonFactory
-	preSingletonTypes  map[string]SingletonFactory
 	moduleTypesForDocs map[string]reflect.Value
 }
 
@@ -360,14 +310,6 @@
 	ctx.registerSingletonType(name, factory, true)
 }
 
-func (ctx *initRegistrationContext) RegisterPreSingletonType(name string, factory SingletonFactory) {
-	if _, present := ctx.preSingletonTypes[name]; present {
-		panic(fmt.Sprintf("pre singleton type %q is already registered", name))
-	}
-	ctx.preSingletonTypes[name] = factory
-	RegisterPreSingletonType(name, factory)
-}
-
 func (ctx *initRegistrationContext) PreArchMutators(f RegisterMutatorFunc) {
 	PreArchMutators(f)
 }
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 777c1cf..85e29bd 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -336,41 +336,6 @@
 	return outputList
 }
 
-func (r *RuleBuilder) symlinkOutputSet() map[string]WritablePath {
-	symlinkOutputs := make(map[string]WritablePath)
-	for _, c := range r.commands {
-		for _, symlinkOutput := range c.symlinkOutputs {
-			symlinkOutputs[symlinkOutput.String()] = symlinkOutput
-		}
-	}
-	return symlinkOutputs
-}
-
-// SymlinkOutputs returns the list of paths that the executor (Ninja) would
-// verify, after build edge completion, that:
-//
-// 1) Created output symlinks match the list of paths in this list exactly (no more, no fewer)
-// 2) Created output files are *not* declared in this list.
-//
-// These symlink outputs are expected to be a subset of outputs or implicit
-// outputs, or they would fail validation at build param construction time
-// later, to support other non-rule-builder approaches for constructing
-// statements.
-func (r *RuleBuilder) SymlinkOutputs() WritablePaths {
-	symlinkOutputs := r.symlinkOutputSet()
-
-	var symlinkOutputList WritablePaths
-	for _, symlinkOutput := range symlinkOutputs {
-		symlinkOutputList = append(symlinkOutputList, symlinkOutput)
-	}
-
-	sort.Slice(symlinkOutputList, func(i, j int) bool {
-		return symlinkOutputList[i].String() < symlinkOutputList[j].String()
-	})
-
-	return symlinkOutputList
-}
-
 func (r *RuleBuilder) depFileSet() map[string]WritablePath {
 	depFiles := make(map[string]WritablePath)
 	for _, c := range r.commands {
@@ -474,13 +439,23 @@
 		Inputs(depFiles.Paths())
 }
 
+// BuildWithNinjaVars adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
+// Outputs. This function will not escape Ninja variables, so it may be used to write sandbox manifests using Ninja variables.
+func (r *RuleBuilder) BuildWithUnescapedNinjaVars(name string, desc string) {
+	r.build(name, desc, false)
+}
+
 // Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
 // Outputs.
 func (r *RuleBuilder) Build(name string, desc string) {
+	r.build(name, desc, true)
+}
+
+func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString bool) {
 	name = ninjaNameEscape(name)
 
 	if len(r.missingDeps) > 0 {
-		r.ctx.Build(pctx, BuildParams{
+		r.ctx.Build(r.pctx, BuildParams{
 			Rule:        ErrorRule,
 			Outputs:     r.Outputs(),
 			Description: desc,
@@ -580,7 +555,7 @@
 							To:   proto.String(sboxOutSubDir),
 						},
 						{
-							From: proto.String(PathForOutput(r.ctx).String()),
+							From: proto.String(r.ctx.Config().OutDir()),
 							To:   proto.String(sboxOutSubDir),
 						},
 					},
@@ -619,12 +594,36 @@
 				name, r.sboxManifestPath.String(), r.outDir.String())
 		}
 
-		// Create a rule to write the manifest as a the textproto.
-		pbText, err := prototext.Marshal(&manifest)
+		// Create a rule to write the manifest as textproto. Pretty print it by indenting and
+		// splitting across multiple lines.
+		pbText, err := prototext.MarshalOptions{Indent: " "}.Marshal(&manifest)
 		if err != nil {
 			ReportPathErrorf(r.ctx, "sbox manifest failed to marshal: %q", err)
 		}
-		WriteFileRule(r.ctx, r.sboxManifestPath, string(pbText))
+		if ninjaEscapeCommandString {
+			WriteFileRule(r.ctx, r.sboxManifestPath, string(pbText))
+		} else {
+			// We need  to have a rule to write files that is
+			// defined on the RuleBuilder's pctx in order to
+			// write Ninja variables in the string.
+			// The WriteFileRule function above rule can only write
+			// raw strings because it is defined on the android
+			// package's pctx, and it can't access variables defined
+			// in another context.
+			r.ctx.Build(r.pctx, BuildParams{
+				Rule: r.ctx.Rule(r.pctx, "unescapedWriteFile", blueprint.RuleParams{
+					Command:        `rm -rf ${out} && cat ${out}.rsp > ${out}`,
+					Rspfile:        "${out}.rsp",
+					RspfileContent: "${content}",
+					Description:    "write file",
+				}, "content"),
+				Output:      r.sboxManifestPath,
+				Description: "write sbox manifest " + r.sboxManifestPath.Base(),
+				Args: map[string]string{
+					"content": string(pbText),
+				},
+			})
+		}
 
 		// Generate a new string to use as the command line of the sbox rule.  This uses
 		// a RuleBuilderCommand as a convenience method of building the command line, then
@@ -723,9 +722,13 @@
 		pool = localPool
 	}
 
+	if ninjaEscapeCommandString {
+		commandString = proptools.NinjaEscape(commandString)
+	}
+
 	r.ctx.Build(r.pctx, BuildParams{
-		Rule: r.ctx.Rule(pctx, name, blueprint.RuleParams{
-			Command:        proptools.NinjaEscape(commandString),
+		Rule: r.ctx.Rule(r.pctx, name, blueprint.RuleParams{
+			Command:        commandString,
 			CommandDeps:    proptools.NinjaEscapeList(tools.Strings()),
 			Restat:         r.restat,
 			Rspfile:        proptools.NinjaEscape(rspFile),
@@ -738,7 +741,6 @@
 		Validations:     r.Validations(),
 		Output:          output,
 		ImplicitOutputs: implicitOutputs,
-		SymlinkOutputs:  r.SymlinkOutputs(),
 		Depfile:         depFile,
 		Deps:            depFormat,
 		Description:     desc,
@@ -752,17 +754,16 @@
 type RuleBuilderCommand struct {
 	rule *RuleBuilder
 
-	buf            strings.Builder
-	inputs         Paths
-	implicits      Paths
-	orderOnlys     Paths
-	validations    Paths
-	outputs        WritablePaths
-	symlinkOutputs WritablePaths
-	depFiles       WritablePaths
-	tools          Paths
-	packagedTools  []PackagingSpec
-	rspFiles       []rspFileAndPaths
+	buf           strings.Builder
+	inputs        Paths
+	implicits     Paths
+	orderOnlys    Paths
+	validations   Paths
+	outputs       WritablePaths
+	depFiles      WritablePaths
+	tools         Paths
+	packagedTools []PackagingSpec
+	rspFiles      []rspFileAndPaths
 }
 
 type rspFileAndPaths struct {
@@ -834,7 +835,7 @@
 
 func sboxPathForToolRel(ctx BuilderContext, path Path) string {
 	// Errors will be handled in RuleBuilder.Build where we have a context to report them
-	toolDir := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "", false)
+	toolDir := pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "")
 	relOutSoong, isRelOutSoong, _ := maybeRelErr(toolDir.String(), path.String())
 	if isRelOutSoong {
 		// The tool is in the Soong output directory, it will be copied to __SBOX_OUT_DIR__/tools/out
@@ -854,7 +855,7 @@
 		// When sandboxing inputs all inputs have to be copied into the sandbox.  Input files that
 		// are outputs of other rules could be an arbitrary absolute path if OUT_DIR is set, so they
 		// will be copied to relative paths under __SBOX_OUT_DIR__/out.
-		rel, isRelOut, _ := maybeRelErr(PathForOutput(r.ctx).String(), path.String())
+		rel, isRelOut, _ := maybeRelErr(r.ctx.Config().OutDir(), path.String())
 		if isRelOut {
 			return filepath.Join(sboxOutSubDir, rel), true
 		}
@@ -1156,11 +1157,15 @@
 
 // OutputDir adds the output directory to the command line. This is only available when used with RuleBuilder.Sbox,
 // and will be the temporary output directory managed by sbox, not the final one.
-func (c *RuleBuilderCommand) OutputDir() *RuleBuilderCommand {
+func (c *RuleBuilderCommand) OutputDir(subPathComponents ...string) *RuleBuilderCommand {
 	if !c.rule.sbox {
 		panic("OutputDir only valid with Sbox")
 	}
-	return c.Text(sboxOutDir)
+	path := sboxOutDir
+	if len(subPathComponents) > 0 {
+		path = filepath.Join(append([]string{sboxOutDir}, subPathComponents...)...)
+	}
+	return c.Text(path)
 }
 
 // DepFile adds the specified depfile path to the paths returned by RuleBuilder.DepFiles and adds it to the command
@@ -1186,42 +1191,6 @@
 	return c
 }
 
-// ImplicitSymlinkOutput declares the specified path as an implicit output that
-// will be a symlink instead of a regular file. Does not modify the command
-// line.
-func (c *RuleBuilderCommand) ImplicitSymlinkOutput(path WritablePath) *RuleBuilderCommand {
-	checkPathNotNil(path)
-	c.symlinkOutputs = append(c.symlinkOutputs, path)
-	return c.ImplicitOutput(path)
-}
-
-// ImplicitSymlinkOutputs declares the specified paths as implicit outputs that
-// will be a symlinks instead of regular files. Does not modify the command
-// line.
-func (c *RuleBuilderCommand) ImplicitSymlinkOutputs(paths WritablePaths) *RuleBuilderCommand {
-	for _, path := range paths {
-		c.ImplicitSymlinkOutput(path)
-	}
-	return c
-}
-
-// SymlinkOutput declares the specified path as an output that will be a symlink
-// instead of a regular file. Modifies the command line.
-func (c *RuleBuilderCommand) SymlinkOutput(path WritablePath) *RuleBuilderCommand {
-	checkPathNotNil(path)
-	c.symlinkOutputs = append(c.symlinkOutputs, path)
-	return c.Output(path)
-}
-
-// SymlinkOutputsl declares the specified paths as outputs that will be symlinks
-// instead of regular files. Modifies the command line.
-func (c *RuleBuilderCommand) SymlinkOutputs(paths WritablePaths) *RuleBuilderCommand {
-	for _, path := range paths {
-		c.SymlinkOutput(path)
-	}
-	return c
-}
-
 // ImplicitDepFile adds the specified depfile path to the paths returned by RuleBuilder.DepFiles without modifying
 // the command line, and causes RuleBuilder.Build file to set the depfile flag for ninja.  If multiple depfiles
 // are added to commands in a single RuleBuilder then RuleBuilder.Build will add an extra command to merge the
@@ -1304,9 +1273,9 @@
 
 // RuleBuilderSboxProtoForTests takes the BuildParams for the manifest passed to RuleBuilder.Sbox()
 // and returns sbox testproto generated by the RuleBuilder.
-func RuleBuilderSboxProtoForTests(t *testing.T, params TestingBuildParams) *sbox_proto.Manifest {
+func RuleBuilderSboxProtoForTests(t *testing.T, ctx *TestContext, params TestingBuildParams) *sbox_proto.Manifest {
 	t.Helper()
-	content := ContentFromFileRuleForTests(t, params)
+	content := ContentFromFileRuleForTests(t, ctx, params)
 	manifest := sbox_proto.Manifest{}
 	err := prototext.Unmarshal([]byte(content), &manifest)
 	if err != nil {
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index 86647eb..6a8a964 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -28,6 +28,17 @@
 	"android/soong/shared"
 )
 
+var (
+	pctx_ruleBuilderTest           = NewPackageContext("android/soong/rule_builder")
+	pctx_ruleBuilderTestSubContext = NewPackageContext("android/soong/rule_builder/config")
+)
+
+func init() {
+	pctx_ruleBuilderTest.Import("android/soong/rule_builder/config")
+	pctx_ruleBuilderTest.StaticVariable("cmdFlags", "${config.ConfigFlags}")
+	pctx_ruleBuilderTestSubContext.StaticVariable("ConfigFlags", "--some-clang-flag")
+}
+
 func builderContext() BuilderContext {
 	return BuilderContextForTesting(TestConfig("out", nil, "", map[string][]byte{
 		"ld":      nil,
@@ -37,7 +48,6 @@
 		"a":       nil,
 		"b":       nil,
 		"ls":      nil,
-		"ln":      nil,
 		"turbine": nil,
 		"java":    nil,
 		"javac":   nil,
@@ -70,32 +80,6 @@
 	// outputs: ["out/soong/linked"]
 }
 
-func ExampleRuleBuilder_SymlinkOutputs() {
-	ctx := builderContext()
-
-	rule := NewRuleBuilder(pctx, ctx)
-
-	rule.Command().
-		Tool(PathForSource(ctx, "ln")).
-		FlagWithInput("-s ", PathForTesting("a.o")).
-		SymlinkOutput(PathForOutput(ctx, "a"))
-	rule.Command().Text("cp out/soong/a out/soong/b").
-		ImplicitSymlinkOutput(PathForOutput(ctx, "b"))
-
-	fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
-	fmt.Printf("tools: %q\n", rule.Tools())
-	fmt.Printf("inputs: %q\n", rule.Inputs())
-	fmt.Printf("outputs: %q\n", rule.Outputs())
-	fmt.Printf("symlink_outputs: %q\n", rule.SymlinkOutputs())
-
-	// Output:
-	// commands: "ln -s a.o out/soong/a && cp out/soong/a out/soong/b"
-	// tools: ["ln"]
-	// inputs: ["a.o"]
-	// outputs: ["out/soong/a" "out/soong/b"]
-	// symlink_outputs: ["out/soong/a" "out/soong/b"]
-}
-
 func ExampleRuleBuilder_Temporary() {
 	ctx := builderContext()
 
@@ -323,8 +307,6 @@
 			Output(PathForOutput(ctx, "module/Output")).
 			OrderOnly(PathForSource(ctx, "OrderOnly")).
 			Validation(PathForSource(ctx, "Validation")).
-			SymlinkOutput(PathForOutput(ctx, "module/SymlinkOutput")).
-			ImplicitSymlinkOutput(PathForOutput(ctx, "module/ImplicitSymlinkOutput")).
 			Text("Text").
 			Tool(PathForSource(ctx, "Tool"))
 
@@ -356,15 +338,13 @@
 	wantRspFileInputs := Paths{PathForSource(ctx, "RspInput"),
 		PathForOutput(ctx, "other/RspOutput2")}
 	wantOutputs := PathsForOutput(ctx, []string{
-		"module/ImplicitOutput", "module/ImplicitSymlinkOutput", "module/Output", "module/SymlinkOutput",
-		"module/output", "module/output2", "module/output3"})
+		"module/ImplicitOutput", "module/Output", "module/output", "module/output2",
+		"module/output3"})
 	wantDepFiles := PathsForOutput(ctx, []string{
 		"module/DepFile", "module/depfile", "module/ImplicitDepFile", "module/depfile2"})
 	wantTools := PathsForSource(ctx, []string{"Tool", "tool2"})
 	wantOrderOnlys := PathsForSource(ctx, []string{"OrderOnly", "OrderOnlys"})
 	wantValidations := PathsForSource(ctx, []string{"Validation", "Validations"})
-	wantSymlinkOutputs := PathsForOutput(ctx, []string{
-		"module/ImplicitSymlinkOutput", "module/SymlinkOutput"})
 
 	t.Run("normal", func(t *testing.T) {
 		rule := NewRuleBuilder(pctx, ctx)
@@ -373,7 +353,7 @@
 		wantCommands := []string{
 			"out_local/soong/module/DepFile Flag FlagWithArg=arg FlagWithDepFile=out_local/soong/module/depfile " +
 				"FlagWithInput=input FlagWithOutput=out_local/soong/module/output FlagWithRspFileInputList=out_local/soong/rsp " +
-				"Input out_local/soong/module/Output out_local/soong/module/SymlinkOutput Text Tool after command2 old cmd",
+				"Input out_local/soong/module/Output Text Tool after command2 old cmd",
 			"command2 out_local/soong/module/depfile2 input2 out_local/soong/module/output2 tool2",
 			"command3 input3 out_local/soong/module/output2 out_local/soong/module/output3 input3 out_local/soong/module/output2",
 		}
@@ -386,7 +366,6 @@
 		AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
 		AssertDeepEquals(t, "rule.RspfileInputs()", wantRspFileInputs, rule.RspFileInputs())
 		AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
-		AssertDeepEquals(t, "rule.SymlinkOutputs()", wantSymlinkOutputs, rule.SymlinkOutputs())
 		AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
 		AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
 		AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
@@ -404,7 +383,7 @@
 			"__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
 				"FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
 				"FlagWithRspFileInputList=out_local/soong/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
-				"__SBOX_SANDBOX_DIR__/out/SymlinkOutput Text Tool after command2 old cmd",
+				"Text Tool after command2 old cmd",
 			"command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 tool2",
 			"command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2",
 		}
@@ -416,7 +395,6 @@
 		AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
 		AssertDeepEquals(t, "rule.RspfileInputs()", wantRspFileInputs, rule.RspFileInputs())
 		AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
-		AssertDeepEquals(t, "rule.SymlinkOutputs()", wantSymlinkOutputs, rule.SymlinkOutputs())
 		AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
 		AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
 		AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
@@ -434,7 +412,7 @@
 			"__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
 				"FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
 				"FlagWithRspFileInputList=out_local/soong/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
-				"__SBOX_SANDBOX_DIR__/out/SymlinkOutput Text __SBOX_SANDBOX_DIR__/tools/src/Tool after command2 old cmd",
+				"Text __SBOX_SANDBOX_DIR__/tools/src/Tool after command2 old cmd",
 			"command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/tools/src/tool2",
 			"command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2",
 		}
@@ -446,7 +424,6 @@
 		AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
 		AssertDeepEquals(t, "rule.RspfileInputs()", wantRspFileInputs, rule.RspFileInputs())
 		AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
-		AssertDeepEquals(t, "rule.SymlinkOutputs()", wantSymlinkOutputs, rule.SymlinkOutputs())
 		AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
 		AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
 		AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
@@ -463,8 +440,8 @@
 		wantCommands := []string{
 			"__SBOX_SANDBOX_DIR__/out/DepFile Flag FlagWithArg=arg FlagWithDepFile=__SBOX_SANDBOX_DIR__/out/depfile " +
 				"FlagWithInput=input FlagWithOutput=__SBOX_SANDBOX_DIR__/out/output " +
-				"FlagWithRspFileInputList=__SBOX_SANDBOX_DIR__/out/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
-				"__SBOX_SANDBOX_DIR__/out/SymlinkOutput Text __SBOX_SANDBOX_DIR__/tools/src/Tool after command2 old cmd",
+				"FlagWithRspFileInputList=__SBOX_SANDBOX_DIR__/out/soong/rsp Input __SBOX_SANDBOX_DIR__/out/Output " +
+				"Text __SBOX_SANDBOX_DIR__/tools/src/Tool after command2 old cmd",
 			"command2 __SBOX_SANDBOX_DIR__/out/depfile2 input2 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/tools/src/tool2",
 			"command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2",
 		}
@@ -476,7 +453,6 @@
 		AssertDeepEquals(t, "rule.Inputs()", wantInputs, rule.Inputs())
 		AssertDeepEquals(t, "rule.RspfileInputs()", wantRspFileInputs, rule.RspFileInputs())
 		AssertDeepEquals(t, "rule.Outputs()", wantOutputs, rule.Outputs())
-		AssertDeepEquals(t, "rule.SymlinkOutputs()", wantSymlinkOutputs, rule.SymlinkOutputs())
 		AssertDeepEquals(t, "rule.DepFiles()", wantDepFiles, rule.DepFiles())
 		AssertDeepEquals(t, "rule.Tools()", wantTools, rule.Tools())
 		AssertDeepEquals(t, "rule.OrderOnlys()", wantOrderOnlys, rule.OrderOnlys())
@@ -496,11 +472,13 @@
 type testRuleBuilderModule struct {
 	ModuleBase
 	properties struct {
-		Srcs []string
+		Srcs  []string
+		Flags []string
 
-		Restat      bool
-		Sbox        bool
-		Sbox_inputs bool
+		Restat              bool
+		Sbox                bool
+		Sbox_inputs         bool
+		Unescape_ninja_vars bool
 	}
 }
 
@@ -518,8 +496,9 @@
 	rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"})
 	manifestPath := PathForModuleOut(ctx, "sbox.textproto")
 
-	testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, out, outDep, outDir,
-		manifestPath, t.properties.Restat, t.properties.Sbox, t.properties.Sbox_inputs,
+	testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, t.properties.Flags,
+		out, outDep, outDir,
+		manifestPath, t.properties.Restat, t.properties.Sbox, t.properties.Sbox_inputs, t.properties.Unescape_ninja_vars,
 		rspFile, rspFileContents, rspFile2, rspFileContents2)
 }
 
@@ -543,17 +522,18 @@
 	rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"})
 	manifestPath := PathForOutput(ctx, "singleton/sbox.textproto")
 
-	testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, out, outDep, outDir,
-		manifestPath, true, false, false,
+	testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, nil, out, outDep, outDir,
+		manifestPath, true, false, false, false,
 		rspFile, rspFileContents, rspFile2, rspFileContents2)
 }
 
 func testRuleBuilder_Build(ctx BuilderContext, in Paths, implicit, orderOnly, validation Path,
+	flags []string,
 	out, outDep, outDir, manifestPath WritablePath,
-	restat, sbox, sboxInputs bool,
+	restat, sbox, sboxInputs, unescapeNinjaVars bool,
 	rspFile WritablePath, rspFileContents Paths, rspFile2 WritablePath, rspFileContents2 Paths) {
 
-	rule := NewRuleBuilder(pctx, ctx)
+	rule := NewRuleBuilder(pctx_ruleBuilderTest, ctx)
 
 	if sbox {
 		rule.Sbox(outDir, manifestPath)
@@ -564,6 +544,7 @@
 
 	rule.Command().
 		Tool(PathForSource(ctx, "cp")).
+		Flags(flags).
 		Inputs(in).
 		Implicit(implicit).
 		OrderOnly(orderOnly).
@@ -577,7 +558,11 @@
 		rule.Restat()
 	}
 
-	rule.Build("rule", "desc")
+	if unescapeNinjaVars {
+		rule.BuildWithUnescapedNinjaVars("rule", "desc")
+	} else {
+		rule.Build("rule", "desc")
+	}
 }
 
 var prepareForRuleBuilderTest = FixtureRegisterWithContext(func(ctx RegistrationContext) {
@@ -663,7 +648,7 @@
 			t.Errorf("want Deps = %q, got %q", blueprint.DepsGCC, params.Deps)
 		}
 
-		rspFile2Content := ContentFromFileRuleForTests(t, rspFile2Params)
+		rspFile2Content := ContentFromFileRuleForTests(t, result.TestContext, rspFile2Params)
 		AssertStringEquals(t, "rspFile2 content", "rsp_in2\n", rspFile2Content)
 	}
 
@@ -777,7 +762,7 @@
 		t.Run(test.name, func(t *testing.T) {
 			t.Run("sbox", func(t *testing.T) {
 				gen := result.ModuleForTests(test.name+"_sbox", "")
-				manifest := RuleBuilderSboxProtoForTests(t, gen.Output("sbox.textproto"))
+				manifest := RuleBuilderSboxProtoForTests(t, result.TestContext, gen.Output("sbox.textproto"))
 				hash := manifest.Commands[0].GetInputHash()
 
 				AssertStringEquals(t, "hash", test.expectedHash, hash)
@@ -792,3 +777,48 @@
 		})
 	}
 }
+
+func TestRuleBuilderWithNinjaVarEscaping(t *testing.T) {
+	bp := `
+		rule_builder_test {
+			name: "foo_sbox_escaped",
+			flags: ["${cmdFlags}"],
+			sbox: true,
+			sbox_inputs: true,
+		}
+		rule_builder_test {
+			name: "foo_sbox_unescaped",
+			flags: ["${cmdFlags}"],
+			sbox: true,
+			sbox_inputs: true,
+			unescape_ninja_vars: true,
+		}
+	`
+	result := GroupFixturePreparers(
+		prepareForRuleBuilderTest,
+		FixtureWithRootAndroidBp(bp),
+	).RunTest(t)
+
+	escapedNinjaMod := result.ModuleForTests("foo_sbox_escaped", "").Output("sbox.textproto")
+	AssertStringEquals(t, "expected rule", "android/soong/android.rawFileCopy", escapedNinjaMod.Rule.String())
+	AssertStringDoesContain(
+		t,
+		"",
+		ContentFromFileRuleForTests(t, result.TestContext, escapedNinjaMod),
+		"${cmdFlags}",
+	)
+
+	unescapedNinjaMod := result.ModuleForTests("foo_sbox_unescaped", "").Rule("unescapedWriteFile")
+	AssertStringDoesContain(
+		t,
+		"",
+		unescapedNinjaMod.BuildParams.Args["content"],
+		"${cmdFlags}",
+	)
+	AssertStringDoesNotContain(
+		t,
+		"",
+		unescapedNinjaMod.BuildParams.Args["content"],
+		"$${cmdFlags}",
+	)
+}
diff --git a/android/sdk.go b/android/sdk.go
index 6b598ab..121470d 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -860,11 +860,19 @@
 	Components []string
 }
 
-var ExportedComponentsInfoProvider = blueprint.NewProvider(ExportedComponentsInfo{})
+var ExportedComponentsInfoProvider = blueprint.NewProvider[ExportedComponentsInfo]()
 
 // AdditionalSdkInfo contains additional properties to add to the generated SDK info file.
 type AdditionalSdkInfo struct {
 	Properties map[string]interface{}
 }
 
-var AdditionalSdkInfoProvider = blueprint.NewProvider(AdditionalSdkInfo{})
+var AdditionalSdkInfoProvider = blueprint.NewProvider[AdditionalSdkInfo]()
+
+var apiFingerprintPathKey = NewOnceKey("apiFingerprintPathKey")
+
+func ApiFingerprintPath(ctx PathContext) OutputPath {
+	return ctx.Config().Once(apiFingerprintPathKey, func() interface{} {
+		return PathForOutput(ctx, "api_fingerprint.txt")
+	}).(OutputPath)
+}
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 1fadda0..b2ff960 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"reflect"
 	"strconv"
 	"strings"
 )
@@ -48,6 +49,7 @@
 	SdkPublic
 	SdkSystem
 	SdkTest
+	SdkTestFrameworksCore
 	SdkModule
 	SdkSystemServer
 	SdkPrivate
@@ -67,6 +69,8 @@
 		return "system"
 	case SdkTest:
 		return "test"
+	case SdkTestFrameworksCore:
+		return "test_frameworks_core"
 	case SdkCore:
 		return "core"
 	case SdkCorePlatform:
@@ -92,6 +96,8 @@
 		return "android_system_stubs_current"
 	case SdkTest:
 		return "android_test_stubs_current"
+	case SdkTestFrameworksCore:
+		return "android_test_frameworks_core_stubs_current"
 	case SdkCore:
 		return "core.current.stubs"
 	case SdkModule:
@@ -103,6 +109,17 @@
 	}
 }
 
+func (k SdkKind) DefaultExportableJavaLibraryName() string {
+	switch k {
+	case SdkPublic, SdkSystem, SdkTest, SdkModule, SdkSystemServer:
+		return k.DefaultJavaLibraryName() + "_exportable"
+	case SdkCore:
+		return k.DefaultJavaLibraryName() + ".exportable"
+	default:
+		panic(fmt.Errorf("API surface %v does not provide exportable stubs", k))
+	}
+}
+
 // SdkSpec represents the kind and the version of an SDK for a module to build against
 type SdkSpec struct {
 	Kind     SdkKind
@@ -137,7 +154,7 @@
 		return true
 	case SdkCore, SdkPublic, SdkSystem, SdkModule, SdkSystemServer:
 		return true
-	case SdkCorePlatform, SdkTest, SdkPrivate:
+	case SdkCorePlatform, SdkTest, SdkTestFrameworksCore, SdkPrivate:
 		return false
 	default:
 		panic(fmt.Errorf("unknown SdkKind=%v", s.Kind))
@@ -157,6 +174,17 @@
 	// If BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES has a numeric value,
 	// use it instead of "current" for the vendor partition.
 	currentSdkVersion := ctx.DeviceConfig().CurrentApiLevelForVendorModules()
+	// b/314011075: special case for Java modules in vendor partition. They can no longer use
+	// SDK 35 or later. Their maximum API level is limited to 34 (Android U). This is to
+	// discourage the use of Java APIs in the vendor partition which hasn't been officially
+	// supported since the Project Treble back in Android 10. We would like to eventually
+	// evacuate all Java modules from the partition, but that shall be done progressively.
+	// Note that the check for the availability of SDK 34 is to not break existing tests where
+	// any of the frozen SDK version is unavailable.
+	if isJava(ctx.Module()) && isSdkVersion34AvailableIn(ctx.Config()) {
+		currentSdkVersion = "34"
+	}
+
 	if currentSdkVersion == "current" {
 		return s
 	}
@@ -185,7 +213,8 @@
 		return ctx.Config().AlwaysUsePrebuiltSdks()
 	} else if !s.ApiLevel.IsPreview() {
 		// validation check
-		if s.Kind != SdkPublic && s.Kind != SdkSystem && s.Kind != SdkTest && s.Kind != SdkModule && s.Kind != SdkSystemServer {
+		if s.Kind != SdkPublic && s.Kind != SdkSystem && s.Kind != SdkTest &&
+			s.Kind != SdkTestFrameworksCore && s.Kind != SdkModule && s.Kind != SdkSystemServer {
 			panic(fmt.Errorf("prebuilt SDK is not not available for SdkKind=%q", s.Kind))
 			return false
 		}
@@ -266,6 +295,8 @@
 			kind = SdkSystem
 		case "test":
 			kind = SdkTest
+		case "test_frameworks_core":
+			kind = SdkTestFrameworksCore
 		case "module":
 			kind = SdkModule
 		case "system_server":
@@ -282,28 +313,79 @@
 	}
 }
 
+// Checks if the use of this SDK `s` is valid for the given module context `ctx`.
 func (s SdkSpec) ValidateSystemSdk(ctx EarlyModuleContext) bool {
-	// Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module)
-	// Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29,
-	// sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current
-	if s.Kind != SdkSystem || s.ApiLevel.IsPreview() {
+	// Do some early checks. This check is currently only for Java modules. And our only concern
+	// is the use of "system" SDKs.
+	if !isJava(ctx.Module()) || s.Kind != SdkSystem || ctx.DeviceConfig().BuildBrokenDontCheckSystemSdk() {
 		return true
 	}
-	allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions()
-	if ctx.DeviceSpecific() || ctx.SocSpecific() || (ctx.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
-		systemSdkVersions := ctx.DeviceConfig().SystemSdkVersions()
-		if len(systemSdkVersions) > 0 {
-			allowedVersions = systemSdkVersions
+
+	inVendor := ctx.DeviceSpecific() || ctx.SocSpecific()
+	inProduct := ctx.ProductSpecific()
+	isProductUnbundled := ctx.Config().EnforceProductPartitionInterface()
+	inApex := false
+	if am, ok := ctx.Module().(ApexModule); ok {
+		inApex = am.InAnyApex()
+	}
+	isUnbundled := inVendor || (inProduct && isProductUnbundled) || inApex
+
+	// Bundled modules can use any SDK
+	if !isUnbundled {
+		return true
+	}
+
+	// Unbundled modules are allowed to use BOARD_SYSTEMSDK_VERSIONS
+	supportedVersions := ctx.DeviceConfig().SystemSdkVersions()
+
+	// b/314011075: special case for vendor modules. Java modules in the vendor partition can
+	// not use SDK 35 or later. This is to discourage the use of Java APIs in the vendor
+	// partition which hasn't been officially supported since the Project Treble back in Android
+	// 10. We would like to eventually evacuate all Java modules from the partition, but that
+	// shall be done progressively.
+	if inVendor {
+		// 28 was the API when BOARD_SYSTEMSDK_VERSIONS was introduced, so that's the oldest
+		// we should allow.
+		supportedVersions = []string{}
+		for v := 28; v <= 34; v++ {
+			supportedVersions = append(supportedVersions, strconv.Itoa(v))
 		}
 	}
-	if len(allowedVersions) > 0 && !InList(s.ApiLevel.String(), allowedVersions) {
+
+	// APEXes in the system partition are still considered as part of the platform, thus can use
+	// more SDKs from PLATFORM_SYSTEMSDK_VERSIONS
+	if inApex && !inVendor {
+		supportedVersions = ctx.DeviceConfig().PlatformSystemSdkVersions()
+	}
+
+	thisVer, err := s.EffectiveVersion(ctx)
+	if err != nil {
+		ctx.PropertyErrorf("sdk_version", "invalid sdk version %q", s.Raw)
+		return false
+	}
+
+	thisVerString := strconv.Itoa(thisVer.FinalOrPreviewInt())
+	if thisVer.IsPreview() {
+		thisVerString = *ctx.Config().productVariables.Platform_sdk_version_or_codename
+	}
+
+	if !InList(thisVerString, supportedVersions) {
 		ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
-			s.Raw, allowedVersions)
+			s.Raw, supportedVersions)
 		return false
 	}
 	return true
 }
 
+func isJava(m Module) bool {
+	moduleType := reflect.TypeOf(m).String()
+	return strings.HasPrefix(moduleType, "*java.")
+}
+
+func isSdkVersion34AvailableIn(c Config) bool {
+	return c.PlatformSdkVersion().FinalInt() >= 34
+}
+
 func init() {
 	RegisterMakeVarsProvider(pctx, javaSdkMakeVars)
 }
@@ -311,6 +393,7 @@
 // Export the name of the soong modules representing the various Java API surfaces.
 func javaSdkMakeVars(ctx MakeVarsContext) {
 	ctx.Strict("ANDROID_PUBLIC_STUBS", SdkPublic.DefaultJavaLibraryName())
+	ctx.Strict("ANDROID_PUBLIC_EXPORTABLE_STUBS", SdkPublic.DefaultExportableJavaLibraryName())
 	ctx.Strict("ANDROID_SYSTEM_STUBS", SdkSystem.DefaultJavaLibraryName())
 	ctx.Strict("ANDROID_TEST_STUBS", SdkTest.DefaultJavaLibraryName())
 	ctx.Strict("ANDROID_MODULE_LIB_STUBS", SdkModule.DefaultJavaLibraryName())
diff --git a/android/selects_test.go b/android/selects_test.go
new file mode 100644
index 0000000..8563285
--- /dev/null
+++ b/android/selects_test.go
@@ -0,0 +1,754 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"fmt"
+	"reflect"
+	"testing"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+func TestSelects(t *testing.T) {
+	testCases := []struct {
+		name          string
+		bp            string
+		provider      selectsTestProvider
+		providers     map[string]selectsTestProvider
+		vendorVars    map[string]map[string]string
+		expectedError string
+	}{
+		{
+			name: "basic string list",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": ["a.cpp"],
+					"b": ["b.cpp"],
+					default: ["c.cpp"],
+				}),
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string_list: &[]string{"c.cpp"},
+			},
+		},
+		{
+			name: "basic string",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": "a.cpp",
+					"b": "b.cpp",
+					default: "c.cpp",
+				}),
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("c.cpp"),
+			},
+		},
+		{
+			name: "basic bool",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": true,
+					"b": false,
+					default: true,
+				}),
+			}
+			`,
+			provider: selectsTestProvider{
+				my_bool: proptools.BoolPtr(true),
+			},
+		},
+		{
+			name: "basic paths",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_paths: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": ["foo.txt"],
+					"b": ["bar.txt"],
+					default: ["baz.txt"],
+				}),
+			}
+			`,
+			provider: selectsTestProvider{
+				my_paths: &[]string{"baz.txt"},
+			},
+		},
+		{
+			name: "paths with module references",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_paths: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": [":a"],
+					"b": [":b"],
+					default: [":c"],
+				}),
+			}
+			`,
+			expectedError: `"foo" depends on undefined module "c"`,
+		},
+		{
+			name: "Differing types",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": "a.cpp",
+					"b": true,
+					default: "c.cpp",
+				}),
+			}
+			`,
+			expectedError: `Android.bp:8:5: Found select statement with differing types "string" and "bool" in its cases`,
+		},
+		{
+			name: "Select type doesn't match property type",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": false,
+					"b": true,
+					default: true,
+				}),
+			}
+			`,
+			expectedError: `can't assign bool value to string property "my_string\[0\]"`,
+		},
+		{
+			name: "String list non-default",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": ["a.cpp"],
+					"b": ["b.cpp"],
+					default: ["c.cpp"],
+				}),
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string_list: &[]string{"a.cpp"},
+			},
+			vendorVars: map[string]map[string]string{
+				"my_namespace": {
+					"my_variable": "a",
+				},
+			},
+		},
+		{
+			name: "String list append",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": ["a.cpp"],
+					"b": ["b.cpp"],
+					default: ["c.cpp"],
+				}) + select(soong_config_variable("my_namespace", "my_variable_2"), {
+					"a2": ["a2.cpp"],
+					"b2": ["b2.cpp"],
+					default: ["c2.cpp"],
+				}),
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string_list: &[]string{"a.cpp", "c2.cpp"},
+			},
+			vendorVars: map[string]map[string]string{
+				"my_namespace": {
+					"my_variable": "a",
+				},
+			},
+		},
+		{
+			name: "String list prepend literal",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string_list: ["literal.cpp"] + select(soong_config_variable("my_namespace", "my_variable"), {
+					"a2": ["a2.cpp"],
+					"b2": ["b2.cpp"],
+					default: ["c2.cpp"],
+				}),
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string_list: &[]string{"literal.cpp", "c2.cpp"},
+			},
+		},
+		{
+			name: "String list append literal",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a2": ["a2.cpp"],
+					"b2": ["b2.cpp"],
+					default: ["c2.cpp"],
+				}) + ["literal.cpp"],
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string_list: &[]string{"c2.cpp", "literal.cpp"},
+			},
+		},
+		{
+			name: "true + false = true",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": true,
+					"b": false,
+					default: true,
+				}) + false,
+			}
+			`,
+			provider: selectsTestProvider{
+				my_bool: proptools.BoolPtr(true),
+			},
+		},
+		{
+			name: "false + false = false",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": true,
+					"b": false,
+					default: true,
+				}) + false,
+			}
+			`,
+			vendorVars: map[string]map[string]string{
+				"my_namespace": {
+					"my_variable": "b",
+				},
+			},
+			provider: selectsTestProvider{
+				my_bool: proptools.BoolPtr(false),
+			},
+		},
+		{
+			name: "Append string",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": "a",
+					"b": "b",
+					default: "c",
+				}) + ".cpp",
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("c.cpp"),
+			},
+		},
+		{
+			name: "Select on arch",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(arch(), {
+					"x86": "my_x86",
+					"x86_64": "my_x86_64",
+					"arm": "my_arm",
+					"arm64": "my_arm64",
+					default: "my_default",
+				}),
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("my_arm64"),
+			},
+		},
+		{
+			name: "Select on os",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(os(), {
+					"android": "my_android",
+					"linux": "my_linux",
+					default: "my_default",
+				}),
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("my_android"),
+			},
+		},
+		{
+			name: "Unset value",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": unset,
+					"b": "b",
+					default: "c",
+				})
+			}
+			`,
+			vendorVars: map[string]map[string]string{
+				"my_namespace": {
+					"my_variable": "a",
+				},
+			},
+			provider: selectsTestProvider{},
+		},
+		{
+			name: "Unset value on different branch",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": unset,
+					"b": "b",
+					default: "c",
+				})
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("c"),
+			},
+		},
+		{
+			name: "unset + unset = unset",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
+					"foo": "bar",
+					default: unset,
+				}) + select(soong_config_variable("my_namespace", "my_variable2"), {
+					"baz": "qux",
+					default: unset,
+				})
+			}
+			`,
+			provider: selectsTestProvider{},
+		},
+		{
+			name: "unset + string = string",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(soong_config_variable("my_namespace", "my_variable"), {
+					"foo": "bar",
+					default: unset,
+				}) + select(soong_config_variable("my_namespace", "my_variable2"), {
+					default: "a",
+				})
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("a"),
+			},
+		},
+		{
+			name: "unset + bool = bool",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_bool: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": true,
+					default: unset,
+				}) + select(soong_config_variable("my_namespace", "my_variable2"), {
+					default: true,
+				})
+			}
+			`,
+			provider: selectsTestProvider{
+				my_bool: proptools.BoolPtr(true),
+			},
+		},
+		{
+			name: "defaults with lists are appended",
+			bp: `
+			my_module_type {
+				name: "foo",
+				defaults: ["bar"],
+				my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": ["a1"],
+					default: ["b1"],
+				}),
+			}
+			my_defaults {
+				name: "bar",
+				my_string_list: select(soong_config_variable("my_namespace", "my_variable2"), {
+					"a": ["a2"],
+					default: ["b2"],
+				}),
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string_list: &[]string{"b2", "b1"},
+			},
+		},
+		{
+			name: "defaults applied to multiple modules",
+			bp: `
+			my_module_type {
+				name: "foo2",
+				defaults: ["bar"],
+				my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": ["a1"],
+					default: ["b1"],
+				}),
+			}
+			my_module_type {
+				name: "foo",
+				defaults: ["bar"],
+				my_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": ["a1"],
+					default: ["b1"],
+				}),
+			}
+			my_defaults {
+				name: "bar",
+				my_string_list: select(soong_config_variable("my_namespace", "my_variable2"), {
+					"a": ["a2"],
+					default: ["b2"],
+				}),
+			}
+			`,
+			providers: map[string]selectsTestProvider{
+				"foo": {
+					my_string_list: &[]string{"b2", "b1"},
+				},
+				"foo2": {
+					my_string_list: &[]string{"b2", "b1"},
+				},
+			},
+		},
+		{
+			name: "Replacing string list",
+			bp: `
+			my_module_type {
+				name: "foo",
+				defaults: ["bar"],
+				replacing_string_list: select(soong_config_variable("my_namespace", "my_variable"), {
+					"a": ["a1"],
+					default: ["b1"],
+				}),
+			}
+			my_defaults {
+				name: "bar",
+				replacing_string_list: select(soong_config_variable("my_namespace", "my_variable2"), {
+					"a": ["a2"],
+					default: ["b2"],
+				}),
+			}
+			`,
+			provider: selectsTestProvider{
+				replacing_string_list: &[]string{"b1"},
+			},
+		},
+		{
+			name: "Multi-condition string 1",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select((
+					soong_config_variable("my_namespace", "my_variable"),
+					soong_config_variable("my_namespace", "my_variable2"),
+				), {
+					("a", "b"): "a+b",
+					("a", default): "a+default",
+					(default, default): "default",
+				}),
+			}
+			`,
+			vendorVars: map[string]map[string]string{
+				"my_namespace": {
+					"my_variable":  "a",
+					"my_variable2": "b",
+				},
+			},
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("a+b"),
+			},
+		},
+		{
+			name: "Multi-condition string 2",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select((
+					soong_config_variable("my_namespace", "my_variable"),
+					soong_config_variable("my_namespace", "my_variable2"),
+				), {
+					("a", "b"): "a+b",
+					("a", default): "a+default",
+					(default, default): "default",
+				}),
+			}
+			`,
+			vendorVars: map[string]map[string]string{
+				"my_namespace": {
+					"my_variable":  "a",
+					"my_variable2": "c",
+				},
+			},
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("a+default"),
+			},
+		},
+		{
+			name: "Multi-condition string 3",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select((
+					soong_config_variable("my_namespace", "my_variable"),
+					soong_config_variable("my_namespace", "my_variable2"),
+				), {
+					("a", "b"): "a+b",
+					("a", default): "a+default",
+					(default, default): "default",
+				}),
+			}
+			`,
+			vendorVars: map[string]map[string]string{
+				"my_namespace": {
+					"my_variable":  "c",
+					"my_variable2": "b",
+				},
+			},
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("default"),
+			},
+		},
+		{
+			name: "Select on boolean",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(boolean_var_for_testing(), {
+					true: "t",
+					false: "f",
+				}),
+			}
+			`,
+			vendorVars: map[string]map[string]string{
+				"boolean_var": {
+					"for_testing": "true",
+				},
+			},
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("t"),
+			},
+		},
+		{
+			name: "Select on boolean false",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(boolean_var_for_testing(), {
+					true: "t",
+					false: "f",
+				}),
+			}
+			`,
+			vendorVars: map[string]map[string]string{
+				"boolean_var": {
+					"for_testing": "false",
+				},
+			},
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("f"),
+			},
+		},
+		{
+			name: "Select on boolean undefined",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(boolean_var_for_testing(), {
+					true: "t",
+					false: "f",
+				}),
+			}
+			`,
+			expectedError: "foo",
+		},
+		{
+			name: "Select on boolean undefined with default",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(boolean_var_for_testing(), {
+					true: "t",
+					false: "f",
+					default: "default",
+				}),
+			}
+			`,
+			provider: selectsTestProvider{
+				my_string: proptools.StringPtr("default"),
+			},
+		},
+		{
+			name: "Mismatched condition types",
+			bp: `
+			my_module_type {
+				name: "foo",
+				my_string: select(boolean_var_for_testing(), {
+					"true": "t",
+					"false": "f",
+					default: "default",
+				}),
+			}
+			`,
+			vendorVars: map[string]map[string]string{
+				"boolean_var": {
+					"for_testing": "false",
+				},
+			},
+			expectedError: "Expected all branches of a select on condition boolean_var_for_testing\\(\\) to have type bool, found string",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			fixtures := GroupFixturePreparers(
+				PrepareForTestWithDefaults,
+				PrepareForTestWithArchMutator,
+				FixtureRegisterWithContext(func(ctx RegistrationContext) {
+					ctx.RegisterModuleType("my_module_type", newSelectsMockModule)
+					ctx.RegisterModuleType("my_defaults", newSelectsMockModuleDefaults)
+				}),
+				FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+					variables.VendorVars = tc.vendorVars
+				}),
+			)
+			if tc.expectedError != "" {
+				fixtures = fixtures.ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(tc.expectedError))
+			}
+			result := fixtures.RunTestWithBp(t, tc.bp)
+
+			if tc.expectedError == "" {
+				if len(tc.providers) == 0 {
+					tc.providers = map[string]selectsTestProvider{
+						"foo": tc.provider,
+					}
+				}
+
+				for moduleName := range tc.providers {
+					expected := tc.providers[moduleName]
+					m := result.ModuleForTests(moduleName, "android_arm64_armv8-a")
+					p, _ := OtherModuleProvider(result.testContext.OtherModuleProviderAdaptor(), m.Module(), selectsTestProviderKey)
+					if !reflect.DeepEqual(p, expected) {
+						t.Errorf("Expected:\n  %q\ngot:\n  %q", expected.String(), p.String())
+					}
+				}
+			}
+		})
+	}
+}
+
+type selectsTestProvider struct {
+	my_bool               *bool
+	my_string             *string
+	my_string_list        *[]string
+	my_paths              *[]string
+	replacing_string_list *[]string
+}
+
+func (p *selectsTestProvider) String() string {
+	myBoolStr := "nil"
+	if p.my_bool != nil {
+		myBoolStr = fmt.Sprintf("%t", *p.my_bool)
+	}
+	myStringStr := "nil"
+	if p.my_string != nil {
+		myStringStr = *p.my_string
+	}
+	return fmt.Sprintf(`selectsTestProvider {
+	my_bool: %v,
+	my_string: %s,
+    my_string_list: %s,
+    my_paths: %s,
+	replacing_string_list %s,
+}`, myBoolStr, myStringStr, p.my_string_list, p.my_paths, p.replacing_string_list)
+}
+
+var selectsTestProviderKey = blueprint.NewProvider[selectsTestProvider]()
+
+type selectsMockModuleProperties struct {
+	My_bool               proptools.Configurable[bool]
+	My_string             proptools.Configurable[string]
+	My_string_list        proptools.Configurable[[]string]
+	My_paths              proptools.Configurable[[]string] `android:"path"`
+	Replacing_string_list proptools.Configurable[[]string] `android:"replace_instead_of_append,arch_variant"`
+}
+
+type selectsMockModule struct {
+	ModuleBase
+	DefaultableModuleBase
+	properties selectsMockModuleProperties
+}
+
+func (p *selectsMockModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+	SetProvider(ctx, selectsTestProviderKey, selectsTestProvider{
+		my_bool:               p.properties.My_bool.Get(ctx),
+		my_string:             p.properties.My_string.Get(ctx),
+		my_string_list:        p.properties.My_string_list.Get(ctx),
+		my_paths:              p.properties.My_paths.Get(ctx),
+		replacing_string_list: p.properties.Replacing_string_list.Get(ctx),
+	})
+}
+
+func newSelectsMockModule() Module {
+	m := &selectsMockModule{}
+	m.AddProperties(&m.properties)
+	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibFirst)
+	InitDefaultableModule(m)
+	return m
+}
+
+type selectsMockModuleDefaults struct {
+	ModuleBase
+	DefaultsModuleBase
+}
+
+func (d *selectsMockModuleDefaults) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+func newSelectsMockModuleDefaults() Module {
+	module := &selectsMockModuleDefaults{}
+
+	module.AddProperties(
+		&selectsMockModuleProperties{},
+	)
+
+	InitDefaultsModule(module)
+
+	return module
+}
diff --git a/android/shared_properties.go b/android/shared_properties.go
new file mode 100644
index 0000000..84d68fa
--- /dev/null
+++ b/android/shared_properties.go
@@ -0,0 +1,26 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+// For storing user-supplied properties about source code on a module to be queried later.
+type SourceProperties struct {
+	// Indicates that the module and its source code are only used in tests, not
+	// production code. Used by coverage reports and potentially other tools.
+	Test_only *bool
+	// Used internally to write if this is a top level test target.
+	// i.e. something that can be run directly or through tradefed as a test.
+	// `java_library` would be false, `java_test` would be true.
+	Top_level_test_target bool `blueprint:"mutated"`
+}
diff --git a/android/singleton.go b/android/singleton.go
index 7c6cf4f..76df1eb 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -20,6 +20,8 @@
 
 // SingletonContext
 type SingletonContext interface {
+	blueprintSingletonContext() blueprint.SingletonContext
+
 	Config() Config
 	DeviceConfig() DeviceConfig
 
@@ -33,15 +35,7 @@
 	// Allows generating build actions for `referer` based on the metadata for `name` deferred until the singleton context.
 	ModuleVariantsFromName(referer Module, name string) []Module
 
-	// ModuleProvider returns the value, if any, for the provider for a module.  If the value for the
-	// provider was not set it returns the zero value of the type of the provider, which means the
-	// return value can always be type-asserted to the type of the provider.  The return value should
-	// always be considered read-only.  It panics if called before the appropriate mutator or
-	// GenerateBuildActions pass for the provider on the module.
-	ModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{}
-
-	// ModuleHasProvider returns true if the provider for the given module has been set.
-	ModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool
+	moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
 
 	ModuleErrorf(module blueprint.Module, format string, args ...interface{})
 	Errorf(format string, args ...interface{})
@@ -93,6 +87,9 @@
 	// builder whenever a file matching the pattern as added or removed, without rerunning if a
 	// file that does not match the pattern is added to a searched directory.
 	GlobWithDeps(pattern string, excludes []string) ([]string, error)
+
+	// OtherModulePropertyErrorf reports an error on the line number of the given property of the given module
+	OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{})
 }
 
 type singletonAdaptor struct {
@@ -135,6 +132,10 @@
 	ruleParams  map[blueprint.Rule]blueprint.RuleParams
 }
 
+func (s *singletonContextAdaptor) blueprintSingletonContext() blueprint.SingletonContext {
+	return s.SingletonContext
+}
+
 func (s *singletonContextAdaptor) Config() Config {
 	return s.SingletonContext.Config().(Config)
 }
@@ -172,12 +173,7 @@
 		s.buildParams = append(s.buildParams, params)
 	}
 	bparams := convertBuildParams(params)
-	err := validateBuildParams(bparams)
-	if err != nil {
-		s.Errorf("%s: build parameter validation failed: %s", s.Name(), err.Error())
-	}
 	s.SingletonContext.Build(pctx.PackageContext, bparams)
-
 }
 
 func (s *singletonContextAdaptor) Phony(name string, deps ...Path) {
@@ -257,8 +253,8 @@
 }
 
 func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name string) []Module {
-	// get qualified module name for visibility enforcement
-	qualified := createQualifiedModuleName(s.ModuleName(referer), s.ModuleDir(referer))
+	// get module reference for visibility enforcement
+	qualified := createVisibilityModuleReference(s.ModuleName(referer), s.ModuleDir(referer), referer)
 
 	modules := s.SingletonContext.ModuleVariantsFromName(referer, name)
 	result := make([]Module, 0, len(modules))
@@ -269,7 +265,7 @@
 			depDir := s.ModuleDir(module)
 			depQualified := qualifiedModuleName{depDir, depName}
 			// Targets are always visible to other targets in their own package.
-			if depQualified.pkg != qualified.pkg {
+			if depQualified.pkg != qualified.name.pkg {
 				rule := effectiveVisibilityRules(s.Config(), depQualified)
 				if !rule.matches(qualified) {
 					s.ModuleErrorf(referer, "module %q references %q which is not visible to this module\nYou may need to add %q to its visibility",
@@ -282,3 +278,11 @@
 	}
 	return result
 }
+
+func (s *singletonContextAdaptor) moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
+	return s.SingletonContext.ModuleProvider(module, provider)
+}
+
+func (s *singletonContextAdaptor) OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{}) {
+	s.blueprintSingletonContext().OtherModulePropertyErrorf(module, property, format, args)
+}
diff --git a/android/singleton_module_test.go b/android/singleton_module_test.go
index 9d98478..3b1bf39 100644
--- a/android/singleton_module_test.go
+++ b/android/singleton_module_test.go
@@ -103,6 +103,9 @@
 }
 
 func TestVariantSingletonModule(t *testing.T) {
+	if testing.Short() {
+		t.Skip("test fails with data race enabled")
+	}
 	bp := `
 		test_singleton_module {
 			name: "test_singleton_module",
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index 0246a08..38db929 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -41,6 +41,7 @@
 	ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
 	ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
 	ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
+	ctx.RegisterModuleType("soong_config_value_variable", SoongConfigValueVariableDummyFactory)
 }
 
 var PrepareForTestWithSoongConfigModuleBuildComponents = FixtureRegisterWithContext(RegisterSoongConfigModuleBuildComponents)
@@ -63,6 +64,7 @@
 // specified in `conditions_default` will only be used under the following conditions:
 //   bool variable: the variable is unspecified or not set to a true value
 //   value variable: the variable is unspecified
+//   list variable: the variable is unspecified
 //   string variable: the variable is unspecified or the variable is set to a string unused in the
 //                    given module. For example, string variable `test` takes values: "a" and "b",
 //                    if the module contains a property `a` and `conditions_default`, when test=b,
@@ -103,6 +105,12 @@
 //                     cflags: ["-DWIDTH=DEFAULT"],
 //                 },
 //             },
+//             impl: {
+//                 srcs: ["impl/%s"],
+//                 conditions_default: {
+//                     srcs: ["impl/default.cpp"],
+//                 },
+//             },
 //         },
 //     }
 //
@@ -121,6 +129,7 @@
 //         variables: ["board"],
 //         bool_variables: ["feature"],
 //         value_variables: ["width"],
+//         list_variables: ["impl"],
 //         properties: ["cflags", "srcs"],
 //     }
 //
@@ -134,8 +143,10 @@
 //     $(call add_soong_config_var_value, acme, board, soc_a)
 //     $(call add_soong_config_var_value, acme, feature, true)
 //     $(call add_soong_config_var_value, acme, width, 200)
+//     $(call add_soong_config_var_value, acme, impl, foo.cpp bar.cpp)
 //
-// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200".
+// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200" and srcs
+// ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"].
 //
 // Alternatively, if acme BoardConfig.mk file contained:
 //
@@ -147,7 +158,9 @@
 //     SOONG_CONFIG_acme_feature := false
 //
 // Then libacme_foo would build with cflags:
-//   "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT".
+//   "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT"
+// and with srcs:
+//   ["*.cpp", "impl/default.cpp"].
 //
 // Similarly, if acme BoardConfig.mk file contained:
 //
@@ -157,9 +170,13 @@
 //         feature \
 //
 //     SOONG_CONFIG_acme_board := soc_c
+//     SOONG_CONFIG_acme_impl := foo.cpp bar.cpp
 //
 // Then libacme_foo would build with cflags:
-//   "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT".
+//   "-DGENERIC -DSOC_DEFAULT -DFEATURE_DEFAULT -DSIZE=DEFAULT"
+// and with srcs:
+//   ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"].
+//
 
 func SoongConfigModuleTypeImportFactory() Module {
 	module := &soongConfigModuleTypeImport{}
@@ -187,7 +204,6 @@
 
 type soongConfigModuleTypeModule struct {
 	ModuleBase
-	BazelModuleBase
 	properties soongconfig.ModuleTypeProperties
 }
 
@@ -201,6 +217,7 @@
 //
 //	bool variable: the variable is unspecified or not set to a true value
 //	value variable: the variable is unspecified
+//	list variable: the variable is unspecified
 //	string variable: the variable is unspecified or the variable is set to a string unused in the
 //	                 given module. For example, string variable `test` takes values: "a" and "b",
 //	                 if the module contains a property `a` and `conditions_default`, when test=b,
@@ -209,56 +226,63 @@
 //
 // For example, an Android.bp file could have:
 //
-//	    soong_config_module_type {
-//	        name: "acme_cc_defaults",
-//	        module_type: "cc_defaults",
-//	        config_namespace: "acme",
-//	        variables: ["board"],
-//	        bool_variables: ["feature"],
-//	        value_variables: ["width"],
-//	        properties: ["cflags", "srcs"],
-//	    }
+//	soong_config_module_type {
+//	    name: "acme_cc_defaults",
+//	    module_type: "cc_defaults",
+//	    config_namespace: "acme",
+//	    variables: ["board"],
+//	    bool_variables: ["feature"],
+//	    value_variables: ["width"],
+//	    list_variables: ["impl"],
+//	    properties: ["cflags", "srcs"],
+//	}
 //
-//	    soong_config_string_variable {
-//	        name: "board",
-//	        values: ["soc_a", "soc_b"],
-//	    }
+//	soong_config_string_variable {
+//	    name: "board",
+//	    values: ["soc_a", "soc_b"],
+//	}
 //
-//	    acme_cc_defaults {
-//	        name: "acme_defaults",
-//	        cflags: ["-DGENERIC"],
-//	        soong_config_variables: {
-//	            board: {
-//	                soc_a: {
-//	                    cflags: ["-DSOC_A"],
-//	                },
-//	                soc_b: {
-//	                    cflags: ["-DSOC_B"],
-//	                },
-//	                conditions_default: {
-//	                    cflags: ["-DSOC_DEFAULT"],
-//	                },
+//	acme_cc_defaults {
+//	    name: "acme_defaults",
+//	    cflags: ["-DGENERIC"],
+//	    soong_config_variables: {
+//	        board: {
+//	            soc_a: {
+//	                cflags: ["-DSOC_A"],
 //	            },
-//	            feature: {
-//	                cflags: ["-DFEATURE"],
-//	                conditions_default: {
-//	                    cflags: ["-DFEATURE_DEFAULT"],
-//	                },
+//	            soc_b: {
+//	                cflags: ["-DSOC_B"],
 //	            },
-//	            width: {
-//		               cflags: ["-DWIDTH=%s"],
-//	                conditions_default: {
-//	                    cflags: ["-DWIDTH=DEFAULT"],
-//	                },
+//	            conditions_default: {
+//	                cflags: ["-DSOC_DEFAULT"],
 //	            },
 //	        },
-//	    }
+//	        feature: {
+//	            cflags: ["-DFEATURE"],
+//	            conditions_default: {
+//	                cflags: ["-DFEATURE_DEFAULT"],
+//	            },
+//	        },
+//	        width: {
+//	            cflags: ["-DWIDTH=%s"],
+//	            conditions_default: {
+//	                cflags: ["-DWIDTH=DEFAULT"],
+//	            },
+//	        },
+//	        impl: {
+//	            srcs: ["impl/%s"],
+//	            conditions_default: {
+//	                srcs: ["impl/default.cpp"],
+//	            },
+//	        },
+//	    },
+//	}
 //
-//	    cc_library {
-//	        name: "libacme_foo",
-//	        defaults: ["acme_defaults"],
-//	        srcs: ["*.cpp"],
-//	    }
+//	cc_library {
+//	    name: "libacme_foo",
+//	    defaults: ["acme_defaults"],
+//	    srcs: ["*.cpp"],
+//	}
 //
 // If an acme BoardConfig.mk file contained:
 //
@@ -270,8 +294,10 @@
 //	SOONG_CONFIG_acme_board := soc_a
 //	SOONG_CONFIG_acme_feature := true
 //	SOONG_CONFIG_acme_width := 200
+//	SOONG_CONFIG_acme_impl := foo.cpp bar.cpp
 //
-// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE".
+// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE" and srcs
+// ["*.cpp", "impl/foo.cpp", "impl/bar.cpp"].
 func SoongConfigModuleTypeFactory() Module {
 	module := &soongConfigModuleTypeModule{}
 
@@ -304,6 +330,11 @@
 	properties soongconfig.VariableProperties
 }
 
+type soongConfigValueVariableDummyModule struct {
+	ModuleBase
+	properties soongconfig.VariableProperties
+}
+
 // soong_config_string_variable defines a variable and a set of possible string values for use
 // in a soong_config_module_type definition.
 func SoongConfigStringVariableDummyFactory() Module {
@@ -322,6 +353,15 @@
 	return module
 }
 
+// soong_config_value_variable defines a variable whose value can be expanded into
+// the value of a string property.
+func SoongConfigValueVariableDummyFactory() Module {
+	module := &soongConfigValueVariableDummyModule{}
+	module.AddProperties(&module.properties)
+	initAndroidModuleBase(module)
+	return module
+}
+
 func (m *soongConfigStringVariableDummyModule) Name() string {
 	return m.properties.Name + fmt.Sprintf("%p", m)
 }
@@ -334,6 +374,12 @@
 func (*soongConfigBoolVariableDummyModule) Namespaceless()                                {}
 func (*soongConfigBoolVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
 
+func (m *soongConfigValueVariableDummyModule) Name() string {
+	return m.properties.Name + fmt.Sprintf("%p", m)
+}
+func (*soongConfigValueVariableDummyModule) Namespaceless()                                {}
+func (*soongConfigValueVariableDummyModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
+
 // importModuleTypes registers the module factories for a list of module types defined
 // in an Android.bp file. These module factories are scoped for the current Android.bp
 // file only.
@@ -395,10 +441,6 @@
 			return (map[string]blueprint.ModuleFactory)(nil)
 		}
 
-		if ctx.Config().BuildMode == Bp2build {
-			ctx.Config().Bp2buildSoongConfigDefinitions.AddVars(mtDef)
-		}
-
 		globalModuleTypes := ctx.moduleFactories()
 
 		factories := make(map[string]blueprint.ModuleFactory)
@@ -406,7 +448,7 @@
 		for name, moduleType := range mtDef.ModuleTypes {
 			factory := globalModuleTypes[moduleType.BaseModuleType]
 			if factory != nil {
-				factories[name] = configModuleFactory(factory, moduleType, ctx.Config().BuildMode == Bp2build)
+				factories[name] = configModuleFactory(factory, moduleType)
 			} else {
 				reportErrors(ctx, from,
 					fmt.Errorf("missing global module type factory for %q", moduleType.BaseModuleType))
@@ -474,7 +516,7 @@
 
 // configModuleFactory takes an existing soongConfigModuleFactory and a
 // ModuleType to create a new ModuleFactory that uses a custom loadhook.
-func configModuleFactory(factory blueprint.ModuleFactory, moduleType *soongconfig.ModuleType, bp2build bool) blueprint.ModuleFactory {
+func configModuleFactory(factory blueprint.ModuleFactory, moduleType *soongconfig.ModuleType) blueprint.ModuleFactory {
 	// Defer creation of conditional properties struct until the first call from the factory
 	// method. That avoids having to make a special call to the factory to create the properties
 	// structs from which the conditional properties struct is created. This is needed in order to
@@ -515,40 +557,22 @@
 		conditionalProps := proptools.CloneEmptyProperties(conditionalFactoryProps)
 		props = append(props, conditionalProps.Interface())
 
-		if bp2build {
-			// The loadhook is different for bp2build, since we don't want to set a specific
-			// set of property values based on a vendor var -- we want __all of them__ to
-			// generate select statements, so we put the entire soong_config_variables
-			// struct, together with the namespace representing those variables, while
-			// creating the custom module with the factory.
-			AddLoadHook(module, func(ctx LoadHookContext) {
-				if m, ok := module.(Bazelable); ok {
-					m.SetBaseModuleType(moduleType.BaseModuleType)
-					// Instead of applying all properties, keep the entire conditionalProps struct as
-					// part of the custom module so dependent modules can create the selects accordingly
-					m.setNamespacedVariableProps(namespacedVariableProperties{
-						moduleType.ConfigNamespace: []interface{}{conditionalProps.Interface()},
-					})
-				}
-			})
-		} else {
-			// Regular Soong operation wraps the existing module factory with a
-			// conditional on Soong config variables by reading the product
-			// config variables from Make.
-			AddLoadHook(module, func(ctx LoadHookContext) {
-				tracingConfig := newTracingConfig(ctx.Config().VendorConfig(moduleType.ConfigNamespace))
-				newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, tracingConfig)
-				if err != nil {
-					ctx.ModuleErrorf("%s", err)
-					return
-				}
-				for _, ps := range newProps {
-					ctx.AppendProperties(ps)
-				}
+		// Regular Soong operation wraps the existing module factory with a
+		// conditional on Soong config variables by reading the product
+		// config variables from Make.
+		AddLoadHook(module, func(ctx LoadHookContext) {
+			tracingConfig := newTracingConfig(ctx.Config().VendorConfig(moduleType.ConfigNamespace))
+			newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, tracingConfig)
+			if err != nil {
+				ctx.ModuleErrorf("%s", err)
+				return
+			}
+			for _, ps := range newProps {
+				ctx.AppendProperties(ps)
+			}
 
-				module.(Module).base().commonProperties.SoongConfigTrace = tracingConfig.getTrace()
-			})
-		}
+			module.(Module).base().commonProperties.SoongConfigTrace = tracingConfig.getTrace()
+		})
 		return module, props
 	}
 }
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index 79bdeb8..a6b2c51 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -376,8 +376,7 @@
 		prepareForSoongConfigTestModule,
 		FixtureWithRootAndroidBp(bp),
 	).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern([]string{
-		// TODO(b/171232169): improve the error message for non-existent properties
-		`unrecognized property "soong_config_variables`,
+		`unrecognized property "soong_config_variables.feature1.made_up_property`,
 	})).RunTest(t)
 }
 
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index 23c8afa..c910974 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -20,12 +20,9 @@
 	"reflect"
 	"sort"
 	"strings"
-	"sync"
 
 	"github.com/google/blueprint/parser"
 	"github.com/google/blueprint/proptools"
-
-	"android/soong/starlark_fmt"
 )
 
 const conditionsDefault = "conditions_default"
@@ -120,6 +117,10 @@
 	// inserted into the properties with %s substitution.
 	Value_variables []string
 
+	// the list of SOONG_CONFIG list variables that this module type will read. Each value will be
+	// inserted into the properties with %s substitution.
+	List_variables []string
+
 	// the list of properties that this module type will extend.
 	Properties []string
 }
@@ -236,110 +237,6 @@
 	variables map[string]soongConfigVariable
 }
 
-// Bp2BuildSoongConfigDefinition keeps a global record of all soong config
-// string vars, bool vars and value vars created by every
-// soong_config_module_type in this build.
-type Bp2BuildSoongConfigDefinitions struct {
-	StringVars map[string]map[string]bool
-	BoolVars   map[string]bool
-	ValueVars  map[string]bool
-}
-
-var bp2buildSoongConfigVarsLock sync.Mutex
-
-// SoongConfigVariablesForBp2build extracts information from a
-// SoongConfigDefinition that bp2build needs to generate constraint settings and
-// values for, in order to migrate soong_config_module_type usages to Bazel.
-func (defs *Bp2BuildSoongConfigDefinitions) AddVars(mtDef *SoongConfigDefinition) {
-	// In bp2build mode, this method is called concurrently in goroutines from
-	// loadhooks while parsing soong_config_module_type, so add a mutex to
-	// prevent concurrent map writes. See b/207572723
-	bp2buildSoongConfigVarsLock.Lock()
-	defer bp2buildSoongConfigVarsLock.Unlock()
-
-	if defs.StringVars == nil {
-		defs.StringVars = make(map[string]map[string]bool)
-	}
-	if defs.BoolVars == nil {
-		defs.BoolVars = make(map[string]bool)
-	}
-	if defs.ValueVars == nil {
-		defs.ValueVars = make(map[string]bool)
-	}
-	// varCache contains a cache of string variables namespace + property
-	// The same variable may be used in multiple module types (for example, if need support
-	// for cc_default and java_default), only need to process once
-	varCache := map[string]bool{}
-
-	for _, moduleType := range mtDef.ModuleTypes {
-		for _, v := range moduleType.Variables {
-			key := strings.Join([]string{moduleType.ConfigNamespace, v.variableProperty()}, "__")
-
-			// The same variable may be used in multiple module types (for example, if need support
-			// for cc_default and java_default), only need to process once
-			if _, keyInCache := varCache[key]; keyInCache {
-				continue
-			} else {
-				varCache[key] = true
-			}
-
-			if strVar, ok := v.(*stringVariable); ok {
-				if _, ok := defs.StringVars[key]; !ok {
-					defs.StringVars[key] = make(map[string]bool, len(strVar.values))
-				}
-				for _, value := range strVar.values {
-					defs.StringVars[key][value] = true
-				}
-			} else if _, ok := v.(*boolVariable); ok {
-				defs.BoolVars[key] = true
-			} else if _, ok := v.(*valueVariable); ok {
-				defs.ValueVars[key] = true
-			} else {
-				panic(fmt.Errorf("Unsupported variable type: %+v", v))
-			}
-		}
-	}
-}
-
-// This is a copy of the one available in soong/android/util.go, but depending
-// on the android package causes a cyclic dependency. A refactoring here is to
-// extract common utils out from android/utils.go for other packages like this.
-func sortedStringKeys(m interface{}) []string {
-	v := reflect.ValueOf(m)
-	if v.Kind() != reflect.Map {
-		panic(fmt.Sprintf("%#v is not a map", m))
-	}
-	keys := v.MapKeys()
-	s := make([]string, 0, len(keys))
-	for _, key := range keys {
-		s = append(s, key.String())
-	}
-	sort.Strings(s)
-	return s
-}
-
-// String emits the Soong config variable definitions as Starlark dictionaries.
-func (defs Bp2BuildSoongConfigDefinitions) String() string {
-	ret := ""
-	ret += "soong_config_bool_variables = "
-	ret += starlark_fmt.PrintBoolDict(defs.BoolVars, 0)
-	ret += "\n\n"
-
-	ret += "soong_config_value_variables = "
-	ret += starlark_fmt.PrintBoolDict(defs.ValueVars, 0)
-	ret += "\n\n"
-
-	stringVars := make(map[string][]string, len(defs.StringVars))
-	for k, v := range defs.StringVars {
-		stringVars[k] = sortedStringKeys(v)
-	}
-
-	ret += "soong_config_string_variables = "
-	ret += starlark_fmt.PrintStringListDict(stringVars, 0)
-
-	return ret
-}
-
 // CreateProperties returns a reflect.Value of a newly constructed type that contains the desired
 // property layout for the Soong config variables, with each possible value an interface{} that
 // contains a nil pointer to another newly constructed type that contains the affectable properties.
@@ -575,6 +472,18 @@
 		})
 	}
 
+	for _, name := range props.List_variables {
+		if err := checkVariableName(name); err != nil {
+			return nil, []error{fmt.Errorf("list_variables %s", err)}
+		}
+
+		mt.Variables = append(mt.Variables, &listVariable{
+			baseVariable: baseVariable{
+				variable: name,
+			},
+		})
+	}
+
 	return mt, nil
 }
 
@@ -788,6 +697,14 @@
 	if !propStruct.IsValid() {
 		return nil, nil
 	}
+	if err := s.printfIntoPropertyRecursive(nil, propStruct, configValue); err != nil {
+		return nil, err
+	}
+
+	return values.Interface(), nil
+}
+
+func (s *valueVariable) printfIntoPropertyRecursive(fieldName []string, propStruct reflect.Value, configValue string) error {
 	for i := 0; i < propStruct.NumField(); i++ {
 		field := propStruct.Field(i)
 		kind := field.Kind()
@@ -796,30 +713,123 @@
 				continue
 			}
 			field = field.Elem()
+			kind = field.Kind()
 		}
 		switch kind {
 		case reflect.String:
 			err := printfIntoProperty(field, configValue)
 			if err != nil {
-				return nil, fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, propStruct.Type().Field(i).Name, err)
+				fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+				return fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, strings.Join(fieldName, "."), err)
 			}
 		case reflect.Slice:
 			for j := 0; j < field.Len(); j++ {
 				err := printfIntoProperty(field.Index(j), configValue)
 				if err != nil {
-					return nil, fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, propStruct.Type().Field(i).Name, err)
+					fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+					return fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, strings.Join(fieldName, "."), err)
 				}
 			}
 		case reflect.Bool:
 			// Nothing to do
+		case reflect.Struct:
+			fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+			if err := s.printfIntoPropertyRecursive(fieldName, field, configValue); err != nil {
+				return err
+			}
+			fieldName = fieldName[:len(fieldName)-1]
 		default:
-			return nil, fmt.Errorf("soong_config_variables.%s.%s: unsupported property type %q", s.variable, propStruct.Type().Field(i).Name, kind)
+			fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+			return fmt.Errorf("soong_config_variables.%s.%s: unsupported property type %q", s.variable, strings.Join(fieldName, "."), kind)
 		}
 	}
+	return nil
+}
+
+// Struct to allow conditions set based on a list variable, supporting string substitution.
+type listVariable struct {
+	baseVariable
+}
+
+func (s *listVariable) variableValuesType() reflect.Type {
+	return emptyInterfaceType
+}
+
+// initializeProperties initializes a property to zero value of typ with an additional conditions
+// default field.
+func (s *listVariable) initializeProperties(v reflect.Value, typ reflect.Type) {
+	initializePropertiesWithDefault(v, typ)
+}
+
+// PropertiesToApply returns an interface{} value based on initializeProperties to be applied to
+// the module. If the variable was not set, conditions_default interface will be returned;
+// otherwise, the interface in values, without conditions_default will be returned with all
+// appropriate string substitutions based on variable being set.
+func (s *listVariable) PropertiesToApply(config SoongConfig, values reflect.Value) (interface{}, error) {
+	// If this variable was not referenced in the module, there are no properties to apply.
+	if !values.IsValid() || values.Elem().IsZero() {
+		return nil, nil
+	}
+	if !config.IsSet(s.variable) {
+		return conditionsDefaultField(values.Elem().Elem()).Interface(), nil
+	}
+	configValues := strings.Split(config.String(s.variable), " ")
+
+	values = removeDefault(values)
+	propStruct := values.Elem()
+	if !propStruct.IsValid() {
+		return nil, nil
+	}
+	if err := s.printfIntoPropertyRecursive(nil, propStruct, configValues); err != nil {
+		return nil, err
+	}
 
 	return values.Interface(), nil
 }
 
+func (s *listVariable) printfIntoPropertyRecursive(fieldName []string, propStruct reflect.Value, configValues []string) error {
+	for i := 0; i < propStruct.NumField(); i++ {
+		field := propStruct.Field(i)
+		kind := field.Kind()
+		if kind == reflect.Ptr {
+			if field.IsNil() {
+				continue
+			}
+			field = field.Elem()
+			kind = field.Kind()
+		}
+		switch kind {
+		case reflect.Slice:
+			elemType := field.Type().Elem()
+			newLen := field.Len() * len(configValues)
+			newField := reflect.MakeSlice(field.Type(), 0, newLen)
+			for j := 0; j < field.Len(); j++ {
+				for _, configValue := range configValues {
+					res := reflect.Indirect(reflect.New(elemType))
+					res.Set(field.Index(j))
+					err := printfIntoProperty(res, configValue)
+					if err != nil {
+						fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+						return fmt.Errorf("soong_config_variables.%s.%s: %s", s.variable, strings.Join(fieldName, "."), err)
+					}
+					newField = reflect.Append(newField, res)
+				}
+			}
+			field.Set(newField)
+		case reflect.Struct:
+			fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+			if err := s.printfIntoPropertyRecursive(fieldName, field, configValues); err != nil {
+				return err
+			}
+			fieldName = fieldName[:len(fieldName)-1]
+		default:
+			fieldName = append(fieldName, propStruct.Type().Field(i).Name)
+			return fmt.Errorf("soong_config_variables.%s.%s: unsupported property type %q", s.variable, strings.Join(fieldName, "."), kind)
+		}
+	}
+	return nil
+}
+
 func printfIntoProperty(propertyValue reflect.Value, configValue string) error {
 	s := propertyValue.String()
 
@@ -829,7 +839,7 @@
 	}
 
 	if count > 1 {
-		return fmt.Errorf("value variable properties only support a single '%%'")
+		return fmt.Errorf("list/value variable properties only support a single '%%'")
 	}
 
 	if !strings.Contains(s, "%s") {
diff --git a/android/soongconfig/modules_test.go b/android/soongconfig/modules_test.go
index a5fa349..d76794c 100644
--- a/android/soongconfig/modules_test.go
+++ b/android/soongconfig/modules_test.go
@@ -291,15 +291,17 @@
 type properties struct {
 	A *string
 	B bool
+	C []string
 }
 
-type boolVarProps struct {
+type varProps struct {
 	A                  *string
 	B                  bool
+	C                  []string
 	Conditions_default *properties
 }
 
-type soongConfigVars struct {
+type boolSoongConfigVars struct {
 	Bool_var interface{}
 }
 
@@ -307,7 +309,24 @@
 	String_var interface{}
 }
 
-func Test_PropertiesToApply(t *testing.T) {
+type valueSoongConfigVars struct {
+	My_value_var interface{}
+}
+
+type listProperties struct {
+	C []string
+}
+
+type listVarProps struct {
+	C                  []string
+	Conditions_default *listProperties
+}
+
+type listSoongConfigVars struct {
+	List_var interface{}
+}
+
+func Test_PropertiesToApply_Bool(t *testing.T) {
 	mt, _ := newModuleType(&ModuleTypeProperties{
 		Module_type:      "foo",
 		Config_namespace: "bar",
@@ -323,10 +342,10 @@
 		B: false,
 	}
 	actualProps := &struct {
-		Soong_config_variables soongConfigVars
+		Soong_config_variables boolSoongConfigVars
 	}{
-		Soong_config_variables: soongConfigVars{
-			Bool_var: &boolVarProps{
+		Soong_config_variables: boolSoongConfigVars{
+			Bool_var: &varProps{
 				A:                  boolVarPositive.A,
 				B:                  boolVarPositive.B,
 				Conditions_default: conditionsDefault,
@@ -369,6 +388,185 @@
 	}
 }
 
+func Test_PropertiesToApply_List(t *testing.T) {
+	mt, _ := newModuleType(&ModuleTypeProperties{
+		Module_type:      "foo",
+		Config_namespace: "bar",
+		List_variables:   []string{"my_list_var"},
+		Properties:       []string{"c"},
+	})
+	conditionsDefault := &listProperties{
+		C: []string{"default"},
+	}
+	actualProps := &struct {
+		Soong_config_variables listSoongConfigVars
+	}{
+		Soong_config_variables: listSoongConfigVars{
+			List_var: &listVarProps{
+				C:                  []string{"A=%s", "B=%s"},
+				Conditions_default: conditionsDefault,
+			},
+		},
+	}
+	props := reflect.ValueOf(actualProps)
+
+	testCases := []struct {
+		name      string
+		config    SoongConfig
+		wantProps []interface{}
+	}{
+		{
+			name:      "no_vendor_config",
+			config:    Config(map[string]string{}),
+			wantProps: []interface{}{conditionsDefault},
+		},
+		{
+			name:   "value_var_set",
+			config: Config(map[string]string{"my_list_var": "hello there"}),
+			wantProps: []interface{}{&listProperties{
+				C: []string{"A=hello", "A=there", "B=hello", "B=there"},
+			}},
+		},
+	}
+
+	for _, tc := range testCases {
+		gotProps, err := PropertiesToApply(mt, props, tc.config)
+		if err != nil {
+			t.Errorf("%s: Unexpected error in PropertiesToApply: %s", tc.name, err)
+		}
+
+		if !reflect.DeepEqual(gotProps, tc.wantProps) {
+			t.Errorf("%s: Expected %s, got %s", tc.name, tc.wantProps, gotProps)
+		}
+	}
+}
+
+func Test_PropertiesToApply_Value(t *testing.T) {
+	mt, _ := newModuleType(&ModuleTypeProperties{
+		Module_type:      "foo",
+		Config_namespace: "bar",
+		Value_variables:  []string{"my_value_var"},
+		Properties:       []string{"a", "b"},
+	})
+	conditionsDefault := &properties{
+		A: proptools.StringPtr("default"),
+		B: false,
+	}
+	actualProps := &struct {
+		Soong_config_variables valueSoongConfigVars
+	}{
+		Soong_config_variables: valueSoongConfigVars{
+			My_value_var: &varProps{
+				A:                  proptools.StringPtr("A=%s"),
+				B:                  true,
+				Conditions_default: conditionsDefault,
+			},
+		},
+	}
+	props := reflect.ValueOf(actualProps)
+
+	testCases := []struct {
+		name      string
+		config    SoongConfig
+		wantProps []interface{}
+	}{
+		{
+			name:      "no_vendor_config",
+			config:    Config(map[string]string{}),
+			wantProps: []interface{}{conditionsDefault},
+		},
+		{
+			name:   "value_var_set",
+			config: Config(map[string]string{"my_value_var": "Hello"}),
+			wantProps: []interface{}{&properties{
+				A: proptools.StringPtr("A=Hello"),
+				B: true,
+			}},
+		},
+	}
+
+	for _, tc := range testCases {
+		gotProps, err := PropertiesToApply(mt, props, tc.config)
+		if err != nil {
+			t.Errorf("%s: Unexpected error in PropertiesToApply: %s", tc.name, err)
+		}
+
+		if !reflect.DeepEqual(gotProps, tc.wantProps) {
+			t.Errorf("%s: Expected %s, got %s", tc.name, tc.wantProps, gotProps)
+		}
+	}
+}
+
+func Test_PropertiesToApply_Value_Nested(t *testing.T) {
+	mt, _ := newModuleType(&ModuleTypeProperties{
+		Module_type:      "foo",
+		Config_namespace: "bar",
+		Value_variables:  []string{"my_value_var"},
+		Properties:       []string{"a.b"},
+	})
+	type properties struct {
+		A struct {
+			B string
+		}
+	}
+	conditionsDefault := &properties{
+		A: struct{ B string }{
+			B: "default",
+		},
+	}
+	type valueVarProps struct {
+		A struct {
+			B string
+		}
+		Conditions_default *properties
+	}
+	actualProps := &struct {
+		Soong_config_variables valueSoongConfigVars
+	}{
+		Soong_config_variables: valueSoongConfigVars{
+			My_value_var: &valueVarProps{
+				A: struct{ B string }{
+					B: "A.B=%s",
+				},
+				Conditions_default: conditionsDefault,
+			},
+		},
+	}
+	props := reflect.ValueOf(actualProps)
+
+	testCases := []struct {
+		name      string
+		config    SoongConfig
+		wantProps []interface{}
+	}{
+		{
+			name:      "no_vendor_config",
+			config:    Config(map[string]string{}),
+			wantProps: []interface{}{conditionsDefault},
+		},
+		{
+			name:   "value_var_set",
+			config: Config(map[string]string{"my_value_var": "Hello"}),
+			wantProps: []interface{}{&properties{
+				A: struct{ B string }{
+					B: "A.B=Hello",
+				},
+			}},
+		},
+	}
+
+	for _, tc := range testCases {
+		gotProps, err := PropertiesToApply(mt, props, tc.config)
+		if err != nil {
+			t.Errorf("%s: Unexpected error in PropertiesToApply: %s", tc.name, err)
+		}
+
+		if !reflect.DeepEqual(gotProps, tc.wantProps) {
+			t.Errorf("%s: Expected %s, got %s", tc.name, tc.wantProps, gotProps)
+		}
+	}
+}
+
 func Test_PropertiesToApply_String_Error(t *testing.T) {
 	mt, _ := newModuleType(&ModuleTypeProperties{
 		Module_type:      "foo",
@@ -394,7 +592,7 @@
 		Soong_config_variables stringSoongConfigVars
 	}{
 		Soong_config_variables: stringSoongConfigVars{
-			String_var: &boolVarProps{
+			String_var: &varProps{
 				A:                  stringVarPositive.A,
 				B:                  stringVarPositive.B,
 				Conditions_default: conditionsDefault,
@@ -413,220 +611,3 @@
 		t.Fatalf("Error message was not correct, expected %q, got %q", expected, err.Error())
 	}
 }
-
-func Test_Bp2BuildSoongConfigDefinitionsAddVars(t *testing.T) {
-	testCases := []struct {
-		desc     string
-		defs     []*SoongConfigDefinition
-		expected Bp2BuildSoongConfigDefinitions
-	}{
-		{
-			desc: "non-overlapping",
-			defs: []*SoongConfigDefinition{
-				&SoongConfigDefinition{
-					ModuleTypes: map[string]*ModuleType{
-						"a": &ModuleType{
-							ConfigNamespace: "foo",
-							Variables: []soongConfigVariable{
-								&stringVariable{
-									baseVariable: baseVariable{"string_var"},
-									values:       []string{"a", "b", "c"},
-								},
-							},
-						},
-					},
-				},
-				&SoongConfigDefinition{
-					ModuleTypes: map[string]*ModuleType{
-						"b": &ModuleType{
-							ConfigNamespace: "foo",
-							Variables: []soongConfigVariable{
-								&stringVariable{
-									baseVariable: baseVariable{"string_var"},
-									values:       []string{"a", "b", "c"},
-								},
-								&boolVariable{baseVariable: baseVariable{"bool_var"}},
-								&valueVariable{baseVariable: baseVariable{"variable_var"}},
-							},
-						},
-					},
-				},
-			},
-			expected: Bp2BuildSoongConfigDefinitions{
-				StringVars: map[string]map[string]bool{
-					"foo__string_var": map[string]bool{"a": true, "b": true, "c": true},
-				},
-				BoolVars:  map[string]bool{"foo__bool_var": true},
-				ValueVars: map[string]bool{"foo__variable_var": true},
-			},
-		},
-		{
-			desc: "overlapping",
-			defs: []*SoongConfigDefinition{
-				&SoongConfigDefinition{
-					ModuleTypes: map[string]*ModuleType{
-						"a": &ModuleType{
-							ConfigNamespace: "foo",
-							Variables: []soongConfigVariable{
-								&stringVariable{
-									baseVariable: baseVariable{"string_var"},
-									values:       []string{"a", "b", "c"},
-								},
-							},
-						},
-					},
-				},
-				&SoongConfigDefinition{
-					ModuleTypes: map[string]*ModuleType{
-						"b": &ModuleType{
-							ConfigNamespace: "foo",
-							Variables: []soongConfigVariable{
-								&stringVariable{
-									baseVariable: baseVariable{"string_var"},
-									values:       []string{"b", "c", "d"},
-								},
-								&boolVariable{baseVariable: baseVariable{"bool_var"}},
-								&valueVariable{baseVariable: baseVariable{"variable_var"}},
-							},
-						},
-					},
-				},
-			},
-			expected: Bp2BuildSoongConfigDefinitions{
-				StringVars: map[string]map[string]bool{
-					"foo__string_var": map[string]bool{"a": true, "b": true, "c": true, "d": true},
-				},
-				BoolVars:  map[string]bool{"foo__bool_var": true},
-				ValueVars: map[string]bool{"foo__variable_var": true},
-			},
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.desc, func(t *testing.T) {
-			actual := &Bp2BuildSoongConfigDefinitions{}
-			for _, d := range tc.defs {
-				func(def *SoongConfigDefinition) {
-					actual.AddVars(def)
-				}(d)
-			}
-			if !reflect.DeepEqual(*actual, tc.expected) {
-				t.Errorf("Expected %#v, got %#v", tc.expected, *actual)
-			}
-		})
-	}
-
-}
-
-func Test_Bp2BuildSoongConfigDefinitions(t *testing.T) {
-	testCases := []struct {
-		desc     string
-		defs     Bp2BuildSoongConfigDefinitions
-		expected string
-	}{
-		{
-			desc: "all empty",
-			defs: Bp2BuildSoongConfigDefinitions{},
-			expected: `soong_config_bool_variables = {}
-
-soong_config_value_variables = {}
-
-soong_config_string_variables = {}`}, {
-			desc: "only bool",
-			defs: Bp2BuildSoongConfigDefinitions{
-				BoolVars: map[string]bool{
-					"bool_var": true,
-				},
-			},
-			expected: `soong_config_bool_variables = {
-    "bool_var": True,
-}
-
-soong_config_value_variables = {}
-
-soong_config_string_variables = {}`}, {
-			desc: "only value vars",
-			defs: Bp2BuildSoongConfigDefinitions{
-				ValueVars: map[string]bool{
-					"value_var": true,
-				},
-			},
-			expected: `soong_config_bool_variables = {}
-
-soong_config_value_variables = {
-    "value_var": True,
-}
-
-soong_config_string_variables = {}`}, {
-			desc: "only string vars",
-			defs: Bp2BuildSoongConfigDefinitions{
-				StringVars: map[string]map[string]bool{
-					"string_var": map[string]bool{
-						"choice1": true,
-						"choice2": true,
-						"choice3": true,
-					},
-				},
-			},
-			expected: `soong_config_bool_variables = {}
-
-soong_config_value_variables = {}
-
-soong_config_string_variables = {
-    "string_var": [
-        "choice1",
-        "choice2",
-        "choice3",
-    ],
-}`}, {
-			desc: "all vars",
-			defs: Bp2BuildSoongConfigDefinitions{
-				BoolVars: map[string]bool{
-					"bool_var_one": true,
-				},
-				ValueVars: map[string]bool{
-					"value_var_one": true,
-					"value_var_two": true,
-				},
-				StringVars: map[string]map[string]bool{
-					"string_var_one": map[string]bool{
-						"choice1": true,
-						"choice2": true,
-						"choice3": true,
-					},
-					"string_var_two": map[string]bool{
-						"foo": true,
-						"bar": true,
-					},
-				},
-			},
-			expected: `soong_config_bool_variables = {
-    "bool_var_one": True,
-}
-
-soong_config_value_variables = {
-    "value_var_one": True,
-    "value_var_two": True,
-}
-
-soong_config_string_variables = {
-    "string_var_one": [
-        "choice1",
-        "choice2",
-        "choice3",
-    ],
-    "string_var_two": [
-        "bar",
-        "foo",
-    ],
-}`},
-	}
-	for _, test := range testCases {
-		t.Run(test.desc, func(t *testing.T) {
-			actual := test.defs.String()
-			if actual != test.expected {
-				t.Errorf("Expected:\n%s\nbut got:\n%s", test.expected, actual)
-			}
-		})
-	}
-}
diff --git a/android/team.go b/android/team.go
new file mode 100644
index 0000000..c273dc6
--- /dev/null
+++ b/android/team.go
@@ -0,0 +1,67 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import "github.com/google/blueprint"
+
+func init() {
+	RegisterTeamBuildComponents(InitRegistrationContext)
+}
+
+func RegisterTeamBuildComponents(ctx RegistrationContext) {
+	ctx.RegisterModuleType("team", TeamFactory)
+}
+
+var PrepareForTestWithTeamBuildComponents = GroupFixturePreparers(
+	FixtureRegisterWithContext(RegisterTeamBuildComponents),
+)
+
+type teamProperties struct {
+	Trendy_team_id *string `json:"trendy_team_id"`
+}
+
+type teamModule struct {
+	ModuleBase
+	DefaultableModuleBase
+
+	properties teamProperties
+}
+
+type TestModuleInformation struct {
+	TestOnly       bool
+	TopLevelTarget bool
+}
+
+var TestOnlyProviderKey = blueprint.NewProvider[TestModuleInformation]()
+
+// Real work is done for the module that depends on us.
+// If needed, the team can serialize the config to json/proto file as well.
+func (t *teamModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
+
+func (t *teamModule) TrendyTeamId(ctx ModuleContext) string {
+	return *t.properties.Trendy_team_id
+}
+
+func TeamFactory() Module {
+	module := &teamModule{}
+
+	base := module.base()
+	module.AddProperties(&base.nameProperties, &module.properties)
+
+	InitAndroidModule(module)
+	InitDefaultableModule(module)
+
+	return module
+}
diff --git a/android/team_proto/Android.bp b/android/team_proto/Android.bp
new file mode 100644
index 0000000..7e2a4c1
--- /dev/null
+++ b/android/team_proto/Android.bp
@@ -0,0 +1,43 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-android_team_proto",
+    pkgPath: "android/soong/android/team_proto",
+    deps: [
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+    ],
+    srcs: [
+        "team.pb.go",
+    ],
+}
+
+python_library_host {
+    name: "teams-proto-py",
+    pkg_path: "teams",
+    srcs: [
+        "team.proto",
+    ],
+    libs: [
+        "libprotobuf-python",
+    ],
+    proto: {
+        canonical_path_from_root: false,
+    },
+}
diff --git a/android/team_proto/OWNERS b/android/team_proto/OWNERS
new file mode 100644
index 0000000..2beb4f4
--- /dev/null
+++ b/android/team_proto/OWNERS
@@ -0,0 +1,5 @@
+dariofreni@google.com
+joeo@google.com
+ronish@google.com
+caditya@google.com
+rbraunstein@google.com
diff --git a/android/team_proto/regen.sh b/android/team_proto/regen.sh
new file mode 100755
index 0000000..63b2016
--- /dev/null
+++ b/android/team_proto/regen.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+aprotoc --go_out=paths=source_relative:. team.proto
diff --git a/android/team_proto/team.pb.go b/android/team_proto/team.pb.go
new file mode 100644
index 0000000..8414d17
--- /dev/null
+++ b/android/team_proto/team.pb.go
@@ -0,0 +1,287 @@
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.30.0
+// 	protoc        v3.21.12
+// source: team.proto
+
+package team_proto
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Team struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// REQUIRED: Name of the build target
+	TargetName *string `protobuf:"bytes,1,opt,name=target_name,json=targetName" json:"target_name,omitempty"`
+	// REQUIRED: Code location of the target.
+	// To be used to support legacy/backup systems that use OWNERS file and is
+	// also required for our dashboard to support per code location basis UI
+	Path *string `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"`
+	// REQUIRED: Team ID of the team that owns this target.
+	TrendyTeamId *string `protobuf:"bytes,3,opt,name=trendy_team_id,json=trendyTeamId" json:"trendy_team_id,omitempty"`
+	// OPTIONAL: Files directly owned by this module.
+	File []string `protobuf:"bytes,4,rep,name=file" json:"file,omitempty"`
+	// OPTIONAL: Is this a test-only module.
+	TestOnly *bool `protobuf:"varint,5,opt,name=test_only,json=testOnly" json:"test_only,omitempty"`
+	// OPTIONAL: Is this intended to be run as a test target.
+	// This target can be run directly as a test or passed to tradefed.
+	TopLevelTarget *bool `protobuf:"varint,6,opt,name=top_level_target,json=topLevelTarget" json:"top_level_target,omitempty"`
+	// OPTIONAL: Name of module kind, i.e. java_library
+	Kind *string `protobuf:"bytes,7,opt,name=kind" json:"kind,omitempty"`
+}
+
+func (x *Team) Reset() {
+	*x = Team{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_team_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Team) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Team) ProtoMessage() {}
+
+func (x *Team) ProtoReflect() protoreflect.Message {
+	mi := &file_team_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Team.ProtoReflect.Descriptor instead.
+func (*Team) Descriptor() ([]byte, []int) {
+	return file_team_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Team) GetTargetName() string {
+	if x != nil && x.TargetName != nil {
+		return *x.TargetName
+	}
+	return ""
+}
+
+func (x *Team) GetPath() string {
+	if x != nil && x.Path != nil {
+		return *x.Path
+	}
+	return ""
+}
+
+func (x *Team) GetTrendyTeamId() string {
+	if x != nil && x.TrendyTeamId != nil {
+		return *x.TrendyTeamId
+	}
+	return ""
+}
+
+func (x *Team) GetFile() []string {
+	if x != nil {
+		return x.File
+	}
+	return nil
+}
+
+func (x *Team) GetTestOnly() bool {
+	if x != nil && x.TestOnly != nil {
+		return *x.TestOnly
+	}
+	return false
+}
+
+func (x *Team) GetTopLevelTarget() bool {
+	if x != nil && x.TopLevelTarget != nil {
+		return *x.TopLevelTarget
+	}
+	return false
+}
+
+func (x *Team) GetKind() string {
+	if x != nil && x.Kind != nil {
+		return *x.Kind
+	}
+	return ""
+}
+
+type AllTeams struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Teams []*Team `protobuf:"bytes,1,rep,name=teams" json:"teams,omitempty"`
+}
+
+func (x *AllTeams) Reset() {
+	*x = AllTeams{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_team_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *AllTeams) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*AllTeams) ProtoMessage() {}
+
+func (x *AllTeams) ProtoReflect() protoreflect.Message {
+	mi := &file_team_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use AllTeams.ProtoReflect.Descriptor instead.
+func (*AllTeams) Descriptor() ([]byte, []int) {
+	return file_team_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *AllTeams) GetTeams() []*Team {
+	if x != nil {
+		return x.Teams
+	}
+	return nil
+}
+
+var File_team_proto protoreflect.FileDescriptor
+
+var file_team_proto_rawDesc = []byte{
+	0x0a, 0x0a, 0x74, 0x65, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x74, 0x65,
+	0x61, 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd0, 0x01, 0x0a, 0x04, 0x54, 0x65, 0x61,
+	0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61,
+	0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79,
+	0x5f, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
+	0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x54, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04,
+	0x66, 0x69, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65,
+	0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20,
+	0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x65, 0x73, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x28, 0x0a,
+	0x10, 0x74, 0x6f, 0x70, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65,
+	0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x74, 0x6f, 0x70, 0x4c, 0x65, 0x76, 0x65,
+	0x6c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18,
+	0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0x32, 0x0a, 0x08, 0x41,
+	0x6c, 0x6c, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x26, 0x0a, 0x05, 0x74, 0x65, 0x61, 0x6d, 0x73,
+	0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x65, 0x61, 0x6d, 0x52, 0x05, 0x74, 0x65, 0x61, 0x6d, 0x73, 0x42,
+	0x22, 0x5a, 0x20, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
+	0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x70, 0x72,
+	0x6f, 0x74, 0x6f,
+}
+
+var (
+	file_team_proto_rawDescOnce sync.Once
+	file_team_proto_rawDescData = file_team_proto_rawDesc
+)
+
+func file_team_proto_rawDescGZIP() []byte {
+	file_team_proto_rawDescOnce.Do(func() {
+		file_team_proto_rawDescData = protoimpl.X.CompressGZIP(file_team_proto_rawDescData)
+	})
+	return file_team_proto_rawDescData
+}
+
+var file_team_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_team_proto_goTypes = []interface{}{
+	(*Team)(nil),     // 0: team_proto.Team
+	(*AllTeams)(nil), // 1: team_proto.AllTeams
+}
+var file_team_proto_depIdxs = []int32{
+	0, // 0: team_proto.AllTeams.teams:type_name -> team_proto.Team
+	1, // [1:1] is the sub-list for method output_type
+	1, // [1:1] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_team_proto_init() }
+func file_team_proto_init() {
+	if File_team_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_team_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Team); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_team_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*AllTeams); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_team_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_team_proto_goTypes,
+		DependencyIndexes: file_team_proto_depIdxs,
+		MessageInfos:      file_team_proto_msgTypes,
+	}.Build()
+	File_team_proto = out.File
+	file_team_proto_rawDesc = nil
+	file_team_proto_goTypes = nil
+	file_team_proto_depIdxs = nil
+}
diff --git a/android/team_proto/team.proto b/android/team_proto/team.proto
new file mode 100644
index 0000000..69ebf43
--- /dev/null
+++ b/android/team_proto/team.proto
@@ -0,0 +1,44 @@
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+package team_proto;
+option go_package = "android/soong/android/team_proto";
+
+message Team {
+  // REQUIRED: Name of the build target
+  optional string target_name = 1;
+
+  // REQUIRED: Code location of the target.
+  // To be used to support legacy/backup systems that use OWNERS file and is
+  // also required for our dashboard to support per code location basis UI
+  optional string path = 2;
+
+  // REQUIRED: Team ID of the team that owns this target.
+  optional string trendy_team_id = 3;
+
+  // OPTIONAL: Files directly owned by this module.
+  repeated string file = 4;
+
+  // OPTIONAL: Is this a test-only module.
+  optional bool test_only = 5;
+
+  // OPTIONAL: Is this intended to be run as a test target.
+  // This target can be run directly as a test or passed to tradefed.
+  optional bool top_level_target = 6;
+
+  // OPTIONAL: Name of module kind, i.e. java_library
+  optional string kind = 7;
+}
+
+message AllTeams {
+  repeated Team teams = 1;
+}
diff --git a/android/team_test.go b/android/team_test.go
new file mode 100644
index 0000000..ccfcaaa
--- /dev/null
+++ b/android/team_test.go
@@ -0,0 +1,94 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package android
+
+import (
+	"testing"
+)
+
+type fakeModuleForTests struct {
+	ModuleBase
+}
+
+func fakeModuleFactory() Module {
+	module := &fakeModuleForTests{}
+	InitAndroidModule(module)
+	return module
+}
+
+var prepareForTestWithTeamAndFakeBuildComponents = GroupFixturePreparers(
+	FixtureRegisterWithContext(RegisterTeamBuildComponents),
+	FixtureRegisterWithContext(func(ctx RegistrationContext) {
+		ctx.RegisterModuleType("fake", fakeModuleFactory)
+	}),
+)
+
+func (*fakeModuleForTests) GenerateAndroidBuildActions(ModuleContext) {}
+
+func TestTeam(t *testing.T) {
+	t.Parallel()
+	ctx := prepareForTestWithTeamAndFakeBuildComponents.
+		RunTestWithBp(t, `
+		fake {
+			name: "main_test",
+			team: "someteam",
+		}
+		team {
+			name: "someteam",
+			trendy_team_id: "cool_team",
+		}
+
+		team {
+			name: "team2",
+			trendy_team_id: "22222",
+		}
+
+		fake {
+			name: "tool",
+			team: "team2",
+		}
+	`)
+
+	// Assert the rule from GenerateAndroidBuildActions exists.
+	m := ctx.ModuleForTests("main_test", "")
+	AssertStringEquals(t, "msg", m.Module().base().Team(), "someteam")
+	m = ctx.ModuleForTests("tool", "")
+	AssertStringEquals(t, "msg", m.Module().base().Team(), "team2")
+}
+
+func TestMissingTeamFails(t *testing.T) {
+	t.Parallel()
+	prepareForTestWithTeamAndFakeBuildComponents.
+		ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern("depends on undefined module \"ring-bearer")).
+		RunTestWithBp(t, `
+		fake {
+			name: "you_cannot_pass",
+			team: "ring-bearer",
+		}
+	`)
+}
+
+func TestPackageBadTeamNameFails(t *testing.T) {
+	t.Parallel()
+	GroupFixturePreparers(
+		PrepareForTestWithTeamBuildComponents,
+		PrepareForTestWithPackageModule,
+	).
+		ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern("depends on undefined module \"ring-bearer")).
+		RunTestWithBp(t, `
+		package {
+			default_team: "ring-bearer",
+		}
+	`)
+}
diff --git a/android/test_asserts.go b/android/test_asserts.go
index 3a2cb1a..c33ade5 100644
--- a/android/test_asserts.go
+++ b/android/test_asserts.go
@@ -148,7 +148,7 @@
 		return
 	}
 	if !ok {
-		t.Errorf("%s does not match regular expression %s", s, expectedRex)
+		t.Errorf("%s: %s does not match regular expression %s", message, s, expectedRex)
 	}
 }
 
diff --git a/android/test_config.go b/android/test_config.go
index 2a59d92..a15343a 100644
--- a/android/test_config.go
+++ b/android/test_config.go
@@ -39,11 +39,12 @@
 			DeviceName:                          stringPtr("test_device"),
 			DeviceProduct:                       stringPtr("test_product"),
 			Platform_sdk_version:                intPtr(30),
+			Platform_sdk_version_or_codename:    stringPtr("S"),
 			Platform_sdk_codename:               stringPtr("S"),
 			Platform_base_sdk_extension_version: intPtr(1),
 			Platform_version_active_codenames:   []string{"S", "Tiramisu"},
-			DeviceSystemSdkVersions:             []string{"14", "15"},
-			Platform_systemsdk_versions:         []string{"29", "30"},
+			DeviceSystemSdkVersions:             []string{"29", "30", "S"},
+			Platform_systemsdk_versions:         []string{"29", "30", "S", "Tiramisu"},
 			AAPTConfig:                          []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
 			AAPTPreferredConfig:                 stringPtr("xhdpi"),
 			AAPTCharacteristics:                 stringPtr("nosdcard"),
@@ -61,11 +62,7 @@
 		// passed to PathForSource or PathForModuleSrc.
 		TestAllowNonExistentPaths: true,
 
-		BazelContext:              noopBazelContext{},
-		BuildMode:                 BazelProdMode,
-		mixedBuildDisabledModules: make(map[string]struct{}),
-		mixedBuildEnabledModules:  make(map[string]struct{}),
-		bazelForceEnabledModules:  make(map[string]struct{}),
+		BuildMode: AnalysisNoBazel,
 	}
 	config.deviceConfig = &deviceConfig{
 		config: config,
diff --git a/android/test_suites.go b/android/test_suites.go
index 63a709f..ff75f26 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -14,6 +14,11 @@
 
 package android
 
+import (
+	"path/filepath"
+	"strings"
+)
+
 func init() {
 	RegisterParallelSingletonType("testsuites", testSuiteFilesFactory)
 }
@@ -23,7 +28,8 @@
 }
 
 type testSuiteFiles struct {
-	robolectric WritablePath
+	robolectric []Path
+	ravenwood   []Path
 }
 
 type TestSuiteModule interface {
@@ -47,30 +53,107 @@
 	})
 
 	t.robolectric = robolectricTestSuite(ctx, files["robolectric-tests"])
+	ctx.Phony("robolectric-tests", t.robolectric...)
 
-	ctx.Phony("robolectric-tests", t.robolectric)
+	t.ravenwood = ravenwoodTestSuite(ctx, files["ravenwood-tests"])
+	ctx.Phony("ravenwood-tests", t.ravenwood...)
 }
 
 func (t *testSuiteFiles) MakeVars(ctx MakeVarsContext) {
-	ctx.DistForGoal("robolectric-tests", t.robolectric)
+	ctx.DistForGoal("robolectric-tests", t.robolectric...)
+	ctx.DistForGoal("ravenwood-tests", t.ravenwood...)
 }
 
-func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) WritablePath {
+func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) []Path {
 	var installedPaths InstallPaths
 	for _, module := range SortedKeys(files) {
 		installedPaths = append(installedPaths, files[module]...)
 	}
-	testCasesDir := pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases", false)
 
-	outputFile := PathForOutput(ctx, "packaging", "robolectric-tests.zip")
+	outputFile := pathForPackaging(ctx, "robolectric-tests.zip")
 	rule := NewRuleBuilder(pctx, ctx)
 	rule.Command().BuiltTool("soong_zip").
 		FlagWithOutput("-o ", outputFile).
 		FlagWithArg("-P ", "host/testcases").
-		FlagWithArg("-C ", testCasesDir.String()).
+		FlagWithArg("-C ", pathForTestCases(ctx).String()).
 		FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths()).
-        Flag("-sha256")
+		Flag("-sha256") // necessary to save cas_uploader's time
+
+	testList := buildTestList(ctx, "robolectric-tests_list", installedPaths)
+	testListZipOutputFile := pathForPackaging(ctx, "robolectric-tests_list.zip")
+
+	rule.Command().BuiltTool("soong_zip").
+		FlagWithOutput("-o ", testListZipOutputFile).
+		FlagWithArg("-C ", pathForPackaging(ctx).String()).
+		FlagWithInput("-f ", testList).
+		Flag("-sha256")
+
 	rule.Build("robolectric_tests_zip", "robolectric-tests.zip")
 
+	return []Path{outputFile, testListZipOutputFile}
+}
+
+func ravenwoodTestSuite(ctx SingletonContext, files map[string]InstallPaths) []Path {
+	var installedPaths InstallPaths
+	for _, module := range SortedKeys(files) {
+		installedPaths = append(installedPaths, files[module]...)
+	}
+
+	outputFile := pathForPackaging(ctx, "ravenwood-tests.zip")
+	rule := NewRuleBuilder(pctx, ctx)
+	rule.Command().BuiltTool("soong_zip").
+		FlagWithOutput("-o ", outputFile).
+		FlagWithArg("-P ", "host/testcases").
+		FlagWithArg("-C ", pathForTestCases(ctx).String()).
+		FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths()).
+		Flag("-sha256") // necessary to save cas_uploader's time
+
+	testList := buildTestList(ctx, "ravenwood-tests_list", installedPaths)
+	testListZipOutputFile := pathForPackaging(ctx, "ravenwood-tests_list.zip")
+
+	rule.Command().BuiltTool("soong_zip").
+		FlagWithOutput("-o ", testListZipOutputFile).
+		FlagWithArg("-C ", pathForPackaging(ctx).String()).
+		FlagWithInput("-f ", testList).
+		Flag("-sha256")
+
+	rule.Build("ravenwood_tests_zip", "ravenwood-tests.zip")
+
+	return []Path{outputFile, testListZipOutputFile}
+}
+
+func buildTestList(ctx SingletonContext, listFile string, installedPaths InstallPaths) Path {
+	buf := &strings.Builder{}
+	for _, p := range installedPaths {
+		if p.Ext() != ".config" {
+			continue
+		}
+		pc, err := toTestListPath(p.String(), pathForTestCases(ctx).String(), "host/testcases")
+		if err != nil {
+			ctx.Errorf("Failed to convert path: %s, %v", p.String(), err)
+			continue
+		}
+		buf.WriteString(pc)
+		buf.WriteString("\n")
+	}
+	outputFile := pathForPackaging(ctx, listFile)
+	WriteFileRuleVerbatim(ctx, outputFile, buf.String())
 	return outputFile
 }
+
+func toTestListPath(path, relativeRoot, prefix string) (string, error) {
+	dest, err := filepath.Rel(relativeRoot, path)
+	if err != nil {
+		return "", err
+	}
+	return filepath.Join(prefix, dest), nil
+}
+
+func pathForPackaging(ctx PathContext, pathComponents ...string) OutputPath {
+	pathComponents = append([]string{"packaging"}, pathComponents...)
+	return PathForOutput(ctx, pathComponents...)
+}
+
+func pathForTestCases(ctx PathContext) InstallPath {
+	return pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases")
+}
diff --git a/android/test_suites_test.go b/android/test_suites_test.go
new file mode 100644
index 0000000..db9a34d
--- /dev/null
+++ b/android/test_suites_test.go
@@ -0,0 +1,117 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"path/filepath"
+	"testing"
+)
+
+func TestBuildTestList(t *testing.T) {
+	t.Parallel()
+	ctx := GroupFixturePreparers(
+		prepareForFakeTestSuite,
+		FixtureRegisterWithContext(func(ctx RegistrationContext) {
+			ctx.RegisterParallelSingletonType("testsuites", testSuiteFilesFactory)
+		}),
+	).RunTestWithBp(t, `
+		fake_module {
+			name: "module1",
+			outputs: [
+				"Test1/Test1.config",
+				"Test1/Test1.apk",
+			],
+			test_suites: ["ravenwood-tests"],
+		}
+		fake_module {
+			name: "module2",
+			outputs: [
+				"Test2/Test21/Test21.config",
+				"Test2/Test21/Test21.apk",
+			],
+			test_suites: ["ravenwood-tests", "robolectric-tests"],
+		}
+		fake_module {
+			name: "module_without_config",
+			outputs: [
+				"BadTest/BadTest.jar",
+			],
+			test_suites: ["robolectric-tests"],
+		}
+	`)
+
+	config := ctx.SingletonForTests("testsuites")
+	allOutputs := config.AllOutputs()
+
+	wantContents := map[string]string{
+		"robolectric-tests.zip":      "",
+		"robolectric-tests_list.zip": "",
+		"robolectric-tests_list": `host/testcases/Test2/Test21/Test21.config
+`,
+		"ravenwood-tests.zip":      "",
+		"ravenwood-tests_list.zip": "",
+		"ravenwood-tests_list": `host/testcases/Test1/Test1.config
+host/testcases/Test2/Test21/Test21.config
+`,
+	}
+	for _, output := range allOutputs {
+		want, ok := wantContents[filepath.Base(output)]
+		if !ok {
+			t.Errorf("unexpected output: %q", output)
+			continue
+		}
+
+		got := ""
+		if want != "" {
+			got = ContentFromFileRuleForTests(t, ctx.TestContext, config.MaybeOutput(output))
+		}
+
+		if want != got {
+			t.Errorf("want %q, got %q", want, got)
+		}
+	}
+}
+
+type fake_module struct {
+	ModuleBase
+	props struct {
+		Outputs     []string
+		Test_suites []string
+	}
+}
+
+func fakeTestSuiteFactory() Module {
+	module := &fake_module{}
+	base := module.base()
+	module.AddProperties(&base.nameProperties, &module.props)
+	InitAndroidModule(module)
+	return module
+}
+
+var prepareForFakeTestSuite = GroupFixturePreparers(
+	FixtureRegisterWithContext(func(ctx RegistrationContext) {
+		ctx.RegisterModuleType("fake_module", fakeTestSuiteFactory)
+	}),
+)
+
+func (f *fake_module) GenerateAndroidBuildActions(ctx ModuleContext) {
+	for _, output := range f.props.Outputs {
+		ctx.InstallFile(pathForTestCases(ctx), output, nil)
+	}
+}
+
+func (f *fake_module) TestSuites() []string {
+	return f.props.Test_suites
+}
diff --git a/android/testing.go b/android/testing.go
index 5ad7ad0..7b4411e 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -183,15 +183,14 @@
 type TestContext struct {
 	*Context
 	preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc
-	bp2buildPreArch, bp2buildMutators     []RegisterMutatorFunc
 	NameResolver                          *NameResolver
 
-	// The list of pre-singletons and singletons registered for the test.
-	preSingletons, singletons sortableComponents
+	// The list of singletons registered for the test.
+	singletons sortableComponents
 
-	// The order in which the pre-singletons, mutators and singletons will be run in this test
+	// The order in which the mutators and singletons will be run in this test
 	// context; for debugging.
-	preSingletonOrder, mutatorOrder, singletonOrder []string
+	mutatorOrder, singletonOrder []string
 }
 
 func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) {
@@ -203,7 +202,7 @@
 	ctx.PreArchMutators(f)
 }
 
-func (ctx *TestContext) ModuleProvider(m blueprint.Module, p blueprint.ProviderKey) interface{} {
+func (ctx *TestContext) moduleProvider(m blueprint.Module, p blueprint.AnyProviderKey) (any, bool) {
 	return ctx.Context.ModuleProvider(m, p)
 }
 
@@ -219,14 +218,10 @@
 	ctx.finalDeps = append(ctx.finalDeps, f)
 }
 
-func (ctx *TestContext) RegisterBp2BuildConfig(config Bp2BuildConversionAllowlist) {
-	ctx.config.Bp2buildPackageConfig = config
-}
-
-// PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules
-// into Bazel BUILD targets that should run prior to deps and conversion.
-func (ctx *TestContext) PreArchBp2BuildMutators(f RegisterMutatorFunc) {
-	ctx.bp2buildPreArch = append(ctx.bp2buildPreArch, f)
+func (ctx *TestContext) OtherModuleProviderAdaptor() OtherModuleProviderContext {
+	return NewOtherModuleProviderAdaptor(func(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
+		return ctx.moduleProvider(module, provider)
+	})
 }
 
 // registeredComponentOrder defines the order in which a sortableComponent type is registered at
@@ -397,9 +392,6 @@
 	// Used to ensure that this is only created once.
 	once sync.Once
 
-	// The order of pre-singletons
-	preSingletonOrder registeredComponentOrder
-
 	// The order of mutators
 	mutatorOrder registeredComponentOrder
 
@@ -412,9 +404,6 @@
 // Only the first call has any effect.
 func (s *registrationSorter) populate() {
 	s.once.Do(func() {
-		// Create an ordering from the globally registered pre-singletons.
-		s.preSingletonOrder = registeredComponentOrderFromExistingOrder("pre-singleton", preSingletons)
-
 		// Created an ordering from the globally registered mutators.
 		globallyRegisteredMutators := collateGloballyRegisteredMutators()
 		s.mutatorOrder = registeredComponentOrderFromExistingOrder("mutator", globallyRegisteredMutators)
@@ -441,11 +430,6 @@
 func (ctx *TestContext) Register() {
 	globalOrder := globallyRegisteredComponentsOrder()
 
-	// Ensure that the pre-singletons used in the test are in the same order as they are used at
-	// runtime.
-	globalOrder.preSingletonOrder.enforceOrdering(ctx.preSingletons)
-	ctx.preSingletons.registerAll(ctx.Context)
-
 	mutators := collateRegisteredMutators(ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps)
 	// Ensure that the mutators used in the test are in the same order as they are used at runtime.
 	globalOrder.mutatorOrder.enforceOrdering(mutators)
@@ -456,23 +440,10 @@
 	ctx.singletons.registerAll(ctx.Context)
 
 	// Save the sorted components order away to make them easy to access while debugging.
-	ctx.preSingletonOrder = componentsToNames(preSingletons)
 	ctx.mutatorOrder = componentsToNames(mutators)
 	ctx.singletonOrder = componentsToNames(singletons)
 }
 
-// RegisterForBazelConversion prepares a test context for bp2build conversion.
-func (ctx *TestContext) RegisterForBazelConversion() {
-	ctx.config.BuildMode = Bp2build
-	RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch)
-}
-
-// RegisterForApiBazelConversion prepares a test context for API bp2build conversion.
-func (ctx *TestContext) RegisterForApiBazelConversion() {
-	ctx.config.BuildMode = ApiBp2build
-	RegisterMutatorsForApiBazelConversion(ctx.Context, ctx.bp2buildPreArch)
-}
-
 func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) {
 	// This function adapts the old style ParseFileList calls that are spread throughout the tests
 	// to the new style that takes a config.
@@ -509,10 +480,6 @@
 	ctx.singletons = append(ctx.singletons, newSingleton(name, factory, true))
 }
 
-func (ctx *TestContext) RegisterPreSingletonType(name string, factory SingletonFactory) {
-	ctx.preSingletons = append(ctx.preSingletons, newPreSingleton(name, factory))
-}
-
 // ModuleVariantForTests selects a specific variant of the module with the given
 // name by matching the variations map against the variations of each module
 // variant. A module variant matches the map if every variation that exists in
@@ -758,7 +725,6 @@
 //   - Depfile
 //   - Rspfile
 //   - RspfileContent
-//   - SymlinkOutputs
 //   - CommandDeps
 //   - CommandOrderOnly
 //
@@ -780,8 +746,6 @@
 	bparams.Depfile = normalizeWritablePathRelativeToTop(bparams.Depfile)
 	bparams.Output = normalizeWritablePathRelativeToTop(bparams.Output)
 	bparams.Outputs = bparams.Outputs.RelativeToTop()
-	bparams.SymlinkOutput = normalizeWritablePathRelativeToTop(bparams.SymlinkOutput)
-	bparams.SymlinkOutputs = bparams.SymlinkOutputs.RelativeToTop()
 	bparams.ImplicitOutput = normalizeWritablePathRelativeToTop(bparams.ImplicitOutput)
 	bparams.ImplicitOutputs = bparams.ImplicitOutputs.RelativeToTop()
 	bparams.Input = normalizePathRelativeToTop(bparams.Input)
@@ -799,7 +763,6 @@
 	rparams.Depfile = normalizeStringRelativeToTop(p.config, rparams.Depfile)
 	rparams.Rspfile = normalizeStringRelativeToTop(p.config, rparams.Rspfile)
 	rparams.RspfileContent = normalizeStringRelativeToTop(p.config, rparams.RspfileContent)
-	rparams.SymlinkOutputs = normalizeStringArrayRelativeToTop(p.config, rparams.SymlinkOutputs)
 	rparams.CommandDeps = normalizeStringArrayRelativeToTop(p.config, rparams.CommandDeps)
 	rparams.CommandOrderOnly = normalizeStringArrayRelativeToTop(p.config, rparams.CommandOrderOnly)
 
@@ -1158,6 +1121,7 @@
 	}
 
 	entriesList := p.AndroidMkEntries()
+	aconfigUpdateAndroidMkEntries(ctx, mod.(Module), &entriesList)
 	for i, _ := range entriesList {
 		entriesList[i].fillInEntries(ctx, mod)
 	}
@@ -1173,6 +1137,7 @@
 	}
 	data := p.AndroidMk()
 	data.fillInData(ctx, mod)
+	aconfigUpdateAndroidMkData(ctx, mod.(Module), &data)
 	return data
 }
 
@@ -1315,3 +1280,10 @@
 func StringsRelativeToTop(config Config, command []string) []string {
 	return normalizeStringArrayRelativeToTop(config, command)
 }
+
+func EnsureListContainsSuffix(t *testing.T, result []string, expected string) {
+	t.Helper()
+	if !SuffixInList(result, expected) {
+		t.Errorf("%q is not found in %v", expected, result)
+	}
+}
diff --git a/android/updatable_modules.go b/android/updatable_modules.go
index 71c76c5..1548170 100644
--- a/android/updatable_modules.go
+++ b/android/updatable_modules.go
@@ -14,9 +14,9 @@
 
 package android
 
-// This file contains branch specific constants for building updatable modules.
-// They are stored in a separate file to minimise the potential of merge
-// conflicts between branches when the code from the package is changed.
+// This file contains branch specific constants. They are stored in a separate
+// file to minimise the potential of merge conflicts between branches when
+// the code from the package is changed.
 
 // The default manifest version for all the modules on this branch.
 // This version code will be used only if there is no version field in the
@@ -33,4 +33,4 @@
 // * AOSP            - xx9990000
 // * x-mainline-prod - xx9990000
 // * master          - 990090000
-const DefaultUpdatableModuleVersion = "339990000"
+const DefaultUpdatableModuleVersion = "990090000"
diff --git a/android/util.go b/android/util.go
index 5375373..698a856 100644
--- a/android/util.go
+++ b/android/util.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"cmp"
 	"fmt"
 	"path/filepath"
 	"reflect"
@@ -22,6 +23,7 @@
 	"runtime"
 	"sort"
 	"strings"
+	"sync"
 )
 
 // CopyOf returns a new slice that has the same contents as s.
@@ -61,17 +63,39 @@
 // JoinWithPrefixAndSeparator prepends the prefix to each string in the list and
 // returns them joined together with the given separator.
 func JoinWithPrefixAndSeparator(strs []string, prefix string, sep string) string {
+	return JoinWithPrefixSuffixAndSeparator(strs, prefix, "", sep)
+}
+
+// JoinWithSuffixAndSeparator appends the suffix to each string in the list and
+// returns them joined together with the given separator.
+func JoinWithSuffixAndSeparator(strs []string, suffix string, sep string) string {
+	return JoinWithPrefixSuffixAndSeparator(strs, "", suffix, sep)
+}
+
+// JoinWithPrefixSuffixAndSeparator appends the prefix/suffix to each string in the list and
+// returns them joined together with the given separator.
+func JoinWithPrefixSuffixAndSeparator(strs []string, prefix, suffix, sep string) string {
 	if len(strs) == 0 {
 		return ""
 	}
 
+	// Pre-calculate the length of the result
+	length := 0
+	for _, s := range strs {
+		length += len(s)
+	}
+	length += (len(prefix)+len(suffix))*len(strs) + len(sep)*(len(strs)-1)
+
 	var buf strings.Builder
+	buf.Grow(length)
 	buf.WriteString(prefix)
 	buf.WriteString(strs[0])
+	buf.WriteString(suffix)
 	for i := 1; i < len(strs); i++ {
 		buf.WriteString(sep)
 		buf.WriteString(prefix)
 		buf.WriteString(strs[i])
+		buf.WriteString(suffix)
 	}
 	return buf.String()
 }
@@ -83,15 +107,8 @@
 	return SortedKeys(m)
 }
 
-type Ordered interface {
-	~string |
-		~float32 | ~float64 |
-		~int | ~int8 | ~int16 | ~int32 | ~int64 |
-		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
-}
-
 // SortedKeys returns the keys of the given map in the ascending order.
-func SortedKeys[T Ordered, V any](m map[T]V) []T {
+func SortedKeys[T cmp.Ordered, V any](m map[T]V) []T {
 	if len(m) == 0 {
 		return nil
 	}
@@ -507,22 +524,27 @@
 	return root, suffix, ext
 }
 
-// ShardPaths takes a Paths, and returns a slice of Paths where each one has at most shardSize paths.
-func ShardPaths(paths Paths, shardSize int) []Paths {
-	if len(paths) == 0 {
+func shard[T ~[]E, E any](toShard T, shardSize int) []T {
+	if len(toShard) == 0 {
 		return nil
 	}
-	ret := make([]Paths, 0, (len(paths)+shardSize-1)/shardSize)
-	for len(paths) > shardSize {
-		ret = append(ret, paths[0:shardSize])
-		paths = paths[shardSize:]
+
+	ret := make([]T, 0, (len(toShard)+shardSize-1)/shardSize)
+	for len(toShard) > shardSize {
+		ret = append(ret, toShard[0:shardSize])
+		toShard = toShard[shardSize:]
 	}
-	if len(paths) > 0 {
-		ret = append(ret, paths)
+	if len(toShard) > 0 {
+		ret = append(ret, toShard)
 	}
 	return ret
 }
 
+// ShardPaths takes a Paths, and returns a slice of Paths where each one has at most shardSize paths.
+func ShardPaths(paths Paths, shardSize int) []Paths {
+	return shard(paths, shardSize)
+}
+
 // ShardString takes a string and returns a slice of strings where the length of each one is
 // at most shardSize.
 func ShardString(s string, shardSize int) []string {
@@ -543,18 +565,7 @@
 // ShardStrings takes a slice of strings, and returns a slice of slices of strings where each one has at most shardSize
 // elements.
 func ShardStrings(s []string, shardSize int) [][]string {
-	if len(s) == 0 {
-		return nil
-	}
-	ret := make([][]string, 0, (len(s)+shardSize-1)/shardSize)
-	for len(s) > shardSize {
-		ret = append(ret, s[0:shardSize])
-		s = s[shardSize:]
-	}
-	if len(s) > 0 {
-		ret = append(ret, s)
-	}
-	return ret
+	return shard(s, shardSize)
 }
 
 // CheckDuplicate checks if there are duplicates in given string list.
@@ -569,3 +580,38 @@
 	}
 	return "", false
 }
+
+func AddToStringSet(set map[string]bool, items []string) {
+	for _, item := range items {
+		set[item] = true
+	}
+}
+
+// SyncMap is a wrapper around sync.Map that provides type safety via generics.
+type SyncMap[K comparable, V any] struct {
+	sync.Map
+}
+
+// Load returns the value stored in the map for a key, or the zero value if no
+// value is present.
+// The ok result indicates whether value was found in the map.
+func (m *SyncMap[K, V]) Load(key K) (value V, ok bool) {
+	v, ok := m.Map.Load(key)
+	if !ok {
+		return *new(V), false
+	}
+	return v.(V), true
+}
+
+// Store sets the value for a key.
+func (m *SyncMap[K, V]) Store(key K, value V) {
+	m.Map.Store(key, value)
+}
+
+// LoadOrStore returns the existing value for the key if present.
+// Otherwise, it stores and returns the given value.
+// The loaded result is true if the value was loaded, false if stored.
+func (m *SyncMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) {
+	v, loaded := m.Map.LoadOrStore(key, value)
+	return v.(V), loaded
+}
diff --git a/android/util_test.go b/android/util_test.go
index 20161e5..8e73d83 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"cmp"
 	"fmt"
 	"reflect"
 	"strconv"
@@ -650,7 +651,7 @@
 	}
 }
 
-func testSortedKeysHelper[K Ordered, V any](t *testing.T, name string, input map[K]V, expected []K) {
+func testSortedKeysHelper[K cmp.Ordered, V any](t *testing.T, name string, input map[K]V, expected []K) {
 	t.Helper()
 	t.Run(name, func(t *testing.T) {
 		actual := SortedKeys(input)
@@ -811,7 +812,7 @@
 			if !reflect.DeepEqual(slice, testCase.expected) {
 				t.Errorf("expected %#v, got %#v", testCase.expected, slice)
 			}
-			if slice != nil && unsafe.SliceData(testCase.in) == unsafe.SliceData(slice) {
+			if cap(slice) > 0 && unsafe.SliceData(testCase.in) == unsafe.SliceData(slice) {
 				t.Errorf("expected slices to have different backing arrays")
 			}
 		})
diff --git a/android/variable.go b/android/variable.go
index 664ead7..599f88e 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -20,9 +20,6 @@
 	"runtime"
 	"strings"
 
-	"android/soong/android/soongconfig"
-	"android/soong/bazel"
-
 	"github.com/google/blueprint/proptools"
 )
 
@@ -74,6 +71,7 @@
 			Cflags              []string `android:"arch_variant"`
 			Shared_libs         []string `android:"arch_variant"`
 			Whole_static_libs   []string `android:"arch_variant"`
+			Static_libs         []string `android:"arch_variant"`
 			Exclude_static_libs []string `android:"arch_variant"`
 			Srcs                []string `android:"arch_variant"`
 			Header_libs         []string `android:"arch_variant"`
@@ -138,6 +136,9 @@
 
 			Srcs         []string
 			Exclude_srcs []string
+			Cmd          *string
+
+			Deps []string
 		}
 
 		// eng is true for -eng builds, and can be used to turn on additional heavyweight debugging
@@ -192,26 +193,28 @@
 	// Suffix to add to generated Makefiles
 	Make_suffix *string `json:",omitempty"`
 
-	BuildId         *string `json:",omitempty"`
-	BuildNumberFile *string `json:",omitempty"`
+	BuildId             *string `json:",omitempty"`
+	BuildNumberFile     *string `json:",omitempty"`
+	BuildHostnameFile   *string `json:",omitempty"`
+	BuildThumbprintFile *string `json:",omitempty"`
+	DisplayBuildNumber  *bool   `json:",omitempty"`
 
-	Platform_version_name                     *string  `json:",omitempty"`
-	Platform_sdk_version                      *int     `json:",omitempty"`
-	Platform_sdk_codename                     *string  `json:",omitempty"`
-	Platform_sdk_version_or_codename          *string  `json:",omitempty"`
-	Platform_sdk_final                        *bool    `json:",omitempty"`
-	Platform_sdk_extension_version            *int     `json:",omitempty"`
-	Platform_base_sdk_extension_version       *int     `json:",omitempty"`
-	Platform_version_active_codenames         []string `json:",omitempty"`
-	Platform_version_all_preview_codenames    []string `json:",omitempty"`
-	Platform_vndk_version                     *string  `json:",omitempty"`
-	Platform_systemsdk_versions               []string `json:",omitempty"`
-	Platform_security_patch                   *string  `json:",omitempty"`
-	Platform_preview_sdk_version              *string  `json:",omitempty"`
-	Platform_min_supported_target_sdk_version *string  `json:",omitempty"`
-	Platform_base_os                          *string  `json:",omitempty"`
-	Platform_version_last_stable              *string  `json:",omitempty"`
-	Platform_version_known_codenames          *string  `json:",omitempty"`
+	Platform_display_version_name          *string  `json:",omitempty"`
+	Platform_version_name                  *string  `json:",omitempty"`
+	Platform_sdk_version                   *int     `json:",omitempty"`
+	Platform_sdk_codename                  *string  `json:",omitempty"`
+	Platform_sdk_version_or_codename       *string  `json:",omitempty"`
+	Platform_sdk_final                     *bool    `json:",omitempty"`
+	Platform_sdk_extension_version         *int     `json:",omitempty"`
+	Platform_base_sdk_extension_version    *int     `json:",omitempty"`
+	Platform_version_active_codenames      []string `json:",omitempty"`
+	Platform_version_all_preview_codenames []string `json:",omitempty"`
+	Platform_systemsdk_versions            []string `json:",omitempty"`
+	Platform_security_patch                *string  `json:",omitempty"`
+	Platform_preview_sdk_version           *string  `json:",omitempty"`
+	Platform_base_os                       *string  `json:",omitempty"`
+	Platform_version_last_stable           *string  `json:",omitempty"`
+	Platform_version_known_codenames       *string  `json:",omitempty"`
 
 	DeviceName                            *string  `json:",omitempty"`
 	DeviceProduct                         *string  `json:",omitempty"`
@@ -223,7 +226,9 @@
 	DeviceCurrentApiLevelForVendorModules *string  `json:",omitempty"`
 	DeviceSystemSdkVersions               []string `json:",omitempty"`
 	DeviceMaxPageSizeSupported            *string  `json:",omitempty"`
-	DevicePageSizeAgnostic                *bool    `json:",omitempty"`
+	DeviceNoBionicPageSizeMacro           *bool    `json:",omitempty"`
+
+	VendorApiLevel *string `json:",omitempty"`
 
 	RecoverySnapshotVersion *string `json:",omitempty"`
 
@@ -293,6 +298,8 @@
 	MinimizeJavaDebugInfo        *bool    `json:",omitempty"`
 	Build_from_text_stub         *bool    `json:",omitempty"`
 
+	BuildType *string `json:",omitempty"`
+
 	Check_elf_files *bool `json:",omitempty"`
 
 	UncompressPrivAppDex             *bool    `json:",omitempty"`
@@ -314,6 +321,7 @@
 	MemtagHeapSyncIncludePaths  []string `json:",omitempty"`
 
 	HWASanIncludePaths []string `json:",omitempty"`
+	HWASanExcludePaths []string `json:",omitempty"`
 
 	VendorPath    *string `json:",omitempty"`
 	OdmPath       *string `json:",omitempty"`
@@ -371,21 +379,14 @@
 
 	MultitreeUpdateMeta bool `json:",omitempty"`
 
-	BoardVendorSepolicyDirs           []string `json:",omitempty"`
-	BoardOdmSepolicyDirs              []string `json:",omitempty"`
-	BoardReqdMaskPolicy               []string `json:",omitempty"`
-	BoardPlatVendorPolicy             []string `json:",omitempty"`
-	BoardSystemExtPublicPrebuiltDirs  []string `json:",omitempty"`
-	BoardSystemExtPrivatePrebuiltDirs []string `json:",omitempty"`
-	BoardProductPublicPrebuiltDirs    []string `json:",omitempty"`
-	BoardProductPrivatePrebuiltDirs   []string `json:",omitempty"`
-	SystemExtPublicSepolicyDirs       []string `json:",omitempty"`
-	SystemExtPrivateSepolicyDirs      []string `json:",omitempty"`
-	BoardSepolicyM4Defs               []string `json:",omitempty"`
+	BoardVendorSepolicyDirs      []string `json:",omitempty"`
+	BoardOdmSepolicyDirs         []string `json:",omitempty"`
+	SystemExtPublicSepolicyDirs  []string `json:",omitempty"`
+	SystemExtPrivateSepolicyDirs []string `json:",omitempty"`
+	BoardSepolicyM4Defs          []string `json:",omitempty"`
 
 	BoardSepolicyVers       *string `json:",omitempty"`
 	PlatformSepolicyVersion *string `json:",omitempty"`
-	TotSepolicyVersion      *string `json:",omitempty"`
 
 	SystemExtSepolicyPrebuiltApiDir *string `json:",omitempty"`
 	ProductSepolicyPrebuiltApiDir   *string `json:",omitempty"`
@@ -422,8 +423,6 @@
 	ProductPublicSepolicyDirs  []string `json:",omitempty"`
 	ProductPrivateSepolicyDirs []string `json:",omitempty"`
 
-	ProductVndkVersion *string `json:",omitempty"`
-
 	TargetFSConfigGen []string `json:",omitempty"`
 
 	EnforceProductPartitionInterface *bool `json:",omitempty"`
@@ -442,16 +441,18 @@
 
 	ShippingApiLevel *string `json:",omitempty"`
 
-	BuildBrokenPluginValidation        []string `json:",omitempty"`
-	BuildBrokenClangAsFlags            bool     `json:",omitempty"`
-	BuildBrokenClangCFlags             bool     `json:",omitempty"`
-	BuildBrokenClangProperty           bool     `json:",omitempty"`
-	GenruleSandboxing                  *bool    `json:",omitempty"`
-	BuildBrokenEnforceSyspropOwner     bool     `json:",omitempty"`
-	BuildBrokenTrebleSyspropNeverallow bool     `json:",omitempty"`
-	BuildBrokenUsesSoongPython2Modules bool     `json:",omitempty"`
-	BuildBrokenVendorPropertyNamespace bool     `json:",omitempty"`
-	BuildBrokenInputDirModules         []string `json:",omitempty"`
+	BuildBrokenPluginValidation         []string `json:",omitempty"`
+	BuildBrokenClangAsFlags             bool     `json:",omitempty"`
+	BuildBrokenClangCFlags              bool     `json:",omitempty"`
+	BuildBrokenClangProperty            bool     `json:",omitempty"`
+	GenruleSandboxing                   *bool    `json:",omitempty"`
+	BuildBrokenEnforceSyspropOwner      bool     `json:",omitempty"`
+	BuildBrokenTrebleSyspropNeverallow  bool     `json:",omitempty"`
+	BuildBrokenUsesSoongPython2Modules  bool     `json:",omitempty"`
+	BuildBrokenVendorPropertyNamespace  bool     `json:",omitempty"`
+	BuildBrokenIncorrectPartitionImages bool     `json:",omitempty"`
+	BuildBrokenInputDirModules          []string `json:",omitempty"`
+	BuildBrokenDontCheckSystemSdk       bool     `json:",omitempty"`
 
 	BuildWarningBadOptionalUsesLibsAllowlist []string `json:",omitempty"`
 
@@ -475,14 +476,96 @@
 
 	AfdoProfiles []string `json:",omitempty"`
 
-	ProductManufacturer string   `json:",omitempty"`
-	ProductBrand        string   `json:",omitempty"`
-	BuildVersionTags    []string `json:",omitempty"`
+	ProductManufacturer string `json:",omitempty"`
+	ProductBrand        string `json:",omitempty"`
 
 	ReleaseVersion          string   `json:",omitempty"`
 	ReleaseAconfigValueSets []string `json:",omitempty"`
 
+	ReleaseAconfigFlagDefaultPermission string `json:",omitempty"`
+
+	ReleaseDefaultModuleBuildFromSource *bool `json:",omitempty"`
+
 	KeepVndk *bool `json:",omitempty"`
+
+	CheckVendorSeappViolations *bool `json:",omitempty"`
+
+	BuildFlags map[string]string `json:",omitempty"`
+
+	BuildFromSourceStub *bool `json:",omitempty"`
+
+	BuildIgnoreApexContributionContents *bool `json:",omitempty"`
+
+	HiddenapiExportableStubs *bool `json:",omitempty"`
+
+	ExportRuntimeApis *bool `json:",omitempty"`
+
+	AconfigContainerValidation string `json:",omitempty"`
+
+	ProductLocales []string `json:",omitempty"`
+
+	ProductDefaultWifiChannels []string `json:",omitempty"`
+
+	BoardUseVbmetaDigestInFingerprint *bool `json:",omitempty"`
+
+	OemProperties []string `json:",omitempty"`
+}
+
+type PartitionQualifiedVariablesType struct {
+	BuildingImage               bool   `json:",omitempty"`
+	BoardErofsCompressor        string `json:",omitempty"`
+	BoardErofsCompressHints     string `json:",omitempty"`
+	BoardErofsPclusterSize      string `json:",omitempty"`
+	BoardExtfsInodeCount        string `json:",omitempty"`
+	BoardExtfsRsvPct            string `json:",omitempty"`
+	BoardF2fsSloadCompressFlags string `json:",omitempty"`
+	BoardFileSystemCompress     string `json:",omitempty"`
+	BoardFileSystemType         string `json:",omitempty"`
+	BoardJournalSize            string `json:",omitempty"`
+	BoardPartitionReservedSize  string `json:",omitempty"`
+	BoardPartitionSize          string `json:",omitempty"`
+	BoardSquashfsBlockSize      string `json:",omitempty"`
+	BoardSquashfsCompressor     string `json:",omitempty"`
+	BoardSquashfsCompressorOpt  string `json:",omitempty"`
+	BoardSquashfsDisable4kAlign string `json:",omitempty"`
+	ProductBaseFsPath           string `json:",omitempty"`
+	ProductHeadroom             string `json:",omitempty"`
+	ProductVerityPartition      string `json:",omitempty"`
+
+	BoardAvbAddHashtreeFooterArgs string `json:",omitempty"`
+	BoardAvbKeyPath               string `json:",omitempty"`
+	BoardAvbAlgorithm             string `json:",omitempty"`
+	BoardAvbRollbackIndex         string `json:",omitempty"`
+	BoardAvbRollbackIndexLocation string `json:",omitempty"`
+}
+
+type PartitionVariables struct {
+	ProductDirectory            string `json:",omitempty"`
+	PartitionQualifiedVariables map[string]PartitionQualifiedVariablesType
+	TargetUserimagesUseExt2     bool `json:",omitempty"`
+	TargetUserimagesUseExt3     bool `json:",omitempty"`
+	TargetUserimagesUseExt4     bool `json:",omitempty"`
+
+	TargetUserimagesSparseExtDisabled      bool `json:",omitempty"`
+	TargetUserimagesSparseErofsDisabled    bool `json:",omitempty"`
+	TargetUserimagesSparseSquashfsDisabled bool `json:",omitempty"`
+	TargetUserimagesSparseF2fsDisabled     bool `json:",omitempty"`
+
+	BoardErofsCompressor           string `json:",omitempty"`
+	BoardErofsCompressorHints      string `json:",omitempty"`
+	BoardErofsPclusterSize         string `json:",omitempty"`
+	BoardErofsShareDupBlocks       string `json:",omitempty"`
+	BoardErofsUseLegacyCompression string `json:",omitempty"`
+	BoardExt4ShareDupBlocks        string `json:",omitempty"`
+	BoardFlashLogicalBlockSize     string `json:",omitempty"`
+	BoardFlashEraseBlockSize       string `json:",omitempty"`
+	BoardUsesRecoveryAsBoot        bool   `json:",omitempty"`
+	ProductUseDynamicPartitionSize bool   `json:",omitempty"`
+	CopyImagesForTargetFilesZip    bool   `json:",omitempty"`
+
+	BoardAvbEnable bool `json:",omitempty"`
+
+	ProductPackages []string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
@@ -508,22 +591,21 @@
 		Platform_sdk_final:                     boolPtr(false),
 		Platform_version_active_codenames:      []string{"S"},
 		Platform_version_all_preview_codenames: []string{"S"},
-		Platform_vndk_version:                  stringPtr("S"),
 
-		HostArch:                   stringPtr("x86_64"),
-		HostSecondaryArch:          stringPtr("x86"),
-		DeviceName:                 stringPtr("generic_arm64"),
-		DeviceProduct:              stringPtr("aosp_arm-eng"),
-		DeviceArch:                 stringPtr("arm64"),
-		DeviceArchVariant:          stringPtr("armv8-a"),
-		DeviceCpuVariant:           stringPtr("generic"),
-		DeviceAbi:                  []string{"arm64-v8a"},
-		DeviceSecondaryArch:        stringPtr("arm"),
-		DeviceSecondaryArchVariant: stringPtr("armv8-a"),
-		DeviceSecondaryCpuVariant:  stringPtr("generic"),
-		DeviceSecondaryAbi:         []string{"armeabi-v7a", "armeabi"},
-		DeviceMaxPageSizeSupported: stringPtr("4096"),
-		DevicePageSizeAgnostic:     boolPtr(false),
+		HostArch:                    stringPtr("x86_64"),
+		HostSecondaryArch:           stringPtr("x86"),
+		DeviceName:                  stringPtr("generic_arm64"),
+		DeviceProduct:               stringPtr("aosp_arm-eng"),
+		DeviceArch:                  stringPtr("arm64"),
+		DeviceArchVariant:           stringPtr("armv8-a"),
+		DeviceCpuVariant:            stringPtr("generic"),
+		DeviceAbi:                   []string{"arm64-v8a"},
+		DeviceSecondaryArch:         stringPtr("arm"),
+		DeviceSecondaryArchVariant:  stringPtr("armv8-a"),
+		DeviceSecondaryCpuVariant:   stringPtr("generic"),
+		DeviceSecondaryAbi:          []string{"armeabi-v7a", "armeabi"},
+		DeviceMaxPageSizeSupported:  stringPtr("4096"),
+		DeviceNoBionicPageSizeMacro: boolPtr(false),
 
 		AAPTConfig:          []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
 		AAPTPreferredConfig: stringPtr("xhdpi"),
@@ -548,417 +630,12 @@
 	}
 }
 
-// ProductConfigContext requires the access to the Module to get product config properties.
-type ProductConfigContext interface {
-	Module() Module
-}
-
-// ProductConfigOrSoongConfigProperty represents either a soong config variable + its value
-// or a product config variable. You can get both a ConfigurationAxis and a SelectKey from it
-// for use in bazel attributes. ProductVariableProperties() will return a map from properties ->
-// this interface -> property structs for use in bp2build converters
-type ProductConfigOrSoongConfigProperty interface {
-	// Name of the product variable or soong config variable
-	Name() string
-	// AlwaysEmit returns true for soong config variables but false for product variables. This
-	// is intended to indicate if we need to always emit empty lists in the select statements.
-	AlwaysEmit() bool
-	// ConfigurationAxis returns the bazel.ConfigurationAxis that represents this variable. The
-	// configuration axis will change depending on the variable and whether it's arch/os variant
-	// as well.
-	ConfigurationAxis() bazel.ConfigurationAxis
-	// SelectKey returns a string that represents the key of a select branch, however, it is not
-	// actually the real label written out to the build file.
-	// this.ConfigurationAxis().SelectKey(this.SelectKey()) will give the actual label.
-	SelectKey() string
-}
-
-// ProductConfigProperty represents a product config variable, and if it is arch-variant or not.
-type ProductConfigProperty struct {
-	// The name of the product variable, e.g. "safestack", "malloc_not_svelte",
-	// "board"
-	name string
-
-	arch string
-}
-
-func (p ProductConfigProperty) Name() string {
-	return p.name
-}
-
-func (p ProductConfigProperty) AlwaysEmit() bool {
-	return false
-}
-
-func (p ProductConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis {
-	return bazel.ProductVariableConfigurationAxis(p.arch != "", p.name+"__"+p.arch)
-}
-
-func (p ProductConfigProperty) SelectKey() string {
-	if p.arch == "" {
-		return strings.ToLower(p.name)
-	} else {
-		return strings.ToLower(p.name + "-" + p.arch)
+func (this *ProductVariables) GetBuildFlagBool(flag string) bool {
+	val, ok := this.BuildFlags[flag]
+	if !ok {
+		return false
 	}
-}
-
-// SoongConfigProperty represents a soong config variable, its value if it's a string variable,
-// and if it's dependent on the OS or not
-type SoongConfigProperty struct {
-	name      string
-	namespace string
-	// Can be an empty string for bool/value soong config variables
-	value string
-	// If there is a target: field inside a soong config property struct, the os that it selects
-	// on will be represented here.
-	os string
-}
-
-func (p SoongConfigProperty) Name() string {
-	return p.name
-}
-
-func (p SoongConfigProperty) AlwaysEmit() bool {
-	return true
-}
-
-func (p SoongConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis {
-	return bazel.ProductVariableConfigurationAxis(false, p.namespace+"__"+p.name+"__"+p.os)
-}
-
-// SelectKey returns the literal string that represents this variable in a BUILD
-// select statement.
-func (p SoongConfigProperty) SelectKey() string {
-	// p.value being conditions_default can happen with or without a desired os. When not using
-	// an os, we want to emit literally just //conditions:default in the select statement, but
-	// when using an os, we want to emit namespace__name__conditions_default__os, so that
-	// the branch is only taken if the variable is not set, and we're on the desired os.
-	// ConfigurationAxis#SelectKey will map the conditions_default result of this function to
-	// //conditions:default.
-	if p.value == bazel.ConditionsDefaultConfigKey && p.os == "" {
-		return bazel.ConditionsDefaultConfigKey
-	}
-
-	parts := []string{p.namespace, p.name}
-	if p.value != "" && p.value != bazel.ConditionsDefaultSelectKey {
-		parts = append(parts, p.value)
-	}
-	if p.os != "" {
-		parts = append(parts, p.os)
-	}
-
-	// e.g. acme__feature1, android__board__soc_a, my_namespace__my_variables__my_value__my_os
-	return strings.ToLower(strings.Join(parts, "__"))
-}
-
-// ProductConfigProperties is a map of maps to group property values according
-// their property name and the product config variable they're set under.
-//
-// The outer map key is the name of the property, like "cflags".
-//
-// The inner map key is a ProductConfigProperty, which is a struct of product
-// variable name, namespace, and the "full configuration" of the product
-// variable.
-//
-// e.g. product variable name: board, namespace: acme, full config: vendor_chip_foo
-//
-// The value of the map is the interface{} representing the value of the
-// property, like ["-DDEFINES"] for cflags.
-type ProductConfigProperties map[string]map[ProductConfigOrSoongConfigProperty]interface{}
-
-// ProductVariableProperties returns a ProductConfigProperties containing only the properties which
-// have been set for the given module.
-func ProductVariableProperties(ctx ArchVariantContext, module Module) ProductConfigProperties {
-	moduleBase := module.base()
-
-	productConfigProperties := ProductConfigProperties{}
-
-	if moduleBase.variableProperties != nil {
-		productVariablesProperty := proptools.FieldNameForProperty("product_variables")
-		for /* axis */ _, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
-			for config, props := range configToProps {
-				variableValues := reflect.ValueOf(props).Elem().FieldByName(productVariablesProperty)
-				productConfigProperties.AddProductConfigProperties(variableValues, config)
-			}
-		}
-	}
-
-	if m, ok := module.(Bazelable); ok && m.namespacedVariableProps() != nil {
-		for namespace, namespacedVariableProps := range m.namespacedVariableProps() {
-			for _, namespacedVariableProp := range namespacedVariableProps {
-				variableValues := reflect.ValueOf(namespacedVariableProp).Elem().FieldByName(soongconfig.SoongConfigProperty)
-				productConfigProperties.AddSoongConfigProperties(namespace, variableValues)
-			}
-		}
-	}
-
-	return productConfigProperties
-}
-
-func (p *ProductConfigProperties) AddProductConfigProperty(
-	propertyName, productVariableName, arch string, propertyValue interface{}) {
-
-	productConfigProp := ProductConfigProperty{
-		name: productVariableName, // e.g. size, feature1, feature2, FEATURE3, board
-		arch: arch,                // e.g. "", x86, arm64
-	}
-
-	p.AddEitherProperty(propertyName, productConfigProp, propertyValue)
-}
-
-func (p *ProductConfigProperties) AddSoongConfigProperty(
-	propertyName, namespace, variableName, value, os string, propertyValue interface{}) {
-
-	soongConfigProp := SoongConfigProperty{
-		namespace: namespace,
-		name:      variableName, // e.g. size, feature1, feature2, FEATURE3, board
-		value:     value,
-		os:        os, // e.g. android, linux_x86
-	}
-
-	p.AddEitherProperty(propertyName, soongConfigProp, propertyValue)
-}
-
-func (p *ProductConfigProperties) AddEitherProperty(
-	propertyName string, key ProductConfigOrSoongConfigProperty, propertyValue interface{}) {
-	if (*p)[propertyName] == nil {
-		(*p)[propertyName] = make(map[ProductConfigOrSoongConfigProperty]interface{})
-	}
-
-	if existing, ok := (*p)[propertyName][key]; ok {
-		switch dst := existing.(type) {
-		case []string:
-			src, ok := propertyValue.([]string)
-			if !ok {
-				panic("Conflicting types")
-			}
-			dst = append(dst, src...)
-			(*p)[propertyName][key] = dst
-		default:
-			if existing != propertyValue {
-				panic(fmt.Errorf("TODO: handle merging value %#v", existing))
-			}
-		}
-	} else {
-		(*p)[propertyName][key] = propertyValue
-	}
-}
-
-var (
-	conditionsDefaultField string = proptools.FieldNameForProperty(bazel.ConditionsDefaultConfigKey)
-)
-
-// maybeExtractConfigVarProp attempts to read this value as a config var struct
-// wrapped by interfaces and ptrs. If it's not the right type, the second return
-// value is false.
-func maybeExtractConfigVarProp(v reflect.Value) (reflect.Value, bool) {
-	if v.Kind() == reflect.Interface {
-		// The conditions_default value can be either
-		// 1) an ptr to an interface of a struct (bool config variables and product variables)
-		// 2) an interface of 1) (config variables with nested structs, like string vars)
-		v = v.Elem()
-	}
-	if v.Kind() != reflect.Ptr {
-		return v, false
-	}
-	v = reflect.Indirect(v)
-	if v.Kind() == reflect.Interface {
-		// Extract the struct from the interface
-		v = v.Elem()
-	}
-
-	if !v.IsValid() {
-		return v, false
-	}
-
-	if v.Kind() != reflect.Struct {
-		return v, false
-	}
-	return v, true
-}
-
-func (productConfigProperties *ProductConfigProperties) AddProductConfigProperties(variableValues reflect.Value, arch string) {
-	// Example of product_variables:
-	//
-	// product_variables: {
-	//     malloc_not_svelte: {
-	//         shared_libs: ["malloc_not_svelte_shared_lib"],
-	//         whole_static_libs: ["malloc_not_svelte_whole_static_lib"],
-	//         exclude_static_libs: [
-	//             "malloc_not_svelte_static_lib_excludes",
-	//             "malloc_not_svelte_whole_static_lib_excludes",
-	//         ],
-	//     },
-	// },
-
-	for i := 0; i < variableValues.NumField(); i++ {
-		// e.g. Platform_sdk_version, Unbundled_build, Malloc_not_svelte, etc.
-		productVariableName := variableValues.Type().Field(i).Name
-
-		variableValue := variableValues.Field(i)
-		// Check if any properties were set for the module
-		if variableValue.IsZero() {
-			// e.g. feature1: {}, malloc_not_svelte: {}
-			continue
-		}
-
-		for j := 0; j < variableValue.NumField(); j++ {
-			property := variableValue.Field(j)
-			// e.g. Asflags, Cflags, Enabled, etc.
-			propertyName := variableValue.Type().Field(j).Name
-			if property.Kind() != reflect.Interface {
-				productConfigProperties.AddProductConfigProperty(propertyName, productVariableName, arch, property.Interface())
-			}
-		}
-	}
-
-}
-
-func (productConfigProperties *ProductConfigProperties) AddSoongConfigProperties(namespace string, soongConfigVariablesStruct reflect.Value) {
-	//
-	// Example of soong_config_variables:
-	//
-	// soong_config_variables: {
-	//      feature1: {
-	//          conditions_default: {
-	//               ...
-	//          },
-	//          cflags: ...
-	//      },
-	//      feature2: {
-	//          cflags: ...
-	//          conditions_default: {
-	//               ...
-	//          },
-	//      },
-	//      board: {
-	//         soc_a: {
-	//             ...
-	//         },
-	//         soc_b: {
-	//             ...
-	//         },
-	//         soc_c: {},
-	//         conditions_default: {
-	//              ...
-	//         },
-	//      },
-	// }
-	for i := 0; i < soongConfigVariablesStruct.NumField(); i++ {
-		// e.g. feature1, feature2, board
-		variableName := soongConfigVariablesStruct.Type().Field(i).Name
-		variableStruct := soongConfigVariablesStruct.Field(i)
-		// Check if any properties were set for the module
-		if variableStruct.IsZero() {
-			// e.g. feature1: {}
-			continue
-		}
-
-		// Unlike product variables, config variables require a few more
-		// indirections to extract the struct from the reflect.Value.
-		if v, ok := maybeExtractConfigVarProp(variableStruct); ok {
-			variableStruct = v
-		} else if !v.IsValid() {
-			// Skip invalid variables which may not used, else leads to panic
-			continue
-		}
-
-		for j := 0; j < variableStruct.NumField(); j++ {
-			propertyOrStruct := variableStruct.Field(j)
-			// propertyOrValueName can either be:
-			//  - A property, like: Asflags, Cflags, Enabled, etc.
-			//  - A soong config string variable's value, like soc_a, soc_b, soc_c in the example above
-			//  - "conditions_default"
-			propertyOrValueName := variableStruct.Type().Field(j).Name
-
-			// If the property wasn't set, no need to pass it along
-			if propertyOrStruct.IsZero() {
-				continue
-			}
-
-			if v, ok := maybeExtractConfigVarProp(propertyOrStruct); ok {
-				// The field is a struct, which is used by:
-				// 1) soong_config_string_variables
-				//
-				// soc_a: {
-				//     cflags: ...,
-				// }
-				//
-				// soc_b: {
-				//     cflags: ...,
-				// }
-				//
-				// 2) conditions_default structs for all soong config variable types.
-				//
-				// conditions_default: {
-				//     cflags: ...,
-				//     static_libs: ...
-				// }
-				//
-				// This means that propertyOrValueName is either conditions_default, or a soong
-				// config string variable's value.
-				field := v
-				// Iterate over fields of this struct prop.
-				for k := 0; k < field.NumField(); k++ {
-					// For product variables, zero values are irrelevant; however, for soong config variables,
-					// empty values are relevant because there can also be a conditions default which is not
-					// applied for empty variables.
-					if field.Field(k).IsZero() && namespace == "" {
-						continue
-					}
-
-					propertyName := field.Type().Field(k).Name
-					if propertyName == "Target" {
-						productConfigProperties.AddSoongConfigPropertiesFromTargetStruct(namespace, variableName, proptools.PropertyNameForField(propertyOrValueName), field.Field(k))
-					} else if propertyName == "Arch" || propertyName == "Multilib" {
-						panic("Arch/Multilib are not currently supported in soong config variable structs")
-					} else {
-						productConfigProperties.AddSoongConfigProperty(propertyName, namespace, variableName, proptools.PropertyNameForField(propertyOrValueName), "", field.Field(k).Interface())
-					}
-				}
-			} else if propertyOrStruct.Kind() != reflect.Interface {
-				// If not an interface, then this is not a conditions_default or
-				// a struct prop. That is, this is a bool/value config variable.
-				if propertyOrValueName == "Target" {
-					productConfigProperties.AddSoongConfigPropertiesFromTargetStruct(namespace, variableName, "", propertyOrStruct)
-				} else if propertyOrValueName == "Arch" || propertyOrValueName == "Multilib" {
-					panic("Arch/Multilib are not currently supported in soong config variable structs")
-				} else {
-					productConfigProperties.AddSoongConfigProperty(propertyOrValueName, namespace, variableName, "", "", propertyOrStruct.Interface())
-				}
-			}
-		}
-	}
-}
-
-func (productConfigProperties *ProductConfigProperties) AddSoongConfigPropertiesFromTargetStruct(namespace, soongConfigVariableName string, soongConfigVariableValue string, targetStruct reflect.Value) {
-	// targetStruct will be a struct with fields like "android", "host", "arm", "x86",
-	// "android_arm", etc. The values of each of those fields will be a regular property struct.
-	for i := 0; i < targetStruct.NumField(); i++ {
-		targetFieldName := targetStruct.Type().Field(i).Name
-		archOrOsSpecificStruct := targetStruct.Field(i)
-		for j := 0; j < archOrOsSpecificStruct.NumField(); j++ {
-			property := archOrOsSpecificStruct.Field(j)
-			// e.g. Asflags, Cflags, Enabled, etc.
-			propertyName := archOrOsSpecificStruct.Type().Field(j).Name
-
-			if targetFieldName == "Android" {
-				productConfigProperties.AddSoongConfigProperty(propertyName, namespace, soongConfigVariableName, soongConfigVariableValue, "android", property.Interface())
-			} else if targetFieldName == "Host" {
-				for _, os := range osTypeList {
-					if os.Class == Host {
-						productConfigProperties.AddSoongConfigProperty(propertyName, namespace, soongConfigVariableName, soongConfigVariableValue, os.Name, property.Interface())
-					}
-				}
-			} else if !archOrOsSpecificStruct.IsZero() {
-				// One problem with supporting additional fields is that if multiple branches of
-				// "target" overlap, we don't want them to be in the same select statement (aka
-				// configuration axis). "android" and "host" are disjoint, so it's ok that we only
-				// have 2 axes right now. (soongConfigVariables and soongConfigVariablesPlusOs)
-				panic("TODO: support other target types in soong config variable structs: " + targetFieldName)
-			}
-		}
-	}
+	return val == "true"
 }
 
 func VariableMutator(mctx BottomUpMutatorContext) {
diff --git a/android/visibility.go b/android/visibility.go
index 3130135..89c0adc 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -57,12 +57,24 @@
 
 var visibilityRuleRegexp = regexp.MustCompile(visibilityRulePattern)
 
+type visibilityModuleReference struct {
+	name   qualifiedModuleName
+	module Module
+}
+
+func createVisibilityModuleReference(name, dir string, module Module) visibilityModuleReference {
+	return visibilityModuleReference{
+		name:   createQualifiedModuleName(name, dir),
+		module: module,
+	}
+}
+
 // A visibility rule is associated with a module and determines which other modules it is visible
 // to, i.e. which other modules can depend on the rule's module.
 type visibilityRule interface {
 	// Check to see whether this rules matches m.
 	// Returns true if it does, false otherwise.
-	matches(m qualifiedModuleName) bool
+	matches(m visibilityModuleReference) bool
 
 	String() string
 }
@@ -108,8 +120,10 @@
 // ["//visibility:private"].
 type compositeRule []visibilityRule
 
+var _ visibilityRule = compositeRule{}
+
 // A compositeRule matches if and only if any of its rules matches.
-func (c compositeRule) matches(m qualifiedModuleName) bool {
+func (c compositeRule) matches(m visibilityModuleReference) bool {
 	for _, r := range c {
 		if r.matches(m) {
 			return true
@@ -135,8 +149,10 @@
 	pkg string
 }
 
-func (r packageRule) matches(m qualifiedModuleName) bool {
-	return m.pkg == r.pkg
+var _ visibilityRule = packageRule{}
+
+func (r packageRule) matches(m visibilityModuleReference) bool {
+	return m.name.pkg == r.pkg
 }
 
 func (r packageRule) String() string {
@@ -149,8 +165,10 @@
 	pkgPrefix string
 }
 
-func (r subpackagesRule) matches(m qualifiedModuleName) bool {
-	return isAncestor(r.pkgPrefix, m.pkg)
+var _ visibilityRule = subpackagesRule{}
+
+func (r subpackagesRule) matches(m visibilityModuleReference) bool {
+	return isAncestor(r.pkgPrefix, m.name.pkg)
 }
 
 func isAncestor(p1 string, p2 string) bool {
@@ -168,7 +186,9 @@
 // visibilityRule for //visibility:public
 type publicRule struct{}
 
-func (r publicRule) matches(_ qualifiedModuleName) bool {
+var _ visibilityRule = publicRule{}
+
+func (r publicRule) matches(_ visibilityModuleReference) bool {
 	return true
 }
 
@@ -179,7 +199,9 @@
 // visibilityRule for //visibility:private
 type privateRule struct{}
 
-func (r privateRule) matches(_ qualifiedModuleName) bool {
+var _ visibilityRule = privateRule{}
+
+func (r privateRule) matches(_ visibilityModuleReference) bool {
 	return false
 }
 
@@ -187,8 +209,37 @@
 	return "//visibility:private"
 }
 
+var anyPartitionRegex = regexp.MustCompile("^any_(system|system_ext|vendor|product|data|odm)_partition$")
+
+// visibilityRule for //visibility:any_partition
+type anyPartitionRule struct {
+	partitionType string
+}
+
+var _ visibilityRule = anyPartitionRule{}
+
+type PartitionTypeInterface interface {
+	PartitionType() string
+}
+
+func (r anyPartitionRule) matches(m visibilityModuleReference) bool {
+	if m2, ok := m.module.(PartitionTypeInterface); ok {
+		return m2.PartitionType() == r.partitionType
+	}
+	return false
+}
+
+func (r anyPartitionRule) String() string {
+	return "//visibility:any_" + r.partitionType + "_partition"
+}
+
 var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
 
+type visibilityRulesForModule struct {
+	rule                   compositeRule
+	implicitPartitionRules compositeRule
+}
+
 // The map from qualifiedModuleName to visibilityRule.
 func moduleToVisibilityRuleMap(config Config) *sync.Map {
 	return config.Once(visibilityRuleMap, func() interface{} {
@@ -237,13 +288,10 @@
 
 // Checks the per-module visibility rule lists before defaults expansion.
 func visibilityRuleChecker(ctx BottomUpMutatorContext) {
-	qualified := createQualifiedModuleName(ctx.ModuleName(), ctx.ModuleDir())
-	if m, ok := ctx.Module().(Module); ok {
-		visibilityProperties := m.visibilityProperties()
-		for _, p := range visibilityProperties {
-			if visibility := p.getStrings(); visibility != nil {
-				checkRules(ctx, qualified.pkg, p.getName(), visibility)
-			}
+	visibilityProperties := ctx.Module().visibilityProperties()
+	for _, p := range visibilityProperties {
+		if visibility := p.getStrings(); visibility != nil {
+			checkRules(ctx, ctx.ModuleDir(), p.getName(), visibility)
 		}
 	}
 }
@@ -274,6 +322,10 @@
 				// This keyword does not create a rule so pretend it does not exist.
 				ruleCount -= 1
 			default:
+				if anyPartitionRegex.MatchString(name) {
+					// any_*_partition can be used with another visibility fields
+					continue
+				}
 				ctx.PropertyErrorf(property, "unrecognized visibility rule %q", v)
 				continue
 			}
@@ -305,25 +357,27 @@
 //
 // See ../README.md#Visibility for information on the format of the visibility rules.
 func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
-	m, ok := ctx.Module().(Module)
-	if !ok {
-		return
-	}
+	m := ctx.Module()
 
 	qualifiedModuleId := m.qualifiedModuleId(ctx)
 	currentPkg := qualifiedModuleId.pkg
 
 	// Parse the visibility rules that control access to the module and store them by id
 	// for use when enforcing the rules.
+	var rule compositeRule
 	primaryProperty := m.base().primaryVisibilityProperty
 	if primaryProperty != nil {
 		if visibility := primaryProperty.getStrings(); visibility != nil {
-			rule := parseRules(ctx, currentPkg, primaryProperty.getName(), visibility)
-			if rule != nil {
-				moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, rule)
-			}
+			rule = parseRules(ctx, currentPkg, primaryProperty.getName(), visibility)
 		}
 	}
+	ipr := implicitPartitionRules(ctx)
+	if rule != nil || ipr != nil {
+		moduleToVisibilityRuleMap(ctx.Config()).Store(qualifiedModuleId, visibilityRulesForModule{
+			rule:                   rule,
+			implicitPartitionRules: ipr,
+		})
+	}
 }
 
 func parseRules(ctx BaseModuleContext, currentPkg, property string, visibility []string) compositeRule {
@@ -355,6 +409,13 @@
 				hasNonPrivateRule = false
 				// This does not actually create a rule so continue onto the next rule.
 				continue
+			default:
+				match := anyPartitionRegex.FindStringSubmatch(name)
+				if match != nil {
+					r = anyPartitionRule{
+						partitionType: match[1],
+					}
+				}
 			}
 		} else {
 			switch name {
@@ -393,12 +454,25 @@
 	return rules
 }
 
+func implicitPartitionRules(ctx BaseModuleContext) compositeRule {
+	var result compositeRule
+	if ctx.SocSpecific() {
+		result = append(result, anyPartitionRule{partitionType: "vendor"})
+	} else if ctx.ProductSpecific() {
+		result = append(result, anyPartitionRule{partitionType: "product"})
+	} else if ctx.Module().InstallInData() {
+		result = append(result, anyPartitionRule{partitionType: "data"})
+	} else if ctx.SystemExtSpecific() {
+		result = append(result, anyPartitionRule{partitionType: "system_ext"})
+	} else if ctx.DeviceSpecific() {
+		result = append(result, anyPartitionRule{partitionType: "odm"})
+	}
+	return result
+}
+
 func isAllowedFromOutsideVendor(pkg string, name string) bool {
 	if pkg == "vendor" {
-		if name == "__subpackages__" {
-			return true
-		}
-		return false
+		return name == "__subpackages__"
 	}
 
 	return !isAncestor("vendor", pkg)
@@ -434,11 +508,7 @@
 }
 
 func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
-	if _, ok := ctx.Module().(Module); !ok {
-		return
-	}
-
-	qualified := createQualifiedModuleName(ctx.ModuleName(), ctx.ModuleDir())
+	qualified := createVisibilityModuleReference(ctx.ModuleName(), ctx.ModuleDir(), ctx.Module())
 
 	// Visit all the dependencies making sure that this module has access to them all.
 	ctx.VisitDirectDeps(func(dep Module) {
@@ -453,7 +523,7 @@
 		depQualified := qualifiedModuleName{depDir, depName}
 
 		// Targets are always visible to other targets in their own package.
-		if depQualified.pkg == qualified.pkg {
+		if depQualified.pkg == qualified.name.pkg {
 			return
 		}
 
@@ -473,12 +543,15 @@
 // which is currently //visibility:public.
 func effectiveVisibilityRules(config Config, qualified qualifiedModuleName) compositeRule {
 	moduleToVisibilityRule := moduleToVisibilityRuleMap(config)
-	value, ok := moduleToVisibilityRule.Load(qualified)
+	value := visibilityRulesForModule{}
+	if valueRaw, ok := moduleToVisibilityRule.Load(qualified); ok {
+		value = valueRaw.(visibilityRulesForModule)
+	}
 	var rule compositeRule
-	if ok {
-		rule = value.(compositeRule)
+	if value.rule != nil {
+		rule = value.rule
 	} else {
-		rule = packageDefaultVisibility(config, qualified)
+		rule = packageDefaultVisibility(moduleToVisibilityRule, qualified)
 	}
 
 	// If no rule is specified then return the default visibility rule to avoid
@@ -486,6 +559,20 @@
 	if rule == nil {
 		rule = defaultVisibility
 	}
+
+	// If a partition rule wasn't specified, add implicit partition visibility
+	// rules based on the partition properties like vendor: true.
+	foundPartitionRule := false
+	for _, r := range rule {
+		if _, ok := r.(anyPartitionRule); ok {
+			foundPartitionRule = true
+			break
+		}
+	}
+	if !foundPartitionRule {
+		rule = append(rule, value.implicitPartitionRules...)
+	}
+
 	return rule
 }
 
@@ -494,13 +581,12 @@
 	return qualified
 }
 
-func packageDefaultVisibility(config Config, moduleId qualifiedModuleName) compositeRule {
-	moduleToVisibilityRule := moduleToVisibilityRuleMap(config)
+func packageDefaultVisibility(moduleToVisibilityRule *sync.Map, moduleId qualifiedModuleName) compositeRule {
 	packageQualifiedId := moduleId.getContainingPackageId()
 	for {
 		value, ok := moduleToVisibilityRule.Load(packageQualifiedId)
 		if ok {
-			return value.(compositeRule)
+			return value.(visibilityRulesForModule).rule
 		}
 
 		if packageQualifiedId.isRootPackage() {
@@ -574,10 +660,12 @@
 
 	rule := effectiveVisibilityRules(ctx.Config(), qualified)
 
+	currentModule := createVisibilityModuleReference(moduleName, dir, module)
+
 	// Modules are implicitly visible to other modules in the same package,
 	// without checking the visibility rules. Here we need to add that visibility
 	// explicitly.
-	if !rule.matches(qualified) {
+	if !rule.matches(currentModule) {
 		if len(rule) == 1 {
 			if _, ok := rule[0].(privateRule); ok {
 				// If the rule is //visibility:private we can't append another
diff --git a/android/visibility_test.go b/android/visibility_test.go
index a66f0b6..1a2eeca 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -1904,6 +1904,124 @@
 				}`),
 		},
 	},
+	{
+		name: "any_system_partition visibility works",
+		fs: MockFS{
+			"top/Android.bp": []byte(`
+				android_filesystem {
+					name: "foo",
+					deps: ["bar"],
+				}`),
+			"top/nested/Android.bp": []byte(`
+				package(default_visibility=["//visibility:private"])
+				mock_library {
+					name: "bar",
+					visibility: ["//visibility:any_system_partition"],
+				}`),
+		},
+	},
+	{
+		name: "any_system_partition visibility works with the other visibility",
+		fs: MockFS{
+			"top/Android.bp": []byte(`
+				android_filesystem {
+					name: "foo",
+					deps: ["bar"],
+				}`),
+			"top2/Android.bp": []byte(``),
+			"top/nested/Android.bp": []byte(`
+				package(default_visibility=["//visibility:private"])
+				mock_library {
+					name: "bar",
+					visibility: [
+						"//top2",
+						"//visibility:any_system_partition"
+					],
+				}`),
+		},
+	},
+	{
+		name: "any_system_partition visibility doesn't work for non-partitions",
+		fs: MockFS{
+			"top/Android.bp": []byte(`
+				mock_library {
+					name: "foo",
+					deps: ["bar"],
+				}`),
+			"top/nested/Android.bp": []byte(`
+				mock_library {
+					name: "bar",
+					visibility: ["//visibility:any_system_partition"],
+				}`),
+		},
+		expectedErrors: []string{`module "foo" variant "android_common": depends on //top/nested:bar which is not visible to this module`},
+	},
+	{
+		name: "any_system_partition visibility doesn't work for vendor partitions",
+		fs: MockFS{
+			"top/Android.bp": []byte(`
+				android_filesystem {
+					name: "foo",
+					partition_type: "vendor",
+					deps: ["bar"],
+				}`),
+			"top/nested/Android.bp": []byte(`
+				package(default_visibility=["//visibility:private"])
+				mock_library {
+					name: "bar",
+					visibility: ["//visibility:any_system_partition"],
+				}`),
+		},
+		expectedErrors: []string{`module "foo" variant "android_common": depends on //top/nested:bar which is not visible to this module`},
+	},
+	{
+		name: "Vendor modules are visible to any vendor partition by default",
+		fs: MockFS{
+			"top/Android.bp": []byte(`
+				android_filesystem {
+					name: "foo",
+					partition_type: "vendor",
+					deps: ["bar"],
+				}`),
+			"top/nested/Android.bp": []byte(`
+				package(default_visibility=["//visibility:private"])
+				mock_library {
+					name: "bar",
+					vendor: true,
+				}`),
+		},
+	},
+	{
+		name: "Not visible to vendor partitions when using any_system_partiton, even if vendor: true",
+		fs: MockFS{
+			"top/Android.bp": []byte(`
+				android_filesystem {
+					name: "foo",
+					partition_type: "vendor",
+					deps: ["bar"],
+				}`),
+			"top/nested/Android.bp": []byte(`
+				package(default_visibility=["//visibility:private"])
+				mock_library {
+					name: "bar",
+					vendor: true,
+					visibility: ["//visibility:any_system_partition"],
+				}`),
+		},
+		expectedErrors: []string{`module "foo" variant "android_common": depends on //top/nested:bar which is not visible to this module`},
+	},
+	{
+		name: "unknown any_partition specs throw errors",
+		fs: MockFS{
+			"top/nested/Android.bp": []byte(`
+				package(default_visibility=["//visibility:private"])
+				mock_library {
+					name: "bar",
+					visibility: ["//visibility:any_unknown_partition"],
+				}`),
+		},
+		expectedErrors: []string{`unrecognized visibility rule "//visibility:any_unknown_partition"`},
+	},
 }
 
 func TestVisibility(t *testing.T) {
@@ -1925,6 +2043,7 @@
 					ctx.RegisterModuleType("mock_library", newMockLibraryModule)
 					ctx.RegisterModuleType("mock_parent", newMockParentFactory)
 					ctx.RegisterModuleType("mock_defaults", defaultsFactory)
+					ctx.RegisterModuleType("android_filesystem", newMockFilesystemModule)
 				}),
 				prepareForTestWithFakePrebuiltModules,
 				// Add additional files to the mock filesystem
@@ -1978,6 +2097,37 @@
 func (p *mockLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
 }
 
+type mockFilesystemModuleProperties struct {
+	Partition_type *string
+	Deps           []string
+}
+
+type mockFilesystemModule struct {
+	ModuleBase
+	properties mockFilesystemModuleProperties
+}
+
+func (j *mockFilesystemModule) DepsMutator(ctx BottomUpMutatorContext) {
+	ctx.AddVariationDependencies(nil, dependencyTag{name: "mockdeps"}, j.properties.Deps...)
+}
+
+func (p *mockFilesystemModule) GenerateAndroidBuildActions(ModuleContext) {
+}
+
+func (p *mockFilesystemModule) PartitionType() string {
+	if p.properties.Partition_type == nil {
+		return "system"
+	}
+	return *p.properties.Partition_type
+}
+
+func newMockFilesystemModule() Module {
+	m := &mockFilesystemModule{}
+	m.AddProperties(&m.properties)
+	InitAndroidArchModule(m, DeviceSupported, MultilibCommon)
+	return m
+}
+
 type mockDefaults struct {
 	ModuleBase
 	DefaultsModuleBase
diff --git a/android_sdk/sdk_repo_host.go b/android_sdk/sdk_repo_host.go
index 7212a07..373e883 100644
--- a/android_sdk/sdk_repo_host.go
+++ b/android_sdk/sdk_repo_host.go
@@ -165,10 +165,11 @@
 				Flag(dir.Join(ctx, strip).String())
 		}
 	} else {
+		llvmObjCopy := config.ClangPath(ctx, "bin/llvm-objcopy")
 		llvmStrip := config.ClangPath(ctx, "bin/llvm-strip")
 		llvmLib := config.ClangPath(ctx, "lib/x86_64-unknown-linux-gnu/libc++.so")
 		for _, strip := range s.properties.Strip_files {
-			cmd := builder.Command().Tool(llvmStrip).ImplicitTool(llvmLib)
+			cmd := builder.Command().Tool(llvmStrip).ImplicitTool(llvmLib).ImplicitTool(llvmObjCopy)
 			if !ctx.Windows() {
 				cmd.Flag("-x")
 			}
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index 954f8d0..9d61e1c 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -64,6 +64,8 @@
 	"LOCAL_SANITIZE_DIAG":                  sanitize("diag."),
 	"LOCAL_STRIP_MODULE":                   strip(),
 	"LOCAL_CFLAGS":                         cflags,
+	"LOCAL_PROTOC_FLAGS":                   protoLocalIncludeDirs,
+	"LOCAL_PROTO_JAVA_OUTPUT_PARAMS":       protoOutputParams,
 	"LOCAL_UNINSTALLABLE_MODULE":           invert("installable"),
 	"LOCAL_PROGUARD_ENABLED":               proguardEnabled,
 	"LOCAL_MODULE_PATH":                    prebuiltModulePath,
@@ -86,6 +88,7 @@
 
 	"LOCAL_ANNOTATION_PROCESSOR_CLASSES": skip, // Soong gets the processor classes from the plugin
 	"LOCAL_CTS_TEST_PACKAGE":             skip, // Obsolete
+	"LOCAL_XTS_TEST_PACKAGE":             skip, // Obsolete
 	"LOCAL_JACK_ENABLED":                 skip, // Obselete
 	"LOCAL_JACK_FLAGS":                   skip, // Obselete
 }
@@ -106,6 +109,7 @@
 			"LOCAL_ARM_MODE_HACK":           "instruction_set",
 			"LOCAL_SDK_VERSION":             "sdk_version",
 			"LOCAL_MIN_SDK_VERSION":         "min_sdk_version",
+			"LOCAL_TARGET_SDK_VERSION":      "target_sdk_version",
 			"LOCAL_NDK_STL_VARIANT":         "stl",
 			"LOCAL_JAR_MANIFEST":            "manifest",
 			"LOCAL_CERTIFICATE":             "certificate",
@@ -758,6 +762,27 @@
 	return includeVariableNow(bpVariable{"cflags", bpparser.ListType}, ctx)
 }
 
+func protoOutputParams(ctx variableAssignmentContext) error {
+	// The Soong replacement for LOCAL_PROTO_JAVA_OUTPUT_PARAMS doesn't need ","
+	ctx.mkvalue = ctx.mkvalue.Clone()
+	ctx.mkvalue.ReplaceLiteral(`, `, ` `)
+	return includeVariableNow(bpVariable{"proto.output_params", bpparser.ListType}, ctx)
+}
+
+func protoLocalIncludeDirs(ctx variableAssignmentContext) error {
+	// The Soong replacement for LOCAL_PROTOC_FLAGS includes "--proto_path=$(LOCAL_PATH)/..."
+	ctx.mkvalue = ctx.mkvalue.Clone()
+	if len(ctx.mkvalue.Strings) >= 1 && strings.Contains(ctx.mkvalue.Strings[0], "--proto_path=") {
+		ctx.mkvalue.Strings[0] = strings.Replace(ctx.mkvalue.Strings[0], "--proto_path=", "", 1)
+		paths, err := localizePaths(ctx)
+		if err == nil {
+			err = setVariable(ctx.file, ctx.append, ctx.prefix, "proto.local_include_dirs", paths, true)
+		}
+		return err
+	}
+	return fmt.Errorf("Currently LOCAL_PROTOC_FLAGS only support with value '--proto_path=$(LOCAL_PATH)/...'")
+}
+
 func proguardEnabled(ctx variableAssignmentContext) error {
 	val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType)
 	if err != nil {
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index afde68b..1dd479c 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -511,6 +511,22 @@
 		`,
 	},
 	{
+		// Unsupported function case because that doesn't work in bp
+		desc: "error for unsupported functions",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(filter-out filter-out-file.java ,$(call all-java-files-under, src))
+LOCAL_PACKAGE_NAME := foo
+include $(BUILD_PACKAGE)
+`,
+		expected: `
+android_app {
+	name: "foo",
+	srcs: ["UNSUPPORTED FUNCTION:filter-out filter-out-file.java  src/**/*.java"],
+}
+		`,
+	},
+	{
 		desc: "ignore all-makefiles-under",
 		in: `
 include $(call all-makefiles-under,$(LOCAL_PATH))
@@ -823,6 +839,26 @@
 `,
 	},
 	{
+		desc: "IGNORE_LOCAL_XTS_TEST_PACKAGE",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := FooTest
+LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_XTS_TEST_PACKAGE := foo.bar
+LOCAL_COMPATIBILITY_SUPPORT_FILES := file1
+include $(BUILD_CTS_PACKAGE)
+`,
+		expected: `
+android_test {
+    name: "FooTest",
+    defaults: ["cts_defaults"],
+    test_suites: ["cts"],
+
+    data: ["file1"],
+}
+`,
+	},
+	{
 		desc: "BUILD_CTS_*_JAVA_LIBRARY",
 		in: `
 include $(CLEAR_VARS)
@@ -1450,6 +1486,7 @@
 LOCAL_PRODUCT_MODULE := true
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
 LOCAL_SDK_VERSION := current
+LOCAL_TARGET_SDK_VERSION := target_version
 LOCAL_RRO_THEME := FooTheme
 
 include $(BUILD_RRO_PACKAGE)
@@ -1460,6 +1497,7 @@
 	product_specific: true,
 
 	sdk_version: "current",
+	target_sdk_version: "target_version",
 	theme: "FooTheme",
 
 }
@@ -1705,9 +1743,34 @@
 }
 `,
 	},
+	{
+		desc: "LOCAL_PROTO_JAVA_OUTPUT_PARAMS",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := enum_style=java, parcelable_messages=true
+LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos
+include $(BUILD_PACKAGE)
+		`,
+		expected: `
+android_app {
+	name: "foo",
+	proto: {
+        output_params: [
+            "enum_style=java",
+            "parcelable_messages=true",
+        ],
+		local_include_dirs: ["protos"],
+    },
+}
+`,
+	},
 }
 
 func TestEndToEnd(t *testing.T) {
+	// Skip checking Android.mk path with cleaning "ANDROID_BUILD_TOP"
+	t.Setenv("ANDROID_BUILD_TOP", "")
+
 	for i, test := range testCases {
 		expected, err := bpfix.Reformat(test.expected)
 		if err != nil {
diff --git a/androidmk/parser/parser.go b/androidmk/parser/parser.go
index fb6be38..8a20bb0 100644
--- a/androidmk/parser/parser.go
+++ b/androidmk/parser/parser.go
@@ -413,6 +413,9 @@
 				p.accept('\t')
 				newLine = false
 				continue loop
+			} else if p.tok == '\n' {
+				p.accept('\n')
+				continue loop
 			} else if p.parseDirective() {
 				newLine = false
 				continue
diff --git a/androidmk/parser/parser_test.go b/androidmk/parser/parser_test.go
index 9efebf8..db3313d 100644
--- a/androidmk/parser/parser_test.go
+++ b/androidmk/parser/parser_test.go
@@ -84,6 +84,22 @@
 			},
 		},
 	},
+	{
+		name: "Blank line in rule's command",
+		in:   `all:
+	echo first line
+
+	echo second line`,
+		out: []Node{
+			&Rule{
+				Target: SimpleMakeString("all", NoPos),
+				RecipePos: NoPos,
+				Recipe: "echo first line\necho second line",
+				Prerequisites: SimpleMakeString("", NoPos),
+			},
+		},
+	},
+
 }
 
 func TestParse(t *testing.T) {
diff --git a/androidmk/parser/scope.go b/androidmk/parser/scope.go
index 8111c89..e1a523a 100644
--- a/androidmk/parser/scope.go
+++ b/androidmk/parser/scope.go
@@ -14,9 +14,7 @@
 
 package parser
 
-import (
-	"strings"
-)
+import "strings"
 
 type Scope interface {
 	Get(name string) string
@@ -88,7 +86,7 @@
 			if fname == "call" {
 				return scope.Call(argVals[0], argVals[1:]), true
 			} else {
-				return []string{"__builtin_func:" + fname + " " + strings.Join(argVals, " ")}, true
+				return []string{"UNSUPPORTED FUNCTION:" + fname + " " + strings.Join(argVals, " ")}, true
 			}
 		}
 	}
diff --git a/apex/Android.bp b/apex/Android.bp
index 0791497..abae9e2 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -8,8 +8,9 @@
     deps: [
         "blueprint",
         "soong",
+        "soong-aconfig",
+        "soong-aconfig-codegen",
         "soong-android",
-        "soong-bazel",
         "soong-bpf",
         "soong-cc",
         "soong-filesystem",
@@ -26,7 +27,6 @@
         "apex_sdk_member.go",
         "apex_singleton.go",
         "builder.go",
-        "bp2build.go",
         "deapexer.go",
         "key.go",
         "prebuilt.go",
@@ -40,7 +40,6 @@
         "dexpreopt_bootjars_test.go",
         "platform_bootclasspath_test.go",
         "systemserver_classpath_fragment_test.go",
-        "vndk_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/apex/aconfig_test.go b/apex/aconfig_test.go
new file mode 100644
index 0000000..726041c
--- /dev/null
+++ b/apex/aconfig_test.go
@@ -0,0 +1,800 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package apex
+
+import (
+	"testing"
+
+	"android/soong/aconfig/codegen"
+	"android/soong/android"
+	"android/soong/cc"
+	"android/soong/genrule"
+	"android/soong/java"
+	"android/soong/rust"
+	"github.com/google/blueprint/proptools"
+)
+
+var withAconfigValidationError = android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+	variables.AconfigContainerValidation = "error"
+	variables.BuildId = proptools.StringPtr("TEST.BUILD_ID")
+})
+
+func TestValidationAcrossContainersExportedPass(t *testing.T) {
+	testCases := []struct {
+		name string
+		bp   string
+	}{
+		{
+			name: "Java lib passes for exported containers cross",
+			bp: apex_default_bp + `
+				apex {
+					name: "myapex",
+					manifest: ":myapex.manifest",
+					androidManifest: ":myapex.androidmanifest",
+					key: "myapex.key",
+					java_libs: [
+						"my_java_library_foo",
+					],
+					updatable: false,
+				}
+				java_library {
+					name: "my_java_library_foo",
+					srcs: ["foo/bar/MyClass.java"],
+					sdk_version: "none",
+					system_modules: "none",
+					static_libs: ["my_java_aconfig_library_foo"],
+					apex_available: [
+						"myapex",
+					],
+				}
+				aconfig_declarations {
+					name: "my_aconfig_declarations_foo",
+					package: "com.example.package",
+					container: "otherapex",
+					srcs: ["foo.aconfig"],
+					exportable: true,
+				}
+				java_aconfig_library {
+					name: "my_java_aconfig_library_foo",
+					aconfig_declarations: "my_aconfig_declarations_foo",
+					mode: "exported",
+					apex_available: [
+						"myapex",
+					],
+				}`,
+		},
+		{
+			name: "Android app passes for exported containers cross",
+			bp: apex_default_bp + `
+				apex {
+					name: "myapex",
+					manifest: ":myapex.manifest",
+					androidManifest: ":myapex.androidmanifest",
+					key: "myapex.key",
+					apps: [
+						"my_android_app_foo",
+					],
+					updatable: false,
+				}
+				android_app {
+					name: "my_android_app_foo",
+					srcs: ["foo/MyClass.java"],
+					sdk_version: "none",
+					system_modules: "none",
+					stl: "none",
+					static_libs: ["my_java_library_bar"],
+					apex_available: [ "myapex" ],
+				}
+				java_library {
+					name: "my_java_library_bar",
+					srcs: ["foo/bar/MyClass.java"],
+					sdk_version: "none",
+					system_modules: "none",
+					static_libs: ["my_java_aconfig_library_bar"],
+					apex_available: [
+						"myapex",
+					],
+				}
+				aconfig_declarations {
+					name: "my_aconfig_declarations_bar",
+					package: "com.example.package",
+					container: "otherapex",
+					srcs: ["bar.aconfig"],
+					exportable: true,
+				}
+				java_aconfig_library {
+					name: "my_java_aconfig_library_bar",
+					aconfig_declarations: "my_aconfig_declarations_bar",
+					mode: "exported",
+					apex_available: [
+						"myapex",
+					],
+				}`,
+		},
+		{
+			name: "Cc lib passes for exported containers cross",
+			bp: apex_default_bp + `
+				apex {
+					name: "myapex",
+					manifest: ":myapex.manifest",
+					androidManifest: ":myapex.androidmanifest",
+					key: "myapex.key",
+					native_shared_libs: [
+						"my_cc_library_bar",
+					],
+					binaries: [
+						"my_cc_binary_baz",
+					],
+					updatable: false,
+				}
+				cc_library {
+					name: "my_cc_library_bar",
+					srcs: ["foo/bar/MyClass.cc"],
+					static_libs: [
+						"my_cc_aconfig_library_bar",
+						"my_cc_aconfig_library_baz",
+					],
+					apex_available: [
+						"myapex",
+					],
+				}
+				cc_binary {
+					name: "my_cc_binary_baz",
+					srcs: ["foo/bar/MyClass.cc"],
+					static_libs: ["my_cc_aconfig_library_baz"],
+					apex_available: [
+						"myapex",
+					],
+				}
+				cc_library {
+					name: "server_configurable_flags",
+					srcs: ["server_configurable_flags.cc"],
+				}
+				cc_library {
+					name: "libbase",
+					srcs: ["libbase.cc"],
+			                apex_available: [
+				            "myapex",
+			                ],
+				}
+				cc_library {
+					name: "libaconfig_storage_read_api_cc",
+					srcs: ["libaconfig_storage_read_api_cc.cc"],
+				}
+				cc_library {
+					name: "libaconfig_storage_protos_cc",
+					srcs: ["libaconfig_storage_protos_cc.cc"],
+				}
+				aconfig_declarations {
+					name: "my_aconfig_declarations_bar",
+					package: "com.example.package",
+					container: "otherapex",
+					srcs: ["bar.aconfig"],
+					exportable: true,
+				}
+				cc_aconfig_library {
+					name: "my_cc_aconfig_library_bar",
+					aconfig_declarations: "my_aconfig_declarations_bar",
+					apex_available: [
+						"myapex",
+					],
+					mode: "exported",
+				}
+				aconfig_declarations {
+					name: "my_aconfig_declarations_baz",
+					package: "com.example.package",
+					container: "otherapex",
+					srcs: ["baz.aconfig"],
+					exportable: true,
+				}
+				cc_aconfig_library {
+					name: "my_cc_aconfig_library_baz",
+					aconfig_declarations: "my_aconfig_declarations_baz",
+					apex_available: [
+						"myapex",
+					],
+					mode: "exported",
+				}`,
+		},
+		{
+			name: "Rust lib passes for exported containers cross",
+			bp: apex_default_bp + `
+			apex {
+				name: "myapex",
+				manifest: ":myapex.manifest",
+				androidManifest: ":myapex.androidmanifest",
+				key: "myapex.key",
+				native_shared_libs: ["libmy_rust_library"],
+				binaries: ["my_rust_binary"],
+				updatable: false,
+			}
+			rust_library {
+				name: "libflags_rust", // test mock
+				crate_name: "flags_rust",
+				srcs: ["lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "liblazy_static", // test mock
+				crate_name: "lazy_static",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "libaconfig_storage_read_api", // test mock
+				crate_name: "aconfig_storage_read_api",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "liblogger", // test mock
+				crate_name: "logger",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "liblog_rust", // test mock
+				crate_name: "log_rust",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+                        }
+			rust_ffi_shared {
+				name: "libmy_rust_library",
+				srcs: ["src/lib.rs"],
+				rustlibs: ["libmy_rust_aconfig_library_foo"],
+				crate_name: "my_rust_library",
+				apex_available: ["myapex"],
+			}
+			rust_binary {
+				name: "my_rust_binary",
+				srcs: ["foo/bar/MyClass.rs"],
+				rustlibs: ["libmy_rust_aconfig_library_bar"],
+				apex_available: ["myapex"],
+			}
+			aconfig_declarations {
+				name: "my_aconfig_declarations_foo",
+				package: "com.example.package",
+				container: "otherapex",
+				srcs: ["foo.aconfig"],
+			}
+			aconfig_declarations {
+				name: "my_aconfig_declarations_bar",
+				package: "com.example.package",
+				container: "otherapex",
+				srcs: ["bar.aconfig"],
+			}
+			rust_aconfig_library {
+				name: "libmy_rust_aconfig_library_foo",
+				aconfig_declarations: "my_aconfig_declarations_foo",
+				crate_name: "my_rust_aconfig_library_foo",
+				apex_available: ["myapex"],
+				mode: "exported",
+			}
+			rust_aconfig_library {
+				name: "libmy_rust_aconfig_library_bar",
+				aconfig_declarations: "my_aconfig_declarations_bar",
+				crate_name: "my_rust_aconfig_library_bar",
+				apex_available: ["myapex"],
+				mode: "exported",
+			}`,
+		},
+	}
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			android.GroupFixturePreparers(
+				java.PrepareForTestWithJavaDefaultModules,
+				cc.PrepareForTestWithCcBuildComponents,
+				rust.PrepareForTestWithRustDefaultModules,
+				codegen.PrepareForTestWithAconfigBuildComponents,
+				PrepareForTestWithApexBuildComponents,
+				prepareForTestWithMyapex,
+				withAconfigValidationError,
+			).
+				RunTestWithBp(t, test.bp)
+		})
+	}
+}
+
+func TestValidationAcrossContainersNotExportedFail(t *testing.T) {
+	testCases := []struct {
+		name          string
+		expectedError string
+		bp            string
+	}{
+		{
+			name: "Java lib fails for non-exported containers cross",
+			bp: apex_default_bp + `
+				apex {
+					name: "myapex",
+					manifest: ":myapex.manifest",
+					androidManifest: ":myapex.androidmanifest",
+					key: "myapex.key",
+					java_libs: [
+						"my_java_library_foo",
+					],
+					updatable: false,
+				}
+				java_library {
+					name: "my_java_library_foo",
+					srcs: ["foo/bar/MyClass.java"],
+					sdk_version: "none",
+					system_modules: "none",
+					static_libs: ["my_java_aconfig_library_foo"],
+					apex_available: [
+						"myapex",
+					],
+				}
+				aconfig_declarations {
+					name: "my_aconfig_declarations_foo",
+					package: "com.example.package",
+					container: "otherapex",
+					srcs: ["foo.aconfig"],
+				}
+				java_aconfig_library {
+					name: "my_java_aconfig_library_foo",
+					aconfig_declarations: "my_aconfig_declarations_foo",
+					apex_available: [
+						"myapex",
+					],
+				}`,
+			expectedError: `.*my_java_library_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
+		},
+		{
+			name: "Android app fails for non-exported containers cross",
+			bp: apex_default_bp + `
+				apex {
+					name: "myapex",
+					manifest: ":myapex.manifest",
+					androidManifest: ":myapex.androidmanifest",
+					key: "myapex.key",
+					apps: [
+						"my_android_app_foo",
+					],
+					updatable: false,
+				}
+				android_app {
+					name: "my_android_app_foo",
+					srcs: ["foo/MyClass.java"],
+					sdk_version: "none",
+					system_modules: "none",
+					stl: "none",
+					static_libs: ["my_java_library_foo"],
+					apex_available: [ "myapex" ],
+				}
+				java_library {
+					name: "my_java_library_foo",
+					srcs: ["foo/bar/MyClass.java"],
+					sdk_version: "none",
+					system_modules: "none",
+					static_libs: ["my_java_aconfig_library_foo"],
+					apex_available: [
+						"myapex",
+					],
+				}
+				aconfig_declarations {
+					name: "my_aconfig_declarations_foo",
+					package: "com.example.package",
+					container: "otherapex",
+					srcs: ["bar.aconfig"],
+				}
+				java_aconfig_library {
+					name: "my_java_aconfig_library_foo",
+					aconfig_declarations: "my_aconfig_declarations_foo",
+					apex_available: [
+						"myapex",
+					],
+				}`,
+			expectedError: `.*my_android_app_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
+		},
+		{
+			name: "Cc lib fails for non-exported containers cross",
+			bp: apex_default_bp + `
+				apex {
+					name: "myapex",
+					manifest: ":myapex.manifest",
+					androidManifest: ":myapex.androidmanifest",
+					key: "myapex.key",
+					native_shared_libs: [
+						"my_cc_library_foo",
+					],
+					updatable: false,
+				}
+				cc_library {
+					name: "my_cc_library_foo",
+					srcs: ["foo/bar/MyClass.cc"],
+					shared_libs: [
+						"my_cc_aconfig_library_foo",
+					],
+					apex_available: [
+						"myapex",
+					],
+				}
+				cc_library {
+					name: "server_configurable_flags",
+					srcs: ["server_configurable_flags.cc"],
+				}
+				cc_library {
+					name: "libbase",
+					srcs: ["libbase.cc"],
+			                apex_available: [
+				            "myapex",
+			                ],
+				}
+				cc_library {
+					name: "libaconfig_storage_read_api_cc",
+					srcs: ["libaconfig_storage_read_api_cc.cc"],
+				}
+				cc_library {
+					name: "libaconfig_storage_protos_cc",
+					srcs: ["libaconfig_storage_protos_cc.cc"],
+				}
+				aconfig_declarations {
+					name: "my_aconfig_declarations_foo",
+					package: "com.example.package",
+					container: "otherapex",
+					srcs: ["foo.aconfig"],
+				}
+				cc_aconfig_library {
+					name: "my_cc_aconfig_library_foo",
+					aconfig_declarations: "my_aconfig_declarations_foo",
+					apex_available: [
+						"myapex",
+					],
+				}`,
+			expectedError: `.*my_cc_library_foo/myapex depends on my_cc_aconfig_library_foo/otherapex/production across containers`,
+		},
+		{
+			name: "Cc binary fails for non-exported containers cross",
+			bp: apex_default_bp + `
+				apex {
+					name: "myapex",
+					manifest: ":myapex.manifest",
+					androidManifest: ":myapex.androidmanifest",
+					key: "myapex.key",
+					binaries: [
+						"my_cc_binary_foo",
+					],
+					updatable: false,
+				}
+				cc_library {
+					name: "my_cc_library_foo",
+					srcs: ["foo/bar/MyClass.cc"],
+					static_libs: [
+						"my_cc_aconfig_library_foo",
+					],
+					apex_available: [
+						"myapex",
+					],
+				}
+				cc_binary {
+					name: "my_cc_binary_foo",
+					srcs: ["foo/bar/MyClass.cc"],
+					static_libs: ["my_cc_library_foo"],
+					apex_available: [
+						"myapex",
+					],
+				}
+				cc_library {
+					name: "server_configurable_flags",
+					srcs: ["server_configurable_flags.cc"],
+				}
+				cc_library {
+					name: "libbase",
+					srcs: ["libbase.cc"],
+			                apex_available: [
+				            "myapex",
+			                ],
+				}
+				cc_library {
+					name: "libaconfig_storage_read_api_cc",
+					srcs: ["libaconfig_storage_read_api_cc.cc"],
+				}
+				cc_library {
+					name: "libaconfig_storage_protos_cc",
+					srcs: ["libaconfig_storage_protos_cc.cc"],
+				}
+				aconfig_declarations {
+					name: "my_aconfig_declarations_foo",
+					package: "com.example.package",
+					container: "otherapex",
+					srcs: ["foo.aconfig"],
+				}
+				cc_aconfig_library {
+					name: "my_cc_aconfig_library_foo",
+					aconfig_declarations: "my_aconfig_declarations_foo",
+					apex_available: [
+						"myapex",
+					],
+				}`,
+			expectedError: `.*my_cc_binary_foo/myapex depends on my_cc_aconfig_library_foo/otherapex/production across containers`,
+		},
+		{
+			name: "Rust lib fails for non-exported containers cross",
+			bp: apex_default_bp + `
+			apex {
+				name: "myapex",
+				manifest: ":myapex.manifest",
+				androidManifest: ":myapex.androidmanifest",
+				key: "myapex.key",
+				native_shared_libs: ["libmy_rust_library"],
+				updatable: false,
+			}
+			rust_library {
+				name: "libflags_rust", // test mock
+				crate_name: "flags_rust",
+				srcs: ["lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "liblazy_static", // test mock
+				crate_name: "lazy_static",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "libaconfig_storage_read_api", // test mock
+				crate_name: "aconfig_storage_read_api",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "liblogger", // test mock
+				crate_name: "logger",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "liblog_rust", // test mock
+				crate_name: "log_rust",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_ffi_shared {
+				name: "libmy_rust_library",
+				srcs: ["src/lib.rs"],
+				rustlibs: ["libmy_rust_aconfig_library_foo"],
+				crate_name: "my_rust_library",
+				apex_available: ["myapex"],
+			}
+			aconfig_declarations {
+				name: "my_aconfig_declarations_foo",
+				package: "com.example.package",
+				container: "otherapex",
+				srcs: ["foo.aconfig"],
+			}
+			rust_aconfig_library {
+				name: "libmy_rust_aconfig_library_foo",
+				aconfig_declarations: "my_aconfig_declarations_foo",
+				crate_name: "my_rust_aconfig_library_foo",
+				apex_available: ["myapex"],
+			}`,
+			expectedError: `.*libmy_rust_aconfig_library_foo/myapex depends on libmy_rust_aconfig_library_foo/otherapex/production across containers`,
+		},
+		{
+			name: "Rust binary fails for non-exported containers cross",
+			bp: apex_default_bp + `
+			apex {
+				name: "myapex",
+				manifest: ":myapex.manifest",
+				androidManifest: ":myapex.androidmanifest",
+				key: "myapex.key",
+				binaries: ["my_rust_binary"],
+				updatable: false,
+			}
+			rust_library {
+				name: "libflags_rust", // test mock
+				crate_name: "flags_rust",
+				srcs: ["lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "liblazy_static", // test mock
+				crate_name: "lazy_static",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "libaconfig_storage_read_api", // test mock
+				crate_name: "aconfig_storage_read_api",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "liblogger", // test mock
+				crate_name: "logger",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_library {
+				name: "liblog_rust", // test mock
+				crate_name: "log_rust",
+				srcs: ["src/lib.rs"],
+				apex_available: ["myapex"],
+			}
+			rust_binary {
+				name: "my_rust_binary",
+				srcs: ["foo/bar/MyClass.rs"],
+				rustlibs: ["libmy_rust_aconfig_library_bar"],
+				apex_available: ["myapex"],
+			}
+			aconfig_declarations {
+				name: "my_aconfig_declarations_bar",
+				package: "com.example.package",
+				container: "otherapex",
+				srcs: ["bar.aconfig"],
+			}
+			rust_aconfig_library {
+				name: "libmy_rust_aconfig_library_bar",
+				aconfig_declarations: "my_aconfig_declarations_bar",
+				crate_name: "my_rust_aconfig_library_bar",
+				apex_available: ["myapex"],
+			}`,
+			expectedError: `.*libmy_rust_aconfig_library_bar/myapex depends on libmy_rust_aconfig_library_bar/otherapex/production across containers`,
+		},
+		{
+			name: "Aconfig validation propagate along sourceOrOutputDependencyTag",
+			bp: apex_default_bp + `
+				apex {
+					name: "myapex",
+					manifest: ":myapex.manifest",
+					androidManifest: ":myapex.androidmanifest",
+					key: "myapex.key",
+					apps: [
+						"my_android_app_foo",
+					],
+					updatable: false,
+				}
+				android_app {
+					name: "my_android_app_foo",
+					srcs: ["foo/MyClass.java"],
+					sdk_version: "none",
+					system_modules: "none",
+					stl: "none",
+					static_libs: ["my_java_library_foo"],
+					apex_available: [ "myapex" ],
+				}
+				java_library {
+					name: "my_java_library_foo",
+					srcs: [":my_genrule_foo"],
+					sdk_version: "none",
+					system_modules: "none",
+					apex_available: [
+						"myapex",
+					],
+				}
+				aconfig_declarations_group {
+						name: "my_aconfig_declarations_group_foo",
+						java_aconfig_libraries: [
+								"my_java_aconfig_library_foo",
+						],
+				}
+				filegroup {
+						name: "my_filegroup_foo_srcjars",
+						srcs: [
+								":my_aconfig_declarations_group_foo{.srcjars}",
+						],
+				}
+				genrule {
+						name: "my_genrule_foo",
+						srcs: [":my_filegroup_foo_srcjars"],
+						cmd: "cp $(in) $(out)",
+						out: ["my_genrule_foo.srcjar"],
+				}
+				aconfig_declarations {
+					name: "my_aconfig_declarations_foo",
+					package: "com.example.package",
+					container: "otherapex",
+					srcs: ["bar.aconfig"],
+				}
+				java_aconfig_library {
+					name: "my_java_aconfig_library_foo",
+					aconfig_declarations: "my_aconfig_declarations_foo",
+					apex_available: [
+						"myapex",
+					],
+				}`,
+			expectedError: `.*my_android_app_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`,
+		},
+	}
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			errorHandler := android.FixtureExpectsNoErrors
+			if test.expectedError != "" {
+				errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(test.expectedError)
+			}
+			android.GroupFixturePreparers(
+				java.PrepareForTestWithJavaDefaultModules,
+				cc.PrepareForTestWithCcBuildComponents,
+				rust.PrepareForTestWithRustDefaultModules,
+				codegen.PrepareForTestWithAconfigBuildComponents,
+				genrule.PrepareForIntegrationTestWithGenrule,
+				PrepareForTestWithApexBuildComponents,
+				prepareForTestWithMyapex,
+				withAconfigValidationError,
+			).
+				ExtendWithErrorHandler(errorHandler).
+				RunTestWithBp(t, test.bp)
+		})
+	}
+}
+
+func TestValidationNotPropagateAcrossShared(t *testing.T) {
+	testCases := []struct {
+		name string
+		bp   string
+	}{
+		{
+			name: "Java shared lib not propagate aconfig validation",
+			bp: apex_default_bp + `
+				apex {
+					name: "myapex",
+					manifest: ":myapex.manifest",
+					androidManifest: ":myapex.androidmanifest",
+					key: "myapex.key",
+					java_libs: [
+						"my_java_library_bar",
+					],
+					updatable: false,
+				}
+				java_library {
+					name: "my_java_library_bar",
+					srcs: ["foo/bar/MyClass.java"],
+					sdk_version: "none",
+					system_modules: "none",
+					libs: ["my_java_library_foo"],
+					apex_available: [
+						"myapex",
+					],
+				}
+				java_library {
+					name: "my_java_library_foo",
+					srcs: ["foo/bar/MyClass.java"],
+					sdk_version: "none",
+					system_modules: "none",
+					static_libs: ["my_java_aconfig_library_foo"],
+					apex_available: [
+						"myapex",
+					],
+				}
+				aconfig_declarations {
+					name: "my_aconfig_declarations_foo",
+					package: "com.example.package",
+					container: "otherapex",
+					srcs: ["foo.aconfig"],
+				}
+				java_aconfig_library {
+					name: "my_java_aconfig_library_foo",
+					aconfig_declarations: "my_aconfig_declarations_foo",
+					apex_available: [
+						"myapex",
+					],
+				}`,
+		},
+	}
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			android.GroupFixturePreparers(
+				java.PrepareForTestWithJavaDefaultModules,
+				cc.PrepareForTestWithCcBuildComponents,
+				rust.PrepareForTestWithRustDefaultModules,
+				codegen.PrepareForTestWithAconfigBuildComponents,
+				PrepareForTestWithApexBuildComponents,
+				prepareForTestWithMyapex,
+				withAconfigValidationError,
+			).
+				RunTestWithBp(t, test.bp)
+		})
+	}
+}
diff --git a/apex/androidmk.go b/apex/androidmk.go
index f469062..619be8d 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -42,7 +42,7 @@
 		return "ETC"
 	case nativeSharedLib:
 		return "SHARED_LIBRARIES"
-	case nativeExecutable, shBinary, pyBinary, goBinary:
+	case nativeExecutable, shBinary:
 		return "EXECUTABLES"
 	case javaSharedLib:
 		return "JAVA_LIBRARIES"
@@ -67,7 +67,7 @@
 	if linkToSystemLib {
 		return fi.androidMkModuleName
 	}
-	return fi.androidMkModuleName + "." + apexBundleName + a.suffix
+	return fi.androidMkModuleName + "." + apexBundleName
 }
 
 // androidMkForFiles generates Make definitions for the contents of an
@@ -85,11 +85,6 @@
 	// conflicts between two apexes with the same apexName.
 
 	moduleNames := []string{}
-	// To avoid creating duplicate build rules, run this function only when primaryApexType is true
-	// to install symbol files in $(PRODUCT_OUT}/apex.
-	if !a.primaryApexType {
-		return moduleNames
-	}
 
 	for _, fi := range a.filesInfo {
 		linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform()
@@ -129,6 +124,10 @@
 		pathForSymbol := filepath.Join("$(PRODUCT_OUT)", "apex", apexBundleName, fi.installDir)
 		modulePath := pathForSymbol
 		fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", modulePath)
+		// AconfigUpdateAndroidMkData may have added elements to Extra.  Process them here.
+		for _, extra := range apexAndroidMkData.Extra {
+			extra(w, fi.builtFile)
+		}
 
 		// For non-flattend APEXes, the merged notice file is attached to the APEX itself.
 		// We don't need to have notice file for the individual modules in it. Otherwise,
@@ -140,36 +139,10 @@
 		fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.nameInMake())
 		if fi.module != nil {
 			// This apexFile's module comes from Soong
-			archStr := fi.module.Target().Arch.ArchType.String()
-			host := false
-			switch fi.module.Target().Os.Class {
-			case android.Host:
-				if fi.module.Target().HostCross {
-					if fi.module.Target().Arch.ArchType != android.Common {
-						fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr)
-					}
-				} else {
-					if fi.module.Target().Arch.ArchType != android.Common {
-						fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr)
-					}
-				}
-				host = true
-			case android.Device:
-				if fi.module.Target().Arch.ArchType != android.Common {
-					fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
-				}
+			if fi.module.Target().Arch.ArchType != android.Common {
+				archStr := fi.module.Target().Arch.ArchType.String()
+				fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
 			}
-			if host {
-				makeOs := fi.module.Target().Os.String()
-				if fi.module.Target().Os == android.Linux || fi.module.Target().Os == android.LinuxBionic || fi.module.Target().Os == android.LinuxMusl {
-					makeOs = "linux"
-				}
-				fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", makeOs)
-				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
-			}
-		} else if fi.isBazelPrebuilt && fi.arch != "" {
-			// This apexFile comes from Bazel
-			fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", fi.arch)
 		}
 		if fi.jacocoReportClassesFile != nil {
 			fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", fi.jacocoReportClassesFile.String())
@@ -213,21 +186,17 @@
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_android_app_set.mk")
 		case nativeSharedLib, nativeExecutable, nativeTest:
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.stem())
-			if fi.isBazelPrebuilt {
-				fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", fi.unstrippedBuiltFile)
-			} else {
-				if ccMod, ok := fi.module.(*cc.Module); ok {
-					if ccMod.UnstrippedOutputFile() != nil {
-						fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", ccMod.UnstrippedOutputFile().String())
-					}
-					ccMod.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
-					if ccMod.CoverageOutputFile().Valid() {
-						fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", ccMod.CoverageOutputFile().String())
-					}
-				} else if rustMod, ok := fi.module.(*rust.Module); ok {
-					if rustMod.UnstrippedOutputFile() != nil {
-						fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", rustMod.UnstrippedOutputFile().String())
-					}
+			if ccMod, ok := fi.module.(*cc.Module); ok {
+				if ccMod.UnstrippedOutputFile() != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", ccMod.UnstrippedOutputFile().String())
+				}
+				ccMod.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
+				if ccMod.CoverageOutputFile().Valid() {
+					fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", ccMod.CoverageOutputFile().String())
+				}
+			} else if rustMod, ok := fi.module.(*rust.Module); ok {
+				if rustMod.UnstrippedOutputFile() != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", rustMod.UnstrippedOutputFile().String())
 				}
 			}
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk")
@@ -237,7 +206,7 @@
 		}
 
 		// m <module_name> will build <module_name>.<apex_name> as well.
-		if fi.androidMkModuleName != moduleName && a.primaryApexType {
+		if fi.androidMkModuleName != moduleName {
 			fmt.Fprintf(w, ".PHONY: %s\n", fi.androidMkModuleName)
 			fmt.Fprintf(w, "%s: %s\n", fi.androidMkModuleName, moduleName)
 		}
@@ -264,21 +233,20 @@
 
 func (a *apexBundle) androidMkForType() android.AndroidMkData {
 	return android.AndroidMkData{
+		// While we do not provide a value for `Extra`, AconfigUpdateAndroidMkData may add some, which we must honor.
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
 			moduleNames := []string{}
-			apexType := a.properties.ApexType
 			if a.installable() {
 				moduleNames = a.androidMkForFiles(w, name, moduleDir, data)
 			}
 
 			fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)  # apex.apexBundle")
 			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
-			fmt.Fprintln(w, "LOCAL_MODULE :=", name+a.suffix)
-			data.Entries.WriteLicenseVariables(w)
+			fmt.Fprintln(w, "LOCAL_MODULE :=", name)
 			fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class?
 			fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String())
 			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.String())
-			stemSuffix := apexType.suffix()
+			stemSuffix := imageApexSuffix
 			if a.isCompressed {
 				stemSuffix = imageCapexSuffix
 			}
@@ -287,7 +255,9 @@
 			if a.installable() {
 				fmt.Fprintln(w, "LOCAL_SOONG_INSTALLED_MODULE :=", a.installedFile.String())
 				fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", a.outputFile.String()+":"+a.installedFile.String())
+				fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_SYMLINKS := ", strings.Join(a.compatSymlinks.Strings(), " "))
 			}
+			fmt.Fprintln(w, "LOCAL_APEX_KEY_PATH := ", a.apexKeysPath.String())
 
 			// Because apex writes .mk with Custom(), we need to write manually some common properties
 			// which are available via data.Entries
@@ -304,12 +274,13 @@
 
 			android.AndroidMkEmitAssignList(w, "LOCAL_OVERRIDES_MODULES", a.overridableProperties.Overrides)
 			a.writeRequiredModules(w, moduleNames)
+			// AconfigUpdateAndroidMkData may have added elements to Extra.  Process them here.
+			for _, extra := range data.Extra {
+				extra(w, a.outputFile)
+			}
 
 			fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
-
-			if apexType == imageApex {
-				fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).BUNDLE :=", a.bundleModuleFile.String())
-			}
+			fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).BUNDLE :=", a.bundleModuleFile.String())
 			android.AndroidMkEmitAssignList(w, "ALL_MODULES.$(my_register_name).LINT_REPORTS", a.lintReports.Strings())
 
 			if a.installedFilesFile != nil {
diff --git a/apex/apex.go b/apex/apex.go
index 8c21d3d..ef57d7e 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -18,26 +18,22 @@
 
 import (
 	"fmt"
+	"log"
 	"path/filepath"
 	"regexp"
 	"sort"
 	"strings"
 
-	"android/soong/bazel/cquery"
-
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/bpf"
 	"android/soong/cc"
 	prebuilt_etc "android/soong/etc"
 	"android/soong/filesystem"
 	"android/soong/java"
 	"android/soong/multitree"
-	"android/soong/python"
 	"android/soong/rust"
 	"android/soong/sh"
 )
@@ -77,9 +73,8 @@
 	// Run mark_platform_availability before the apexMutator as the apexMutator needs to know whether
 	// it should create a platform variant.
 	ctx.BottomUp("mark_platform_availability", markPlatformAvailability).Parallel()
-	ctx.BottomUp("apex", apexMutator).Parallel()
+	ctx.Transition("apex", &apexTransitionMutator{})
 	ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).Parallel()
-	ctx.BottomUp("apex_packaging", apexPackagingMutator).Parallel()
 	ctx.BottomUp("apex_dcla_deps", apexDCLADepsMutator).Parallel()
 	// Register after apex_info mutator so that it can use ApexVariationName
 	ctx.TopDown("apex_strict_updatability_lint", apexStrictUpdatibilityLintMutator).Parallel()
@@ -137,6 +132,11 @@
 	// List of filesystem images that are embedded inside this APEX bundle.
 	Filesystems []string
 
+	// List of module names which we don't want to add as transitive deps. This can be used as
+	// a workaround when the current implementation collects more than necessary. For example,
+	// Rust binaries with prefer_rlib:true add unnecessary dependencies.
+	Unwanted_transitive_deps []string
+
 	// The minimum SDK version that this APEX must support at minimum. This is usually set to
 	// the SDK version that the APEX was first introduced.
 	Min_sdk_version *string
@@ -166,15 +166,7 @@
 	// Should be only used in non-system apexes (e.g. vendor: true). Default is false.
 	Use_vndk_as_stable *bool
 
-	// The type of APEX to build. Controls what the APEX payload is. Either 'image', 'zip' or
-	// 'both'. When set to image, contents are stored in a filesystem image inside a zip
-	// container. When set to zip, contents are stored in a zip container directly. This type is
-	// mostly for host-side debugging. When set to both, the two types are both built. Default
-	// is 'image'.
-	Payload_type *string
-
-	// The type of filesystem to use when the payload_type is 'image'. Either 'ext4', 'f2fs'
-	// or 'erofs'. Default 'ext4'.
+	// The type of filesystem to use. Either 'ext4', 'f2fs' or 'erofs'. Default 'ext4'.
 	Payload_fs_type *string
 
 	// For telling the APEX to ignore special handling for system libraries such as bionic.
@@ -216,9 +208,6 @@
 
 	HideFromMake bool `blueprint:"mutated"`
 
-	// Internal package method for this APEX.
-	ApexType apexPackaging `blueprint:"mutated"`
-
 	// Name that dependencies can specify in their apex_available properties to refer to this module.
 	// If not specified, this defaults to Soong module name. This must be the name of a Soong module.
 	Apex_available_name *string
@@ -246,6 +235,9 @@
 	// List of filesystem images that are embedded inside this APEX bundle.
 	Filesystems []string
 
+	// List of prebuilt_etcs that are embedded inside this APEX bundle.
+	Prebuilts []string
+
 	// List of native libraries to exclude from this APEX.
 	Exclude_native_shared_libs []string
 
@@ -263,6 +255,9 @@
 
 	// List of filesystem images to exclude from this APEX bundle.
 	Exclude_filesystems []string
+
+	// List of prebuilt_etcs to exclude from this APEX bundle.
+	Exclude_prebuilts []string
 }
 
 // Merge combines another ApexNativeDependencies into this one
@@ -273,6 +268,7 @@
 	a.Binaries = append(a.Binaries, b.Binaries...)
 	a.Tests = append(a.Tests, b.Tests...)
 	a.Filesystems = append(a.Filesystems, b.Filesystems...)
+	a.Prebuilts = append(a.Prebuilts, b.Prebuilts...)
 
 	a.Exclude_native_shared_libs = append(a.Exclude_native_shared_libs, b.Exclude_native_shared_libs...)
 	a.Exclude_jni_libs = append(a.Exclude_jni_libs, b.Exclude_jni_libs...)
@@ -280,6 +276,7 @@
 	a.Exclude_binaries = append(a.Exclude_binaries, b.Exclude_binaries...)
 	a.Exclude_tests = append(a.Exclude_tests, b.Exclude_tests...)
 	a.Exclude_filesystems = append(a.Exclude_filesystems, b.Exclude_filesystems...)
+	a.Exclude_prebuilts = append(a.Exclude_prebuilts, b.Exclude_prebuilts...)
 }
 
 type apexMultilibProperties struct {
@@ -361,6 +358,8 @@
 	// be removed from PRODUCT_PACKAGES.
 	Overrides []string
 
+	Multilib apexMultilibProperties
+
 	// Logging parent value.
 	Logging_parent string
 
@@ -396,7 +395,6 @@
 	android.ModuleBase
 	android.DefaultableModuleBase
 	android.OverridableModuleBase
-	android.BazelModuleBase
 	multitree.ExportableModuleBase
 
 	// Properties
@@ -421,13 +419,6 @@
 	testApex bool
 	vndkApex bool
 
-	// Tells whether this variant of the APEX bundle is the primary one or not. Only the primary
-	// one gets installed to the device.
-	primaryApexType bool
-
-	// Suffix of module name in Android.mk ".apex", ".zipapex", or ""
-	suffix string
-
 	// File system type of apex_payload.img
 	payloadFsType fsType
 
@@ -474,6 +465,9 @@
 	// Path where this APEX was installed.
 	installedFile android.InstallPath
 
+	// fragment for this apex for apexkeys.txt
+	apexKeysPath android.WritablePath
+
 	// Installed locations of symlinks for backward compatibility.
 	compatSymlinks android.InstallPaths
 
@@ -495,8 +489,10 @@
 	nativeApisBackedByModuleFile android.ModuleOutPath
 	javaApisUsedByModuleFile     android.ModuleOutPath
 
-	// Collect the module directory for IDE info in java/jdeps.go.
-	modulePaths []string
+	aconfigFiles []android.Path
+
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
 }
 
 // apexFileClass represents a type of file that can be included in APEX.
@@ -506,12 +502,10 @@
 	app apexFileClass = iota
 	appSet
 	etc
-	goBinary
 	javaSharedLib
 	nativeExecutable
 	nativeSharedLib
 	nativeTest
-	pyBinary
 	shBinary
 )
 
@@ -520,12 +514,10 @@
 		"app":              app,
 		"appSet":           appSet,
 		"etc":              etc,
-		"goBinary":         goBinary,
 		"javaSharedLib":    javaSharedLib,
 		"nativeExecutable": nativeExecutable,
 		"nativeSharedLib":  nativeSharedLib,
 		"nativeTest":       nativeTest,
-		"pyBinary":         pyBinary,
 		"shBinary":         shBinary,
 	}
 )
@@ -563,10 +555,6 @@
 
 	multilib string
 
-	isBazelPrebuilt     bool
-	unstrippedBuiltFile android.Path
-	arch                string
-
 	// TODO(jiyong): remove this
 	module android.Module
 }
@@ -716,11 +704,10 @@
 	libVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"})
 	rustLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "rust_libraries", Variation: "dylib"})
 
-	if ctx.Device() {
-		binVariations = append(binVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
-		libVariations = append(libVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
-		rustLibVariations = append(rustLibVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
-	}
+	// Append "image" variation
+	binVariations = append(binVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
+	libVariations = append(libVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
+	rustLibVariations = append(rustLibVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
 
 	// Use *FarVariation* to be able to depend on modules having conflicting variations with
 	// this module. This is required since arch variant of an APEX bundle is 'common' but it is
@@ -737,56 +724,38 @@
 		android.RemoveListFromList(nativeModules.Rust_dyn_libs, nativeModules.Exclude_rust_dyn_libs)...)
 	ctx.AddFarVariationDependencies(target.Variations(), fsTag,
 		android.RemoveListFromList(nativeModules.Filesystems, nativeModules.Exclude_filesystems)...)
+	ctx.AddFarVariationDependencies(target.Variations(), prebuiltTag,
+		android.RemoveListFromList(nativeModules.Prebuilts, nativeModules.Exclude_prebuilts)...)
 }
 
 func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
-	if ctx.Device() {
-		proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Android.Multilib, nil)
-	} else {
-		proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Host.Multilib, nil)
-		if ctx.Os().Bionic() {
-			proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Linux_bionic.Multilib, nil)
-		} else {
-			proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Linux_glibc.Multilib, nil)
-		}
-	}
+	proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Android.Multilib, nil)
 }
 
 // getImageVariationPair returns a pair for the image variation name as its
 // prefix and suffix. The prefix indicates whether it's core/vendor/product and the
-// suffix indicates the vndk version when it's vendor or product.
+// suffix indicates the vndk version for vendor/product if vndk is enabled.
 // getImageVariation can simply join the result of this function to get the
 // image variation name.
-func (a *apexBundle) getImageVariationPair(deviceConfig android.DeviceConfig) (string, string) {
+func (a *apexBundle) getImageVariationPair() (string, string) {
 	if a.vndkApex {
-		return cc.VendorVariationPrefix, a.vndkVersion(deviceConfig)
+		return cc.VendorVariationPrefix, a.vndkVersion()
 	}
 
-	var prefix string
-	var vndkVersion string
-	if deviceConfig.VndkVersion() != "" {
-		if a.SocSpecific() || a.DeviceSpecific() {
-			prefix = cc.VendorVariationPrefix
-			vndkVersion = deviceConfig.VndkVersion()
-		} else if a.ProductSpecific() {
-			prefix = cc.ProductVariationPrefix
-			vndkVersion = deviceConfig.ProductVndkVersion()
-		}
-	}
-	if vndkVersion == "current" {
-		vndkVersion = deviceConfig.PlatformVndkVersion()
-	}
-	if vndkVersion != "" {
-		return prefix, vndkVersion
+	prefix := android.CoreVariation
+	if a.SocSpecific() || a.DeviceSpecific() {
+		prefix = cc.VendorVariation
+	} else if a.ProductSpecific() {
+		prefix = cc.ProductVariation
 	}
 
-	return android.CoreVariation, "" // The usual case
+	return prefix, ""
 }
 
 // getImageVariation returns the image variant name for this apexBundle. In most cases, it's simply
 // android.CoreVariation, but gets complicated for the vendor APEXes and the VNDK APEX.
-func (a *apexBundle) getImageVariation(ctx android.BottomUpMutatorContext) string {
-	prefix, vndkVersion := a.getImageVariationPair(ctx.DeviceConfig())
+func (a *apexBundle) getImageVariation() string {
+	prefix, vndkVersion := a.getImageVariationPair()
 	return prefix + vndkVersion
 }
 
@@ -796,7 +765,7 @@
 	// each target os/architectures, appropriate dependencies are selected by their
 	// target.<os>.multilib.<type> groups and are added as (direct) dependencies.
 	targets := ctx.MultiTargets()
-	imageVariation := a.getImageVariation(ctx)
+	imageVariation := a.getImageVariation()
 
 	a.combineProperties(ctx)
 
@@ -807,12 +776,6 @@
 		}
 	}
 	for i, target := range targets {
-		// Don't include artifacts for the host cross targets because there is no way for us
-		// to run those artifacts natively on host
-		if target.HostCross {
-			continue
-		}
-
 		var deps ApexNativeDependencies
 
 		// Add native modules targeting both ABIs. When multilib.* is omitted for
@@ -867,10 +830,12 @@
 		}
 
 		addDependenciesForNativeModules(ctx, deps, target, imageVariation)
-		ctx.AddFarVariationDependencies([]blueprint.Variation{
-			{Mutator: "os", Variation: target.OsVariation()},
-			{Mutator: "arch", Variation: target.ArchVariation()},
-		}, shBinaryTag, a.properties.Sh_binaries...)
+		if isPrimaryAbi {
+			ctx.AddFarVariationDependencies([]blueprint.Variation{
+				{Mutator: "os", Variation: target.OsVariation()},
+				{Mutator: "arch", Variation: target.ArchVariation()},
+			}, shBinaryTag, a.properties.Sh_binaries...)
+		}
 	}
 
 	// Common-arch dependencies come next
@@ -952,13 +917,7 @@
 	ProvidedLibs []string
 }
 
-var DCLAInfoProvider = blueprint.NewMutatorProvider(DCLAInfo{}, "apex_info")
-
-type ApexBundleInfo struct {
-	Contents *android.ApexContents
-}
-
-var ApexBundleInfoProvider = blueprint.NewMutatorProvider(ApexBundleInfo{}, "apex_info")
+var DCLAInfoProvider = blueprint.NewMutatorProvider[DCLAInfo]("apex_info")
 
 var _ ApexInfoMutator = (*apexBundle)(nil)
 
@@ -1032,6 +991,13 @@
 				return false
 			}
 		}
+
+		//TODO: b/296491928 Vendor APEX should use libbinder.ndk instead of libbinder once VNDK is fully deprecated.
+		if useVndk && mctx.Config().IsVndkDeprecated() && child.Name() == "libbinder" {
+			log.Print("Libbinder is linked from Vendor APEX ", a.Name(), " with module ", parent.Name())
+			return false
+		}
+
 		// By default, all the transitive dependencies are collected, unless filtered out
 		// above.
 		return true
@@ -1053,7 +1019,7 @@
 
 	// The membership information is saved for later access
 	apexContents := android.NewApexContents(contents)
-	mctx.SetProvider(ApexBundleInfoProvider, ApexBundleInfo{
+	android.SetProvider(mctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{
 		Contents: apexContents,
 	})
 
@@ -1091,7 +1057,7 @@
 	})
 
 	if a.dynamic_common_lib_apex() {
-		mctx.SetProvider(DCLAInfoProvider, DCLAInfo{
+		android.SetProvider(mctx, DCLAInfoProvider, DCLAInfo{
 			ProvidedLibs: a.properties.Native_shared_libs,
 		})
 	}
@@ -1118,6 +1084,10 @@
 	if a, ok := mctx.Module().(ApexInfoMutator); ok {
 		a.ApexInfoMutator(mctx)
 	}
+
+	if am, ok := mctx.Module().(android.ApexModule); ok {
+		android.ApexInfoMutator(mctx, am)
+	}
 	enforceAppUpdatability(mctx)
 }
 
@@ -1170,15 +1140,43 @@
 // Skip these mainline modules for now
 var (
 	skipStrictUpdatabilityLintAllowlist = []string{
+		// go/keep-sorted start
+		"PackageManagerTestApex",
+		"com.android.adservices",
+		"com.android.appsearch",
 		"com.android.art",
 		"com.android.art.debug",
+		"com.android.btservices",
+		"com.android.cellbroadcast",
+		"com.android.configinfrastructure",
 		"com.android.conscrypt",
+		"com.android.extservices",
+		"com.android.extservices_tplus",
+		"com.android.healthfitness",
+		"com.android.ipsec",
 		"com.android.media",
-		// test apexes
+		"com.android.mediaprovider",
+		"com.android.ondevicepersonalization",
+		"com.android.os.statsd",
+		"com.android.permission",
+		"com.android.profiling",
+		"com.android.rkpd",
+		"com.android.scheduling",
+		"com.android.tethering",
+		"com.android.uwb",
+		"com.android.wifi",
 		"test_com.android.art",
+		"test_com.android.cellbroadcast",
 		"test_com.android.conscrypt",
+		"test_com.android.extservices",
+		"test_com.android.ipsec",
 		"test_com.android.media",
+		"test_com.android.mediaprovider",
+		"test_com.android.os.statsd",
+		"test_com.android.permission",
+		"test_com.android.wifi",
 		"test_jitzygote_com.android.art",
+		// go/keep-sorted end
 	}
 
 	// TODO: b/215736885 Remove this list
@@ -1234,10 +1232,10 @@
 	if _, ok := mctx.Module().(android.ApexModule); ok {
 		var contents []*android.ApexContents
 		for _, testFor := range mctx.GetDirectDepsWithTag(testForTag) {
-			abInfo := mctx.OtherModuleProvider(testFor, ApexBundleInfoProvider).(ApexBundleInfo)
+			abInfo, _ := android.OtherModuleProvider(mctx, testFor, android.ApexBundleInfoProvider)
 			contents = append(contents, abInfo.Contents)
 		}
-		mctx.SetProvider(android.ApexTestForInfoProvider, android.ApexTestForInfo{
+		android.SetProvider(mctx, android.ApexTestForInfoProvider, android.ApexTestForInfo{
 			ApexContents: contents,
 		})
 	}
@@ -1249,8 +1247,8 @@
 // be) available to platform
 // TODO(jiyong): move this to android/apex.go?
 func markPlatformAvailability(mctx android.BottomUpMutatorContext) {
-	// Host and recovery are not considered as platform
-	if mctx.Host() || mctx.Module().InstallInRecovery() {
+	// Recovery is not considered as platform
+	if mctx.Module().InstallInRecovery() {
 		return
 	}
 
@@ -1290,44 +1288,41 @@
 	}
 }
 
-// apexMutator visits each module and creates apex variations if the module was marked in the
-// previous run of apexInfoMutator.
-func apexMutator(mctx android.BottomUpMutatorContext) {
-	if !mctx.Module().Enabled() {
-		return
-	}
+type apexTransitionMutator struct{}
 
-	// This is the usual path.
-	if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
-		android.CreateApexVariations(mctx, am)
-		return
-	}
-
+func (a *apexTransitionMutator) Split(ctx android.BaseModuleContext) []string {
 	// apexBundle itself is mutated so that it and its dependencies have the same apex variant.
-	if ai, ok := mctx.Module().(ApexInfoMutator); ok && apexModuleTypeRequiresVariant(ai) {
-		apexBundleName := ai.ApexVariationName()
-		mctx.CreateVariations(apexBundleName)
-		if strings.HasPrefix(apexBundleName, "com.android.art") {
-			// Create an alias from the platform variant. This is done to make
-			// test_for dependencies work for modules that are split by the APEX
-			// mutator, since test_for dependencies always go to the platform variant.
-			// This doesn't happen for normal APEXes that are disjunct, so only do
-			// this for the overlapping ART APEXes.
-			// TODO(b/183882457): Remove this if the test_for functionality is
-			// refactored to depend on the proper APEX variants instead of platform.
-			mctx.CreateAliasVariation("", apexBundleName)
-		}
-	} else if o, ok := mctx.Module().(*OverrideApex); ok {
+	if ai, ok := ctx.Module().(ApexInfoMutator); ok && apexModuleTypeRequiresVariant(ai) {
+		return []string{ai.ApexVariationName()}
+	} else if o, ok := ctx.Module().(*OverrideApex); ok {
 		apexBundleName := o.GetOverriddenModuleName()
 		if apexBundleName == "" {
-			mctx.ModuleErrorf("base property is not set")
-			return
+			ctx.ModuleErrorf("base property is not set")
 		}
-		mctx.CreateVariations(apexBundleName)
-		if strings.HasPrefix(apexBundleName, "com.android.art") {
-			// TODO(b/183882457): See note for CreateAliasVariation above.
-			mctx.CreateAliasVariation("", apexBundleName)
-		}
+		return []string{apexBundleName}
+	}
+	return []string{""}
+}
+
+func (a *apexTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+	return sourceVariation
+}
+
+func (a *apexTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+	if am, ok := ctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
+		return android.IncomingApexTransition(ctx, incomingVariation)
+	} else if ai, ok := ctx.Module().(ApexInfoMutator); ok {
+		return ai.ApexVariationName()
+	} else if o, ok := ctx.Module().(*OverrideApex); ok {
+		return o.GetOverriddenModuleName()
+	}
+
+	return ""
+}
+
+func (a *apexTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+	if am, ok := ctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
+		android.MutateApexTransition(ctx, variation)
 	}
 }
 
@@ -1353,95 +1348,19 @@
 	}
 }
 
-// apexPackaging represents a specific packaging method for an APEX.
-type apexPackaging int
-
-const (
-	// imageApex is a packaging method where contents are included in a filesystem image which
-	// is then included in a zip container. This is the most typical way of packaging.
-	imageApex apexPackaging = iota
-
-	// zipApex is a packaging method where contents are directly included in the zip container.
-	// This is used for host-side testing - because the contents are easily accessible by
-	// unzipping the container.
-	// TODO(b/279835185) deprecate zipApex
-	zipApex
-)
-
 const (
 	// File extensions of an APEX for different packaging methods
 	imageApexSuffix  = ".apex"
 	imageCapexSuffix = ".capex"
-	zipApexSuffix    = ".zipapex"
 
 	// variant names each of which is for a packaging method
 	imageApexType = "image"
-	zipApexType   = "zip"
 
 	ext4FsType  = "ext4"
 	f2fsFsType  = "f2fs"
 	erofsFsType = "erofs"
 )
 
-// The suffix for the output "file", not the module
-func (a apexPackaging) suffix() string {
-	switch a {
-	case imageApex:
-		return imageApexSuffix
-	case zipApex:
-		return zipApexSuffix
-	default:
-		panic(fmt.Errorf("unknown APEX type %d", a))
-	}
-}
-
-func (a apexPackaging) name() string {
-	switch a {
-	case imageApex:
-		return imageApexType
-	case zipApex:
-		return zipApexType
-	default:
-		panic(fmt.Errorf("unknown APEX type %d", a))
-	}
-}
-
-// apexPackagingMutator creates one or more variations each of which is for a packaging method.
-func apexPackagingMutator(mctx android.BottomUpMutatorContext) {
-	if !mctx.Module().Enabled() {
-		return
-	}
-	if ab, ok := mctx.Module().(*apexBundle); ok {
-		var variants []string
-		switch proptools.StringDefault(ab.properties.Payload_type, "image") {
-		case "image":
-			variants = append(variants, imageApexType)
-		case "zip":
-			variants = append(variants, zipApexType)
-		case "both":
-			variants = append(variants, imageApexType, zipApexType)
-		default:
-			mctx.PropertyErrorf("payload_type", "%q is not one of \"image\", \"zip\", or \"both\".", *ab.properties.Payload_type)
-			return
-		}
-
-		modules := mctx.CreateLocalVariations(variants...)
-
-		for i, v := range variants {
-			switch v {
-			case imageApexType:
-				modules[i].(*apexBundle).properties.ApexType = imageApex
-			case zipApexType:
-				modules[i].(*apexBundle).properties.ApexType = zipApex
-			}
-		}
-	} else if _, ok := mctx.Module().(*OverrideApex); ok {
-		// payload_type is forcibly overridden to "image"
-		// TODO(jiyong): is this the right decision?
-		mctx.CreateVariations(imageApexType)
-	}
-}
-
 var _ android.DepIsInSameApex = (*apexBundle)(nil)
 
 // Implements android.DepInInSameApex
@@ -1485,8 +1404,8 @@
 var _ cc.Coverage = (*apexBundle)(nil)
 
 // Implements cc.Coverage
-func (a *apexBundle) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
-	return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
+func (a *apexBundle) IsNativeCoverageNeeded(ctx android.IncomingTransitionContext) bool {
+	return ctx.DeviceConfig().NativeCoverageEnabled()
 }
 
 // Implements cc.Coverage
@@ -1574,7 +1493,7 @@
 		panic(fmt.Errorf("expected exactly at most one dcla dependency, got %d", len(dclaModules)))
 	}
 	if len(dclaModules) > 0 {
-		DCLAInfo := ctx.OtherModuleProvider(dclaModules[0], DCLAInfoProvider).(DCLAInfo)
+		DCLAInfo, _ := android.OtherModuleProvider(ctx, dclaModules[0], DCLAInfoProvider)
 		return DCLAInfo.ProvidedLibs
 	}
 	return []string{}
@@ -1597,13 +1516,9 @@
 
 	// Then follow the global setting
 	var globalSanitizerNames []string
-	if a.Host() {
-		globalSanitizerNames = config.SanitizeHost()
-	} else {
-		arches := config.SanitizeDeviceArch()
-		if len(arches) == 0 || android.InList(a.Arch().ArchType.Name, arches) {
-			globalSanitizerNames = config.SanitizeDevice()
-		}
+	arches := config.SanitizeDeviceArch()
+	if len(arches) == 0 || android.InList(a.Arch().ArchType.Name, arches) {
+		globalSanitizerNames = config.SanitizeDevice()
 	}
 	return android.InList(sanitizerName, globalSanitizerNames)
 }
@@ -1611,8 +1526,8 @@
 func (a *apexBundle) AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string) {
 	// TODO(jiyong): move this info (the sanitizer name, the lib name, etc.) to cc/sanitize.go
 	// Keep only the mechanism here.
-	if ctx.Device() && sanitizerName == "hwaddress" && strings.HasPrefix(a.Name(), "com.android.runtime") {
-		imageVariation := a.getImageVariation(ctx)
+	if sanitizerName == "hwaddress" && strings.HasPrefix(a.Name(), "com.android.runtime") {
+		imageVariation := a.getImageVariation()
 		for _, target := range ctx.MultiTargets() {
 			if target.Arch.ArchType.Multilib == "lib64" {
 				addDependenciesForNativeModules(ctx, ApexNativeDependencies{
@@ -1711,22 +1626,6 @@
 	return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, rustm)
 }
 
-func apexFileForPyBinary(ctx android.BaseModuleContext, py *python.PythonBinaryModule) apexFile {
-	dirInApex := "bin"
-	fileToCopy := py.HostToolPath().Path()
-	return newApexFile(ctx, fileToCopy, py.BaseModuleName(), dirInApex, pyBinary, py)
-}
-
-func apexFileForGoBinary(ctx android.BaseModuleContext, depName string, gb bootstrap.GoBinaryTool) apexFile {
-	dirInApex := "bin"
-	fileToCopy := android.PathForGoBinary(ctx, gb)
-	// NB: Since go binaries are static we don't need the module for anything here, which is
-	// good since the go tool is a blueprint.Module not an android.Module like we would
-	// normally use.
-	//
-	return newApexFile(ctx, fileToCopy, depName, dirInApex, goBinary, nil)
-}
-
 func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFile {
 	dirInApex := filepath.Join("bin", sh.SubDir())
 	if sh.Target().NativeBridge == android.NativeBridgeEnabled {
@@ -1738,10 +1637,9 @@
 	return af
 }
 
-func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, prebuilt prebuilt_etc.PrebuiltEtcModule, depName string) apexFile {
+func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, prebuilt prebuilt_etc.PrebuiltEtcModule, outputFile android.Path) apexFile {
 	dirInApex := filepath.Join(prebuilt.BaseDir(), prebuilt.SubDir())
-	fileToCopy := prebuilt.OutputFile()
-	return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, prebuilt)
+	return newApexFile(ctx, outputFile, outputFile.Base(), dirInApex, etc, prebuilt)
 }
 
 func apexFileForCompatConfig(ctx android.BaseModuleContext, config java.PlatformCompatConfigIntf, depName string) apexFile {
@@ -1755,7 +1653,7 @@
 type javaModule interface {
 	android.Module
 	BaseModuleName() string
-	DexJarBuildPath() java.OptionalDexJarPath
+	DexJarBuildPath(ctx android.ModuleErrorfContext) java.OptionalDexJarPath
 	JacocoReportClassesFile() android.Path
 	LintDepSets() java.LintDepSets
 	Stem() string
@@ -1769,7 +1667,7 @@
 
 // apexFileForJavaModule creates an apexFile for a java module's dex implementation jar.
 func apexFileForJavaModule(ctx android.BaseModuleContext, module javaModule) apexFile {
-	return apexFileForJavaModuleWithFile(ctx, module, module.DexJarBuildPath().PathOrNil())
+	return apexFileForJavaModuleWithFile(ctx, module, module.DexJarBuildPath(ctx).PathOrNil())
 }
 
 // apexFileForJavaModuleWithFile creates an apexFile for a java module with the supplied file.
@@ -1911,8 +1809,11 @@
 		if dt, ok := depTag.(*dependencyTag); ok && !dt.payload {
 			return false
 		}
+		if depTag == android.RequiredDepTag {
+			return false
+		}
 
-		ai := ctx.OtherModuleProvider(child, android.ApexInfoProvider).(android.ApexInfo)
+		ai, _ := android.OtherModuleProvider(ctx, child, android.ApexInfoProvider)
 		externalDep := !android.InList(ctx.ModuleName(), ai.InApexVariants)
 
 		// Visit actually
@@ -1942,132 +1843,8 @@
 	}
 }
 
-var _ android.MixedBuildBuildable = (*apexBundle)(nil)
-
-func (a *apexBundle) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
-	return a.properties.ApexType == imageApex
-}
-
-func (a *apexBundle) QueueBazelCall(ctx android.BaseModuleContext) {
-	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(a.GetBazelLabel(ctx, a), cquery.GetApexInfo, android.GetConfigKey(ctx))
-}
-
-// GetBazelLabel returns the bazel label of this apexBundle, or the label of the
-// override_apex module overriding this apexBundle. An apexBundle can be
-// overridden by different override_apex modules (e.g. Google or Go variants),
-// which is handled by the overrides mutators.
-func (a *apexBundle) GetBazelLabel(ctx android.BazelConversionPathContext, module blueprint.Module) string {
-	return a.BazelModuleBase.GetBazelLabel(ctx, a)
-}
-
-func (a *apexBundle) ProcessBazelQueryResponse(ctx android.ModuleContext) {
-	if !a.commonBuildActions(ctx) {
-		return
-	}
-
-	a.setApexTypeAndSuffix(ctx)
-	a.setPayloadFsType(ctx)
-	a.setSystemLibLink(ctx)
-
-	if a.properties.ApexType != zipApex {
-		a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType)
-	}
-
-	bazelCtx := ctx.Config().BazelContext
-	outputs, err := bazelCtx.GetApexInfo(a.GetBazelLabel(ctx, a), android.GetConfigKey(ctx))
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-		return
-	}
-	a.installDir = android.PathForModuleInstall(ctx, "apex")
-
-	// Set the output file to .apex or .capex depending on the compression configuration.
-	a.setCompression(ctx)
-	if a.isCompressed {
-		a.outputApexFile = android.PathForBazelOutRelative(ctx, ctx.ModuleDir(), outputs.SignedCompressedOutput)
-	} else {
-		a.outputApexFile = android.PathForBazelOutRelative(ctx, ctx.ModuleDir(), outputs.SignedOutput)
-	}
-	a.outputFile = a.outputApexFile
-
-	if len(outputs.TidyFiles) > 0 {
-		tidyFiles := android.PathsForBazelOut(ctx, outputs.TidyFiles)
-		a.outputFile = android.AttachValidationActions(ctx, a.outputFile, tidyFiles)
-	}
-
-	// TODO(b/257829940): These are used by the apex_keys_text singleton; would probably be a clearer
-	// interface if these were set in a provider rather than the module itself
-	a.publicKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyInfo[0])
-	a.privateKeyFile = android.PathForBazelOut(ctx, outputs.BundleKeyInfo[1])
-	a.containerCertificateFile = android.PathForBazelOut(ctx, outputs.ContainerKeyInfo[0])
-	a.containerPrivateKeyFile = android.PathForBazelOut(ctx, outputs.ContainerKeyInfo[1])
-
-	// Ensure ApexMkInfo.install_to_system make module names are installed as
-	// part of a bundled build.
-	a.makeModulesToInstall = append(a.makeModulesToInstall, outputs.MakeModulesToInstall...)
-
-	apexType := a.properties.ApexType
-	switch apexType {
-	case imageApex:
-		a.bundleModuleFile = android.PathForBazelOut(ctx, outputs.BundleFile)
-		a.nativeApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.SymbolsUsedByApex))
-		a.nativeApisBackedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.BackingLibs))
-		// TODO(b/239084755): Generate the java api using.xml file from Bazel.
-		a.javaApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.JavaSymbolsUsedByApex))
-		a.installedFilesFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.InstalledFiles))
-		installSuffix := imageApexSuffix
-		if a.isCompressed {
-			installSuffix = imageCapexSuffix
-		}
-		a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile,
-			a.compatSymlinks.Paths()...)
-	default:
-		panic(fmt.Errorf("internal error: unexpected apex_type for the ProcessBazelQueryResponse: %v", a.properties.ApexType))
-	}
-
-	// filesInfo in mixed mode must retrieve all information about the apex's
-	// contents completely from the Starlark providers. It should never rely on
-	// Android.bp information, as they might not exist for fully migrated
-	// dependencies.
-	//
-	// Prevent accidental writes to filesInfo in the earlier parts Soong by
-	// asserting it to be nil.
-	if a.filesInfo != nil {
-		panic(
-			fmt.Errorf("internal error: filesInfo must be nil for an apex handled by Bazel. " +
-				"Did something else set filesInfo before this line of code?"))
-	}
-	for _, f := range outputs.PayloadFilesInfo {
-		fileInfo := apexFile{
-			isBazelPrebuilt: true,
-
-			builtFile:           android.PathForBazelOut(ctx, f["built_file"]),
-			unstrippedBuiltFile: android.PathForBazelOut(ctx, f["unstripped_built_file"]),
-			androidMkModuleName: f["make_module_name"],
-			installDir:          f["install_dir"],
-			class:               classes[f["class"]],
-			customStem:          f["basename"],
-			moduleDir:           f["package"],
-		}
-
-		arch := f["arch"]
-		fileInfo.arch = arch
-		if len(arch) > 0 {
-			fileInfo.multilib = "lib32"
-			if strings.HasSuffix(arch, "64") {
-				fileInfo.multilib = "lib64"
-			}
-		}
-
-		a.filesInfo = append(a.filesInfo, fileInfo)
-	}
-}
-
 func (a *apexBundle) setCompression(ctx android.ModuleContext) {
-	if a.properties.ApexType != imageApex {
-		a.isCompressed = false
-	} else if a.testOnlyShouldForceCompression() {
+	if a.testOnlyShouldForceCompression() {
 		a.isCompressed = true
 	} else {
 		a.isCompressed = ctx.Config().ApexCompressionEnabled() && a.isCompressable()
@@ -2093,12 +1870,7 @@
 
 	// We don't need the optimization for updatable APEXes, as it might give false signal
 	// to the system health when the APEXes are still bundled (b/149805758).
-	if !forced && updatable && a.properties.ApexType == imageApex {
-		a.linkToSystemLib = false
-	}
-
-	// We also don't want the optimization for host APEXes, because it doesn't make sense.
-	if ctx.Host() {
+	if !forced && updatable {
 		a.linkToSystemLib = false
 	}
 }
@@ -2116,22 +1888,6 @@
 	}
 }
 
-func (a *apexBundle) setApexTypeAndSuffix(ctx android.ModuleContext) {
-	// Set suffix and primaryApexType depending on the ApexType
-	switch a.properties.ApexType {
-	case imageApex:
-		a.suffix = ""
-		a.primaryApexType = true
-	case zipApex:
-		if proptools.String(a.properties.Payload_type) == "zip" {
-			a.suffix = ""
-			a.primaryApexType = true
-		} else {
-			a.suffix = zipApexSuffix
-		}
-	}
-}
-
 func (a *apexBundle) isCompressable() bool {
 	return proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex
 }
@@ -2161,11 +1917,23 @@
 
 	// if true, raise error on duplicate apexFile
 	checkDuplicate bool
+
+	// visitor skips these from this list of module names
+	unwantedTransitiveDeps []string
+
+	aconfigFiles []android.Path
 }
 
 func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) {
 	encountered := make(map[string]apexFile)
 	for _, f := range vctx.filesInfo {
+		// Skips unwanted transitive deps. This happens, for example, with Rust binaries with prefer_rlib:true.
+		// TODO(b/295593640)
+		// Needs additional verification for the resulting APEX to ensure that skipped artifacts don't make problems.
+		// For example, DT_NEEDED modules should be found within the APEX unless they are marked in `requiredNativeLibs`.
+		if f.transitiveDep && f.module != nil && android.InList(mctx.OtherModuleName(f.module), vctx.unwantedTransitiveDeps) {
+			continue
+		}
 		dest := filepath.Join(f.installDir, f.builtFile.Base())
 		if e, ok := encountered[dest]; !ok {
 			encountered[dest] = f
@@ -2178,6 +1946,9 @@
 			// If a module is directly included and also transitively depended on
 			// consider it as directly included.
 			e.transitiveDep = e.transitiveDep && f.transitiveDep
+			// If a module is added as both a JNI library and a regular shared library, consider it as a
+			// JNI library.
+			e.isJniLib = e.isJniLib || f.isJniLib
 			encountered[dest] = e
 		}
 	}
@@ -2205,11 +1976,19 @@
 		switch depTag {
 		case sharedLibTag, jniLibTag:
 			isJniLib := depTag == jniLibTag
+			propertyName := "native_shared_libs"
+			if isJniLib {
+				propertyName = "jni_libs"
+			}
 			switch ch := child.(type) {
 			case *cc.Module:
+				if ch.IsStubs() {
+					ctx.PropertyErrorf(propertyName, "%q is a stub. Remove it from the list.", depName)
+				}
 				fi := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
 				fi.isJniLib = isJniLib
 				vctx.filesInfo = append(vctx.filesInfo, fi)
+				addAconfigFiles(vctx, ctx, child)
 				// Collect the list of stub-providing libs except:
 				// - VNDK libs are only for vendors
 				// - bootstrap bionic libs are treated as provided by system
@@ -2221,29 +2000,20 @@
 				fi := apexFileForRustLibrary(ctx, ch)
 				fi.isJniLib = isJniLib
 				vctx.filesInfo = append(vctx.filesInfo, fi)
+				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			default:
-				propertyName := "native_shared_libs"
-				if isJniLib {
-					propertyName = "jni_libs"
-				}
 				ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName)
 			}
 		case executableTag:
 			switch ch := child.(type) {
 			case *cc.Module:
 				vctx.filesInfo = append(vctx.filesInfo, apexFileForExecutable(ctx, ch))
+				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
-			case *python.PythonBinaryModule:
-				if ch.HostToolPath().Valid() {
-					vctx.filesInfo = append(vctx.filesInfo, apexFileForPyBinary(ctx, ch))
-				}
-			case bootstrap.GoBinaryTool:
-				if a.Host() {
-					vctx.filesInfo = append(vctx.filesInfo, apexFileForGoBinary(ctx, depName, ch))
-				}
 			case *rust.Module:
 				vctx.filesInfo = append(vctx.filesInfo, apexFileForRustExecutable(ctx, ch))
+				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			default:
 				ctx.PropertyErrorf("binaries",
@@ -2283,6 +2053,7 @@
 					return false
 				}
 				vctx.filesInfo = append(vctx.filesInfo, af)
+				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			default:
 				ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
@@ -2291,11 +2062,14 @@
 			switch ap := child.(type) {
 			case *java.AndroidApp:
 				vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
+				addAconfigFiles(vctx, ctx, child)
 				return true // track transitive dependencies
 			case *java.AndroidAppImport:
 				vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
+				addAconfigFiles(vctx, ctx, child)
 			case *java.AndroidTestHelperApp:
 				vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, ap)...)
+				addAconfigFiles(vctx, ctx, child)
 			case *java.AndroidAppSet:
 				appDir := "app"
 				if ap.Privileged() {
@@ -2309,6 +2083,7 @@
 				af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), appDirName, appSet, ap)
 				af.certificate = java.PresignedCertificate
 				vctx.filesInfo = append(vctx.filesInfo, af)
+				addAconfigFiles(vctx, ctx, child)
 			default:
 				ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
 			}
@@ -2336,7 +2111,11 @@
 			}
 		case prebuiltTag:
 			if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
-				vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+				filesToCopy, _ := prebuilt.OutputFiles("")
+				for _, etcFile := range filesToCopy {
+					vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, etcFile))
+				}
+				addAconfigFiles(vctx, ctx, child)
 			} else {
 				ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
 			}
@@ -2360,6 +2139,7 @@
 					af := apexFileForExecutable(ctx, ccTest)
 					af.class = nativeTest
 					vctx.filesInfo = append(vctx.filesInfo, af)
+					addAconfigFiles(vctx, ctx, child)
 				}
 				return true // track transitive dependencies
 			} else {
@@ -2400,16 +2180,15 @@
 				vctx.requireNativeLibs = append(vctx.requireNativeLibs, ":vndk")
 				return false
 			}
+
+			//TODO: b/296491928 Vendor APEX should use libbinder.ndk instead of libbinder once VNDK is fully deprecated.
+			if ch.InVendorOrProduct() && ctx.Config().IsVndkDeprecated() && child.Name() == "libbinder" {
+				return false
+			}
 			af := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
 			af.transitiveDep = true
 
-			// Always track transitive dependencies for host.
-			if a.Host() {
-				vctx.filesInfo = append(vctx.filesInfo, af)
-				return true
-			}
-
-			abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo)
+			abInfo, _ := android.ModuleProvider(ctx, android.ApexBundleInfoProvider)
 			if !abInfo.Contents.DirectlyInApex(depName) && (ch.IsStubs() || ch.HasStubsVariants()) {
 				// If the dependency is a stubs lib, don't include it in this APEX,
 				// but make sure that the lib is installed on the device.
@@ -2450,11 +2229,13 @@
 			}
 
 			vctx.filesInfo = append(vctx.filesInfo, af)
+			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		} else if rm, ok := child.(*rust.Module); ok {
 			af := apexFileForRustLibrary(ctx, rm)
 			af.transitiveDep = true
 			vctx.filesInfo = append(vctx.filesInfo, af)
+			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		}
 	} else if cc.IsTestPerSrcDepTag(depTag) {
@@ -2476,13 +2257,17 @@
 		// Because APK-in-APEX embeds jni_libs transitively, we don't need to track transitive deps
 	} else if java.IsXmlPermissionsFileDepTag(depTag) {
 		if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
-			vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
+			filesToCopy, _ := prebuilt.OutputFiles("")
+			for _, etcFile := range filesToCopy {
+				vctx.filesInfo = append(vctx.filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, etcFile))
+			}
 		}
 	} else if rust.IsDylibDepTag(depTag) {
 		if rustm, ok := child.(*rust.Module); ok && rustm.IsInstallableToApex() {
 			af := apexFileForRustLibrary(ctx, rustm)
 			af.transitiveDep = true
 			vctx.filesInfo = append(vctx.filesInfo, af)
+			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		}
 	} else if rust.IsRlibDepTag(depTag) {
@@ -2501,6 +2286,7 @@
 				return false
 			}
 			vctx.filesInfo = append(vctx.filesInfo, af)
+			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		default:
 			ctx.PropertyErrorf("bootclasspath_fragments",
@@ -2515,6 +2301,7 @@
 			if profileAf := apexFileForJavaModuleProfile(ctx, child.(javaModule)); profileAf != nil {
 				vctx.filesInfo = append(vctx.filesInfo, *profileAf)
 			}
+			addAconfigFiles(vctx, ctx, child)
 			return true // track transitive dependencies
 		default:
 			ctx.PropertyErrorf("systemserverclasspath_fragments",
@@ -2524,26 +2311,33 @@
 		// nothing
 	} else if depTag == android.DarwinUniversalVariantTag {
 		// nothing
+	} else if depTag == android.RequiredDepTag {
+		// nothing
 	} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
 		ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
 	}
 	return false
 }
 
+func addAconfigFiles(vctx *visitorContext, ctx android.ModuleContext, module blueprint.Module) {
+	if dep, ok := android.OtherModuleProvider(ctx, module, android.AconfigTransitiveDeclarationsInfoProvider); ok {
+		if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil {
+			vctx.aconfigFiles = append(vctx.aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...)
+		}
+	}
+
+	validationFlag := ctx.DeviceConfig().AconfigContainerValidation()
+	if validationFlag == "error" || validationFlag == "warning" {
+		android.VerifyAconfigBuildMode(ctx, ctx.ModuleName(), module, validationFlag == "error")
+	}
+}
+
 func (a *apexBundle) shouldCheckDuplicate(ctx android.ModuleContext) bool {
 	// TODO(b/263308293) remove this
 	if a.properties.IsCoverageVariant {
 		return false
 	}
-	// TODO(b/263308515) remove this
-	if a.testApex {
-		return false
-	}
-	// TODO(b/263309864) remove this
-	if a.Host() {
-		return false
-	}
-	if a.Device() && ctx.DeviceConfig().DeviceArch() == "" {
+	if ctx.DeviceConfig().DeviceArch() == "" {
 		return false
 	}
 	return true
@@ -2563,14 +2357,13 @@
 	}
 	////////////////////////////////////////////////////////////////////////////////////////////
 	// 2) traverse the dependency tree to collect apexFile structs from them.
-	// Collect the module directory for IDE info in java/jdeps.go.
-	a.modulePaths = append(a.modulePaths, ctx.ModuleDir())
 
 	// TODO(jiyong): do this using WalkPayloadDeps
 	// TODO(jiyong): make this clean!!!
 	vctx := visitorContext{
-		handleSpecialLibs: !android.Bool(a.properties.Ignore_system_library_special_case),
-		checkDuplicate:    a.shouldCheckDuplicate(ctx),
+		handleSpecialLibs:      !android.Bool(a.properties.Ignore_system_library_special_case),
+		checkDuplicate:         a.shouldCheckDuplicate(ctx),
+		unwantedTransitiveDeps: a.properties.Unwanted_transitive_deps,
 	}
 	ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool { return a.depVisitor(&vctx, ctx, child, parent) })
 	vctx.normalizeFileInfo(ctx)
@@ -2615,18 +2408,17 @@
 			return
 		}
 	}
+	android.CollectDependencyAconfigFiles(ctx, &a.mergedAconfigFiles)
 
 	////////////////////////////////////////////////////////////////////////////////////////////
 	// 3) some fields in apexBundle struct are configured
 	a.installDir = android.PathForModuleInstall(ctx, "apex")
 	a.filesInfo = vctx.filesInfo
+	a.aconfigFiles = android.FirstUniquePaths(vctx.aconfigFiles)
 
-	a.setApexTypeAndSuffix(ctx)
 	a.setPayloadFsType(ctx)
 	a.setSystemLibLink(ctx)
-	if a.properties.ApexType != zipApex {
-		a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType)
-	}
+	a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx)
 
 	////////////////////////////////////////////////////////////////////////////////////////////
 	// 4) generate the build rules to create the APEX. This is done in builder.go.
@@ -2634,12 +2426,43 @@
 	a.buildApex(ctx)
 	a.buildApexDependencyInfo(ctx)
 	a.buildLintReports(ctx)
+
+	// Set a provider for dexpreopt of bootjars
+	a.provideApexExportsInfo(ctx)
+
+	a.providePrebuiltInfo(ctx)
+}
+
+// Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file
+// with information about whether source or prebuilt of an apex was used during the build.
+func (a *apexBundle) providePrebuiltInfo(ctx android.ModuleContext) {
+	info := android.PrebuiltInfo{
+		Name:        a.Name(),
+		Is_prebuilt: false,
+	}
+	android.SetProvider(ctx, android.PrebuiltInfoProvider, info)
+}
+
+// Set a provider containing information about the jars and .prof provided by the apex
+// Apexes built from source retrieve this information by visiting `bootclasspath_fragments`
+// Used by dex_bootjars to generate the boot image
+func (a *apexBundle) provideApexExportsInfo(ctx android.ModuleContext) {
+	ctx.VisitDirectDepsWithTag(bcpfTag, func(child android.Module) {
+		if info, ok := android.OtherModuleProvider(ctx, child, java.BootclasspathFragmentApexContentInfoProvider); ok {
+			exports := android.ApexExportsInfo{
+				ApexName:                      a.ApexVariationName(),
+				ProfilePathOnHost:             info.ProfilePathOnHost(),
+				LibraryNameToDexJarPathOnHost: info.DexBootJarPathMap(),
+			}
+			android.SetProvider(ctx, android.ApexExportsInfoProvider, exports)
+		}
+	})
 }
 
 // apexBootclasspathFragmentFiles returns the list of apexFile structures defining the files that
 // the bootclasspath_fragment contributes to the apex.
 func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module blueprint.Module) []apexFile {
-	bootclasspathFragmentInfo := ctx.OtherModuleProvider(module, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
+	bootclasspathFragmentInfo, _ := android.OtherModuleProvider(ctx, module, java.BootclasspathFragmentApexContentInfoProvider)
 	var filesToAdd []apexFile
 
 	// Add classpaths.proto config.
@@ -2688,7 +2511,7 @@
 // apexClasspathFragmentProtoFile returns *apexFile structure defining the classpath.proto config that
 // the module contributes to the apex; or nil if the proto config was not generated.
 func apexClasspathFragmentProtoFile(ctx android.ModuleContext, module blueprint.Module) *apexFile {
-	info := ctx.OtherModuleProvider(module, java.ClasspathFragmentProtoContentInfoProvider).(java.ClasspathFragmentProtoContentInfo)
+	info, _ := android.OtherModuleProvider(ctx, module, java.ClasspathFragmentProtoContentInfoProvider)
 	if !info.ClasspathFragmentProtoGenerated {
 		return nil
 	}
@@ -2700,7 +2523,7 @@
 // apexFileForBootclasspathFragmentContentModule creates an apexFile for a bootclasspath_fragment
 // content module, i.e. a library that is part of the bootclasspath.
 func apexFileForBootclasspathFragmentContentModule(ctx android.ModuleContext, fragmentModule blueprint.Module, javaModule javaModule) apexFile {
-	bootclasspathFragmentInfo := ctx.OtherModuleProvider(fragmentModule, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
+	bootclasspathFragmentInfo, _ := android.OtherModuleProvider(ctx, fragmentModule, java.BootclasspathFragmentApexContentInfoProvider)
 
 	// Get the dexBootJar from the bootclasspath_fragment as that is responsible for performing the
 	// hidden API encpding.
@@ -2727,10 +2550,9 @@
 	module.AddProperties(&module.archProperties)
 	module.AddProperties(&module.overridableProperties)
 
-	android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
+	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
 	android.InitOverridableModule(module, &module.overridableProperties.Overrides)
-	android.InitBazelModule(module)
 	multitree.InitExportableModule(module)
 	return module
 }
@@ -2758,6 +2580,9 @@
 type Defaults struct {
 	android.ModuleBase
 	android.DefaultsModuleBase
+
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
 }
 
 // apex_defaults provides defaultable properties to other apex modules.
@@ -2778,7 +2603,10 @@
 type OverrideApex struct {
 	android.ModuleBase
 	android.OverrideModuleBase
-	android.BazelModuleBase
+}
+
+func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	android.CollectDependencyAconfigFiles(ctx, &d.mergedAconfigFiles)
 }
 
 func (o *OverrideApex) GenerateAndroidBuildActions(_ android.ModuleContext) {
@@ -2794,104 +2622,9 @@
 
 	android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon)
 	android.InitOverrideModule(m)
-	android.InitBazelModule(m)
 	return m
 }
 
-func (o *OverrideApex) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	if ctx.ModuleType() != "override_apex" {
-		return
-	}
-
-	baseApexModuleName := o.OverrideModuleBase.GetOverriddenModuleName()
-	baseModule, baseApexExists := ctx.ModuleFromName(baseApexModuleName)
-	if !baseApexExists {
-		panic(fmt.Errorf("Base apex module doesn't exist: %s", baseApexModuleName))
-	}
-
-	a, baseModuleIsApex := baseModule.(*apexBundle)
-	if !baseModuleIsApex {
-		panic(fmt.Errorf("Base module is not apex module: %s", baseApexModuleName))
-	}
-	attrs, props, commonAttrs := convertWithBp2build(a, ctx)
-
-	// We just want the name, not module reference.
-	baseApexName := strings.TrimPrefix(baseApexModuleName, ":")
-	attrs.Base_apex_name = &baseApexName
-
-	for _, p := range o.GetProperties() {
-		overridableProperties, ok := p.(*overridableProperties)
-		if !ok {
-			continue
-		}
-
-		// Manifest is either empty or a file in the directory of base APEX and is not overridable.
-		// After it is converted in convertWithBp2build(baseApex, ctx),
-		// the attrs.Manifest.Value.Label is the file path relative to the directory
-		// of base apex. So the following code converts it to a label that looks like
-		// <package of base apex>:<path of manifest file> if base apex and override
-		// apex are not in the same package.
-		baseApexPackage := ctx.OtherModuleDir(a)
-		overrideApexPackage := ctx.ModuleDir()
-		if baseApexPackage != overrideApexPackage {
-			attrs.Manifest.Value.Label = "//" + baseApexPackage + ":" + attrs.Manifest.Value.Label
-		}
-
-		// Key
-		if overridableProperties.Key != nil {
-			attrs.Key = bazel.LabelAttribute{}
-			attrs.Key.SetValue(android.BazelLabelForModuleDepSingle(ctx, *overridableProperties.Key))
-		}
-
-		// Certificate
-		if overridableProperties.Certificate == nil {
-			// If overridableProperties.Certificate is nil, clear this out as
-			// well with zeroed structs, so the override_apex does not use the
-			// base apex's certificate.
-			attrs.Certificate = bazel.LabelAttribute{}
-			attrs.Certificate_name = bazel.StringAttribute{}
-		} else {
-			attrs.Certificate, attrs.Certificate_name = android.BazelStringOrLabelFromProp(ctx, overridableProperties.Certificate)
-		}
-
-		// Prebuilts
-		if overridableProperties.Prebuilts != nil {
-			prebuiltsLabelList := android.BazelLabelForModuleDeps(ctx, overridableProperties.Prebuilts)
-			attrs.Prebuilts = bazel.MakeLabelListAttribute(prebuiltsLabelList)
-		}
-
-		// Compressible
-		if overridableProperties.Compressible != nil {
-			attrs.Compressible = bazel.BoolAttribute{Value: overridableProperties.Compressible}
-		}
-
-		// Package name
-		//
-		// e.g. com.android.adbd's package name is com.android.adbd, but
-		// com.google.android.adbd overrides the package name to com.google.android.adbd
-		//
-		// TODO: this can be overridden from the product configuration, see
-		// getOverrideManifestPackageName and
-		// PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES.
-		//
-		// Instead of generating the BUILD files differently based on the product config
-		// at the point of conversion, this should be handled by the BUILD file loading
-		// from the soong_injection's product_vars, so product config is decoupled from bp2build.
-		if overridableProperties.Package_name != "" {
-			attrs.Package_name = &overridableProperties.Package_name
-		}
-
-		// Logging parent
-		if overridableProperties.Logging_parent != "" {
-			attrs.Logging_parent = &overridableProperties.Logging_parent
-		}
-	}
-
-	commonAttrs.Name = o.Name()
-
-	ctx.CreateBazelTargetModule(props, commonAttrs, &attrs)
-}
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Vality check routines
 //
@@ -2918,13 +2651,13 @@
 	// Only override the minSdkVersion value on Apexes which already specify
 	// a min_sdk_version (it's optional for non-updatable apexes), and that its
 	// min_sdk_version value is lower than the one to override with.
-	minApiLevel := minSdkVersionFromValue(ctx, proptools.String(a.properties.Min_sdk_version))
+	minApiLevel := android.MinSdkVersionFromValue(ctx, proptools.String(a.properties.Min_sdk_version))
 	if minApiLevel.IsNone() {
 		return ""
 	}
 
 	overrideMinSdkValue := ctx.DeviceConfig().ApexGlobalMinSdkVersionOverride()
-	overrideApiLevel := minSdkVersionFromValue(ctx, overrideMinSdkValue)
+	overrideApiLevel := android.MinSdkVersionFromValue(ctx, overrideMinSdkValue)
 	if !overrideApiLevel.IsNone() && overrideApiLevel.CompareTo(minApiLevel) > 0 {
 		minApiLevel = overrideApiLevel
 	}
@@ -2939,30 +2672,17 @@
 
 // Returns apex's min_sdk_version ApiLevel, honoring overrides
 func (a *apexBundle) minSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
-	return minSdkVersionFromValue(ctx, a.minSdkVersionValue(ctx))
-}
-
-// Construct ApiLevel object from min_sdk_version string value
-func minSdkVersionFromValue(ctx android.EarlyModuleContext, value string) android.ApiLevel {
-	if value == "" {
-		return android.NoneApiLevel
-	}
-	apiLevel, err := android.ApiLevelFromUser(ctx, value)
-	if err != nil {
-		ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
-		return android.NoneApiLevel
-	}
-	return apiLevel
+	return android.MinSdkVersionFromValue(ctx, a.minSdkVersionValue(ctx))
 }
 
 // Ensures that a lib providing stub isn't statically linked
 func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext) {
 	// Practically, we only care about regular APEXes on the device.
-	if ctx.Host() || a.testApex || a.vndkApex {
+	if a.testApex || a.vndkApex {
 		return
 	}
 
-	abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo)
+	abInfo, _ := android.ModuleProvider(ctx, android.ApexBundleInfoProvider)
 
 	a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		if ccm, ok := to.(*cc.Module); ok {
@@ -3023,7 +2743,7 @@
 func (a *apexBundle) checkClasspathFragments(ctx android.ModuleContext) {
 	ctx.VisitDirectDeps(func(module android.Module) {
 		if tag := ctx.OtherModuleDependencyTag(module); tag == bcpfTag || tag == sscpfTag {
-			info := ctx.OtherModuleProvider(module, java.ClasspathFragmentProtoContentInfoProvider).(java.ClasspathFragmentProtoContentInfo)
+			info, _ := android.OtherModuleProvider(ctx, module, java.ClasspathFragmentProtoContentInfoProvider)
 			if !info.ClasspathFragmentProtoGenerated {
 				ctx.OtherModuleErrorf(module, "is included in updatable apex %v, it must not set generate_classpaths_proto to false", ctx.ModuleName())
 			}
@@ -3053,7 +2773,7 @@
 // checkApexAvailability ensures that the all the dependencies are marked as available for this APEX.
 func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
 	// Let's be practical. Availability for test, host, and the VNDK apex isn't important
-	if ctx.Host() || a.testApex || a.vndkApex {
+	if a.testApex || a.vndkApex {
 		return
 	}
 
@@ -3111,11 +2831,6 @@
 
 // checkStaticExecutable ensures that executables in an APEX are not static.
 func (a *apexBundle) checkStaticExecutables(ctx android.ModuleContext) {
-	// No need to run this for host APEXes
-	if ctx.Host() {
-		return
-	}
-
 	ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
 		if ctx.OtherModuleDependencyTag(module) != executableTag {
 			return
@@ -3149,7 +2864,6 @@
 	dpInfo.Deps = append(dpInfo.Deps, a.properties.Java_libs...)
 	dpInfo.Deps = append(dpInfo.Deps, a.properties.Bootclasspath_fragments...)
 	dpInfo.Deps = append(dpInfo.Deps, a.properties.Systemserverclasspath_fragments...)
-	dpInfo.Paths = append(dpInfo.Paths, a.modulePaths...)
 }
 
 var (
@@ -3214,130 +2928,8 @@
 	//
 	// Module separator
 	//
-	m["com.android.appsearch"] = []string{
-		"icing-java-proto-lite",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.btservices"] = []string{
-		// empty
-	}
-	//
-	// Module separator
-	//
-	m["com.android.cellbroadcast"] = []string{}
-	//
-	// Module separator
-	//
-	m["com.android.extservices"] = []string{
-		"ExtServices-core",
-		"libtextclassifier-java",
-		"textclassifier-statsd",
-		"TextClassifierNotificationLibNoManifest",
-		"TextClassifierServiceLibNoManifest",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.neuralnetworks"] = []string{
-		"android.hardware.neuralnetworks@1.0",
-		"android.hardware.neuralnetworks@1.1",
-		"android.hardware.neuralnetworks@1.2",
-		"android.hardware.neuralnetworks@1.3",
-		"android.hidl.allocator@1.0",
-		"android.hidl.memory.token@1.0",
-		"android.hidl.memory@1.0",
-		"android.hidl.safe_union@1.0",
-		"libarect",
-		"libprocpartition",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.media"] = []string{
-		// empty
-	}
-	//
-	// Module separator
-	//
-	m["com.android.media.swcodec"] = []string{
-		// empty
-	}
-	//
-	// Module separator
-	//
-	m["com.android.mediaprovider"] = []string{
-		"MediaProvider",
-		"MediaProviderGoogle",
-		"fmtlib_ndk",
-		"libbase_ndk",
-		"libfuse",
-		"libfuse_jni",
-	}
-	//
-	// Module separator
-	//
 	m["com.android.runtime"] = []string{
-		"libdebuggerd",
-		"libdebuggerd_common_headers",
-		"libdebuggerd_handler_core",
-		"libdl_static",
-		"libjemalloc5",
-		"liblinker_main",
-		"liblinker_malloc",
-		"liblzma",
-		"libprocinfo",
-		"libpropertyinfoparser",
-		"libscudo",
-		"libsystemproperties",
-		"libtombstoned_client_static",
-		"libunwindstack",
 		"libz",
-		"libziparchive",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.tethering"] = []string{
-		"android.hardware.tetheroffload.config-V1.0-java",
-		"android.hardware.tetheroffload.control-V1.0-java",
-		"net-utils-framework-common",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.wifi"] = []string{
-		"PlatformProperties",
-		"android.hardware.wifi-V1.0-java",
-		"android.hardware.wifi-V1.0-java-constants",
-		"android.hardware.wifi-V1.1-java",
-		"android.hardware.wifi-V1.2-java",
-		"android.hardware.wifi-V1.3-java",
-		"android.hardware.wifi-V1.4-java",
-		"android.hardware.wifi.hostapd-V1.0-java",
-		"android.hardware.wifi.hostapd-V1.1-java",
-		"android.hardware.wifi.hostapd-V1.2-java",
-		"android.hardware.wifi.supplicant-V1.0-java",
-		"android.hardware.wifi.supplicant-V1.1-java",
-		"android.hardware.wifi.supplicant-V1.2-java",
-		"android.hardware.wifi.supplicant-V1.3-java",
-		"bouncycastle-unbundled",
-		"framework-wifi-util-lib",
-		"ksoap2",
-		"libnanohttpd",
-		"wifi-lite-protos",
-		"wifi-nano-protos",
-		"wifi-service-pre-jarjar",
-	}
-	//
-	// Module separator
-	//
-	m[android.AvailableToAnyApex] = []string{
-		"libprofile-clang-extras",
-		"libprofile-clang-extras_ndk",
-		"libprofile-extras",
-		"libprofile-extras_ndk",
 	}
 	return m
 }
@@ -3418,303 +3010,6 @@
 	}
 }
 
-// For Bazel / bp2build
-
-type bazelApexBundleAttributes struct {
-	Manifest              bazel.LabelAttribute
-	Android_manifest      bazel.LabelAttribute
-	File_contexts         bazel.LabelAttribute
-	Canned_fs_config      bazel.LabelAttribute
-	Key                   bazel.LabelAttribute
-	Certificate           bazel.LabelAttribute  // used when the certificate prop is a module
-	Certificate_name      bazel.StringAttribute // used when the certificate prop is a string
-	Min_sdk_version       bazel.StringAttribute
-	Updatable             bazel.BoolAttribute
-	Installable           bazel.BoolAttribute
-	Binaries              bazel.LabelListAttribute
-	Prebuilts             bazel.LabelListAttribute
-	Native_shared_libs_32 bazel.LabelListAttribute
-	Native_shared_libs_64 bazel.LabelListAttribute
-	Compressible          bazel.BoolAttribute
-	Package_name          *string
-	Logging_parent        *string
-	Tests                 bazel.LabelListAttribute
-	Base_apex_name        *string
-	Apex_available_name   *string
-	Variant_version       *string
-}
-
-type convertedNativeSharedLibs struct {
-	Native_shared_libs_32 bazel.LabelListAttribute
-	Native_shared_libs_64 bazel.LabelListAttribute
-}
-
-const (
-	minSdkVersionPropName = "Min_sdk_version"
-)
-
-// ConvertWithBp2build performs bp2build conversion of an apex
-func (a *apexBundle) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	// We only convert apex and apex_test modules at this time
-	if ctx.ModuleType() != "apex" && ctx.ModuleType() != "apex_test" {
-		return
-	}
-
-	attrs, props, commonAttrs := convertWithBp2build(a, ctx)
-	commonAttrs.Name = a.Name()
-	ctx.CreateBazelTargetModule(props, commonAttrs, &attrs)
-}
-
-func convertWithBp2build(a *apexBundle, ctx android.TopDownMutatorContext) (bazelApexBundleAttributes, bazel.BazelTargetModuleProperties, android.CommonAttributes) {
-	var manifestLabelAttribute bazel.LabelAttribute
-	manifestLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json")))
-
-	var androidManifestLabelAttribute bazel.LabelAttribute
-	if a.properties.AndroidManifest != nil {
-		androidManifestLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *a.properties.AndroidManifest))
-	}
-
-	var fileContextsLabelAttribute bazel.LabelAttribute
-	if a.properties.File_contexts == nil {
-		// See buildFileContexts(), if file_contexts is not specified the default one is used, which is //system/sepolicy/apex:<module name>-file_contexts
-		fileContextsLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, a.Name()+"-file_contexts"))
-	} else if strings.HasPrefix(*a.properties.File_contexts, ":") {
-		// File_contexts is a module
-		fileContextsLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *a.properties.File_contexts))
-	} else {
-		// File_contexts is a file
-		fileContextsLabelAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *a.properties.File_contexts))
-	}
-
-	var cannedFsConfigAttribute bazel.LabelAttribute
-	if a.properties.Canned_fs_config != nil {
-		cannedFsConfigAttribute.SetValue(android.BazelLabelForModuleSrcSingle(ctx, *a.properties.Canned_fs_config))
-	}
-
-	productVariableProps := android.ProductVariableProperties(ctx, a)
-	// TODO(b/219503907) this would need to be set to a.MinSdkVersionValue(ctx) but
-	// given it's coming via config, we probably don't want to put it in here.
-	var minSdkVersion bazel.StringAttribute
-	if a.properties.Min_sdk_version != nil {
-		minSdkVersion.SetValue(*a.properties.Min_sdk_version)
-	}
-	if props, ok := productVariableProps[minSdkVersionPropName]; ok {
-		for c, p := range props {
-			if val, ok := p.(*string); ok {
-				minSdkVersion.SetSelectValue(c.ConfigurationAxis(), c.SelectKey(), val)
-			}
-		}
-	}
-
-	var keyLabelAttribute bazel.LabelAttribute
-	if a.overridableProperties.Key != nil {
-		keyLabelAttribute.SetValue(android.BazelLabelForModuleDepSingle(ctx, *a.overridableProperties.Key))
-	}
-
-	// Certificate
-	certificate, certificateName := android.BazelStringOrLabelFromProp(ctx, a.overridableProperties.Certificate)
-
-	nativeSharedLibs := &convertedNativeSharedLibs{
-		Native_shared_libs_32: bazel.LabelListAttribute{},
-		Native_shared_libs_64: bazel.LabelListAttribute{},
-	}
-
-	// https://cs.android.com/android/platform/superproject/+/master:build/soong/android/arch.go;l=698;drc=f05b0d35d2fbe51be9961ce8ce8031f840295c68
-	// https://cs.android.com/android/platform/superproject/+/master:build/soong/apex/apex.go;l=2549;drc=ec731a83e3e2d80a1254e32fd4ad7ef85e262669
-	// In Soong, decodeMultilib, used to get multilib, return "first" if defaultMultilib is set to "common".
-	// Since apex sets defaultMultilib to be "common", equivalent compileMultilib in bp2build for apex should be "first"
-	compileMultilib := "first"
-	if a.CompileMultilib() != nil {
-		compileMultilib = *a.CompileMultilib()
-	}
-
-	// properties.Native_shared_libs is treated as "both"
-	convertBothLibs(ctx, compileMultilib, a.properties.Native_shared_libs, nativeSharedLibs)
-	convertBothLibs(ctx, compileMultilib, a.properties.Multilib.Both.Native_shared_libs, nativeSharedLibs)
-	convert32Libs(ctx, compileMultilib, a.properties.Multilib.Lib32.Native_shared_libs, nativeSharedLibs)
-	convert64Libs(ctx, compileMultilib, a.properties.Multilib.Lib64.Native_shared_libs, nativeSharedLibs)
-	convertFirstLibs(ctx, compileMultilib, a.properties.Multilib.First.Native_shared_libs, nativeSharedLibs)
-
-	prebuilts := a.overridableProperties.Prebuilts
-	prebuiltsLabelList := android.BazelLabelForModuleDeps(ctx, prebuilts)
-	prebuiltsLabelListAttribute := bazel.MakeLabelListAttribute(prebuiltsLabelList)
-
-	binaries := android.BazelLabelForModuleDeps(ctx, a.properties.ApexNativeDependencies.Binaries)
-	binariesLabelListAttribute := bazel.MakeLabelListAttribute(binaries)
-
-	var testsAttrs bazel.LabelListAttribute
-	if a.testApex && len(a.properties.ApexNativeDependencies.Tests) > 0 {
-		tests := android.BazelLabelForModuleDeps(ctx, a.properties.ApexNativeDependencies.Tests)
-		testsAttrs = bazel.MakeLabelListAttribute(tests)
-	}
-
-	var updatableAttribute bazel.BoolAttribute
-	if a.properties.Updatable != nil {
-		updatableAttribute.Value = a.properties.Updatable
-	}
-
-	var installableAttribute bazel.BoolAttribute
-	if a.properties.Installable != nil {
-		installableAttribute.Value = a.properties.Installable
-	}
-
-	var compressibleAttribute bazel.BoolAttribute
-	if a.overridableProperties.Compressible != nil {
-		compressibleAttribute.Value = a.overridableProperties.Compressible
-	}
-
-	var packageName *string
-	if a.overridableProperties.Package_name != "" {
-		packageName = &a.overridableProperties.Package_name
-	}
-
-	var loggingParent *string
-	if a.overridableProperties.Logging_parent != "" {
-		loggingParent = &a.overridableProperties.Logging_parent
-	}
-
-	attrs := bazelApexBundleAttributes{
-		Manifest:              manifestLabelAttribute,
-		Android_manifest:      androidManifestLabelAttribute,
-		File_contexts:         fileContextsLabelAttribute,
-		Canned_fs_config:      cannedFsConfigAttribute,
-		Min_sdk_version:       minSdkVersion,
-		Key:                   keyLabelAttribute,
-		Certificate:           certificate,
-		Certificate_name:      certificateName,
-		Updatable:             updatableAttribute,
-		Installable:           installableAttribute,
-		Native_shared_libs_32: nativeSharedLibs.Native_shared_libs_32,
-		Native_shared_libs_64: nativeSharedLibs.Native_shared_libs_64,
-		Binaries:              binariesLabelListAttribute,
-		Prebuilts:             prebuiltsLabelListAttribute,
-		Compressible:          compressibleAttribute,
-		Package_name:          packageName,
-		Logging_parent:        loggingParent,
-		Tests:                 testsAttrs,
-		Apex_available_name:   a.properties.Apex_available_name,
-		Variant_version:       a.properties.Variant_version,
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "apex",
-		Bzl_load_location: "//build/bazel/rules/apex:apex.bzl",
-	}
-
-	commonAttrs := android.CommonAttributes{}
-	if a.testApex {
-		commonAttrs.Testonly = proptools.BoolPtr(true)
-		// Set the api_domain of the test apex
-		attrs.Base_apex_name = proptools.StringPtr(cc.GetApiDomain(a.Name()))
-	}
-
-	return attrs, props, commonAttrs
-}
-
-// The following conversions are based on this table where the rows are the compile_multilib
-// values and the columns are the properties.Multilib.*.Native_shared_libs. Each cell
-// represents how the libs should be compiled for a 64-bit/32-bit device: 32 means it
-// should be compiled as 32-bit, 64 means it should be compiled as 64-bit, none means it
-// should not be compiled.
-// multib/compile_multilib, 32,        64,        both,     first
-// 32,                      32/32,     none/none, 32/32,    none/32
-// 64,                      none/none, 64/none,   64/none,  64/none
-// both,                    32/32,     64/none,   32&64/32, 64/32
-// first,                   32/32,     64/none,   64/32,    64/32
-
-func convert32Libs(ctx android.TopDownMutatorContext, compileMultilb string,
-	libs []string, nativeSharedLibs *convertedNativeSharedLibs) {
-	libsLabelList := android.BazelLabelForModuleDeps(ctx, libs)
-	switch compileMultilb {
-	case "both", "32":
-		makeNoConfig32SharedLibsAttributes(libsLabelList, nativeSharedLibs)
-	case "first":
-		make32SharedLibsAttributes(libsLabelList, nativeSharedLibs)
-	case "64":
-		// Incompatible, ignore
-	default:
-		invalidCompileMultilib(ctx, compileMultilb)
-	}
-}
-
-func convert64Libs(ctx android.TopDownMutatorContext, compileMultilb string,
-	libs []string, nativeSharedLibs *convertedNativeSharedLibs) {
-	libsLabelList := android.BazelLabelForModuleDeps(ctx, libs)
-	switch compileMultilb {
-	case "both", "64", "first":
-		make64SharedLibsAttributes(libsLabelList, nativeSharedLibs)
-	case "32":
-		// Incompatible, ignore
-	default:
-		invalidCompileMultilib(ctx, compileMultilb)
-	}
-}
-
-func convertBothLibs(ctx android.TopDownMutatorContext, compileMultilb string,
-	libs []string, nativeSharedLibs *convertedNativeSharedLibs) {
-	libsLabelList := android.BazelLabelForModuleDeps(ctx, libs)
-	switch compileMultilb {
-	case "both":
-		makeNoConfig32SharedLibsAttributes(libsLabelList, nativeSharedLibs)
-		make64SharedLibsAttributes(libsLabelList, nativeSharedLibs)
-	case "first":
-		makeFirstSharedLibsAttributes(libsLabelList, nativeSharedLibs)
-	case "32":
-		makeNoConfig32SharedLibsAttributes(libsLabelList, nativeSharedLibs)
-	case "64":
-		make64SharedLibsAttributes(libsLabelList, nativeSharedLibs)
-	default:
-		invalidCompileMultilib(ctx, compileMultilb)
-	}
-}
-
-func convertFirstLibs(ctx android.TopDownMutatorContext, compileMultilb string,
-	libs []string, nativeSharedLibs *convertedNativeSharedLibs) {
-	libsLabelList := android.BazelLabelForModuleDeps(ctx, libs)
-	switch compileMultilb {
-	case "both", "first":
-		makeFirstSharedLibsAttributes(libsLabelList, nativeSharedLibs)
-	case "32":
-		make32SharedLibsAttributes(libsLabelList, nativeSharedLibs)
-	case "64":
-		make64SharedLibsAttributes(libsLabelList, nativeSharedLibs)
-	default:
-		invalidCompileMultilib(ctx, compileMultilb)
-	}
-}
-
-func makeFirstSharedLibsAttributes(libsLabelList bazel.LabelList, nativeSharedLibs *convertedNativeSharedLibs) {
-	make32SharedLibsAttributes(libsLabelList, nativeSharedLibs)
-	make64SharedLibsAttributes(libsLabelList, nativeSharedLibs)
-}
-
-func makeNoConfig32SharedLibsAttributes(libsLabelList bazel.LabelList, nativeSharedLibs *convertedNativeSharedLibs) {
-	list := bazel.LabelListAttribute{}
-	list.SetSelectValue(bazel.NoConfigAxis, "", libsLabelList)
-	nativeSharedLibs.Native_shared_libs_32.Append(list)
-}
-
-func make32SharedLibsAttributes(libsLabelList bazel.LabelList, nativeSharedLibs *convertedNativeSharedLibs) {
-	makeSharedLibsAttributes("x86", libsLabelList, &nativeSharedLibs.Native_shared_libs_32)
-	makeSharedLibsAttributes("arm", libsLabelList, &nativeSharedLibs.Native_shared_libs_32)
-}
-
-func make64SharedLibsAttributes(libsLabelList bazel.LabelList, nativeSharedLibs *convertedNativeSharedLibs) {
-	makeSharedLibsAttributes("x86_64", libsLabelList, &nativeSharedLibs.Native_shared_libs_64)
-	makeSharedLibsAttributes("arm64", libsLabelList, &nativeSharedLibs.Native_shared_libs_64)
-}
-
-func makeSharedLibsAttributes(config string, libsLabelList bazel.LabelList,
-	labelListAttr *bazel.LabelListAttribute) {
-	list := bazel.LabelListAttribute{}
-	list.SetSelectValue(bazel.ArchConfigurationAxis, config, libsLabelList)
-	labelListAttr.Append(list)
-}
-
-func invalidCompileMultilib(ctx android.TopDownMutatorContext, value string) {
-	ctx.PropertyErrorf("compile_multilib", "Invalid value: %s", value)
-}
-
 func (a *apexBundle) IsTestApex() bool {
 	return a.testApex
 }
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index a63344f..e6ebff2 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -17,6 +17,8 @@
 package apex
 
 import (
+	"encoding/json"
+
 	"github.com/google/blueprint"
 
 	"android/soong/android"
@@ -83,7 +85,7 @@
 	updatableFlatLists := android.Paths{}
 	ctx.VisitAllModules(func(module android.Module) {
 		if binaryInfo, ok := module.(android.ApexBundleDepsInfoIntf); ok {
-			apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+			apexInfo, _ := android.SingletonModuleProvider(ctx, module, android.ApexInfoProvider)
 			if path := binaryInfo.FlatListPath(); path != nil {
 				if binaryInfo.Updatable() || apexInfo.Updatable {
 					updatableFlatLists = append(updatableFlatLists, path)
@@ -129,3 +131,43 @@
 	// Export check result to Make. The path is added to droidcore.
 	ctx.Strict("APEX_ALLOWED_DEPS_CHECK", s.allowedApexDepsInfoCheckResult.String())
 }
+
+func init() {
+	registerApexPrebuiltInfoComponents(android.InitRegistrationContext)
+}
+
+func registerApexPrebuiltInfoComponents(ctx android.RegistrationContext) {
+	ctx.RegisterParallelSingletonType("apex_prebuiltinfo_singleton", apexPrebuiltInfoFactory)
+}
+
+func apexPrebuiltInfoFactory() android.Singleton {
+	return &apexPrebuiltInfo{}
+}
+
+type apexPrebuiltInfo struct {
+	out android.WritablePath
+}
+
+func (a *apexPrebuiltInfo) GenerateBuildActions(ctx android.SingletonContext) {
+	prebuiltInfos := []android.PrebuiltInfo{}
+
+	ctx.VisitAllModules(func(m android.Module) {
+		prebuiltInfo, exists := android.SingletonModuleProvider(ctx, m, android.PrebuiltInfoProvider)
+		// Use prebuiltInfoProvider to filter out non apex soong modules.
+		// Use HideFromMake to filter out the unselected variants of a specific apex.
+		if exists && !m.IsHideFromMake() {
+			prebuiltInfos = append(prebuiltInfos, prebuiltInfo)
+		}
+	})
+
+	j, err := json.Marshal(prebuiltInfos)
+	if err != nil {
+		ctx.Errorf("Could not convert prebuilt info of apexes to json due to error: %v", err)
+	}
+	a.out = android.PathForOutput(ctx, "prebuilt_info.json")
+	android.WriteFileRule(ctx, a.out, string(j))
+}
+
+func (a *apexPrebuiltInfo) MakeVars(ctx android.MakeVarsContext) {
+	ctx.DistForGoal("droidcore", a.out)
+}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index bd19cb5..3e284b1 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -25,6 +25,8 @@
 	"strings"
 	"testing"
 
+	"android/soong/aconfig/codegen"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -151,6 +153,7 @@
 	prebuilt_etc.PrepareForTestWithPrebuiltEtc,
 	rust.PrepareForTestWithRustDefaultModules,
 	sh.PrepareForTestWithShBuildComponents,
+	codegen.PrepareForTestWithAconfigBuildComponents,
 
 	PrepareForTestWithApexBuildComponents,
 
@@ -215,7 +218,6 @@
 	),
 
 	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-		variables.DeviceVndkVersion = proptools.StringPtr("current")
 		variables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test")
 		variables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"}
 		variables.Platform_sdk_codename = proptools.StringPtr("Q")
@@ -223,7 +225,6 @@
 		// "Tiramisu" needs to be in the next line for compatibility with soong code,
 		// not because of these tests specifically (it's not used by the tests)
 		variables.Platform_version_active_codenames = []string{"Q", "Tiramisu"}
-		variables.Platform_vndk_version = proptools.StringPtr("29")
 		variables.BuildId = proptools.StringPtr("TEST.BUILD_ID")
 	}),
 )
@@ -390,7 +391,7 @@
 			name: "foo.rust",
 			srcs: ["foo.rs"],
 			rlibs: ["libfoo.rlib.rust"],
-			dylibs: ["libfoo.dylib.rust"],
+			rustlibs: ["libfoo.dylib.rust"],
 			apex_available: ["myapex"],
 		}
 
@@ -518,10 +519,10 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 
 	// Make sure that Android.mk is created
-	ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	ab := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, ab)
 	var builder strings.Builder
 	data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data)
@@ -533,7 +534,7 @@
 	optFlags := apexRule.Args["opt_flags"]
 	ensureContains(t, optFlags, "--pubkey vendor/foo/devkeys/testkey.avbpubkey")
 	// Ensure that the NOTICE output is being packaged as an asset.
-	ensureContains(t, optFlags, "--assets_dir out/soong/.intermediates/myapex/android_common_myapex_image/NOTICE")
+	ensureContains(t, optFlags, "--assets_dir out/soong/.intermediates/myapex/android_common_myapex/NOTICE")
 
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -595,13 +596,15 @@
 		t.Errorf("Could not find all expected symlinks! foo: %t, foo_link_64: %t. Command was %s", found_foo, found_foo_link_64, copyCmds)
 	}
 
-	fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
+	fullDepsInfo := strings.Split(android.ContentFromFileRuleForTests(t, ctx,
+		ctx.ModuleForTests("myapex", "android_common_myapex").Output("depsinfo/fulllist.txt")), "\n")
 	ensureListContains(t, fullDepsInfo, "  myjar(minSdkVersion:(no version)) <- myapex")
 	ensureListContains(t, fullDepsInfo, "  mylib2(minSdkVersion:(no version)) <- mylib")
 	ensureListContains(t, fullDepsInfo, "  myotherjar(minSdkVersion:(no version)) <- myjar")
 	ensureListContains(t, fullDepsInfo, "  mysharedjar(minSdkVersion:(no version)) (external) <- myjar")
 
-	flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/flatlist.txt").Args["content"], "\\n")
+	flatDepsInfo := strings.Split(android.ContentFromFileRuleForTests(t, ctx,
+		ctx.ModuleForTests("myapex", "android_common_myapex").Output("depsinfo/flatlist.txt")), "\n")
 	ensureListContains(t, flatDepsInfo, "myjar(minSdkVersion:(no version))")
 	ensureListContains(t, flatDepsInfo, "mylib2(minSdkVersion:(no version))")
 	ensureListContains(t, flatDepsInfo, "myotherjar(minSdkVersion:(no version))")
@@ -678,7 +681,7 @@
 		}
 
 	`)
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"etc/myetc",
 		"javalib/myjar.jar",
 		"lib64/mylib.so",
@@ -705,7 +708,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	args := module.Rule("apexRule").Args
 	if manifest := args["manifest"]; manifest != module.Output("apex_manifest.pb").Output.String() {
 		t.Error("manifest should be apex_manifest.pb, but " + manifest)
@@ -776,7 +779,80 @@
 		},
 	}
 	for _, tc := range testCases {
-		module := ctx.ModuleForTests(tc.module, "android_common_"+tc.module+"_image")
+		module := ctx.ModuleForTests(tc.module, "android_common_"+tc.module)
+		args := module.Rule("apexRule").Args
+		optFlags := args["opt_flags"]
+		if !strings.Contains(optFlags, "--min_sdk_version "+tc.minSdkVersion) {
+			t.Errorf("%s: Expected min_sdk_version=%s, got: %s", tc.module, tc.minSdkVersion, optFlags)
+		}
+	}
+}
+
+func TestApexWithDessertSha(t *testing.T) {
+	ctx := testApex(t, `
+		apex_defaults {
+			name: "my_defaults",
+			key: "myapex.key",
+			product_specific: true,
+			file_contexts: ":my-file-contexts",
+			updatable: false,
+		}
+		apex {
+			name: "myapex_30",
+			min_sdk_version: "30",
+			defaults: ["my_defaults"],
+		}
+
+		apex {
+			name: "myapex_current",
+			min_sdk_version: "current",
+			defaults: ["my_defaults"],
+		}
+
+		apex {
+			name: "myapex_none",
+			defaults: ["my_defaults"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		filegroup {
+			name: "my-file-contexts",
+			srcs: ["product_specific_file_contexts"],
+		}
+	`, withFiles(map[string][]byte{
+		"product_specific_file_contexts": nil,
+	}), android.FixtureModifyProductVariables(
+		func(variables android.FixtureProductVariables) {
+			variables.Unbundled_build = proptools.BoolPtr(true)
+			variables.Always_use_prebuilt_sdks = proptools.BoolPtr(false)
+		}), android.FixtureMergeEnv(map[string]string{
+		"UNBUNDLED_BUILD_TARGET_SDK_WITH_DESSERT_SHA": "UpsideDownCake.abcdefghijklmnopqrstuvwxyz123456",
+	}))
+
+	testCases := []struct {
+		module        string
+		minSdkVersion string
+	}{
+		{
+			module:        "myapex_30",
+			minSdkVersion: "30",
+		},
+		{
+			module:        "myapex_current",
+			minSdkVersion: "UpsideDownCake.abcdefghijklmnopqrstuvwxyz123456",
+		},
+		{
+			module:        "myapex_none",
+			minSdkVersion: "UpsideDownCake.abcdefghijklmnopqrstuvwxyz123456",
+		},
+	}
+	for _, tc := range testCases {
+		module := ctx.ModuleForTests(tc.module, "android_common_"+tc.module)
 		args := module.Rule("apexRule").Args
 		optFlags := args["opt_flags"]
 		if !strings.Contains(optFlags, "--min_sdk_version "+tc.minSdkVersion) {
@@ -806,7 +882,7 @@
 			}
 		`)
 
-		rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("file_contexts")
+		rule := ctx.ModuleForTests("myapex", "android_common_myapex").Output("file_contexts")
 		if vendor {
 			android.AssertStringDoesContain(t, "should force-label as vendor_apex_metadata_file",
 				rule.RuleParams.Command,
@@ -819,57 +895,6 @@
 	}
 }
 
-func TestBasicZipApex(t *testing.T) {
-	ctx := testApex(t, `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			payload_type: "zip",
-			native_shared_libs: ["mylib"],
-			updatable: false,
-		}
-
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-
-		cc_library {
-			name: "mylib",
-			srcs: ["mylib.cpp"],
-			shared_libs: ["mylib2"],
-			system_shared_libs: [],
-			stl: "none",
-			apex_available: [ "myapex" ],
-		}
-
-		cc_library {
-			name: "mylib2",
-			srcs: ["mylib.cpp"],
-			system_shared_libs: [],
-			stl: "none",
-			apex_available: [ "myapex" ],
-		}
-	`)
-
-	zipApexRule := ctx.ModuleForTests("myapex", "android_common_myapex_zip").Rule("zipApexRule")
-	copyCmds := zipApexRule.Args["copy_commands"]
-
-	// Ensure that main rule creates an output
-	ensureContains(t, zipApexRule.Output.String(), "myapex.zipapex.unsigned")
-
-	// Ensure that APEX variant is created for the direct dep
-	ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000")
-
-	// Ensure that APEX variant is created for the indirect dep
-	ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000")
-
-	// Ensure that both direct and indirect deps are copied into apex
-	ensureContains(t, copyCmds, "image.zipapex/lib64/mylib.so")
-	ensureContains(t, copyCmds, "image.zipapex/lib64/mylib2.so")
-}
-
 func TestApexWithStubs(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
@@ -946,7 +971,7 @@
 
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -987,7 +1012,7 @@
 	// Ensure that genstub for apex-provided lib is invoked with --apex
 	ensureContains(t, ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_shared_12").Rule("genStubSrc").Args["flags"], "--apex")
 
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"lib64/mylib.so",
 		"lib64/mylib3.so",
 		"lib64/mylib4.so",
@@ -999,14 +1024,40 @@
 	// Ensure that stub dependency from a rust module is not included
 	ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
 	// The rust module is linked to the stub cc library
-	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustLink").Args["linkFlags"]
+	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"]
 	ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
 	ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
 
-	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
 	ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.shared_from_rust.so")
 }
 
+func TestApexShouldNotEmbedStubVariant(t *testing.T) {
+	testApexError(t, `module "myapex" .*: native_shared_libs: "libbar" is a stub`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			vendor: true,
+			updatable: false,
+			native_shared_libs: ["libbar"], // should not add an LLNDK stub in a vendor apex
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "libbar",
+			srcs: ["mylib.cpp"],
+			llndk: {
+				symbol_file: "libbar.map.txt",
+			}
+		}
+	`)
+}
+
 func TestApexCanUsePrivateApis(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
@@ -1063,7 +1114,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that indirect stubs dep is not included
@@ -1075,7 +1126,7 @@
 	mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
 	ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so")
 	ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
-	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustLink").Args["linkFlags"]
+	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"]
 	ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
 	ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
 }
@@ -1141,7 +1192,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -1172,7 +1223,7 @@
 	// Ensure that genstub is invoked with --systemapi
 	ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"], "--systemapi")
 
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"lib64/mylib.so",
 		"lib64/mylib3.so",
 		"lib64/mylib4.so",
@@ -1308,7 +1359,7 @@
 
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex2", "android_common_myapex2").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -1332,10 +1383,12 @@
 	// Ensure that libfoo stubs is not linking to libbar (since it is a stubs)
 	ensureNotContains(t, libFooStubsLdFlags, "libbar.so")
 
-	fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
+	fullDepsInfo := strings.Split(android.ContentFromFileRuleForTests(t, ctx,
+		ctx.ModuleForTests("myapex2", "android_common_myapex2").Output("depsinfo/fulllist.txt")), "\n")
 	ensureListContains(t, fullDepsInfo, "  libfoo(minSdkVersion:(no version)) (external) <- mylib")
 
-	flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/flatlist.txt").Args["content"], "\\n")
+	flatDepsInfo := strings.Split(android.ContentFromFileRuleForTests(t, ctx,
+		ctx.ModuleForTests("myapex2", "android_common_myapex2").Output("depsinfo/flatlist.txt")), "\n")
 	ensureListContains(t, flatDepsInfo, "libfoo(minSdkVersion:(no version)) (external)")
 }
 
@@ -1426,7 +1479,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -1442,7 +1495,7 @@
 
 	ensureNotContains(t, copyCmds, "image.apex/lib64/libstatic_to_runtime.so")
 
-	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
 	ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
 	ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.so")
 }
@@ -1473,6 +1526,7 @@
 			name: "libc",
 			no_libcrt: true,
 			nocrt: true,
+			no_crt_pad_segment: true,
 			stl: "none",
 			system_shared_libs: [],
 			stubs: { versions: ["1"] },
@@ -1487,6 +1541,7 @@
 			name: "libclang_rt.hwasan",
 			no_libcrt: true,
 			nocrt: true,
+			no_crt_pad_segment: true,
 			stl: "none",
 			system_shared_libs: [],
 			srcs: [""],
@@ -1503,7 +1558,7 @@
 		}	`)
 	ctx := result.TestContext
 
-	ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{
+	ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime", []string{
 		"lib64/bionic/libc.so",
 		"lib64/bionic/libclang_rt.hwasan-aarch64-android.so",
 	})
@@ -1529,6 +1584,7 @@
 			name: "libc",
 			no_libcrt: true,
 			nocrt: true,
+			no_crt_pad_segment: true,
 			stl: "none",
 			system_shared_libs: [],
 			stubs: { versions: ["1"] },
@@ -1539,6 +1595,7 @@
 			name: "libclang_rt.hwasan",
 			no_libcrt: true,
 			nocrt: true,
+			no_crt_pad_segment: true,
 			stl: "none",
 			system_shared_libs: [],
 			srcs: [""],
@@ -1556,7 +1613,7 @@
 		`)
 	ctx := result.TestContext
 
-	ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{
+	ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime", []string{
 		"lib64/bionic/libc.so",
 		"lib64/bionic/libclang_rt.hwasan-aarch64-android.so",
 	})
@@ -1637,12 +1694,12 @@
 			)
 
 			// Ensure that LLNDK dep is not included
-			ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+			ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 				"lib64/mylib.so",
 			})
 
 			// Ensure that LLNDK dep is required
-			apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+			apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
 			ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
 			ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so")
 
@@ -1702,7 +1759,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that mylib, libm, libdl are included.
@@ -2003,13 +2060,13 @@
 		}
 	`)
 
-	vendorVariant := "android_vendor.29_arm64_armv8-a"
+	vendorVariant := "android_vendor_arm64_armv8-a"
 
-	mylib := ctx.ModuleForTests("mylib", vendorVariant+"_shared_myapex")
+	mylib := ctx.ModuleForTests("mylib", vendorVariant+"_shared_apex29")
 
 	// Ensure that mylib links with "current" LLNDK
 	libFlags := names(mylib.Rule("ld").Args["libFlags"])
-	ensureListContains(t, libFlags, "out/soong/.intermediates/libbar/"+vendorVariant+"_shared_current/libbar.so")
+	ensureListContains(t, libFlags, "out/soong/.intermediates/libbar/"+vendorVariant+"_shared/libbar.so")
 
 	// Ensure that mylib is targeting 29
 	ccRule := ctx.ModuleForTests("mylib", vendorVariant+"_static_apex29").Output("obj/mylib.o")
@@ -2076,12 +2133,13 @@
 	depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton")
 	inputs := depsinfo.Rule("generateApexDepsInfoFilesRule").BuildParams.Inputs.Strings()
 	android.AssertStringListContains(t, "updatable myapex should generate depsinfo file", inputs,
-		"out/soong/.intermediates/myapex/android_common_myapex_image/depsinfo/flatlist.txt")
+		"out/soong/.intermediates/myapex/android_common_myapex/depsinfo/flatlist.txt")
 	android.AssertStringListDoesNotContain(t, "non-updatable myapex2 should not generate depsinfo file", inputs,
-		"out/soong/.intermediates/myapex2/android_common_myapex2_image/depsinfo/flatlist.txt")
+		"out/soong/.intermediates/myapex2/android_common_myapex2/depsinfo/flatlist.txt")
 
-	myapex := ctx.ModuleForTests("myapex", "android_common_myapex_image")
-	flatlist := strings.Split(myapex.Output("depsinfo/flatlist.txt").BuildParams.Args["content"], "\\n")
+	myapex := ctx.ModuleForTests("myapex", "android_common_myapex")
+	flatlist := strings.Split(android.ContentFromFileRuleForTests(t, ctx,
+		myapex.Output("depsinfo/flatlist.txt")), "\n")
 	android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
 		flatlist, "libbar(minSdkVersion:(no version)) (external)")
 	android.AssertStringListDoesNotContain(t, "do not track if not available for platform",
@@ -2838,7 +2896,7 @@
 		}
 	`)
 
-	generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("generateFsConfig")
+	generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("generateFsConfig")
 	cmd := generateFsRule.RuleParams.Command
 
 	// Ensure that the subdirectories are all listed
@@ -2903,7 +2961,7 @@
 			},
 		}
 	`, withNativeBridgeEnabled)
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"bin/foo/bar/mybin",
 		"bin/foo/bar/mybin64",
 		"bin/arm/foo/bar/mybin",
@@ -2943,14 +3001,14 @@
 		}
 	`)
 
-	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex", []string{
 		"bin/mybin",
 		"lib64/libfoo.so",
 		// TODO(b/159195575): Add an option to use VNDK libs from VNDK APEX
 		"lib64/libc++.so",
 	})
 
-	apexBundle := result.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	apexBundle := result.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, result.TestContext, apexBundle)
 	name := apexBundle.BaseModuleName()
 	prefix := "TARGET_"
@@ -2960,163 +3018,11 @@
 	installPath := "out/target/product/test_device/vendor/apex"
 	ensureContains(t, androidMk, "LOCAL_MODULE_PATH := "+installPath)
 
-	apexManifestRule := result.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+	apexManifestRule := result.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
 	requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
 	ensureListNotContains(t, requireNativeLibs, ":vndk")
 }
 
-func TestVendorApex_use_vndk_as_stable_TryingToIncludeVNDKLib(t *testing.T) {
-	testApexError(t, `Trying to include a VNDK library`, `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			native_shared_libs: ["libc++"], // libc++ is a VNDK lib
-			vendor: true,
-			use_vndk_as_stable: true,
-			updatable: false,
-		}
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}`)
-}
-
-func TestVendorApex_use_vndk_as_stable(t *testing.T) {
-	//   myapex                  myapex2
-	//    |                       |
-	//  mybin ------.           mybin2
-	//   \           \          /  |
-	// (stable)   .---\--------`   |
-	//     \     /     \           |
-	//      \   /       \         /
-	//      libvndk       libvendor
-	//      (vndk)
-	ctx := testApex(t, `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			binaries: ["mybin"],
-			vendor: true,
-			use_vndk_as_stable: true,
-			updatable: false,
-		}
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-		cc_binary {
-			name: "mybin",
-			vendor: true,
-			shared_libs: ["libvndk", "libvendor"],
-		}
-		cc_library {
-			name: "libvndk",
-			vndk: {
-				enabled: true,
-			},
-			vendor_available: true,
-			product_available: true,
-		}
-		cc_library {
-			name: "libvendor",
-			vendor: true,
-			stl: "none",
-		}
-		apex {
-			name: "myapex2",
-			key: "myapex.key",
-			binaries: ["mybin2"],
-			vendor: true,
-			use_vndk_as_stable: false,
-			updatable: false,
-		}
-		cc_binary {
-			name: "mybin2",
-			vendor: true,
-			shared_libs: ["libvndk", "libvendor"],
-		}
-	`,
-		android.FixtureModifyConfig(func(config android.Config) {
-			config.TestProductVariables.KeepVndk = proptools.BoolPtr(true)
-		}),
-	)
-
-	vendorVariant := "android_vendor.29_arm64_armv8-a"
-
-	for _, tc := range []struct {
-		name                 string
-		apexName             string
-		moduleName           string
-		moduleVariant        string
-		libs                 []string
-		contents             []string
-		requireVndkNamespace bool
-	}{
-		{
-			name:          "use_vndk_as_stable",
-			apexName:      "myapex",
-			moduleName:    "mybin",
-			moduleVariant: vendorVariant + "_apex10000",
-			libs: []string{
-				// should link with vendor variants of VNDK libs(libvndk/libc++)
-				"out/soong/.intermediates/libvndk/" + vendorVariant + "_shared/libvndk.so",
-				"out/soong/.intermediates/" + cc.DefaultCcCommonTestModulesDir + "libc++/" + vendorVariant + "_shared/libc++.so",
-				// unstable Vendor libs as APEX variant
-				"out/soong/.intermediates/libvendor/" + vendorVariant + "_shared_apex10000/libvendor.so",
-			},
-			contents: []string{
-				"bin/mybin",
-				"lib64/libvendor.so",
-				// VNDK libs (libvndk/libc++) are not included
-			},
-			requireVndkNamespace: true,
-		},
-		{
-			name:          "!use_vndk_as_stable",
-			apexName:      "myapex2",
-			moduleName:    "mybin2",
-			moduleVariant: vendorVariant + "_myapex2",
-			libs: []string{
-				// should link with "unique" APEX(myapex2) variant of VNDK libs(libvndk/libc++)
-				"out/soong/.intermediates/libvndk/" + vendorVariant + "_shared_myapex2/libvndk.so",
-				"out/soong/.intermediates/" + cc.DefaultCcCommonTestModulesDir + "libc++/" + vendorVariant + "_shared_myapex2/libc++.so",
-				// unstable vendor libs have "merged" APEX variants
-				"out/soong/.intermediates/libvendor/" + vendorVariant + "_shared_apex10000/libvendor.so",
-			},
-			contents: []string{
-				"bin/mybin2",
-				"lib64/libvendor.so",
-				// VNDK libs are included as well
-				"lib64/libvndk.so",
-				"lib64/libc++.so",
-			},
-			requireVndkNamespace: false,
-		},
-	} {
-		t.Run(tc.name, func(t *testing.T) {
-			// Check linked libs
-			ldRule := ctx.ModuleForTests(tc.moduleName, tc.moduleVariant).Rule("ld")
-			libs := names(ldRule.Args["libFlags"])
-			for _, lib := range tc.libs {
-				ensureListContains(t, libs, lib)
-			}
-			// Check apex contents
-			ensureExactContents(t, ctx, tc.apexName, "android_common_"+tc.apexName+"_image", tc.contents)
-
-			// Check "requireNativeLibs"
-			apexManifestRule := ctx.ModuleForTests(tc.apexName, "android_common_"+tc.apexName+"_image").Rule("apexManifestRule")
-			requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
-			if tc.requireVndkNamespace {
-				ensureListContains(t, requireNativeLibs, ":vndk")
-			} else {
-				ensureListNotContains(t, requireNativeLibs, ":vndk")
-			}
-		})
-	}
-}
-
 func TestProductVariant(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
@@ -3139,13 +3045,10 @@
 			apex_available: ["myapex"],
 			srcs: ["foo.cpp"],
 		}
-	`, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-		variables.ProductVndkVersion = proptools.StringPtr("current")
-	}),
-	)
+	`)
 
 	cflags := strings.Fields(
-		ctx.ModuleForTests("foo", "android_product.29_arm64_armv8-a_myapex").Rule("cc").Args["cFlags"])
+		ctx.ModuleForTests("foo", "android_product_arm64_armv8-a_apex10000").Rule("cc").Args["cFlags"])
 	ensureListContains(t, cflags, "-D__ANDROID_VNDK__")
 	ensureListContains(t, cflags, "-D__ANDROID_APEX__")
 	ensureListContains(t, cflags, "-D__ANDROID_PRODUCT__")
@@ -3182,7 +3085,7 @@
 					`+tc.additionalProp+`
 				}
 			`)
-			ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+			ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 				"etc/firmware/myfirmware.bin",
 			})
 		})
@@ -3211,7 +3114,7 @@
 		}
 	`)
 
-	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
 	name := apexBundle.BaseModuleName()
 	prefix := "TARGET_"
@@ -3240,7 +3143,7 @@
 		}
 	`)
 
-	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
 	name := apexBundle.BaseModuleName()
 	prefix := "TARGET_"
@@ -3343,7 +3246,7 @@
 	}
 
 	// check the APK certs. It should be overridden to myapex.certificate.override
-	certs := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk").Args["certificates"]
+	certs := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk").Args["certificates"]
 	if certs != "testkey.override.x509.pem testkey.override.pk8" {
 		t.Errorf("cert and private key %q are not %q", certs,
 			"testkey.override.509.pem testkey.override.pk8")
@@ -3363,7 +3266,7 @@
 				public_key: "testkey.avbpubkey",
 				private_key: "testkey.pem",
 			}`)
-		rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("signapk")
+		rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk")
 		expected := "vendor/foo/devkeys/test.x509.pem vendor/foo/devkeys/test.pk8"
 		if actual := rule.Args["certificates"]; actual != expected {
 			t.Errorf("certificates should be %q, not %q", expected, actual)
@@ -3386,7 +3289,7 @@
 				name: "myapex.certificate.override",
 				certificate: "testkey.override",
 			}`)
-		rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk")
+		rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk")
 		expected := "testkey.override.x509.pem testkey.override.pk8"
 		if actual := rule.Args["certificates"]; actual != expected {
 			t.Errorf("certificates should be %q, not %q", expected, actual)
@@ -3409,7 +3312,7 @@
 				name: "myapex.certificate",
 				certificate: "testkey",
 			}`)
-		rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("signapk")
+		rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk")
 		expected := "testkey.x509.pem testkey.pk8"
 		if actual := rule.Args["certificates"]; actual != expected {
 			t.Errorf("certificates should be %q, not %q", expected, actual)
@@ -3433,7 +3336,7 @@
 				name: "myapex.certificate.override",
 				certificate: "testkey.override",
 			}`)
-		rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk")
+		rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk")
 		expected := "testkey.override.x509.pem testkey.override.pk8"
 		if actual := rule.Args["certificates"]; actual != expected {
 			t.Errorf("certificates should be %q, not %q", expected, actual)
@@ -3452,7 +3355,7 @@
 				public_key: "testkey.avbpubkey",
 				private_key: "testkey.pem",
 			}`)
-		rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("signapk")
+		rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk")
 		expected := "vendor/foo/devkeys/testkey.x509.pem vendor/foo/devkeys/testkey.pk8"
 		if actual := rule.Args["certificates"]; actual != expected {
 			t.Errorf("certificates should be %q, not %q", expected, actual)
@@ -3476,7 +3379,7 @@
 				name: "myapex.certificate.override",
 				certificate: "testkey.override",
 			}`)
-		rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk")
+		rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk")
 		expected := "testkey.override.x509.pem testkey.override.pk8"
 		if actual := rule.Args["certificates"]; actual != expected {
 			t.Errorf("certificates should be %q, not %q", expected, actual)
@@ -3657,10 +3560,6 @@
 	module := ctx.ModuleForTests(moduleName, variant)
 	apexRule := module.MaybeRule("apexRule")
 	apexDir := "/image.apex/"
-	if apexRule.Rule == nil {
-		apexRule = module.Rule("zipApexRule")
-		apexDir = "/image.zipapex/"
-	}
 	copyCmds := apexRule.Args["copy_commands"]
 	var ret []fileInApex
 	for _, cmd := range strings.Split(copyCmds, "&&") {
@@ -3749,7 +3648,7 @@
 }
 
 func ensureExactDeapexedContents(t *testing.T, ctx *android.TestContext, moduleName string, variant string, files []string) {
-	deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Rule("deapexer")
+	deapexer := ctx.ModuleForTests(moduleName+".deapexer", variant).Description("deapex")
 	outputs := make([]string, 0, len(deapexer.ImplicitOutputs)+1)
 	if deapexer.Output != nil {
 		outputs = append(outputs, deapexer.Output.String())
@@ -3770,182 +3669,27 @@
 	assertFileListEquals(t, files, actualFiles)
 }
 
-func TestVndkApexCurrent(t *testing.T) {
-	commonFiles := []string{
-		"lib/libc++.so",
-		"lib64/libc++.so",
-		"etc/llndk.libraries.29.txt",
-		"etc/vndkcore.libraries.29.txt",
-		"etc/vndksp.libraries.29.txt",
-		"etc/vndkprivate.libraries.29.txt",
-		"etc/vndkproduct.libraries.29.txt",
-	}
-	testCases := []struct {
-		vndkVersion   string
-		expectedFiles []string
-	}{
-		{
-			vndkVersion: "current",
-			expectedFiles: append(commonFiles,
-				"lib/libvndk.so",
-				"lib/libvndksp.so",
-				"lib64/libvndk.so",
-				"lib64/libvndksp.so"),
-		},
-		{
-			vndkVersion: "",
-			expectedFiles: append(commonFiles,
-				// Legacy VNDK APEX contains only VNDK-SP files (of core variant)
-				"lib/libvndksp.so",
-				"lib64/libvndksp.so"),
-		},
-	}
-	for _, tc := range testCases {
-		t.Run("VNDK.current with DeviceVndkVersion="+tc.vndkVersion, func(t *testing.T) {
-			ctx := testApex(t, `
-			apex_vndk {
-				name: "com.android.vndk.current",
-				key: "com.android.vndk.current.key",
-				updatable: false,
-			}
-
-			apex_key {
-				name: "com.android.vndk.current.key",
-				public_key: "testkey.avbpubkey",
-				private_key: "testkey.pem",
-			}
-
-			cc_library {
-				name: "libvndk",
-				srcs: ["mylib.cpp"],
-				vendor_available: true,
-				product_available: true,
-				vndk: {
-					enabled: true,
-				},
-				system_shared_libs: [],
-				stl: "none",
-				apex_available: [ "com.android.vndk.current" ],
-			}
-
-			cc_library {
-				name: "libvndksp",
-				srcs: ["mylib.cpp"],
-				vendor_available: true,
-				product_available: true,
-				vndk: {
-					enabled: true,
-					support_system_process: true,
-				},
-				system_shared_libs: [],
-				stl: "none",
-				apex_available: [ "com.android.vndk.current" ],
-			}
-
-			// VNDK-Ext should not cause any problems
-
-			cc_library {
-				name: "libvndk.ext",
-				srcs: ["mylib2.cpp"],
-				vendor: true,
-				vndk: {
-					enabled: true,
-					extends: "libvndk",
-				},
-				system_shared_libs: [],
-				stl: "none",
-			}
-
-			cc_library {
-				name: "libvndksp.ext",
-				srcs: ["mylib2.cpp"],
-				vendor: true,
-				vndk: {
-					enabled: true,
-					support_system_process: true,
-					extends: "libvndksp",
-				},
-				system_shared_libs: [],
-				stl: "none",
-			}
-		`+vndkLibrariesTxtFiles("current"), android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-				variables.DeviceVndkVersion = proptools.StringPtr(tc.vndkVersion)
-			}))
-			ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", tc.expectedFiles)
-		})
-	}
-}
-
-func TestVndkApexWithPrebuilt(t *testing.T) {
-	ctx := testApex(t, `
-		apex_vndk {
-			name: "com.android.vndk.current",
-			key: "com.android.vndk.current.key",
-			updatable: false,
-		}
-
-		apex_key {
-			name: "com.android.vndk.current.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-
-		cc_prebuilt_library_shared {
-			name: "libvndk",
-			srcs: ["libvndk.so"],
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			system_shared_libs: [],
-			stl: "none",
-			apex_available: [ "com.android.vndk.current" ],
-		}
-
-		cc_prebuilt_library_shared {
-			name: "libvndk.arm",
-			srcs: ["libvndk.arm.so"],
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			enabled: false,
-			arch: {
-				arm: {
-					enabled: true,
-				},
-			},
-			system_shared_libs: [],
-			stl: "none",
-			apex_available: [ "com.android.vndk.current" ],
-		}
-		`+vndkLibrariesTxtFiles("current"),
-		withFiles(map[string][]byte{
-			"libvndk.so":     nil,
-			"libvndk.arm.so": nil,
-		}))
-	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
-		"lib/libvndk.so",
-		"lib/libvndk.arm.so",
-		"lib64/libvndk.so",
-		"lib/libc++.so",
-		"lib64/libc++.so",
-		"etc/*",
-	})
-}
-
 func vndkLibrariesTxtFiles(vers ...string) (result string) {
 	for _, v := range vers {
 		if v == "current" {
-			for _, txt := range []string{"llndk", "vndkcore", "vndksp", "vndkprivate", "vndkproduct"} {
+			for _, txt := range []string{"vndkcore", "vndksp", "vndkprivate", "vndkproduct"} {
 				result += `
 					` + txt + `_libraries_txt {
 						name: "` + txt + `.libraries.txt",
+						insert_vndk_version: true,
 					}
 				`
 			}
+			result += `
+				llndk_libraries_txt {
+					name: "llndk.libraries.txt",
+				}
+				llndk_libraries_txt_for_apex {
+					name: "llndk.libraries.txt.apex",
+					stem: "llndk.libraries.txt",
+					insert_vndk_version: true,
+				}
+			`
 		} else {
 			for _, txt := range []string{"llndk", "vndkcore", "vndksp", "vndkprivate", "vndkproduct"} {
 				result += `
@@ -4022,7 +3766,7 @@
 			"libvndk27_x86_64.so": nil,
 		}))
 
-	ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common", []string{
 		"lib/libvndk27_arm.so",
 		"lib64/libvndk27_arm64.so",
 		"etc/*",
@@ -4032,9 +3776,10 @@
 func TestVndkApexNameRule(t *testing.T) {
 	ctx := testApex(t, `
 		apex_vndk {
-			name: "com.android.vndk.current",
+			name: "com.android.vndk.v29",
 			key: "myapex.key",
 			file_contexts: ":myapex-file_contexts",
+			vndk_version: "29",
 			updatable: false,
 		}
 		apex_vndk {
@@ -4048,59 +3793,18 @@
 			name: "myapex.key",
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
-		}`+vndkLibrariesTxtFiles("28", "current"))
+		}`+vndkLibrariesTxtFiles("28", "29"))
 
 	assertApexName := func(expected, moduleName string) {
-		module := ctx.ModuleForTests(moduleName, "android_common_image")
+		module := ctx.ModuleForTests(moduleName, "android_common")
 		apexManifestRule := module.Rule("apexManifestRule")
 		ensureContains(t, apexManifestRule.Args["opt"], "-v name "+expected)
 	}
 
-	assertApexName("com.android.vndk.v29", "com.android.vndk.current")
+	assertApexName("com.android.vndk.v29", "com.android.vndk.v29")
 	assertApexName("com.android.vndk.v28", "com.android.vndk.v28")
 }
 
-func TestVndkApexSkipsNativeBridgeSupportedModules(t *testing.T) {
-	ctx := testApex(t, `
-		apex_vndk {
-			name: "com.android.vndk.current",
-			key: "com.android.vndk.current.key",
-			file_contexts: ":myapex-file_contexts",
-			updatable: false,
-		}
-
-		apex_key {
-			name: "com.android.vndk.current.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-
-		cc_library {
-			name: "libvndk",
-			srcs: ["mylib.cpp"],
-			vendor_available: true,
-			product_available: true,
-			native_bridge_supported: true,
-			host_supported: true,
-			vndk: {
-				enabled: true,
-			},
-			system_shared_libs: [],
-			stl: "none",
-			apex_available: [ "com.android.vndk.current" ],
-		}
-		`+vndkLibrariesTxtFiles("current"),
-		withNativeBridgeEnabled)
-
-	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
-		"lib/libvndk.so",
-		"lib64/libvndk.so",
-		"lib/libc++.so",
-		"lib64/libc++.so",
-		"etc/*",
-	})
-}
-
 func TestVndkApexDoesntSupportNativeBridgeSupported(t *testing.T) {
 	testApexError(t, `module "com.android.vndk.current" .*: native_bridge_supported: .* doesn't support native bridge binary`, `
 		apex_vndk {
@@ -4195,221 +3899,12 @@
 		}),
 	)
 
-	ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common", []string{
 		"lib/libvndk27binder32.so",
 		"etc/*",
 	})
 }
 
-func TestVndkApexShouldNotProvideNativeLibs(t *testing.T) {
-	ctx := testApex(t, `
-		apex_vndk {
-			name: "com.android.vndk.current",
-			key: "com.android.vndk.current.key",
-			file_contexts: ":myapex-file_contexts",
-			updatable: false,
-		}
-
-		apex_key {
-			name: "com.android.vndk.current.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-
-		cc_library {
-			name: "libz",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			stubs: {
-				symbol_file: "libz.map.txt",
-				versions: ["30"],
-			}
-		}
-	`+vndkLibrariesTxtFiles("current"), withFiles(map[string][]byte{
-		"libz.map.txt": nil,
-	}))
-
-	apexManifestRule := ctx.ModuleForTests("com.android.vndk.current", "android_common_image").Rule("apexManifestRule")
-	provideNativeLibs := names(apexManifestRule.Args["provideNativeLibs"])
-	ensureListEmpty(t, provideNativeLibs)
-	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
-		"out/soong/.intermediates/libz/android_vendor.29_arm64_armv8-a_shared/libz.so:lib64/libz.so",
-		"out/soong/.intermediates/libz/android_vendor.29_arm_armv7-a-neon_shared/libz.so:lib/libz.so",
-		"*/*",
-	})
-}
-
-func TestVendorApexWithVndkPrebuilts(t *testing.T) {
-	ctx := testApex(t, "",
-		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-			variables.DeviceVndkVersion = proptools.StringPtr("27")
-		}),
-		android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
-			cc.RegisterVendorSnapshotModules(ctx)
-		}),
-		withFiles(map[string][]byte{
-			"vendor/foo/Android.bp": []byte(`
-				apex {
-					name: "myapex",
-					binaries: ["foo"],
-					key: "myapex.key",
-					min_sdk_version: "27",
-					vendor: true,
-				}
-
-				cc_binary {
-					name: "foo",
-					vendor: true,
-					srcs: ["abc.cpp"],
-					shared_libs: [
-						"libllndk",
-						"libvndk",
-					],
-					nocrt: true,
-					system_shared_libs: [],
-					min_sdk_version: "27",
-				}
-
-				apex_key {
-					name: "myapex.key",
-					public_key: "testkey.avbpubkey",
-					private_key: "testkey.pem",
-				}
-			`),
-			// Simulate VNDK prebuilts with vendor_snapshot
-			"prebuilts/vndk/Android.bp": []byte(`
-				vndk_prebuilt_shared {
-					name: "libllndk",
-					version: "27",
-					vendor_available: true,
-					product_available: true,
-					target_arch: "arm64",
-					arch: {
-						arm64: {
-							srcs: ["libllndk.so"],
-						},
-					},
-				}
-
-				vndk_prebuilt_shared {
-					name: "libvndk",
-					version: "27",
-					vendor_available: true,
-					product_available: true,
-					target_arch: "arm64",
-					arch: {
-						arm64: {
-							srcs: ["libvndk.so"],
-						},
-					},
-					vndk: {
-						enabled: true,
-					},
-					min_sdk_version: "27",
-				}
-
-				vndk_prebuilt_shared {
-					name: "libc++",
-					version: "27",
-					target_arch: "arm64",
-					vendor_available: true,
-					product_available: true,
-					vndk: {
-						enabled: true,
-						support_system_process: true,
-					},
-					arch: {
-						arm64: {
-							srcs: ["libc++.so"],
-						},
-					},
-					min_sdk_version: "apex_inherit",
-				}
-
-				vendor_snapshot {
-					name: "vendor_snapshot",
-					version: "27",
-					arch: {
-						arm64: {
-							vndk_libs: [
-								"libc++",
-								"libllndk",
-								"libvndk",
-							],
-							static_libs: [
-								"libc++demangle",
-								"libclang_rt.builtins",
-								"libunwind",
-							],
-						},
-					}
-				}
-
-				vendor_snapshot_static {
-					name: "libclang_rt.builtins",
-					version: "27",
-					target_arch: "arm64",
-					vendor: true,
-					arch: {
-						arm64: {
-							src: "libclang_rt.builtins-aarch64-android.a",
-						},
-					},
-				}
-
-				vendor_snapshot_static {
-					name: "libc++demangle",
-					version: "27",
-					target_arch: "arm64",
-					compile_multilib: "64",
-					vendor: true,
-					arch: {
-						arm64: {
-							src: "libc++demangle.a",
-						},
-					},
-					min_sdk_version: "apex_inherit",
-				}
-
-				vendor_snapshot_static {
-					name: "libunwind",
-					version: "27",
-					target_arch: "arm64",
-					compile_multilib: "64",
-					vendor: true,
-					arch: {
-						arm64: {
-							src: "libunwind.a",
-						},
-					},
-					min_sdk_version: "apex_inherit",
-				}
-			`),
-		}))
-
-	// Should embed the prebuilt VNDK libraries in the apex
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
-		"bin/foo",
-		"prebuilts/vndk/libc++.so:lib64/libc++.so",
-		"prebuilts/vndk/libvndk.so:lib64/libvndk.so",
-	})
-
-	// Should link foo with prebuilt libraries (shared/static)
-	ldRule := ctx.ModuleForTests("foo", "android_vendor.27_arm64_armv8-a_myapex").Rule("ld")
-	android.AssertStringDoesContain(t, "should link to prebuilt llndk", ldRule.Args["libFlags"], "prebuilts/vndk/libllndk.so")
-	android.AssertStringDoesContain(t, "should link to prebuilt vndk", ldRule.Args["libFlags"], "prebuilts/vndk/libvndk.so")
-	android.AssertStringDoesContain(t, "should link to prebuilt libc++demangle", ldRule.Args["libFlags"], "prebuilts/vndk/libc++demangle.a")
-	android.AssertStringDoesContain(t, "should link to prebuilt libunwind", ldRule.Args["libFlags"], "prebuilts/vndk/libunwind.a")
-
-	// Should declare the LLNDK library as a "required" external dependency
-	manifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
-	requireNativeLibs := names(manifestRule.Args["requireNativeLibs"])
-	ensureListContains(t, requireNativeLibs, "libllndk.so")
-}
-
 func TestDependenciesInApexManifest(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
@@ -4518,25 +4013,25 @@
 	var apexManifestRule android.TestingBuildParams
 	var provideNativeLibs, requireNativeLibs []string
 
-	apexManifestRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep_image").Rule("apexManifestRule")
+	apexManifestRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("apexManifestRule")
 	provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
 	requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
 	ensureListEmpty(t, provideNativeLibs)
 	ensureListEmpty(t, requireNativeLibs)
 
-	apexManifestRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep_image").Rule("apexManifestRule")
+	apexManifestRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("apexManifestRule")
 	provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
 	requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
 	ensureListEmpty(t, provideNativeLibs)
 	ensureListContains(t, requireNativeLibs, "libfoo.so")
 
-	apexManifestRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider_image").Rule("apexManifestRule")
+	apexManifestRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("apexManifestRule")
 	provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
 	requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
 	ensureListContains(t, provideNativeLibs, "libfoo.so")
 	ensureListEmpty(t, requireNativeLibs)
 
-	apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained_image").Rule("apexManifestRule")
+	apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("apexManifestRule")
 	provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
 	requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
 	ensureListContains(t, provideNativeLibs, "libbar.so")
@@ -4572,7 +4067,7 @@
 		"OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION": "1234",
 	}))
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexManifestRule := module.Rule("apexManifestRule")
 	ensureContains(t, apexManifestRule.Args["default_version"], "1234")
 }
@@ -4635,7 +4130,7 @@
 			}
 		`, testCase.compileMultiLibProp),
 		)
-		module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+		module := ctx.ModuleForTests("myapex", "android_common_myapex")
 		apexRule := module.Rule("apexRule")
 		copyCmds := apexRule.Args["copy_commands"]
 		for _, containedLib := range testCase.containedLibs {
@@ -4674,7 +4169,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -4728,7 +4223,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -4749,6 +4244,72 @@
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_shared")
 }
 
+func TestLibzVendorIsntStable(t *testing.T) {
+	ctx := testApex(t, `
+	apex {
+		name: "myapex",
+		key: "myapex.key",
+		updatable: false,
+		binaries: ["mybin"],
+	}
+	apex {
+		name: "myvendorapex",
+		key: "myapex.key",
+		file_contexts: "myvendorapex_file_contexts",
+		vendor: true,
+		updatable: false,
+		binaries: ["mybin"],
+	}
+	apex_key {
+		name: "myapex.key",
+		public_key: "testkey.avbpubkey",
+		private_key: "testkey.pem",
+	}
+	cc_binary {
+		name: "mybin",
+		vendor_available: true,
+		system_shared_libs: [],
+		stl: "none",
+		shared_libs: ["libz"],
+		apex_available: ["//apex_available:anyapex"],
+	}
+	cc_library {
+		name: "libz",
+		vendor_available: true,
+		system_shared_libs: [],
+		stl: "none",
+		stubs: {
+			versions: ["28", "30"],
+		},
+		target: {
+			vendor: {
+				no_stubs: true,
+			},
+		},
+	}
+	`, withFiles(map[string][]byte{
+		"myvendorapex_file_contexts": nil,
+	}))
+
+	// libz provides stubs for core variant.
+	{
+		ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
+			"bin/mybin",
+		})
+		apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
+		android.AssertStringEquals(t, "should require libz", apexManifestRule.Args["requireNativeLibs"], "libz.so")
+	}
+	// libz doesn't provide stubs for vendor variant.
+	{
+		ensureExactContents(t, ctx, "myvendorapex", "android_common_myvendorapex", []string{
+			"bin/mybin",
+			"lib64/libz.so",
+		})
+		apexManifestRule := ctx.ModuleForTests("myvendorapex", "android_common_myvendorapex").Rule("apexManifestRule")
+		android.AssertStringEquals(t, "should not require libz", apexManifestRule.Args["requireNativeLibs"], "")
+	}
+}
+
 func TestApexWithTarget(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
@@ -4818,7 +4379,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that main rule creates an output
@@ -4902,7 +4463,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that apex variant is created for the direct dep
@@ -4922,6 +4483,7 @@
 			key: "myapex.key",
 			sh_binaries: ["myscript"],
 			updatable: false,
+			compile_multilib: "both",
 		}
 
 		apex_key {
@@ -4938,7 +4500,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	ensureContains(t, copyCmds, "image.apex/bin/script/myscript.sh")
@@ -4972,7 +4534,7 @@
 				}
 			`)
 
-			apex := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+			apex := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 			expected := "out/soong/target/product/test_device/" + tc.partition + "/apex"
 			actual := apex.installDir.RelativeToTop().String()
 			if actual != expected {
@@ -4996,7 +4558,7 @@
 			private_key: "testkey.pem",
 		}
 	`)
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	rule := module.Output("file_contexts")
 	ensureContains(t, rule.RuleParams.Command, "cat system/sepolicy/apex/myapex-file_contexts")
 }
@@ -5054,7 +4616,7 @@
 	`, withFiles(map[string][]byte{
 		"product_specific_file_contexts": nil,
 	}))
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	rule := module.Output("file_contexts")
 	ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts")
 }
@@ -5082,7 +4644,7 @@
 	`, withFiles(map[string][]byte{
 		"product_specific_file_contexts": nil,
 	}))
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	rule := module.Output("file_contexts")
 	ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts")
 }
@@ -5301,6 +4863,13 @@
 	).RunTest(t)
 }
 
+// A minimal context object for use with DexJarBuildPath
+type moduleErrorfTestCtx struct {
+}
+
+func (ctx moduleErrorfTestCtx) ModuleErrorf(format string, args ...interface{}) {
+}
+
 // These tests verify that the prebuilt_apex/deapexer to java_import wiring allows for the
 // propagation of paths to dex implementation jars from the former to the latter.
 func TestPrebuiltExportDexImplementationJars(t *testing.T) {
@@ -5310,10 +4879,10 @@
 		t.Helper()
 		// Make sure the import has been given the correct path to the dex jar.
 		p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency)
-		dexJarBuildPath := p.DexJarBuildPath().PathOrNil()
+		dexJarBuildPath := p.DexJarBuildPath(moduleErrorfTestCtx{}).PathOrNil()
 		stem := android.RemoveOptionalPrebuiltPrefix(name)
 		android.AssertStringEquals(t, "DexJarBuildPath should be apex-related path.",
-			".intermediates/myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar",
+			".intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/"+stem+".jar",
 			android.NormalizePathForTesting(dexJarBuildPath))
 	}
 
@@ -5367,8 +4936,8 @@
 		// Make sure that dexpreopt can access dex implementation files from the prebuilt.
 		ctx := testDexpreoptWithApexes(t, bp, "", transform)
 
-		deapexerName := deapexerModuleName("myapex")
-		android.AssertStringEquals(t, "APEX module name from deapexer name", "myapex", apexModuleName(deapexerName))
+		deapexerName := deapexerModuleName("prebuilt_myapex")
+		android.AssertStringEquals(t, "APEX module name from deapexer name", "prebuilt_myapex", apexModuleName(deapexerName))
 
 		// Make sure that the deapexer has the correct input APEX.
 		deapexer := ctx.ModuleForTests(deapexerName, "android_common")
@@ -5505,7 +5074,7 @@
 
 	checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) {
 		t.Helper()
-		s := ctx.ModuleForTests("platform-bootclasspath", "android_common")
+		s := ctx.ModuleForTests("dex_bootjars", "android_common")
 		foundLibfooJar := false
 		base := stem + ".jar"
 		for _, output := range s.AllOutputs() {
@@ -5591,8 +5160,8 @@
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
-		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
-		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
+		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
 
 		// Verify the correct module jars contribute to the hiddenapi index file.
 		checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
@@ -5669,8 +5238,8 @@
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
-		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
-		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
+		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
 
 		// Verify the correct module jars contribute to the hiddenapi index file.
 		checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
@@ -5683,7 +5252,7 @@
 		myApex := ctx.ModuleForTests("myapex", "android_common_myapex").Module()
 
 		overrideNames := []string{
-			"",
+			"myapex",
 			"myjavalib.myapex",
 			"libfoo.myapex",
 			"libbar.myapex",
@@ -5858,8 +5427,8 @@
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
-		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
-		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
+		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
 
 		// Verify the correct module jars contribute to the hiddenapi index file.
 		checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
@@ -5955,8 +5524,8 @@
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
-		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/libfoo/android_common_apex10000/hiddenapi/libfoo.jar")
-		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/libbar/android_common_myapex/hiddenapi/libbar.jar")
+		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/hiddenapi-modular/encoded/libfoo.jar")
+		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/hiddenapi-modular/encoded/libbar.jar")
 
 		// Verify the correct module jars contribute to the hiddenapi index file.
 		checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
@@ -6055,8 +5624,8 @@
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
-		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
-		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
+		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
 
 		// Verify the correct module jars contribute to the hiddenapi index file.
 		checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
@@ -6066,6 +5635,84 @@
 			out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv
 		`)
 	})
+
+	t.Run("Co-existing unflagged apexes should create a duplicate module error", func(t *testing.T) {
+		bp := `
+		// Source
+		apex {
+			name: "myapex",
+			enabled: false,
+			key: "myapex.key",
+			bootclasspath_fragments: ["my-bootclasspath-fragment"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		// Prebuilt
+		prebuilt_apex {
+			name: "myapex.v1",
+			source_apex_name: "myapex",
+			arch: {
+				arm64: {
+					src: "myapex-arm64.apex",
+				},
+				arm: {
+					src: "myapex-arm.apex",
+				},
+			},
+			exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
+			prefer: true,
+		}
+		prebuilt_apex {
+			name: "myapex.v2",
+			source_apex_name: "myapex",
+			arch: {
+				arm64: {
+					src: "myapex-arm64.apex",
+				},
+				arm: {
+					src: "myapex-arm.apex",
+				},
+			},
+			exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
+			prefer: true,
+		}
+
+		prebuilt_bootclasspath_fragment {
+			name: "my-bootclasspath-fragment",
+			contents: ["libfoo", "libbar"],
+			apex_available: ["myapex"],
+			hidden_api: {
+				annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
+				metadata: "my-bootclasspath-fragment/metadata.csv",
+				index: "my-bootclasspath-fragment/index.csv",
+				stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
+				all_flags: "my-bootclasspath-fragment/all-flags.csv",
+			},
+			prefer: true,
+		}
+
+		java_import {
+			name: "libfoo",
+			jars: ["libfoo.jar"],
+			apex_available: ["myapex"],
+			prefer: true,
+		}
+		java_import {
+			name: "libbar",
+			jars: ["libbar.jar"],
+			apex_available: ["myapex"],
+			prefer: true,
+		}
+	`
+
+		testDexpreoptWithApexes(t, bp, "Multiple prebuilt modules prebuilt_myapex.v1 and prebuilt_myapex.v2 have been marked as preferred for this source module", preparer, fragment)
+	})
+
 }
 
 func TestApexWithTests(t *testing.T) {
@@ -6140,7 +5787,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that test dep (and their transitive dependencies) are copied into apex.
@@ -6157,7 +5804,7 @@
 	ensureContains(t, copyCmds, "image.apex/bin/test/mytest3")
 
 	// Ensure the module is correctly translated.
-	bundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	bundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, bundle)
 	name := bundle.BaseModuleName()
 	prefix := "TARGET_"
@@ -6240,7 +5887,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 	ensureContains(t, copyCmds, "image.apex/javalib/myjavaimport.jar")
@@ -6304,7 +5951,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -6410,7 +6057,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -6455,7 +6102,7 @@
 		"AppFooPrebuilt.apk": nil,
 	}))
 
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"app/AppFoo@TEST.BUILD_ID/AppFooPrebuilt.apk",
 	})
 }
@@ -6485,7 +6132,7 @@
 
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -6808,14 +6455,14 @@
 		}
 	`)
 
-	fooManifestRule := result.ModuleForTests("foo", "android_common_foo_image").Rule("apexManifestRule")
+	fooManifestRule := result.ModuleForTests("foo", "android_common_foo").Rule("apexManifestRule")
 	fooExpectedDefaultVersion := android.DefaultUpdatableModuleVersion
 	fooActualDefaultVersion := fooManifestRule.Args["default_version"]
 	if fooActualDefaultVersion != fooExpectedDefaultVersion {
 		t.Errorf("expected to find defaultVersion %q; got %q", fooExpectedDefaultVersion, fooActualDefaultVersion)
 	}
 
-	barManifestRule := result.ModuleForTests("bar", "android_common_bar_image").Rule("apexManifestRule")
+	barManifestRule := result.ModuleForTests("bar", "android_common_bar").Rule("apexManifestRule")
 	defaultVersionInt, _ := strconv.Atoi(android.DefaultUpdatableModuleVersion)
 	barExpectedDefaultVersion := fmt.Sprint(defaultVersionInt + 3)
 	barActualDefaultVersion := barManifestRule.Args["default_version"]
@@ -6823,7 +6470,7 @@
 		t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion)
 	}
 
-	overrideBarManifestRule := result.ModuleForTests("bar", "android_common_myoverrideapex_bar_image").Rule("apexManifestRule")
+	overrideBarManifestRule := result.ModuleForTests("bar", "android_common_myoverrideapex_bar").Rule("apexManifestRule")
 	overrideBarActualDefaultVersion := overrideBarManifestRule.Args["default_version"]
 	if overrideBarActualDefaultVersion != barExpectedDefaultVersion {
 		t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion)
@@ -7124,6 +6771,15 @@
 			bpfs: ["overrideBpf"],
 			prebuilts: ["override_myetc"],
 			overrides: ["unknownapex"],
+			compile_multilib: "first",
+			multilib: {
+				lib32: {
+					native_shared_libs: ["mylib32"],
+				},
+				lib64: {
+					native_shared_libs: ["mylib64"],
+				},
+			},
 			logging_parent: "com.foo.bar",
 			package_name: "test.overridden.package",
 			key: "mynewapex.key",
@@ -7181,10 +6837,20 @@
 			name: "override_myetc",
 			src: "override_myprebuilt",
 		}
+
+		cc_library {
+			name: "mylib32",
+			apex_available: [ "myapex" ],
+		}
+
+		cc_library {
+			name: "mylib64",
+			apex_available: [ "myapex" ],
+		}
 	`, withManifestPackageNameOverrides([]string{"myapex:com.android.myapex"}))
 
-	originalVariant := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(android.OverridableModule)
-	overriddenVariant := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image").Module().(android.OverridableModule)
+	originalVariant := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(android.OverridableModule)
+	overriddenVariant := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex").Module().(android.OverridableModule)
 	if originalVariant.GetOverriddenBy() != "" {
 		t.Errorf("GetOverriddenBy should be empty, but was %q", originalVariant.GetOverriddenBy())
 	}
@@ -7192,7 +6858,7 @@
 		t.Errorf("GetOverriddenBy should be \"override_myapex\", but was %q", overriddenVariant.GetOverriddenBy())
 	}
 
-	module := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -7282,7 +6948,7 @@
 
 	`, withApexGlobalMinSdkVersionOverride(&minSdkOverride31))
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -7341,7 +7007,7 @@
 
 	`, withApexGlobalMinSdkVersionOverride(&minSdkOverride29))
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -7379,7 +7045,7 @@
 		}
 	`, withUnbundledBuild)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	args := module.Rule("apexRule").Args
 	ensureContains(t, args["opt_flags"], "--manifest_json "+module.Output("apex_manifest.json").Output.String())
 	ensureNotContains(t, args["opt_flags"], "--no_hashtree")
@@ -7443,13 +7109,14 @@
 	`, withFiles(filesForSdkLibrary))
 
 	// java_sdk_library installs both impl jar and permission XML
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"javalib/foo.jar",
 		"etc/permissions/foo.xml",
 	})
 	// Permission XML should point to the activated path of impl jar of java_sdk_library
-	sdkLibrary := ctx.ModuleForTests("foo.xml", "android_common_myapex").Rule("java_sdk_xml")
-	ensureMatches(t, sdkLibrary.RuleParams.Command, `<library\\n\s+name=\\\"foo\\\"\\n\s+file=\\\"/apex/myapex/javalib/foo.jar\\\"`)
+	sdkLibrary := ctx.ModuleForTests("foo.xml", "android_common_myapex").Output("foo.xml")
+	contents := android.ContentFromFileRuleForTests(t, ctx, sdkLibrary)
+	ensureMatches(t, contents, "<library\\n\\s+name=\\\"foo\\\"\\n\\s+file=\\\"/apex/myapex/javalib/foo.jar\\\"")
 }
 
 func TestJavaSDKLibrary_WithinApex(t *testing.T) {
@@ -7492,7 +7159,7 @@
 	`, withFiles(filesForSdkLibrary))
 
 	// java_sdk_library installs both impl jar and permission XML
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"javalib/bar.jar",
 		"javalib/foo.jar",
 		"etc/permissions/foo.xml",
@@ -7500,7 +7167,7 @@
 
 	// The bar library should depend on the implementation jar.
 	barLibrary := ctx.ModuleForTests("bar", "android_common_myapex").Rule("javac")
-	if expected, actual := `^-classpath [^:]*/turbine-combined/foo\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
+	if expected, actual := `^-classpath [^:]*/turbine-combined/foo\.impl\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
 		t.Errorf("expected %q, found %#q", expected, actual)
 	}
 }
@@ -7544,7 +7211,7 @@
 	`, withFiles(filesForSdkLibrary))
 
 	// java_sdk_library installs both impl jar and permission XML
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"javalib/foo.jar",
 		"etc/permissions/foo.xml",
 	})
@@ -7633,7 +7300,7 @@
 	)
 
 	// java_sdk_library installs both impl jar and permission XML
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"javalib/bar.jar",
 		"javalib/foo.jar",
 		"etc/permissions/foo.xml",
@@ -7713,7 +7380,7 @@
 		}
 	`)
 	ctx := result.TestContext
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"etc/compatconfig/myjar-platform-compat-config.xml",
 		"javalib/myjar.jar",
 	})
@@ -7755,6 +7422,42 @@
 		`)
 }
 
+func TestApexUnwantedTransitiveDeps(t *testing.T) {
+	bp := `
+	apex {
+		name: "myapex",
+		key: "myapex.key",
+		native_shared_libs: ["libfoo"],
+		updatable: false,
+		unwanted_transitive_deps: ["libbar"],
+	}
+
+	apex_key {
+		name: "myapex.key",
+		public_key: "testkey.avbpubkey",
+		private_key: "testkey.pem",
+	}
+
+	cc_library {
+		name: "libfoo",
+		srcs: ["foo.cpp"],
+		shared_libs: ["libbar"],
+		apex_available: ["myapex"],
+	}
+
+	cc_library {
+		name: "libbar",
+		srcs: ["bar.cpp"],
+		apex_available: ["myapex"],
+	}`
+	ctx := testApex(t, bp)
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
+		"*/libc++.so",
+		"*/libfoo.so",
+		// not libbar.so
+	})
+}
+
 func TestRejectNonInstallableJavaLibrary(t *testing.T) {
 	testApexError(t, `"myjar" is not configured to be compiled into dex`, `
 		apex {
@@ -7808,7 +7511,7 @@
 		}
 	`)
 
-	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
 	name := apexBundle.BaseModuleName()
 	prefix := "TARGET_"
@@ -7947,13 +7650,13 @@
 	// For unbundled build, symlink shouldn't exist regardless of whether an APEX
 	// is updatable or not
 	ctx := testApex(t, bp, withUnbundledBuild)
-	files := getFiles(t, ctx, "myapex", "android_common_myapex_image")
+	files := getFiles(t, ctx, "myapex", "android_common_myapex")
 	ensureRealfileExists(t, files, "javalib/myjar.jar")
 	ensureRealfileExists(t, files, "lib64/mylib.so")
 	ensureRealfileExists(t, files, "lib64/myotherlib.so")
 	ensureRealfileExists(t, files, "lib64/myotherlib_ext.so")
 
-	files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable_image")
+	files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable")
 	ensureRealfileExists(t, files, "javalib/myjar.jar")
 	ensureRealfileExists(t, files, "lib64/mylib.so")
 	ensureRealfileExists(t, files, "lib64/myotherlib.so")
@@ -7961,13 +7664,13 @@
 
 	// For bundled build, symlink to the system for the non-updatable APEXes only
 	ctx = testApex(t, bp)
-	files = getFiles(t, ctx, "myapex", "android_common_myapex_image")
+	files = getFiles(t, ctx, "myapex", "android_common_myapex")
 	ensureRealfileExists(t, files, "javalib/myjar.jar")
 	ensureRealfileExists(t, files, "lib64/mylib.so")
 	ensureSymlinkExists(t, files, "lib64/myotherlib.so", "/system/lib64/myotherlib.so")             // this is symlink
 	ensureSymlinkExists(t, files, "lib64/myotherlib_ext.so", "/system_ext/lib64/myotherlib_ext.so") // this is symlink
 
-	files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable_image")
+	files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable")
 	ensureRealfileExists(t, files, "javalib/myjar.jar")
 	ensureRealfileExists(t, files, "lib64/mylib.so")
 	ensureRealfileExists(t, files, "lib64/myotherlib.so")     // this is a real file
@@ -8013,7 +7716,7 @@
 		}
 	`)
 
-	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
 	var builder strings.Builder
 	data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data)
@@ -8031,7 +7734,8 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
-			jni_libs: ["mylib", "libfoo.rust"],
+			binaries: ["mybin"],
+			jni_libs: ["mylib", "mylib3", "libfoo.rust"],
 			updatable: false,
 		}
 
@@ -8058,6 +7762,24 @@
 			apex_available: [ "myapex" ],
 		}
 
+		// Used as both a JNI library and a regular shared library.
+		cc_library {
+			name: "mylib3",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex" ],
+		}
+
+		cc_binary {
+			name: "mybin",
+			srcs: ["mybin.cpp"],
+			shared_libs: ["mylib3"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex" ],
+		}
+
 		rust_ffi_shared {
 			name: "libfoo.rust",
 			crate_name: "foo",
@@ -8079,12 +7801,14 @@
 
 	`)
 
-	rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+	rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
 	// Notice mylib2.so (transitive dep) is not added as a jni_lib
-	ensureEquals(t, rule.Args["opt"], "-a jniLibs libfoo.rust.so mylib.so")
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureEquals(t, rule.Args["opt"], "-a jniLibs libfoo.rust.so mylib.so mylib3.so")
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
+		"bin/mybin",
 		"lib64/mylib.so",
 		"lib64/mylib2.so",
+		"lib64/mylib3.so",
 		"lib64/libfoo.rust.so",
 		"lib64/libc++.so", // auto-added to libfoo.rust by Soong
 		"lib64/liblog.so", // auto-added to libfoo.rust by Soong
@@ -8142,8 +7866,8 @@
 		}
 		`, withManifestPackageNameOverrides([]string{"AppFoo:com.android.foo"}))
 
-	bundleConfigRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("bundle_config.json")
-	content := bundleConfigRule.Args["content"]
+	bundleConfigRule := ctx.ModuleForTests("myapex", "android_common_myapex").Output("bundle_config.json")
+	content := android.ContentFromFileRuleForTests(t, ctx, bundleConfigRule)
 
 	ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`)
 	ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo@TEST.BUILD_ID/AppFoo.apk"}]}`)
@@ -8168,9 +7892,9 @@
 			name: "AppSet",
 			set: "AppSet.apks",
 		}`)
-	mod := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
 	bundleConfigRule := mod.Output("bundle_config.json")
-	content := bundleConfigRule.Args["content"]
+	content := android.ContentFromFileRuleForTests(t, ctx, bundleConfigRule)
 	ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`)
 	s := mod.Rule("apexRule").Args["copy_commands"]
 	copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
@@ -8202,9 +7926,9 @@
 	ctx := testApex(t, bp, prepareForTestWithSantitizeHwaddress)
 
 	// Check that the extractor produces the correct output file from the correct input file.
-	extractorOutput := "out/soong/.intermediates/myapex.apex.extractor/android_common/extracted/myapex.hwasan.apks"
+	extractorOutput := "out/soong/.intermediates/prebuilt_myapex.apex.extractor/android_common/extracted/myapex.hwasan.apks"
 
-	m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
+	m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
 	extractedApex := m.Output(extractorOutput)
 
 	android.AssertArrayString(t, "extractor input", []string{"myapex.hwasan.apks"}, extractedApex.Inputs.Strings())
@@ -8229,10 +7953,10 @@
 		}
 	`)
 
-	m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
+	m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
 
 	// Check that the extractor produces the correct apks file from the input module
-	extractorOutput := "out/soong/.intermediates/myapex.apex.extractor/android_common/extracted/myapex.apks"
+	extractorOutput := "out/soong/.intermediates/prebuilt_myapex.apex.extractor/android_common/extracted/myapex.apks"
 	extractedApex := m.Output(extractorOutput)
 
 	android.AssertArrayString(t, "extractor input", []string{"myapex.apks"}, extractedApex.Inputs.Strings())
@@ -8297,30 +8021,39 @@
 func TestDuplicateDeapexersFromPrebuiltApexes(t *testing.T) {
 	preparers := android.GroupFixturePreparers(
 		java.PrepareForTestWithJavaDefaultModules,
+		prepareForTestWithBootclasspathFragment,
+		dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:libfoo"),
 		PrepareForTestWithApexBuildComponents,
 	).
 		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
-			"Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.myapex and com.mycompany.android.myapex"))
+			"Multiple installable prebuilt APEXes provide ambiguous deapexers: prebuilt_com.android.art and prebuilt_com.mycompany.android.art"))
 
 	bpBase := `
 		apex_set {
-			name: "com.android.myapex",
+			name: "com.android.art",
 			installable: true,
-			exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
+			exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
 			set: "myapex.apks",
 		}
 
 		apex_set {
-			name: "com.mycompany.android.myapex",
-			apex_name: "com.android.myapex",
+			name: "com.mycompany.android.art",
+			apex_name: "com.android.art",
 			installable: true,
-			exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
+			exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
 			set: "company-myapex.apks",
 		}
 
 		prebuilt_bootclasspath_fragment {
-			name: "my-bootclasspath-fragment",
-			apex_available: ["com.android.myapex"],
+			name: "art-bootclasspath-fragment",
+			apex_available: ["com.android.art"],
+			hidden_api: {
+				annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
+				metadata: "my-bootclasspath-fragment/metadata.csv",
+				index: "my-bootclasspath-fragment/index.csv",
+				stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
+				all_flags: "my-bootclasspath-fragment/all-flags.csv",
+			},
 			%s
 		}
 	`
@@ -8330,7 +8063,7 @@
 			java_import {
 				name: "libfoo",
 				jars: ["libfoo.jar"],
-				apex_available: ["com.android.myapex"],
+				apex_available: ["com.android.art"],
 			}
 		`)
 	})
@@ -8342,7 +8075,8 @@
 				public: {
 					jars: ["libbar.jar"],
 				},
-				apex_available: ["com.android.myapex"],
+				shared_library: false,
+				apex_available: ["com.android.art"],
 			}
 		`)
 	})
@@ -8357,7 +8091,8 @@
 				public: {
 					jars: ["libbar.jar"],
 				},
-				apex_available: ["com.android.myapex"],
+				shared_library: false,
+				apex_available: ["com.android.art"],
 			}
 		`)
 	})
@@ -8369,6 +8104,8 @@
 		PrepareForTestWithApexBuildComponents,
 	)
 
+	errCtx := moduleErrorfTestCtx{}
+
 	bpBase := `
 		apex_set {
 			name: "com.android.myapex",
@@ -8417,8 +8154,8 @@
 		module := result.Module("libfoo", "android_common_com.android.myapex")
 		usesLibraryDep := module.(java.UsesLibraryDependency)
 		android.AssertPathRelativeToTopEquals(t, "dex jar path",
-			"out/soong/.intermediates/com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
-			usesLibraryDep.DexJarBuildPath().Path())
+			"out/soong/.intermediates/prebuilt_com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
+			usesLibraryDep.DexJarBuildPath(errCtx).Path())
 	})
 
 	t.Run("java_sdk_library_import", func(t *testing.T) {
@@ -8440,8 +8177,8 @@
 		module := result.Module("libfoo", "android_common_com.android.myapex")
 		usesLibraryDep := module.(java.UsesLibraryDependency)
 		android.AssertPathRelativeToTopEquals(t, "dex jar path",
-			"out/soong/.intermediates/com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
-			usesLibraryDep.DexJarBuildPath().Path())
+			"out/soong/.intermediates/prebuilt_com.android.myapex.deapexer/android_common/deapexer/javalib/libfoo.jar",
+			usesLibraryDep.DexJarBuildPath(errCtx).Path())
 	})
 
 	t.Run("prebuilt_bootclasspath_fragment", func(t *testing.T) {
@@ -9013,7 +8750,7 @@
 		}),
 	)
 
-	m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
+	m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
 
 	// Check extract_apks tool parameters.
 	extractedApex := m.Output("extracted/myapex.apks")
@@ -9054,7 +8791,7 @@
 		}),
 	)
 
-	m := ctx.ModuleForTests("myapex.apex.extractor", "android_common")
+	m := ctx.ModuleForTests("prebuilt_myapex.apex.extractor", "android_common")
 
 	// Check extract_apks tool parameters. No native bridge arch expected
 	extractedApex := m.Output("extracted/myapex.apks")
@@ -9114,8 +8851,8 @@
 		}
 	`)
 
-	apexKeysText := ctx.SingletonForTests("apex_keys_text")
-	content := apexKeysText.MaybeDescription("apexkeys.txt").BuildParams.Args["content"]
+	myapex := ctx.ModuleForTests("myapex", "android_common_myapex")
+	content := android.ContentFromFileRuleForTests(t, ctx, myapex.Output("apexkeys.txt"))
 	ensureContains(t, content, `name="myapex.apex" public_key="vendor/foo/devkeys/testkey.avbpubkey" private_key="vendor/foo/devkeys/testkey.pem" container_certificate="vendor/foo/devkeys/test.x509.pem" container_private_key="vendor/foo/devkeys/test.pk8" partition="system" sign_tool="sign_myapex"`)
 }
 
@@ -9155,10 +8892,12 @@
 		}
 	`)
 
-	apexKeysText := ctx.SingletonForTests("apex_keys_text")
-	content := apexKeysText.MaybeDescription("apexkeys.txt").BuildParams.Args["content"]
+	content := android.ContentFromFileRuleForTests(t, ctx,
+		ctx.ModuleForTests("myapex", "android_common_myapex").Output("apexkeys.txt"))
+	ensureContains(t, content, `name="myapex.apex" public_key="vendor/foo/devkeys/testkey.avbpubkey" private_key="vendor/foo/devkeys/testkey.pem" container_certificate="vendor/foo/devkeys/test.x509.pem" container_private_key="vendor/foo/devkeys/test.pk8" partition="system" sign_tool="sign_myapex"`)
+	content = android.ContentFromFileRuleForTests(t, ctx,
+		ctx.ModuleForTests("myapex_set", "android_common_myapex_set").Output("apexkeys.txt"))
 	ensureContains(t, content, `name="myapex_set.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" partition="system"`)
-	ensureContains(t, content, `name="myapex.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" partition="system"`)
 }
 
 func TestAllowedFiles(t *testing.T) {
@@ -9206,12 +8945,12 @@
 			`),
 	}))
 
-	rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("diffApexContentRule")
+	rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("diffApexContentRule")
 	if expected, actual := "allowed.txt", rule.Args["allowed_files_file"]; expected != actual {
 		t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
 	}
 
-	rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image").Rule("diffApexContentRule")
+	rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex").Rule("diffApexContentRule")
 	if expected, actual := "sub/allowed.txt", rule2.Args["allowed_files_file"]; expected != actual {
 		t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
 	}
@@ -9272,14 +9011,14 @@
 		}),
 	)
 
-	compressRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("compressRule")
+	compressRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("compressRule")
 	ensureContains(t, compressRule.Output.String(), "myapex.capex.unsigned")
 
-	signApkRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Description("sign compressedApex")
+	signApkRule := ctx.ModuleForTests("myapex", "android_common_myapex").Description("sign compressedApex")
 	ensureEquals(t, signApkRule.Input.String(), compressRule.Output.String())
 
 	// Make sure output of bundle is .capex
-	ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	ab := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	ensureContains(t, ab.outputFile.String(), "myapex.capex")
 
 	// Verify android.mk rules
@@ -9331,7 +9070,7 @@
 		}
 	`)
 
-	ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	ab := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, ab)
 	var builder strings.Builder
 	data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data)
@@ -9388,7 +9127,7 @@
 	ensureNotContains(t, ldFlags, "mylib2/android_arm64_armv8-a_shared_apex10000/mylib2.so")
 
 	// It shouldn't appear in the copy cmd as well.
-	copyCmds := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule").Args["copy_commands"]
+	copyCmds := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule").Args["copy_commands"]
 	ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
 }
 
@@ -9553,28 +9292,6 @@
 	}
 }
 
-func TestHostApexInHostOnlyBuild(t *testing.T) {
-	testApex(t, `
-		apex {
-			name: "myapex",
-			host_supported: true,
-			key: "myapex.key",
-			updatable: false,
-			payload_type: "zip",
-		}
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-	`,
-		android.FixtureModifyConfig(func(config android.Config) {
-			// We may not have device targets in all builds, e.g. in
-			// prebuilts/build-tools/build-prebuilts.sh
-			config.Targets[android.Android] = []android.Target{}
-		}))
-}
-
 func TestApexJavaCoverage(t *testing.T) {
 	bp := `
 		apex {
@@ -9728,7 +9445,7 @@
 		dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
 	)
 
-	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
 	var builder strings.Builder
 	data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data)
@@ -9787,7 +9504,6 @@
 			key: "myapex.key",
 			updatable: false,
 			java_libs: ["foo"],
-			required: ["otherapex"],
 		}
 
 		apex_key {
@@ -9804,7 +9520,7 @@
 		}
 	`)
 
-	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
 	var builder strings.Builder
 	data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data)
@@ -9827,7 +9543,7 @@
 		}
 	`)
 
-	bundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	bundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	bundle.makeModulesToInstall = append(bundle.makeModulesToInstall, "foo")
 	data := android.AndroidMkDataForTest(t, ctx, bundle)
 	var builder strings.Builder
@@ -9845,12 +9561,12 @@
 		{
 			name:          "test_using_output",
 			ref:           ":myapex",
-			expected_data: []string{"out/soong/.intermediates/myapex/android_common_myapex_image/myapex.capex:myapex.capex"},
+			expected_data: []string{"out/soong/.intermediates/myapex/android_common_myapex/myapex.capex:myapex.capex"},
 		},
 		{
 			name:          "test_using_apex",
 			ref:           ":myapex{.apex}",
-			expected_data: []string{"out/soong/.intermediates/myapex/android_common_myapex_image/myapex.apex:myapex.apex"},
+			expected_data: []string{"out/soong/.intermediates/myapex/android_common_myapex/myapex.apex:myapex.apex"},
 		},
 	} {
 		t.Run(tc.name, func(t *testing.T) {
@@ -10576,6 +10292,7 @@
 			min_sdk_version: "29",
 			recovery_available: true,
 			vendor_available: true,
+			product_available: true,
 		}
 		api_imports {
 			name: "api_imports",
@@ -10586,14 +10303,14 @@
 		}
 		`
 	ctx := testApex(t, bp)
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := module.MaybeRule("apexRule")
 	if apexRule.Rule == nil {
 		t.Errorf("Expecting regular apex rule but a non regular apex rule found")
 	}
 
 	ctx = testApex(t, bp, android.FixtureModifyConfig(android.SetTrimmedApexEnabledForTests))
-	trimmedApexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("TrimmedApexRule")
+	trimmedApexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("TrimmedApexRule")
 	libs_to_trim := trimmedApexRule.Args["libs_to_trim"]
 	android.AssertStringDoesContain(t, "missing lib to trim", libs_to_trim, "libfoo")
 	android.AssertStringDoesContain(t, "missing lib to trim", libs_to_trim, "libbar")
@@ -10613,7 +10330,7 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}`)
-	mod := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
 	generateFsRule := mod.Rule("generateFsConfig")
 	cmd := generateFsRule.RuleParams.Command
 
@@ -10634,7 +10351,7 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}`)
-	mod := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
 	generateFsRule := mod.Rule("generateFsConfig")
 	cmd := generateFsRule.RuleParams.Command
 
@@ -10761,8 +10478,1063 @@
 		}
 	`)
 
-	inputs := result.ModuleForTests("myfilesystem", "android_common").Output("deps.zip").Implicits
+	inputs := result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img").Implicits
 	android.AssertStringListDoesNotContain(t, "filesystem should not have libbar",
 		inputs.Strings(),
 		"out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so")
 }
+
+var apex_default_bp = `
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		filegroup {
+			name: "myapex.manifest",
+			srcs: ["apex_manifest.json"],
+		}
+
+		filegroup {
+			name: "myapex.androidmanifest",
+			srcs: ["AndroidManifest.xml"],
+		}
+`
+
+func TestAconfigFilesJavaDeps(t *testing.T) {
+	ctx := testApex(t, apex_default_bp+`
+		apex {
+			name: "myapex",
+			manifest: ":myapex.manifest",
+			androidManifest: ":myapex.androidmanifest",
+			key: "myapex.key",
+			java_libs: [
+				"my_java_library_foo",
+				"my_java_library_bar",
+			],
+			updatable: false,
+		}
+
+		java_library {
+			name: "my_java_library_foo",
+			srcs: ["foo/bar/MyClass.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			static_libs: ["my_java_aconfig_library_foo"],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		java_library {
+			name: "my_java_library_bar",
+			srcs: ["foo/bar/MyClass.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			static_libs: ["my_java_aconfig_library_bar"],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		aconfig_declarations {
+			name: "my_aconfig_declarations_foo",
+			package: "com.example.package",
+			container: "myapex",
+			srcs: ["foo.aconfig"],
+		}
+
+		java_aconfig_library {
+			name: "my_java_aconfig_library_foo",
+			aconfig_declarations: "my_aconfig_declarations_foo",
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		aconfig_declarations {
+			name: "my_aconfig_declarations_bar",
+			package: "com.example.package",
+			container: "myapex",
+			srcs: ["bar.aconfig"],
+		}
+
+		java_aconfig_library {
+			name: "my_java_aconfig_library_bar",
+			aconfig_declarations: "my_aconfig_declarations_bar",
+			apex_available: [
+				"myapex",
+			],
+		}
+	`)
+
+	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
+	s := mod.Rule("apexRule").Args["copy_commands"]
+	copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
+	if len(copyCmds) != 8 {
+		t.Fatalf("Expected 5 commands, got %d in:\n%s", len(copyCmds), s)
+	}
+
+	ensureMatches(t, copyCmds[4], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
+	ensureMatches(t, copyCmds[5], "^cp -f .*/package.map .*/image.apex/etc$")
+	ensureMatches(t, copyCmds[6], "^cp -f .*/flag.map .*/image.apex/etc$")
+	ensureMatches(t, copyCmds[7], "^cp -f .*/flag.val .*/image.apex/etc$")
+
+	inputs := []string{
+		"my_aconfig_declarations_foo/intermediate.pb",
+		"my_aconfig_declarations_bar/intermediate.pb",
+	}
+	VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "")
+	VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map")
+	VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map")
+	VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val")
+}
+
+func TestAconfigFilesJavaAndCcDeps(t *testing.T) {
+	ctx := testApex(t, apex_default_bp+`
+		apex {
+			name: "myapex",
+			manifest: ":myapex.manifest",
+			androidManifest: ":myapex.androidmanifest",
+			key: "myapex.key",
+			java_libs: [
+				"my_java_library_foo",
+			],
+			native_shared_libs: [
+				"my_cc_library_bar",
+			],
+			binaries: [
+				"my_cc_binary_baz",
+			],
+			updatable: false,
+		}
+
+		java_library {
+			name: "my_java_library_foo",
+			srcs: ["foo/bar/MyClass.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			static_libs: ["my_java_aconfig_library_foo"],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		cc_library {
+			name: "my_cc_library_bar",
+			srcs: ["foo/bar/MyClass.cc"],
+			static_libs: [
+				"my_cc_aconfig_library_bar",
+				"my_cc_aconfig_library_baz",
+			],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		cc_binary {
+			name: "my_cc_binary_baz",
+			srcs: ["foo/bar/MyClass.cc"],
+			static_libs: ["my_cc_aconfig_library_baz"],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		aconfig_declarations {
+			name: "my_aconfig_declarations_foo",
+			package: "com.example.package",
+			container: "myapex",
+			srcs: ["foo.aconfig"],
+		}
+
+		java_aconfig_library {
+			name: "my_java_aconfig_library_foo",
+			aconfig_declarations: "my_aconfig_declarations_foo",
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		aconfig_declarations {
+			name: "my_aconfig_declarations_bar",
+			package: "com.example.package",
+			container: "myapex",
+			srcs: ["bar.aconfig"],
+		}
+
+		cc_aconfig_library {
+			name: "my_cc_aconfig_library_bar",
+			aconfig_declarations: "my_aconfig_declarations_bar",
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		aconfig_declarations {
+			name: "my_aconfig_declarations_baz",
+			package: "com.example.package",
+			container: "myapex",
+			srcs: ["baz.aconfig"],
+		}
+
+		cc_aconfig_library {
+			name: "my_cc_aconfig_library_baz",
+			aconfig_declarations: "my_aconfig_declarations_baz",
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		cc_library {
+			name: "server_configurable_flags",
+			srcs: ["server_configurable_flags.cc"],
+		}
+		cc_library {
+			name: "libbase",
+			srcs: ["libbase.cc"],
+			apex_available: [
+				"myapex",
+			],
+		}
+		cc_library {
+			name: "libaconfig_storage_read_api_cc",
+			srcs: ["libaconfig_storage_read_api_cc.cc"],
+		}
+		cc_library {
+			name: "libaconfig_storage_protos_cc",
+			srcs: ["libaconfig_storage_protos_cc.cc"],
+		}
+	`)
+
+	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
+	s := mod.Rule("apexRule").Args["copy_commands"]
+	copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
+	if len(copyCmds) != 12 {
+		t.Fatalf("Expected 12 commands, got %d in:\n%s", len(copyCmds), s)
+	}
+
+	ensureMatches(t, copyCmds[8], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
+	ensureMatches(t, copyCmds[9], "^cp -f .*/package.map .*/image.apex/etc$")
+	ensureMatches(t, copyCmds[10], "^cp -f .*/flag.map .*/image.apex/etc$")
+	ensureMatches(t, copyCmds[11], "^cp -f .*/flag.val .*/image.apex/etc$")
+
+	inputs := []string{
+		"my_aconfig_declarations_foo/intermediate.pb",
+		"my_cc_library_bar/android_arm64_armv8-a_shared_apex10000/myapex/aconfig_merged.pb",
+		"my_aconfig_declarations_baz/intermediate.pb",
+	}
+	VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "")
+	VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map")
+	VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map")
+	VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val")
+}
+
+func TestAconfigFilesRustDeps(t *testing.T) {
+	ctx := testApex(t, apex_default_bp+`
+		apex {
+			name: "myapex",
+			manifest: ":myapex.manifest",
+			androidManifest: ":myapex.androidmanifest",
+			key: "myapex.key",
+			native_shared_libs: [
+				"libmy_rust_library",
+			],
+			binaries: [
+				"my_rust_binary",
+			],
+			rust_dyn_libs: [
+				"libmy_rust_dylib",
+			],
+			updatable: false,
+		}
+
+		rust_library {
+			name: "libflags_rust", // test mock
+			crate_name: "flags_rust",
+			srcs: ["lib.rs"],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		rust_library {
+			name: "liblazy_static", // test mock
+			crate_name: "lazy_static",
+			srcs: ["src/lib.rs"],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		rust_library {
+			name: "libaconfig_storage_read_api", // test mock
+			crate_name: "aconfig_storage_read_api",
+			srcs: ["src/lib.rs"],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		rust_library {
+			name: "liblogger", // test mock
+			crate_name: "logger",
+			srcs: ["src/lib.rs"],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		rust_library {
+			name: "liblog_rust", // test mock
+			crate_name: "log_rust",
+			srcs: ["src/lib.rs"],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		rust_ffi_shared {
+			name: "libmy_rust_library",
+			srcs: ["src/lib.rs"],
+			rustlibs: ["libmy_rust_aconfig_library_foo"],
+			crate_name: "my_rust_library",
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		rust_library_dylib {
+			name: "libmy_rust_dylib",
+			srcs: ["foo/bar/MyClass.rs"],
+			rustlibs: ["libmy_rust_aconfig_library_bar"],
+			crate_name: "my_rust_dylib",
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		rust_binary {
+			name: "my_rust_binary",
+			srcs: ["foo/bar/MyClass.rs"],
+			rustlibs: [
+				"libmy_rust_aconfig_library_baz",
+				"libmy_rust_dylib",
+			],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		aconfig_declarations {
+			name: "my_aconfig_declarations_foo",
+			package: "com.example.package",
+			container: "myapex",
+			srcs: ["foo.aconfig"],
+		}
+
+		aconfig_declarations {
+			name: "my_aconfig_declarations_bar",
+			package: "com.example.package",
+			container: "myapex",
+			srcs: ["bar.aconfig"],
+		}
+
+		aconfig_declarations {
+			name: "my_aconfig_declarations_baz",
+			package: "com.example.package",
+			container: "myapex",
+			srcs: ["baz.aconfig"],
+		}
+
+		rust_aconfig_library {
+			name: "libmy_rust_aconfig_library_foo",
+			aconfig_declarations: "my_aconfig_declarations_foo",
+			crate_name: "my_rust_aconfig_library_foo",
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		rust_aconfig_library {
+			name: "libmy_rust_aconfig_library_bar",
+			aconfig_declarations: "my_aconfig_declarations_bar",
+			crate_name: "my_rust_aconfig_library_bar",
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		rust_aconfig_library {
+			name: "libmy_rust_aconfig_library_baz",
+			aconfig_declarations: "my_aconfig_declarations_baz",
+			crate_name: "my_rust_aconfig_library_baz",
+			apex_available: [
+				"myapex",
+			],
+		}
+	`)
+
+	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
+	s := mod.Rule("apexRule").Args["copy_commands"]
+	copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
+	if len(copyCmds) != 32 {
+		t.Fatalf("Expected 28 commands, got %d in:\n%s", len(copyCmds), s)
+	}
+
+	ensureMatches(t, copyCmds[28], "^cp -f .*/aconfig_flags.pb .*/image.apex/etc$")
+	ensureMatches(t, copyCmds[29], "^cp -f .*/package.map .*/image.apex/etc$")
+	ensureMatches(t, copyCmds[30], "^cp -f .*/flag.map .*/image.apex/etc$")
+	ensureMatches(t, copyCmds[31], "^cp -f .*/flag.val .*/image.apex/etc$")
+
+	inputs := []string{
+		"my_aconfig_declarations_foo/intermediate.pb",
+		"my_aconfig_declarations_bar/intermediate.pb",
+		"my_aconfig_declarations_baz/intermediate.pb",
+		"my_rust_binary/android_arm64_armv8-a_apex10000/myapex/aconfig_merged.pb",
+	}
+	VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "")
+	VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map")
+	VerifyAconfigRule(t, &mod, "create_aconfig_flag_map_file", inputs, "android_common_myapex/flag.map", "myapex", "flag_map")
+	VerifyAconfigRule(t, &mod, "create_aconfig_flag_val_file", inputs, "android_common_myapex/flag.val", "myapex", "flag_val")
+}
+
+func VerifyAconfigRule(t *testing.T, mod *android.TestingModule, desc string, inputs []string, output string, container string, file_type string) {
+	aconfigRule := mod.Description(desc)
+	s := " " + aconfigRule.Args["cache_files"]
+	aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:]
+	if len(aconfigArgs) != len(inputs) {
+		t.Fatalf("Expected %d commands, got %d in:\n%s", len(inputs), len(aconfigArgs), s)
+	}
+
+	ensureEquals(t, container, aconfigRule.Args["container"])
+	ensureEquals(t, file_type, aconfigRule.Args["file_type"])
+
+	buildParams := aconfigRule.BuildParams
+	for _, input := range inputs {
+		android.EnsureListContainsSuffix(t, aconfigArgs, input)
+		android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), input)
+	}
+
+	ensureContains(t, buildParams.Output.String(), output)
+}
+
+func TestAconfigFilesOnlyMatchCurrentApex(t *testing.T) {
+	ctx := testApex(t, apex_default_bp+`
+		apex {
+			name: "myapex",
+			manifest: ":myapex.manifest",
+			androidManifest: ":myapex.androidmanifest",
+			key: "myapex.key",
+			java_libs: [
+				"my_java_library_foo",
+				"other_java_library_bar",
+			],
+			updatable: false,
+		}
+
+		java_library {
+			name: "my_java_library_foo",
+			srcs: ["foo/bar/MyClass.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			static_libs: ["my_java_aconfig_library_foo"],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		java_library {
+			name: "other_java_library_bar",
+			srcs: ["foo/bar/MyClass.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			static_libs: ["other_java_aconfig_library_bar"],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		aconfig_declarations {
+			name: "my_aconfig_declarations_foo",
+			package: "com.example.package",
+			container: "myapex",
+			srcs: ["foo.aconfig"],
+		}
+
+		java_aconfig_library {
+			name: "my_java_aconfig_library_foo",
+			aconfig_declarations: "my_aconfig_declarations_foo",
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		aconfig_declarations {
+			name: "other_aconfig_declarations_bar",
+			package: "com.example.package",
+			container: "otherapex",
+			srcs: ["bar.aconfig"],
+		}
+
+		java_aconfig_library {
+			name: "other_java_aconfig_library_bar",
+			aconfig_declarations: "other_aconfig_declarations_bar",
+			apex_available: [
+				"myapex",
+			],
+		}
+	`)
+
+	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
+	combineAconfigRule := mod.Rule("All_aconfig_declarations_dump")
+	s := " " + combineAconfigRule.Args["cache_files"]
+	aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:]
+	if len(aconfigArgs) != 1 {
+		t.Fatalf("Expected 1 commands, got %d in:\n%s", len(aconfigArgs), s)
+	}
+	android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb")
+
+	buildParams := combineAconfigRule.BuildParams
+	if len(buildParams.Inputs) != 1 {
+		t.Fatalf("Expected 1 input, got %d", len(buildParams.Inputs))
+	}
+	android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb")
+	ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb")
+}
+
+func TestAconfigFilesRemoveDuplicates(t *testing.T) {
+	ctx := testApex(t, apex_default_bp+`
+		apex {
+			name: "myapex",
+			manifest: ":myapex.manifest",
+			androidManifest: ":myapex.androidmanifest",
+			key: "myapex.key",
+			java_libs: [
+				"my_java_library_foo",
+				"my_java_library_bar",
+			],
+			updatable: false,
+		}
+
+		java_library {
+			name: "my_java_library_foo",
+			srcs: ["foo/bar/MyClass.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			static_libs: ["my_java_aconfig_library_foo"],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		java_library {
+			name: "my_java_library_bar",
+			srcs: ["foo/bar/MyClass.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			static_libs: ["my_java_aconfig_library_bar"],
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		aconfig_declarations {
+			name: "my_aconfig_declarations_foo",
+			package: "com.example.package",
+			container: "myapex",
+			srcs: ["foo.aconfig"],
+		}
+
+		java_aconfig_library {
+			name: "my_java_aconfig_library_foo",
+			aconfig_declarations: "my_aconfig_declarations_foo",
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		java_aconfig_library {
+			name: "my_java_aconfig_library_bar",
+			aconfig_declarations: "my_aconfig_declarations_foo",
+			apex_available: [
+				"myapex",
+			],
+		}
+	`)
+
+	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
+	combineAconfigRule := mod.Rule("All_aconfig_declarations_dump")
+	s := " " + combineAconfigRule.Args["cache_files"]
+	aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:]
+	if len(aconfigArgs) != 1 {
+		t.Fatalf("Expected 1 commands, got %d in:\n%s", len(aconfigArgs), s)
+	}
+	android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb")
+
+	buildParams := combineAconfigRule.BuildParams
+	if len(buildParams.Inputs) != 1 {
+		t.Fatalf("Expected 1 input, got %d", len(buildParams.Inputs))
+	}
+	android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb")
+	ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb")
+}
+
+// Test that the boot jars come from the _selected_ apex prebuilt
+// RELEASE_APEX_CONTIRBUTIONS_* build flags will be used to select the correct prebuilt for a specific release config
+func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) {
+	checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) {
+		t.Helper()
+		s := ctx.ModuleForTests("dex_bootjars", "android_common")
+		foundLibfooJar := false
+		base := stem + ".jar"
+		for _, output := range s.AllOutputs() {
+			if filepath.Base(output) == base {
+				foundLibfooJar = true
+				buildRule := s.Output(output)
+				android.AssertStringEquals(t, "boot dex jar path", bootDexJarPath, buildRule.Input.String())
+			}
+		}
+		if !foundLibfooJar {
+			t.Errorf("Rule for libfoo.jar missing in dex_bootjars singleton outputs %q", android.StringPathsRelativeToTop(ctx.Config().SoongOutDir(), s.AllOutputs()))
+		}
+	}
+
+	// Check that the boot jars of the selected apex are run through boot_jars_package_check
+	// This validates that the jars on the bootclasspath do not contain packages outside an allowlist
+	checkBootJarsPackageCheck := func(t *testing.T, ctx *android.TestContext, expectedBootJar string) {
+		platformBcp := ctx.ModuleForTests("platform-bootclasspath", "android_common")
+		bootJarsCheckRule := platformBcp.Rule("boot_jars_package_check")
+		android.AssertStringMatches(t, "Could not find the correct boot dex jar in package check rule", bootJarsCheckRule.RuleParams.Command, "build/soong/scripts/check_boot_jars/package_allowed_list.txt.*"+expectedBootJar)
+	}
+
+	// Check that the boot jars used to generate the monolithic hiddenapi flags come from the selected apex
+	checkBootJarsForMonolithicHiddenapi := func(t *testing.T, ctx *android.TestContext, expectedBootJar string) {
+		monolithicHiddenapiFlagsCmd := ctx.ModuleForTests("platform-bootclasspath", "android_common").Output("out/soong/hiddenapi/hiddenapi-stub-flags.txt").RuleParams.Command
+		android.AssertStringMatches(t, "Could not find the correct boot dex jar in monolithic hiddenapi flags generation command", monolithicHiddenapiFlagsCmd, "--boot-dex="+expectedBootJar)
+	}
+
+	bp := `
+		// Source APEX.
+
+		java_library {
+			name: "framework-foo",
+			srcs: ["foo.java"],
+			installable: true,
+			apex_available: [
+				"com.android.foo",
+			],
+		}
+
+		bootclasspath_fragment {
+			name: "foo-bootclasspath-fragment",
+			contents: ["framework-foo"],
+			apex_available: [
+				"com.android.foo",
+			],
+			hidden_api: {
+				split_packages: ["*"],
+			},
+		}
+
+		apex_key {
+			name: "com.android.foo.key",
+			public_key: "com.android.foo.avbpubkey",
+			private_key: "com.android.foo.pem",
+		}
+
+		apex {
+			name: "com.android.foo",
+			key: "com.android.foo.key",
+			bootclasspath_fragments: ["foo-bootclasspath-fragment"],
+			updatable: false,
+		}
+
+		// Prebuilt APEX.
+
+		java_sdk_library_import {
+			name: "framework-foo",
+			public: {
+				jars: ["foo.jar"],
+			},
+			apex_available: ["com.android.foo"],
+			shared_library: false,
+		}
+
+		prebuilt_bootclasspath_fragment {
+			name: "foo-bootclasspath-fragment",
+			contents: ["framework-foo"],
+			hidden_api: {
+				annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
+				metadata: "my-bootclasspath-fragment/metadata.csv",
+				index: "my-bootclasspath-fragment/index.csv",
+				stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
+				all_flags: "my-bootclasspath-fragment/all-flags.csv",
+			},
+			apex_available: [
+				"com.android.foo",
+			],
+		}
+
+		prebuilt_apex {
+			name: "com.android.foo",
+			apex_name: "com.android.foo",
+			src: "com.android.foo-arm.apex",
+			exported_bootclasspath_fragments: ["foo-bootclasspath-fragment"],
+		}
+
+		// Another Prebuilt ART APEX
+		prebuilt_apex {
+			name: "com.android.foo.v2",
+			apex_name: "com.android.foo", // Used to determine the API domain
+			src: "com.android.foo-arm.apex",
+			exported_bootclasspath_fragments: ["foo-bootclasspath-fragment"],
+		}
+
+		// APEX contribution modules
+
+		apex_contributions {
+			name: "foo.source.contributions",
+			api_domain: "com.android.foo",
+			contents: ["com.android.foo"],
+		}
+
+		apex_contributions {
+			name: "foo.prebuilt.contributions",
+			api_domain: "com.android.foo",
+			contents: ["prebuilt_com.android.foo"],
+		}
+
+		apex_contributions {
+			name: "foo.prebuilt.v2.contributions",
+			api_domain: "com.android.foo",
+			contents: ["com.android.foo.v2"], // prebuilt_ prefix is missing because of prebuilt_rename mutator
+		}
+	`
+
+	testCases := []struct {
+		desc                      string
+		selectedApexContributions string
+		expectedBootJar           string
+	}{
+		{
+			desc:                      "Source apex com.android.foo is selected, bootjar should come from source java library",
+			selectedApexContributions: "foo.source.contributions",
+			expectedBootJar:           "out/soong/.intermediates/foo-bootclasspath-fragment/android_common_apex10000/hiddenapi-modular/encoded/framework-foo.jar",
+		},
+		{
+			desc:                      "Prebuilt apex prebuilt_com.android.foo is selected, profile should come from .prof deapexed from the prebuilt",
+			selectedApexContributions: "foo.prebuilt.contributions",
+			expectedBootJar:           "out/soong/.intermediates/prebuilt_com.android.foo.deapexer/android_common/deapexer/javalib/framework-foo.jar",
+		},
+		{
+			desc:                      "Prebuilt apex prebuilt_com.android.foo.v2 is selected, profile should come from .prof deapexed from the prebuilt",
+			selectedApexContributions: "foo.prebuilt.v2.contributions",
+			expectedBootJar:           "out/soong/.intermediates/prebuilt_com.android.foo.v2.deapexer/android_common/deapexer/javalib/framework-foo.jar",
+		},
+	}
+
+	fragment := java.ApexVariantReference{
+		Apex:   proptools.StringPtr("com.android.foo"),
+		Module: proptools.StringPtr("foo-bootclasspath-fragment"),
+	}
+
+	for _, tc := range testCases {
+		preparer := android.GroupFixturePreparers(
+			java.FixtureConfigureApexBootJars("com.android.foo:framework-foo"),
+			android.FixtureMergeMockFs(map[string][]byte{
+				"system/sepolicy/apex/com.android.foo-file_contexts": nil,
+			}),
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": tc.selectedApexContributions,
+				}
+			}),
+		)
+		ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
+		checkBootDexJarPath(t, ctx, "framework-foo", tc.expectedBootJar)
+		checkBootJarsPackageCheck(t, ctx, tc.expectedBootJar)
+		checkBootJarsForMonolithicHiddenapi(t, ctx, tc.expectedBootJar)
+	}
+}
+
+// Test that product packaging installs the selected mainline module (either source or a specific prebuilt)
+// RELEASE_APEX_CONTIRBUTIONS_* build flags will be used to select the correct prebuilt for a specific release config
+func TestInstallationRulesForMultipleApexPrebuilts(t *testing.T) {
+	// check that the LOCAL_MODULE in the generated mk file matches the name used in PRODUCT_PACKAGES
+	// Since the name used in PRODUCT_PACKAGES does not contain prebuilt_ prefix, LOCAL_MODULE should not contain any prefix either
+	checkLocalModuleName := func(t *testing.T, ctx *android.TestContext, soongApexModuleName string, expectedLocalModuleName string) {
+		// Variations are created based on apex_name
+		entries := android.AndroidMkEntriesForTest(t, ctx, ctx.ModuleForTests(soongApexModuleName, "android_common_com.android.foo").Module())
+		android.AssertStringEquals(t, "LOCAL_MODULE of the prebuilt apex must match the name listed in PRODUCT_PACKAGES", expectedLocalModuleName, entries[0].EntryMap["LOCAL_MODULE"][0])
+	}
+	// for a mainline module family, check that only the flagged soong module is visible to make
+	checkHideFromMake := func(t *testing.T, ctx *android.TestContext, visibleModuleName string, hiddenModuleNames []string) {
+		variation := func(moduleName string) string {
+			ret := "android_common_com.android.foo"
+			if moduleName == "com.google.android.foo" {
+				ret = "android_common_com.google.android.foo_com.android.foo"
+			}
+			return ret
+		}
+
+		visibleModule := ctx.ModuleForTests(visibleModuleName, variation(visibleModuleName)).Module()
+		android.AssertBoolEquals(t, "Apex "+visibleModuleName+" selected using apex_contributions should be visible to make", false, visibleModule.IsHideFromMake())
+
+		for _, hiddenModuleName := range hiddenModuleNames {
+			hiddenModule := ctx.ModuleForTests(hiddenModuleName, variation(hiddenModuleName)).Module()
+			android.AssertBoolEquals(t, "Apex "+hiddenModuleName+" not selected using apex_contributions should be hidden from make", true, hiddenModule.IsHideFromMake())
+
+		}
+	}
+
+	bp := `
+		apex_key {
+			name: "com.android.foo.key",
+			public_key: "com.android.foo.avbpubkey",
+			private_key: "com.android.foo.pem",
+		}
+
+		// AOSP source apex
+		apex {
+			name: "com.android.foo",
+			key: "com.android.foo.key",
+			updatable: false,
+		}
+
+		// Google source apex
+		override_apex {
+			name: "com.google.android.foo",
+			base: "com.android.foo",
+			key: "com.android.foo.key",
+		}
+
+		// Prebuilt Google APEX.
+
+		prebuilt_apex {
+			name: "com.google.android.foo",
+			apex_name: "com.android.foo",
+			src: "com.android.foo-arm.apex",
+			prefer: true, // prefer is set to true on both the prebuilts to induce an error if flagging is not present
+		}
+
+		// Another Prebuilt Google APEX
+		prebuilt_apex {
+			name: "com.google.android.foo.v2",
+			apex_name: "com.android.foo",
+			source_apex_name: "com.google.android.foo", // source_apex_name becomes LOCAL_MODULE in the generated mk file
+			src: "com.android.foo-arm.apex",
+			prefer: true, // prefer is set to true on both the prebuilts to induce an error if flagging is not present
+		}
+
+		// APEX contribution modules
+
+		apex_contributions {
+			name: "foo.source.contributions",
+			api_domain: "com.android.foo",
+			contents: ["com.google.android.foo"],
+		}
+
+		apex_contributions {
+			name: "foo.prebuilt.contributions",
+			api_domain: "com.android.foo",
+			contents: ["prebuilt_com.google.android.foo"],
+		}
+
+		apex_contributions {
+			name: "foo.prebuilt.v2.contributions",
+			api_domain: "com.android.foo",
+			contents: ["prebuilt_com.google.android.foo.v2"],
+		}
+
+		// This is an incompatible module because it selects multiple versions of the same mainline module
+		apex_contributions {
+			name: "foo.prebuilt.duplicate.contributions",
+			api_domain: "com.android.foo",
+			contents: [
+			    "prebuilt_com.google.android.foo",
+			    "prebuilt_com.google.android.foo.v2",
+			],
+		}
+	`
+
+	testCases := []struct {
+		desc                      string
+		selectedApexContributions string
+		expectedVisibleModuleName string
+		expectedHiddenModuleNames []string
+		expectedError             string
+	}{
+		{
+			desc:                      "Source apex is selected, prebuilts should be hidden from make",
+			selectedApexContributions: "foo.source.contributions",
+			expectedVisibleModuleName: "com.google.android.foo",
+			expectedHiddenModuleNames: []string{"prebuilt_com.google.android.foo", "prebuilt_com.google.android.foo.v2"},
+		},
+		{
+			desc:                      "Prebuilt apex prebuilt_com.android.foo is selected, source and the other prebuilt should be hidden from make",
+			selectedApexContributions: "foo.prebuilt.contributions",
+			expectedVisibleModuleName: "prebuilt_com.google.android.foo",
+			expectedHiddenModuleNames: []string{"com.google.android.foo", "prebuilt_com.google.android.foo.v2"},
+		},
+		{
+			desc:                      "Prebuilt apex prebuilt_com.android.fooi.v2 is selected, source and the other prebuilt should be hidden from make",
+			selectedApexContributions: "foo.prebuilt.v2.contributions",
+			expectedVisibleModuleName: "prebuilt_com.google.android.foo.v2",
+			expectedHiddenModuleNames: []string{"com.google.android.foo", "prebuilt_com.google.android.foo"},
+		},
+		{
+			desc:                      "Multiple versions of a prebuilt apex is selected in the same release config",
+			selectedApexContributions: "foo.prebuilt.duplicate.contributions",
+			expectedError:             "Found duplicate variations of the same module in apex_contributions: prebuilt_com.google.android.foo and prebuilt_com.google.android.foo.v2",
+		},
+	}
+
+	for _, tc := range testCases {
+		preparer := android.GroupFixturePreparers(
+			android.FixtureMergeMockFs(map[string][]byte{
+				"system/sepolicy/apex/com.android.foo-file_contexts": nil,
+			}),
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": tc.selectedApexContributions,
+				}
+			}),
+		)
+		if tc.expectedError != "" {
+			preparer = preparer.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(tc.expectedError))
+			testApex(t, bp, preparer)
+			return
+		}
+		ctx := testApex(t, bp, preparer)
+
+		// Check that the LOCAL_MODULE of the two prebuilts is com.android.foo
+		// This ensures that product packaging can pick them for installation if it has been flagged by apex_contributions
+		checkLocalModuleName(t, ctx, "prebuilt_com.google.android.foo", "com.google.android.foo")
+		checkLocalModuleName(t, ctx, "prebuilt_com.google.android.foo.v2", "com.google.android.foo")
+
+		// Check that
+		// 1. The contents of the selected apex_contributions are visible to make
+		// 2. The rest of the apexes in the mainline module family (source or other prebuilt) is hidden from make
+		checkHideFromMake(t, ctx, tc.expectedVisibleModuleName, tc.expectedHiddenModuleNames)
+	}
+}
+
+func TestAconfifDeclarationsValidation(t *testing.T) {
+	aconfigDeclarationLibraryString := func(moduleNames []string) (ret string) {
+		for _, moduleName := range moduleNames {
+			ret += fmt.Sprintf(`
+			aconfig_declarations {
+				name: "%[1]s",
+				package: "com.example.package",
+				srcs: [
+					"%[1]s.aconfig",
+				],
+			}
+			java_aconfig_library {
+				name: "%[1]s-lib",
+				aconfig_declarations: "%[1]s",
+			}
+			`, moduleName)
+		}
+		return ret
+	}
+
+	result := android.GroupFixturePreparers(
+		prepareForApexTest,
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		java.FixtureWithLastReleaseApis("foo"),
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.SetApiLibraries([]string{"foo"})
+		}),
+	).RunTestWithBp(t, `
+		java_library {
+			name: "baz-java-lib",
+			static_libs: [
+				"baz-lib",
+			],
+		}
+		filegroup {
+			name: "qux-filegroup",
+			srcs: [
+				":qux-lib{.generated_srcjars}",
+			],
+		}
+		filegroup {
+			name: "qux-another-filegroup",
+			srcs: [
+				":qux-filegroup",
+			],
+		}
+		java_library {
+			name: "quux-java-lib",
+			srcs: [
+				"a.java",
+			],
+			libs: [
+				"quux-lib",
+			],
+		}
+		java_sdk_library {
+			name: "foo",
+			srcs: [
+				":qux-another-filegroup",
+			],
+			api_packages: ["foo"],
+			system: {
+				enabled: true,
+			},
+			module_lib: {
+				enabled: true,
+			},
+			test: {
+				enabled: true,
+			},
+			static_libs: [
+				"bar-lib",
+			],
+			libs: [
+				"baz-java-lib",
+				"quux-java-lib",
+			],
+			aconfig_declarations: [
+				"bar",
+			],
+		}
+	`+aconfigDeclarationLibraryString([]string{"bar", "baz", "qux", "quux"}))
+
+	m := result.ModuleForTests("foo.stubs.source", "android_common")
+	outDir := "out/soong/.intermediates"
+
+	// Arguments passed to aconfig to retrieve the state of the flags defined in the
+	// textproto files
+	aconfigFlagArgs := m.Output("released-flagged-apis-exportable.txt").Args["flags_path"]
+
+	// "bar-lib" is a static_lib of "foo" and is passed to metalava as classpath. Thus the
+	// cache file provided by the associated aconfig_declarations module "bar" should be passed
+	// to aconfig.
+	android.AssertStringDoesContain(t, "cache file of a java_aconfig_library static_lib "+
+		"passed as an input",
+		aconfigFlagArgs, fmt.Sprintf("%s/%s/intermediate.pb", outDir, "bar"))
+
+	// "baz-java-lib", which statically depends on "baz-lib", is a lib of "foo" and is passed
+	// to metalava as classpath. Thus the cache file provided by the associated
+	// aconfig_declarations module "baz" should be passed to aconfig.
+	android.AssertStringDoesContain(t, "cache file of a lib that statically depends on "+
+		"java_aconfig_library passed as an input",
+		aconfigFlagArgs, fmt.Sprintf("%s/%s/intermediate.pb", outDir, "baz"))
+
+	// "qux-lib" is passed to metalava as src via the filegroup, thus the cache file provided by
+	// the associated aconfig_declarations module "qux" should be passed to aconfig.
+	android.AssertStringDoesContain(t, "cache file of srcs java_aconfig_library passed as an "+
+		"input",
+		aconfigFlagArgs, fmt.Sprintf("%s/%s/intermediate.pb", outDir, "qux"))
+
+	// "quux-java-lib" is a lib of "foo" and is passed to metalava as classpath, but does not
+	// statically depend on "quux-lib". Therefore, the cache file provided by the associated
+	// aconfig_declarations module "quux" should not be passed to aconfig.
+	android.AssertStringDoesNotContain(t, "cache file of a lib that does not statically "+
+		"depend on java_aconfig_library not passed as an input",
+		aconfigFlagArgs, fmt.Sprintf("%s/%s/intermediate.pb", outDir, "quux"))
+}
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index f30f7f6..778c20a 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -53,7 +53,11 @@
 		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz"),
 		java.FixtureConfigureApexBootJars("someapex:foo", "someapex:bar"),
 		prepareForTestWithArtApex,
-
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		java.FixtureWithLastReleaseApis("foo", "baz"),
 	).RunTestWithBp(t, `
@@ -152,11 +156,11 @@
 
 	// Check stub dex paths exported by art.
 	artFragment := result.Module("art-bootclasspath-fragment", "android_common")
-	artInfo := result.ModuleProvider(artFragment, java.HiddenAPIInfoProvider).(java.HiddenAPIInfo)
+	artInfo, _ := android.SingletonModuleProvider(result, artFragment, java.HiddenAPIInfoProvider)
 
-	bazPublicStubs := "out/soong/.intermediates/baz.stubs/android_common/dex/baz.stubs.jar"
-	bazSystemStubs := "out/soong/.intermediates/baz.stubs.system/android_common/dex/baz.stubs.system.jar"
-	bazTestStubs := "out/soong/.intermediates/baz.stubs.test/android_common/dex/baz.stubs.test.jar"
+	bazPublicStubs := "out/soong/.intermediates/baz.stubs.exportable/android_common/dex/baz.stubs.exportable.jar"
+	bazSystemStubs := "out/soong/.intermediates/baz.stubs.exportable.system/android_common/dex/baz.stubs.exportable.system.jar"
+	bazTestStubs := "out/soong/.intermediates/baz.stubs.exportable.test/android_common/dex/baz.stubs.exportable.test.jar"
 
 	checkAPIScopeStubs("art", artInfo, java.PublicHiddenAPIScope, bazPublicStubs)
 	checkAPIScopeStubs("art", artInfo, java.SystemHiddenAPIScope, bazSystemStubs)
@@ -165,10 +169,10 @@
 
 	// Check stub dex paths exported by other.
 	otherFragment := result.Module("other-bootclasspath-fragment", "android_common")
-	otherInfo := result.ModuleProvider(otherFragment, java.HiddenAPIInfoProvider).(java.HiddenAPIInfo)
+	otherInfo, _ := android.SingletonModuleProvider(result, otherFragment, java.HiddenAPIInfoProvider)
 
-	fooPublicStubs := "out/soong/.intermediates/foo.stubs/android_common/dex/foo.stubs.jar"
-	fooSystemStubs := "out/soong/.intermediates/foo.stubs.system/android_common/dex/foo.stubs.system.jar"
+	fooPublicStubs := "out/soong/.intermediates/foo.stubs.exportable/android_common/dex/foo.stubs.exportable.jar"
+	fooSystemStubs := "out/soong/.intermediates/foo.stubs.exportable.system/android_common/dex/foo.stubs.exportable.system.jar"
 
 	checkAPIScopeStubs("other", otherInfo, java.PublicHiddenAPIScope, bazPublicStubs, fooPublicStubs)
 	checkAPIScopeStubs("other", otherInfo, java.SystemHiddenAPIScope, bazSystemStubs, fooSystemStubs)
@@ -302,16 +306,17 @@
 			java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"),
 		).RunTest(t)
 
-		ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+		ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
 			"etc/boot-image.prof",
 			"etc/classpaths/bootclasspath.pb",
 			"javalib/bar.jar",
 			"javalib/foo.jar",
 		})
 
-		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
 			`art-bootclasspath-fragment`,
 			`com.android.art.key`,
+			`dex2oatd`,
 		})
 
 		// Make sure that the source bootclasspath_fragment copies its dex files to the predefined
@@ -332,7 +337,7 @@
 			dexpreopt.FixtureDisableDexpreoptBootImages(true),
 		).RunTest(t)
 
-		ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+		ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
 			"etc/boot-image.prof",
 			"etc/classpaths/bootclasspath.pb",
 			"javalib/bar.jar",
@@ -351,7 +356,7 @@
 			dexpreopt.FixtureDisableGenerateProfile(true),
 		).RunTest(t)
 
-		files := getFiles(t, result.TestContext, "com.android.art", "android_common_com.android.art_image")
+		files := getFiles(t, result.TestContext, "com.android.art", "android_common_com.android.art")
 		for _, file := range files {
 			matched, _ := path.Match("etc/boot-image.prof", file.path)
 			android.AssertBoolEquals(t, "\"etc/boot-image.prof\" should not be in the APEX", matched, false)
@@ -374,15 +379,16 @@
 			java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"),
 		).RunTest(t)
 
-		ensureExactDeapexedContents(t, result.TestContext, "com.android.art", "android_common", []string{
+		ensureExactDeapexedContents(t, result.TestContext, "prebuilt_com.android.art", "android_common", []string{
 			"etc/boot-image.prof",
 			"javalib/bar.jar",
 			"javalib/foo.jar",
 		})
 
-		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
 			`art-bootclasspath-fragment`,
 			`com.android.art.key`,
+			`dex2oatd`,
 			`prebuilt_com.android.art`,
 		})
 
@@ -529,14 +535,16 @@
 		result := preparers.RunTestWithBp(t, fmt.Sprintf(bp, "enabled: false,"))
 
 		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
-			`com.android.art.apex.selector`,
+			`dex2oatd`,
 			`prebuilt_art-bootclasspath-fragment`,
+			`prebuilt_com.android.art.apex.selector`,
+			`prebuilt_com.android.art.deapexer`,
 		})
 
 		java.CheckModuleDependencies(t, result.TestContext, "art-bootclasspath-fragment", "android_common_com.android.art", []string{
-			`com.android.art.deapexer`,
 			`dex2oatd`,
 			`prebuilt_bar`,
+			`prebuilt_com.android.art.deapexer`,
 			`prebuilt_foo`,
 		})
 
@@ -546,7 +554,7 @@
 
 	t.Run("enabled alternative APEX", func(t *testing.T) {
 		preparers.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
-			"Multiple installable prebuilt APEXes provide ambiguous deapexers: com.android.art and com.mycompany.android.art")).
+			"Multiple installable prebuilt APEXes provide ambiguous deapexers: prebuilt_com.android.art and prebuilt_com.mycompany.android.art")).
 			RunTestWithBp(t, fmt.Sprintf(bp, ""))
 	})
 }
@@ -635,7 +643,7 @@
 		}
 	`)
 
-	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex", []string{
 		// This does not include art, oat or vdex files as they are only included for the art boot
 		// image.
 		"etc/classpaths/bootclasspath.pb",
@@ -643,19 +651,20 @@
 		"javalib/foo.jar",
 	})
 
-	java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+	java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex", []string{
+		`dex2oatd`,
 		`myapex.key`,
 		`mybootclasspathfragment`,
 	})
 
-	apex := result.ModuleForTests("myapex", "android_common_myapex_image")
+	apex := result.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := apex.Rule("apexRule")
 	copyCommands := apexRule.Args["copy_commands"]
 
 	// Make sure that the fragment provides the hidden API encoded dex jars to the APEX.
 	fragment := result.Module("mybootclasspathfragment", "android_common_apex10000")
 
-	info := result.ModuleProvider(fragment, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
+	info, _ := android.SingletonModuleProvider(result, fragment, java.BootclasspathFragmentApexContentInfoProvider)
 
 	checkFragmentExportedDexJar := func(name string, expectedDexJar string) {
 		module := result.Module(name, "android_common_apex10000")
@@ -665,7 +674,7 @@
 		}
 		android.AssertPathRelativeToTopEquals(t, name+" dex", expectedDexJar, dexJar)
 
-		expectedCopyCommand := fmt.Sprintf("&& cp -f %s out/soong/.intermediates/myapex/android_common_myapex_image/image.apex/javalib/%s.jar", expectedDexJar, name)
+		expectedCopyCommand := fmt.Sprintf("&& cp -f %s out/soong/.intermediates/myapex/android_common_myapex/image.apex/javalib/%s.jar", expectedDexJar, name)
 		android.AssertStringDoesContain(t, name+" apex copy command", copyCommands, expectedCopyCommand)
 	}
 
@@ -675,7 +684,7 @@
 
 func getDexJarPath(result *android.TestResult, name string) string {
 	module := result.Module(name, "android_common")
-	return module.(java.UsesLibraryDependency).DexJarBuildPath().Path().RelativeToTop().String()
+	return module.(java.UsesLibraryDependency).DexJarBuildPath(moduleErrorfTestCtx{}).Path().RelativeToTop().String()
 }
 
 // TestBootclasspathFragment_HiddenAPIList checks to make sure that the correct parameters are
@@ -694,6 +703,11 @@
 
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		java.FixtureWithLastReleaseApis("foo", "quuz"),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
 	).RunTestWithBp(t, `
 		apex {
 			name: "com.android.art",
@@ -805,11 +819,11 @@
 		"foo",
 	})
 
-	fooStubs := getDexJarPath(result, "foo.stubs")
-	quuzPublicStubs := getDexJarPath(result, "quuz.stubs")
-	quuzSystemStubs := getDexJarPath(result, "quuz.stubs.system")
-	quuzTestStubs := getDexJarPath(result, "quuz.stubs.test")
-	quuzModuleLibStubs := getDexJarPath(result, "quuz.stubs.module_lib")
+	fooStubs := getDexJarPath(result, "foo.stubs.exportable")
+	quuzPublicStubs := getDexJarPath(result, "quuz.stubs.exportable")
+	quuzSystemStubs := getDexJarPath(result, "quuz.stubs.exportable.system")
+	quuzTestStubs := getDexJarPath(result, "quuz.stubs.exportable.test")
+	quuzModuleLibStubs := getDexJarPath(result, "quuz.stubs.exportable.module_lib")
 
 	// Make sure that the fragment uses the quuz stub dex jars when generating the hidden API flags.
 	fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000")
@@ -832,7 +846,7 @@
 // TestBootclasspathFragment_AndroidNonUpdatable checks to make sure that setting
 // additional_stubs: ["android-non-updatable"] causes the source android-non-updatable modules to be
 // added to the hiddenapi list tool.
-func TestBootclasspathFragment_AndroidNonUpdatable(t *testing.T) {
+func TestBootclasspathFragment_AndroidNonUpdatable_FromSource(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForTestWithBootclasspathFragment,
 		prepareForTestWithArtApex,
@@ -843,6 +857,9 @@
 		// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
 		// is disabled.
 		android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.SetBuildFromTextStub(false)
+		}),
 
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		java.FixtureWithLastReleaseApis("foo", "android-non-updatable"),
@@ -1000,6 +1017,168 @@
 	android.AssertStringDoesContain(t, "test", command, "--test-stub-classpath="+nonUpdatableTestStubs)
 }
 
+func TestBootclasspathFragment_AndroidNonUpdatable_FromText(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForTestWithBootclasspathFragment,
+		prepareForTestWithArtApex,
+		prepareForTestWithMyapex,
+		// Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
+		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz"),
+		java.FixtureConfigureApexBootJars("myapex:foo", "myapex:bar"),
+		// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
+		// is disabled.
+		android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.SetBuildFromTextStub(true)
+		}),
+
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		java.FixtureWithLastReleaseApis("foo", "android-non-updatable"),
+	).RunTestWithBp(t, `
+		java_sdk_library {
+			name: "android-non-updatable",
+			srcs: ["b.java"],
+			compile_dex: true,
+			public: {
+				enabled: true,
+			},
+			system: {
+				enabled: true,
+			},
+			test: {
+				enabled: true,
+			},
+			module_lib: {
+				enabled: true,
+			},
+		}
+
+		apex {
+			name: "com.android.art",
+			key: "com.android.art.key",
+			bootclasspath_fragments: ["art-bootclasspath-fragment"],
+			updatable: false,
+		}
+
+		apex_key {
+			name: "com.android.art.key",
+			public_key: "com.android.art.avbpubkey",
+			private_key: "com.android.art.pem",
+		}
+
+		java_library {
+			name: "baz",
+			apex_available: [
+				"com.android.art",
+			],
+			srcs: ["b.java"],
+			compile_dex: true,
+		}
+
+		java_library {
+			name: "quuz",
+			apex_available: [
+				"com.android.art",
+			],
+			srcs: ["b.java"],
+			compile_dex: true,
+		}
+
+		bootclasspath_fragment {
+			name: "art-bootclasspath-fragment",
+			image_name: "art",
+			// Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
+			contents: ["baz", "quuz"],
+			apex_available: [
+				"com.android.art",
+			],
+			hidden_api: {
+				split_packages: ["*"],
+			},
+		}
+
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			bootclasspath_fragments: [
+				"mybootclasspathfragment",
+			],
+			updatable: false,
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		java_sdk_library {
+			name: "foo",
+			srcs: ["b.java"],
+			shared_library: false,
+			public: {enabled: true},
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		java_library {
+			name: "bar",
+			srcs: ["b.java"],
+			installable: true,
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		bootclasspath_fragment {
+			name: "mybootclasspathfragment",
+			contents: [
+				"foo",
+				"bar",
+			],
+			apex_available: [
+				"myapex",
+			],
+			additional_stubs: ["android-non-updatable"],
+			fragments: [
+				{
+					apex: "com.android.art",
+					module: "art-bootclasspath-fragment",
+				},
+			],
+			hidden_api: {
+				split_packages: ["*"],
+			},
+		}
+	`)
+
+	java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
+		"android-non-updatable.stubs",
+		"android-non-updatable.stubs.system",
+		"android-non-updatable.stubs.test",
+		"android-non-updatable.stubs.test_module_lib",
+		"art-bootclasspath-fragment",
+		"bar",
+		"dex2oatd",
+		"foo",
+	})
+
+	nonUpdatableTestModuleLibStubs := getDexJarPath(result, "android-non-updatable.stubs.test_module_lib")
+
+	// Make sure that the fragment uses the android-non-updatable modules when generating the hidden
+	// API flags.
+	fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000")
+
+	rule := fragment.Rule("modularHiddenAPIStubFlagsFile")
+	command := rule.RuleParams.Command
+	android.AssertStringDoesContain(t, "check correct rule", command, "hiddenapi list")
+
+	// Make sure that the test_module_lib non-updatable stubs are available for resolving references from
+	// the implementation boot dex jars provided by this module.
+	android.AssertStringDoesContain(t, "android-non-updatable widest", command, "--dependency-stub-dex="+nonUpdatableTestModuleLibStubs)
+}
+
 // TestBootclasspathFragment_AndroidNonUpdatable_AlwaysUsePrebuiltSdks checks to make sure that
 // setting additional_stubs: ["android-non-updatable"] causes the prebuilt android-non-updatable
 // modules to be added to the hiddenapi list tool.
diff --git a/apex/bp2build.go b/apex/bp2build.go
deleted file mode 100644
index a3dda83..0000000
--- a/apex/bp2build.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (C) 2022 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package apex
-
-import (
-	"android/soong/android"
-	"encoding/json"
-	"strings"
-)
-
-// This file contains the bp2build integration for the apex package.
-
-// Export constants as Starlark using bp2build to Bazel.
-func BazelApexToolchainVars() (string, error) {
-	marshalled, err := json.Marshal(apexAvailBaseline)
-	if err != nil {
-		return "", err
-	}
-	content := []string{
-		"# GENERATED BY SOONG. DO NOT EDIT.",
-		"default_manifest_version = " + android.DefaultUpdatableModuleVersion, // constants.go is different in every branch.
-		"apex_available_baseline = json.decode('''" + string(marshalled) + "''')",
-	}
-	return strings.Join(content, "\n"), nil
-}
diff --git a/apex/bp2build_test.go b/apex/bp2build_test.go
deleted file mode 100644
index b1b6a75..0000000
--- a/apex/bp2build_test.go
+++ /dev/null
@@ -1,545 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package apex
-
-import (
-	"android/soong/android"
-	"android/soong/android/allowlists"
-	"android/soong/bazel/cquery"
-	"fmt"
-	"path/filepath"
-	"strings"
-	"testing"
-)
-
-func TestApexImageInMixedBuilds(t *testing.T) {
-	bp := `
-apex_key{
-	name: "foo_key",
-}
-
-apex {
-	name: "foo",
-	key: "foo_key",
-	updatable: true,
-	min_sdk_version: "31",
-	file_contexts: ":myapex-file_contexts",
-	bazel_module: { label: "//:foo" },
-}`
-
-	outputBaseDir := "out/bazel"
-	result := android.GroupFixturePreparers(
-		prepareForApexTest,
-		android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: outputBaseDir,
-				LabelToApexInfo: map[string]cquery.ApexInfo{
-					"//:foo": cquery.ApexInfo{
-						// ApexInfo Starlark provider.
-						SignedOutput:           "signed_out.apex",
-						SignedCompressedOutput: "signed_out.capex",
-						UnsignedOutput:         "unsigned_out.apex",
-						BundleKeyInfo:          []string{"public_key", "private_key"},
-						ContainerKeyInfo:       []string{"container_cert", "container_private"},
-						SymbolsUsedByApex:      "foo_using.txt",
-						JavaSymbolsUsedByApex:  "foo_using.xml",
-						BundleFile:             "apex_bundle.zip",
-						InstalledFiles:         "installed-files.txt",
-						RequiresLibs:           []string{"//path/c:c", "//path/d:d"},
-
-						// unused
-						PackageName:  "pkg_name",
-						ProvidesLibs: []string{"a", "b"},
-
-						// ApexMkInfo Starlark provider
-						PayloadFilesInfo: []map[string]string{
-							{
-								"built_file":       "bazel-out/adbd",
-								"install_dir":      "bin",
-								"class":            "nativeExecutable",
-								"make_module_name": "adbd",
-								"basename":         "adbd",
-								"package":          "foo",
-							},
-						},
-						MakeModulesToInstall: []string{"c"}, // d deliberately omitted
-					},
-				},
-			}
-		}),
-	).RunTestWithBp(t, bp)
-
-	m := result.ModuleForTests("foo", "android_common_foo_image").Module()
-	ab, ok := m.(*apexBundle)
-
-	if !ok {
-		t.Fatalf("Expected module to be an apexBundle, was not")
-	}
-
-	// TODO: refactor to android.AssertStringEquals
-	if w, g := "out/bazel/execroot/__main__/public_key", ab.publicKeyFile.String(); w != g {
-		t.Errorf("Expected public key %q, got %q", w, g)
-	}
-
-	if w, g := "out/bazel/execroot/__main__/private_key", ab.privateKeyFile.String(); w != g {
-		t.Errorf("Expected private key %q, got %q", w, g)
-	}
-
-	if w, g := "out/bazel/execroot/__main__/container_cert", ab.containerCertificateFile.String(); w != g {
-		t.Errorf("Expected public container key %q, got %q", w, g)
-	}
-
-	if w, g := "out/bazel/execroot/__main__/container_private", ab.containerPrivateKeyFile.String(); w != g {
-		t.Errorf("Expected private container key %q, got %q", w, g)
-	}
-
-	if w, g := "out/bazel/execroot/__main__/signed_out.apex", ab.outputFile.String(); w != g {
-		t.Errorf("Expected output file %q, got %q", w, g)
-	}
-
-	if w, g := "out/bazel/execroot/__main__/foo_using.txt", ab.nativeApisUsedByModuleFile.String(); w != g {
-		t.Errorf("Expected output file %q, got %q", w, g)
-	}
-
-	if w, g := "out/bazel/execroot/__main__/foo_using.xml", ab.javaApisUsedByModuleFile.String(); w != g {
-		t.Errorf("Expected output file %q, got %q", w, g)
-	}
-
-	if w, g := "out/bazel/execroot/__main__/installed-files.txt", ab.installedFilesFile.String(); w != g {
-		t.Errorf("Expected installed-files.txt %q, got %q", w, g)
-	}
-
-	mkData := android.AndroidMkDataForTest(t, result.TestContext, m)
-	var builder strings.Builder
-	mkData.Custom(&builder, "foo", "BAZEL_TARGET_", "", mkData)
-
-	data := builder.String()
-	if w := "ALL_MODULES.$(my_register_name).BUNDLE := out/bazel/execroot/__main__/apex_bundle.zip"; !strings.Contains(data, w) {
-		t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
-	}
-	if w := "$(call dist-for-goals,checkbuild,out/bazel/execroot/__main__/installed-files.txt:foo-installed-files.txt)"; !strings.Contains(data, w) {
-		t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
-	}
-
-	// make modules to be installed to system
-	if len(ab.makeModulesToInstall) != 1 && ab.makeModulesToInstall[0] != "c" {
-		t.Errorf("Expected makeModulesToInstall slice to only contain 'c', got %q", ab.makeModulesToInstall)
-	}
-	if w := "LOCAL_REQUIRED_MODULES := adbd.foo c"; !strings.Contains(data, w) {
-		t.Errorf("Expected %q in androidmk data, but did not find it in %q", w, data)
-	}
-}
-
-func TestApexImageCreatesFilesInfoForMake(t *testing.T) {
-	bp := `
-apex_key{
-	name: "foo_key",
-}
-
-apex {
-	name: "foo",
-	key: "foo_key",
-	updatable: true,
-	min_sdk_version: "31",
-	file_contexts: ":myapex-file_contexts",
-	bazel_module: { label: "//:foo" },
-}`
-
-	outputBaseDir := "out/bazel"
-	result := android.GroupFixturePreparers(
-		prepareForApexTest,
-		android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: outputBaseDir,
-				LabelToApexInfo: map[string]cquery.ApexInfo{
-					"//:foo": {
-						// ApexInfo Starlark provider. Necessary for the test.
-						SignedOutput:     "signed_out.apex",
-						BundleKeyInfo:    []string{"public_key", "private_key"},
-						ContainerKeyInfo: []string{"container_cert", "container_private"},
-
-						// ApexMkInfo Starlark provider
-						PayloadFilesInfo: []map[string]string{
-							{
-								"arch":                  "arm64",
-								"basename":              "libcrypto.so",
-								"built_file":            "bazel-out/64/libcrypto.so",
-								"class":                 "nativeSharedLib",
-								"install_dir":           "lib64",
-								"make_module_name":      "libcrypto",
-								"package":               "foo/bar",
-								"unstripped_built_file": "bazel-out/64/unstripped_libcrypto.so",
-							},
-							{
-								"arch":             "arm",
-								"basename":         "libcrypto.so",
-								"built_file":       "bazel-out/32/libcrypto.so",
-								"class":            "nativeSharedLib",
-								"install_dir":      "lib",
-								"make_module_name": "libcrypto",
-								"package":          "foo/bar",
-							},
-							{
-								"arch":             "arm64",
-								"basename":         "adbd",
-								"built_file":       "bazel-out/adbd",
-								"class":            "nativeExecutable",
-								"install_dir":      "bin",
-								"make_module_name": "adbd",
-								"package":          "foo",
-							},
-						},
-					},
-				},
-			}
-		}),
-	).RunTestWithBp(t, bp)
-
-	m := result.ModuleForTests("foo", "android_common_foo_image").Module()
-	ab, ok := m.(*apexBundle)
-
-	if !ok {
-		t.Fatalf("Expected module to be an apexBundle, was not")
-	}
-
-	expectedFilesInfo := []apexFile{
-		{
-			androidMkModuleName: "libcrypto",
-			builtFile:           android.PathForTesting("out/bazel/execroot/__main__/bazel-out/64/libcrypto.so"),
-			class:               nativeSharedLib,
-			customStem:          "libcrypto.so",
-			installDir:          "lib64",
-			moduleDir:           "foo/bar",
-			arch:                "arm64",
-			unstrippedBuiltFile: android.PathForTesting("out/bazel/execroot/__main__/bazel-out/64/unstripped_libcrypto.so"),
-		},
-		{
-			androidMkModuleName: "libcrypto",
-			builtFile:           android.PathForTesting("out/bazel/execroot/__main__/bazel-out/32/libcrypto.so"),
-			class:               nativeSharedLib,
-			customStem:          "libcrypto.so",
-			installDir:          "lib",
-			moduleDir:           "foo/bar",
-			arch:                "arm",
-		},
-		{
-			androidMkModuleName: "adbd",
-			builtFile:           android.PathForTesting("out/bazel/execroot/__main__/bazel-out/adbd"),
-			class:               nativeExecutable,
-			customStem:          "adbd",
-			installDir:          "bin",
-			moduleDir:           "foo",
-			arch:                "arm64",
-		},
-	}
-
-	if len(ab.filesInfo) != len(expectedFilesInfo) {
-		t.Errorf("Expected %d entries in ab.filesInfo, but got %d", len(ab.filesInfo), len(expectedFilesInfo))
-	}
-
-	for idx, f := range ab.filesInfo {
-		expected := expectedFilesInfo[idx]
-		android.AssertSame(t, "different class", expected.class, f.class)
-		android.AssertStringEquals(t, "different built file", expected.builtFile.String(), f.builtFile.String())
-		android.AssertStringEquals(t, "different custom stem", expected.customStem, f.customStem)
-		android.AssertStringEquals(t, "different install dir", expected.installDir, f.installDir)
-		android.AssertStringEquals(t, "different make module name", expected.androidMkModuleName, f.androidMkModuleName)
-		android.AssertStringEquals(t, "different moduleDir", expected.moduleDir, f.moduleDir)
-		android.AssertStringEquals(t, "different arch", expected.arch, f.arch)
-		if expected.unstrippedBuiltFile != nil {
-			if f.unstrippedBuiltFile == nil {
-				t.Errorf("expected an unstripped built file path.")
-			}
-			android.AssertStringEquals(t, "different unstripped built file", expected.unstrippedBuiltFile.String(), f.unstrippedBuiltFile.String())
-		}
-	}
-}
-
-func TestCompressedApexImageInMixedBuilds(t *testing.T) {
-	bp := `
-apex_key{
-	name: "foo_key",
-}
-apex {
-	name: "foo",
-	key: "foo_key",
-	updatable: true,
-	min_sdk_version: "31",
-	file_contexts: ":myapex-file_contexts",
-	bazel_module: { label: "//:foo" },
-	test_only_force_compression: true, // force compression
-}`
-
-	outputBaseDir := "out/bazel"
-	result := android.GroupFixturePreparers(
-		prepareForApexTest,
-		android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: outputBaseDir,
-				LabelToApexInfo: map[string]cquery.ApexInfo{
-					"//:foo": cquery.ApexInfo{
-						SignedOutput:           "signed_out.apex",
-						SignedCompressedOutput: "signed_out.capex",
-						BundleKeyInfo:          []string{"public_key", "private_key"},
-						ContainerKeyInfo:       []string{"container_cert", "container_private"},
-					},
-				},
-			}
-		}),
-	).RunTestWithBp(t, bp)
-
-	m := result.ModuleForTests("foo", "android_common_foo_image").Module()
-	ab, ok := m.(*apexBundle)
-	if !ok {
-		t.Fatalf("Expected module to be an apexBundle, was not")
-	}
-
-	if w, g := "out/bazel/execroot/__main__/signed_out.capex", ab.outputFile.String(); w != g {
-		t.Errorf("Expected output file to be compressed apex %q, got %q", w, g)
-	}
-
-	mkData := android.AndroidMkDataForTest(t, result.TestContext, m)
-	var builder strings.Builder
-	mkData.Custom(&builder, "foo", "BAZEL_TARGET_", "", mkData)
-
-	data := builder.String()
-
-	expectedAndroidMk := []string{
-		"LOCAL_PREBUILT_MODULE_FILE := out/bazel/execroot/__main__/signed_out.capex",
-
-		// Check that the source install file is the capex. The dest is not important.
-		"LOCAL_SOONG_INSTALL_PAIRS := out/bazel/execroot/__main__/signed_out.capex:",
-	}
-	for _, androidMk := range expectedAndroidMk {
-		if !strings.Contains(data, androidMk) {
-			t.Errorf("Expected %q in androidmk data, but did not find %q", androidMk, data)
-		}
-	}
-}
-
-func TestOverrideApexImageInMixedBuilds(t *testing.T) {
-	originalBp := `
-apex_key{
-	name: "foo_key",
-}
-apex_key{
-	name: "override_foo_key",
-}
-apex {
-	name: "foo",
-	key: "foo_key",
-	updatable: true,
-	min_sdk_version: "31",
-	package_name: "pkg_name",
-	file_contexts: ":myapex-file_contexts",
-	%s
-}`
-	overrideBp := `
-override_apex {
-	name: "override_foo",
-	key: "override_foo_key",
-	package_name: "override_pkg_name",
-	base: "foo",
-	%s
-}
-`
-
-	originalApexBpDir := "original"
-	originalApexName := "foo"
-	overrideApexBpDir := "override"
-	overrideApexName := "override_foo"
-
-	defaultApexLabel := fmt.Sprintf("//%s:%s", originalApexBpDir, originalApexName)
-	defaultOverrideApexLabel := fmt.Sprintf("//%s:%s", overrideApexBpDir, overrideApexName)
-
-	testCases := []struct {
-		desc                    string
-		bazelModuleProp         string
-		apexLabel               string
-		overrideBazelModuleProp string
-		overrideApexLabel       string
-		bp2buildConfiguration   android.Bp2BuildConversionAllowlist
-	}{
-		{
-			desc:                    "both explicit labels",
-			bazelModuleProp:         `bazel_module: { label: "//:foo" },`,
-			apexLabel:               "//:foo",
-			overrideBazelModuleProp: `bazel_module: { label: "//:override_foo" },`,
-			overrideApexLabel:       "//:override_foo",
-			bp2buildConfiguration:   android.NewBp2BuildAllowlist(),
-		},
-		{
-			desc:                    "both explicitly allowed",
-			bazelModuleProp:         `bazel_module: { bp2build_available: true },`,
-			apexLabel:               defaultApexLabel,
-			overrideBazelModuleProp: `bazel_module: { bp2build_available: true },`,
-			overrideApexLabel:       defaultOverrideApexLabel,
-			bp2buildConfiguration:   android.NewBp2BuildAllowlist(),
-		},
-		{
-			desc:              "original allowed by dir, override allowed by name",
-			apexLabel:         defaultApexLabel,
-			overrideApexLabel: defaultOverrideApexLabel,
-			bp2buildConfiguration: android.NewBp2BuildAllowlist().SetDefaultConfig(
-				map[string]allowlists.BazelConversionConfigEntry{
-					originalApexBpDir: allowlists.Bp2BuildDefaultTrue,
-				}).SetModuleAlwaysConvertList([]string{
-				overrideApexName,
-			}),
-		},
-		{
-			desc:              "both allowed by name",
-			apexLabel:         defaultApexLabel,
-			overrideApexLabel: defaultOverrideApexLabel,
-			bp2buildConfiguration: android.NewBp2BuildAllowlist().SetModuleAlwaysConvertList([]string{
-				originalApexName,
-				overrideApexName,
-			}),
-		},
-		{
-			desc:              "override allowed by name",
-			apexLabel:         defaultApexLabel,
-			overrideApexLabel: defaultOverrideApexLabel,
-			bp2buildConfiguration: android.NewBp2BuildAllowlist().SetModuleAlwaysConvertList([]string{
-				overrideApexName,
-			}),
-		},
-		{
-			desc:              "override allowed by dir",
-			apexLabel:         defaultApexLabel,
-			overrideApexLabel: defaultOverrideApexLabel,
-			bp2buildConfiguration: android.NewBp2BuildAllowlist().SetDefaultConfig(
-				map[string]allowlists.BazelConversionConfigEntry{
-					overrideApexBpDir: allowlists.Bp2BuildDefaultTrue,
-				}).SetModuleAlwaysConvertList([]string{}),
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.desc, func(t *testing.T) {
-			outputBaseDir := "out/bazel"
-			result := android.GroupFixturePreparers(
-				prepareForApexTest,
-				android.FixtureAddTextFile(filepath.Join(originalApexBpDir, "Android.bp"), fmt.Sprintf(originalBp, tc.bazelModuleProp)),
-				android.FixtureAddTextFile(filepath.Join(overrideApexBpDir, "Android.bp"), fmt.Sprintf(overrideBp, tc.overrideBazelModuleProp)),
-				android.FixtureModifyContext(func(ctx *android.TestContext) {
-					ctx.RegisterBp2BuildConfig(tc.bp2buildConfiguration)
-				}),
-				android.FixtureModifyConfig(func(config android.Config) {
-					config.BazelContext = android.MockBazelContext{
-						OutputBaseDir: outputBaseDir,
-						LabelToApexInfo: map[string]cquery.ApexInfo{
-							tc.apexLabel: cquery.ApexInfo{
-								// ApexInfo Starlark provider
-								SignedOutput:          "signed_out.apex",
-								UnsignedOutput:        "unsigned_out.apex",
-								BundleKeyInfo:         []string{"public_key", "private_key"},
-								ContainerKeyInfo:      []string{"container_cert", "container_private"},
-								SymbolsUsedByApex:     "foo_using.txt",
-								JavaSymbolsUsedByApex: "foo_using.xml",
-								BundleFile:            "apex_bundle.zip",
-								InstalledFiles:        "installed-files.txt",
-								RequiresLibs:          []string{"//path/c:c", "//path/d:d"},
-
-								// unused
-								PackageName:  "pkg_name",
-								ProvidesLibs: []string{"a", "b"},
-
-								// ApexMkInfo Starlark provider
-								MakeModulesToInstall: []string{"c"}, // d deliberately omitted
-							},
-							tc.overrideApexLabel: cquery.ApexInfo{
-								// ApexInfo Starlark provider
-								SignedOutput:          "override_signed_out.apex",
-								UnsignedOutput:        "override_unsigned_out.apex",
-								BundleKeyInfo:         []string{"override_public_key", "override_private_key"},
-								ContainerKeyInfo:      []string{"override_container_cert", "override_container_private"},
-								SymbolsUsedByApex:     "override_foo_using.txt",
-								JavaSymbolsUsedByApex: "override_foo_using.xml",
-								BundleFile:            "override_apex_bundle.zip",
-								InstalledFiles:        "override_installed-files.txt",
-								RequiresLibs:          []string{"//path/c:c", "//path/d:d"},
-
-								// unused
-								PackageName:  "override_pkg_name",
-								ProvidesLibs: []string{"a", "b"},
-
-								// ApexMkInfo Starlark provider
-								MakeModulesToInstall: []string{"c"}, // d deliberately omitted
-							},
-						},
-					}
-				}),
-			).RunTest(t)
-
-			m := result.ModuleForTests("foo", "android_common_override_foo_foo_image").Module()
-			ab, ok := m.(*apexBundle)
-			if !ok {
-				t.Fatalf("Expected module to be an apexBundle, was not")
-			}
-
-			if w, g := "out/bazel/execroot/__main__/override_public_key", ab.publicKeyFile.String(); w != g {
-				t.Errorf("Expected public key %q, got %q", w, g)
-			}
-
-			if w, g := "out/bazel/execroot/__main__/override_private_key", ab.privateKeyFile.String(); w != g {
-				t.Errorf("Expected private key %q, got %q", w, g)
-			}
-
-			if w, g := "out/bazel/execroot/__main__/override_container_cert", ab.containerCertificateFile; g != nil && w != g.String() {
-				t.Errorf("Expected public container key %q, got %q", w, g)
-			}
-
-			if w, g := "out/bazel/execroot/__main__/override_container_private", ab.containerPrivateKeyFile; g != nil && w != g.String() {
-				t.Errorf("Expected private container key %q, got %q", w, g)
-			}
-
-			if w, g := "out/bazel/execroot/__main__/override_signed_out.apex", ab.outputFile.String(); w != g {
-				t.Errorf("Expected output file %q, got %q", w, g)
-			}
-
-			if w, g := "out/bazel/execroot/__main__/override_foo_using.txt", ab.nativeApisUsedByModuleFile.String(); w != g {
-				t.Errorf("Expected output file %q, got %q", w, g)
-			}
-
-			if w, g := "out/bazel/execroot/__main__/override_foo_using.xml", ab.javaApisUsedByModuleFile.String(); w != g {
-				t.Errorf("Expected output file %q, got %q", w, g)
-			}
-
-			if w, g := "out/bazel/execroot/__main__/override_installed-files.txt", ab.installedFilesFile.String(); w != g {
-				t.Errorf("Expected installed-files.txt %q, got %q", w, g)
-			}
-
-			mkData := android.AndroidMkDataForTest(t, result.TestContext, m)
-			var builder strings.Builder
-			mkData.Custom(&builder, "override_foo", "BAZEL_TARGET_", "", mkData)
-
-			data := builder.String()
-			if w := "ALL_MODULES.$(my_register_name).BUNDLE := out/bazel/execroot/__main__/override_apex_bundle.zip"; !strings.Contains(data, w) {
-				t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
-			}
-			if w := "$(call dist-for-goals,checkbuild,out/bazel/execroot/__main__/override_installed-files.txt:override_foo-installed-files.txt)"; !strings.Contains(data, w) {
-				t.Errorf("Expected %q in androidmk data, but did not find %q", w, data)
-			}
-
-			// make modules to be installed to system
-			if len(ab.makeModulesToInstall) != 1 || ab.makeModulesToInstall[0] != "c" {
-				t.Errorf("Expected makeModulestoInstall slice to only contain 'c', got %q", ab.makeModulesToInstall)
-			}
-			if w := "LOCAL_REQUIRED_MODULES := c"; !strings.Contains(data, w) {
-				t.Errorf("Expected %q in androidmk data, but did not find it in %q", w, data)
-			}
-		})
-	}
-}
diff --git a/apex/builder.go b/apex/builder.go
index db66a72..763ce4d 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -17,12 +17,14 @@
 import (
 	"encoding/json"
 	"fmt"
+	"path"
 	"path/filepath"
 	"runtime"
 	"sort"
 	"strconv"
 	"strings"
 
+	"android/soong/aconfig"
 	"android/soong/android"
 	"android/soong/java"
 
@@ -35,6 +37,7 @@
 )
 
 func init() {
+	pctx.Import("android/soong/aconfig")
 	pctx.Import("android/soong/android")
 	pctx.Import("android/soong/cc/config")
 	pctx.Import("android/soong/java")
@@ -74,7 +77,24 @@
 	pctx.HostBinToolVariable("apex_sepolicy_tests", "apex_sepolicy_tests")
 	pctx.HostBinToolVariable("deapexer", "deapexer")
 	pctx.HostBinToolVariable("debugfs_static", "debugfs_static")
+	pctx.HostBinToolVariable("fsck_erofs", "fsck.erofs")
 	pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh")
+	pctx.HostBinToolVariable("conv_linker_config", "conv_linker_config")
+	pctx.HostBinToolVariable("assemble_vintf", "assemble_vintf")
+	pctx.HostBinToolVariable("apex_elf_checker", "apex_elf_checker")
+	pctx.HostBinToolVariable("aconfig", "aconfig")
+}
+
+type createStorageStruct struct {
+	Output_file string
+	Desc        string
+	File_type   string
+}
+
+var createStorageInfo = []createStorageStruct{
+	{"package.map", "create_aconfig_package_map_file", "package_map"},
+	{"flag.map", "create_aconfig_flag_map_file", "flag_map"},
+	{"flag.val", "create_aconfig_flag_val_file", "flag_val"},
 }
 
 var (
@@ -179,19 +199,6 @@
 	}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key",
 		"opt_flags", "manifest", "libs_to_trim")
 
-	zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
-		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
-			`(. ${out}.copy_commands) && ` +
-			`APEXER_TOOL_PATH=${tool_path} ` +
-			`${apexer} --force --manifest ${manifest} ` +
-			`--payload_type zip ` +
-			`${image_dir} ${out} `,
-		CommandDeps:    []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
-		Rspfile:        "${out}.copy_commands",
-		RspfileContent: "${copy_commands}",
-		Description:    "ZipAPEX ${image_dir} => ${out}",
-	}, "tool_path", "image_dir", "copy_commands", "manifest")
-
 	apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule",
 		blueprint.RuleParams{
 			Command:     `${aapt2} convert --output-format proto $in -o $out`,
@@ -235,6 +242,24 @@
 		CommandDeps: []string{"${apex_sepolicy_tests}", "${deapexer}", "${debugfs_static}"},
 		Description: "run apex_sepolicy_tests",
 	})
+
+	apexLinkerconfigValidationRule = pctx.StaticRule("apexLinkerconfigValidationRule", blueprint.RuleParams{
+		Command:     `${conv_linker_config} validate --type apex ${image_dir} && touch ${out}`,
+		CommandDeps: []string{"${conv_linker_config}"},
+		Description: "run apex_linkerconfig_validation",
+	}, "image_dir")
+
+	assembleVintfRule = pctx.StaticRule("assembleVintfRule", blueprint.RuleParams{
+		Command:     `rm -f $out && VINTF_IGNORE_TARGET_FCM_VERSION=true ${assemble_vintf} -i $in -o $out`,
+		CommandDeps: []string{"${assemble_vintf}"},
+		Description: "run assemble_vintf",
+	})
+
+	apexElfCheckerUnwantedRule = pctx.StaticRule("apexElfCheckerUnwantedRule", blueprint.RuleParams{
+		Command:     `${apex_elf_checker} --tool_path ${tool_path} --unwanted ${unwanted} ${in} && touch ${out}`,
+		CommandDeps: []string{"${apex_elf_checker}", "${deapexer}", "${debugfs_static}", "${fsck_erofs}", "${config.ClangBin}/llvm-readelf"},
+		Description: "run apex_elf_checker --unwanted",
+	}, "tool_path", "unwanted")
 )
 
 // buildManifest creates buile rules to modify the input apex_manifest.json to add information
@@ -252,7 +277,7 @@
 	// VNDK APEX name is determined at runtime, so update "name" in apex_manifest
 	optCommands := []string{}
 	if a.vndkApex {
-		apexName := vndkApexNamePrefix + a.vndkVersion(ctx.DeviceConfig())
+		apexName := vndkApexNamePrefix + a.vndkVersion()
 		optCommands = append(optCommands, "-v name "+apexName)
 	}
 
@@ -268,7 +293,7 @@
 	}
 
 	if android.InList(":vndk", requireNativeLibs) {
-		if _, vndkVersion := a.getImageVariationPair(ctx.DeviceConfig()); vndkVersion != "" {
+		if _, vndkVersion := a.getImageVariationPair(); vndkVersion != "" {
 			optCommands = append(optCommands, "-v vndkVersion "+vndkVersion)
 		}
 	}
@@ -334,10 +359,12 @@
 func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.OutputPath {
 	var fileContexts android.Path
 	var fileContextsDir string
+	isFileContextsModule := false
 	if a.properties.File_contexts == nil {
 		fileContexts = android.PathForSource(ctx, "system/sepolicy/apex", ctx.ModuleName()+"-file_contexts")
 	} else {
 		if m, t := android.SrcIsModuleWithTag(*a.properties.File_contexts); m != "" {
+			isFileContextsModule = true
 			otherModule := android.GetModuleFromPathDep(ctx, m, t)
 			fileContextsDir = ctx.OtherModuleDir(otherModule)
 		}
@@ -353,7 +380,7 @@
 			ctx.PropertyErrorf("file_contexts", "should be under system/sepolicy, but found in  %q", fileContextsDir)
 		}
 	}
-	if !android.ExistentPathForSource(ctx, fileContexts.String()).Valid() {
+	if !isFileContextsModule && !android.ExistentPathForSource(ctx, fileContexts.String()).Valid() {
 		ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", fileContexts.String())
 	}
 
@@ -362,28 +389,23 @@
 	output := android.PathForModuleOut(ctx, "file_contexts")
 	rule := android.NewRuleBuilder(pctx, ctx)
 
-	forceLabel := "u:object_r:system_file:s0"
+	labelForRoot := "u:object_r:system_file:s0"
+	labelForManifest := "u:object_r:system_file:s0"
 	if a.SocSpecific() && !a.vndkApex {
-		// APEX on /vendor should label ./ and ./apex_manifest.pb as vendor_apex_metadata_file.
-		// The reason why we skip VNDK APEX is that aosp_{pixel device} targets install VNDK APEX on /vendor
-		// even though VNDK APEX is supposed to be installed on /system. (See com.android.vndk.current.on_vendor)
-		forceLabel = "u:object_r:vendor_apex_metadata_file:s0"
+		// APEX on /vendor should label ./ and ./apex_manifest.pb as vendor file.
+		labelForRoot = "u:object_r:vendor_file:s0"
+		labelForManifest = "u:object_r:vendor_apex_metadata_file:s0"
 	}
-	switch a.properties.ApexType {
-	case imageApex:
-		// remove old file
-		rule.Command().Text("rm").FlagWithOutput("-f ", output)
-		// copy file_contexts
-		rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
-		// new line
-		rule.Command().Text("echo").Text(">>").Output(output)
-		if !useFileContextsAsIs {
-			// force-label /apex_manifest.pb and /
-			rule.Command().Text("echo").Text("/apex_manifest\\\\.pb").Text(forceLabel).Text(">>").Output(output)
-			rule.Command().Text("echo").Text("/").Text(forceLabel).Text(">>").Output(output)
-		}
-	default:
-		panic(fmt.Errorf("unsupported type %v", a.properties.ApexType))
+	// remove old file
+	rule.Command().Text("rm").FlagWithOutput("-f ", output)
+	// copy file_contexts
+	rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
+	// new line
+	rule.Command().Text("echo").Text(">>").Output(output)
+	if !useFileContextsAsIs {
+		// force-label /apex_manifest.pb and /
+		rule.Command().Text("echo").Text("/apex_manifest\\\\.pb").Text(labelForManifest).Text(">>").Output(output)
+		rule.Command().Text("echo").Text("/").Text(labelForRoot).Text(">>").Output(output)
 	}
 
 	rule.Build("file_contexts."+a.Name(), "Generate file_contexts")
@@ -462,10 +484,25 @@
 	})
 }
 
+func isVintfFragment(fi apexFile) bool {
+	isVintfFragment, _ := path.Match("etc/vintf/*", fi.path())
+	return isVintfFragment
+}
+
+func runAssembleVintf(ctx android.ModuleContext, vintfFragment android.Path) android.Path {
+	processed := android.PathForModuleOut(ctx, "vintf", vintfFragment.Base())
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        assembleVintfRule,
+		Input:       vintfFragment,
+		Output:      processed,
+		Description: "run assemble_vintf for VINTF in APEX",
+	})
+	return processed
+}
+
 // buildApex creates build rules to build an APEX using apexer.
 func (a *apexBundle) buildApex(ctx android.ModuleContext) {
-	apexType := a.properties.ApexType
-	suffix := apexType.suffix()
+	suffix := imageApexSuffix
 	apexName := a.BaseModuleName()
 
 	////////////////////////////////////////////////////////////////////////////////////////////
@@ -500,7 +537,15 @@
 			copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath)
 		} else {
 			// Copy the file into APEX
-			copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
+			if !a.testApex && isVintfFragment(fi) {
+				// copy the output of assemble_vintf instead of the original
+				vintfFragment := runAssembleVintf(ctx, fi.builtFile)
+				copyCommands = append(copyCommands, "cp -f "+vintfFragment.String()+" "+destPath)
+				implicitInputs = append(implicitInputs, vintfFragment)
+			} else {
+				copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
+				implicitInputs = append(implicitInputs, fi.builtFile)
+			}
 
 			var installedPath android.InstallPath
 			if fi.class == appSet {
@@ -518,7 +563,6 @@
 					installedPath = ctx.InstallFile(apexDir.Join(ctx, fi.installDir), fi.stem(), fi.builtFile)
 				}
 			}
-			implicitInputs = append(implicitInputs, fi.builtFile)
 
 			// Create additional symlinks pointing the file inside the APEX (if any). Note that
 			// this is independent from the symlink optimization.
@@ -536,13 +580,8 @@
 		// Copy the test files (if any)
 		for _, d := range fi.dataPaths {
 			// TODO(eakammer): This is now the third repetition of ~this logic for test paths, refactoring should be possible
-			relPath := d.SrcPath.Rel()
-			dataPath := d.SrcPath.String()
-			if !strings.HasSuffix(dataPath, relPath) {
-				panic(fmt.Errorf("path %q does not end with %q", dataPath, relPath))
-			}
-
-			dataDest := imageDir.Join(ctx, fi.apexRelativePath(relPath), d.RelativeInstallPath).String()
+			relPath := d.ToRelativeInstallPath()
+			dataDest := imageDir.Join(ctx, fi.apexRelativePath(relPath)).String()
 
 			copyCommands = append(copyCommands, "cp -f "+d.SrcPath.String()+" "+dataDest)
 			implicitInputs = append(implicitInputs, d.SrcPath)
@@ -550,6 +589,7 @@
 
 		installMapSet[installMapPath.String()+":"+fi.installDir+"/"+fi.builtFile.Base()] = true
 	}
+
 	implicitInputs = append(implicitInputs, a.manifestPbOut)
 
 	if len(installMapSet) > 0 {
@@ -604,263 +644,287 @@
 	outHostBinDir := ctx.Config().HostToolPath(ctx, "").String()
 	prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
 
-	if apexType == imageApex {
-
-		////////////////////////////////////////////////////////////////////////////////////
-		// Step 2: create canned_fs_config which encodes filemode,uid,gid of each files
-		// in this APEX. The file will be used by apexer in later steps.
-		cannedFsConfig := a.buildCannedFsConfig(ctx)
-		implicitInputs = append(implicitInputs, cannedFsConfig)
-
-		////////////////////////////////////////////////////////////////////////////////////
-		// Step 3: Prepare option flags for apexer and invoke it to create an unsigned APEX.
-		// TODO(jiyong): use the RuleBuilder
-		optFlags := []string{}
-
-		fileContexts := a.buildFileContexts(ctx)
-		implicitInputs = append(implicitInputs, fileContexts)
-
-		implicitInputs = append(implicitInputs, a.privateKeyFile, a.publicKeyFile)
-		optFlags = append(optFlags, "--pubkey "+a.publicKeyFile.String())
-
-		manifestPackageName := a.getOverrideManifestPackageName(ctx)
-		if manifestPackageName != "" {
-			optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
-		}
-
-		if a.properties.AndroidManifest != nil {
-			androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
-
-			if a.testApex {
-				androidManifestFile = markManifestTestOnly(ctx, androidManifestFile)
-			}
-
-			implicitInputs = append(implicitInputs, androidManifestFile)
-			optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
-		} else if a.testApex {
-			optFlags = append(optFlags, "--test_only")
-		}
-
-		// Determine target/min sdk version from the context
-		// TODO(jiyong): make this as a function
-		moduleMinSdkVersion := a.minSdkVersion(ctx)
-		minSdkVersion := moduleMinSdkVersion.String()
-
-		// bundletool doesn't understand what "current" is. We need to transform it to
-		// codename
-		if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() {
-			minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
-
-			if java.UseApiFingerprint(ctx) {
-				minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
-				implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
-			}
-		}
-		// apex module doesn't have a concept of target_sdk_version, hence for the time
-		// being targetSdkVersion == default targetSdkVersion of the branch.
-		targetSdkVersion := strconv.Itoa(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt())
-
-		if java.UseApiFingerprint(ctx) {
-			targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
-			implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
-		}
-		optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
-		optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion)
-
-		if a.overridableProperties.Logging_parent != "" {
-			optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent)
-		}
-
-		// Create a NOTICE file, and embed it as an asset file in the APEX.
-		htmlGzNotice := android.PathForModuleOut(ctx, "NOTICE.html.gz")
-		android.BuildNoticeHtmlOutputFromLicenseMetadata(
-			ctx, htmlGzNotice, "", "",
-			[]string{
-				android.PathForModuleInstall(ctx).String() + "/",
-				android.PathForModuleInPartitionInstall(ctx, "apex").String() + "/",
-			})
-		noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
-		builder := android.NewRuleBuilder(pctx, ctx)
-		builder.Command().Text("cp").
-			Input(htmlGzNotice).
-			Output(noticeAssetPath)
-		builder.Build("notice_dir", "Building notice dir")
-		implicitInputs = append(implicitInputs, noticeAssetPath)
-		optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String()))
-
-		// Apexes which are supposed to be installed in builtin dirs(/system, etc)
-		// don't need hashtree for activation. Therefore, by removing hashtree from
-		// apex bundle (filesystem image in it, to be specific), we can save storage.
-		needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) ||
-			a.shouldGenerateHashtree()
-		if ctx.Config().ApexCompressionEnabled() && a.isCompressable() {
-			needHashTree = true
-		}
-		if !needHashTree {
-			optFlags = append(optFlags, "--no_hashtree")
-		}
-
-		if a.testOnlyShouldSkipPayloadSign() {
-			optFlags = append(optFlags, "--unsigned_payload")
-		}
-
-		if moduleMinSdkVersion == android.SdkVersion_Android10 {
-			implicitInputs = append(implicitInputs, a.manifestJsonOut)
-			optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String())
-		}
-
-		optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string())
-
-		if a.dynamic_common_lib_apex() {
-			ctx.Build(pctx, android.BuildParams{
-				Rule:        DCLAApexRule,
-				Implicits:   implicitInputs,
-				Output:      unsignedOutputFile,
-				Description: "apex (" + apexType.name() + ")",
-				Args: map[string]string{
-					"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
-					"image_dir":        imageDir.String(),
-					"copy_commands":    strings.Join(copyCommands, " && "),
-					"manifest":         a.manifestPbOut.String(),
-					"file_contexts":    fileContexts.String(),
-					"canned_fs_config": cannedFsConfig.String(),
-					"key":              a.privateKeyFile.String(),
-					"opt_flags":        strings.Join(optFlags, " "),
-				},
-			})
-		} else if ctx.Config().ApexTrimEnabled() && len(a.libs_to_trim(ctx)) > 0 {
-			ctx.Build(pctx, android.BuildParams{
-				Rule:        TrimmedApexRule,
-				Implicits:   implicitInputs,
-				Output:      unsignedOutputFile,
-				Description: "apex (" + apexType.name() + ")",
-				Args: map[string]string{
-					"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
-					"image_dir":        imageDir.String(),
-					"copy_commands":    strings.Join(copyCommands, " && "),
-					"manifest":         a.manifestPbOut.String(),
-					"file_contexts":    fileContexts.String(),
-					"canned_fs_config": cannedFsConfig.String(),
-					"key":              a.privateKeyFile.String(),
-					"opt_flags":        strings.Join(optFlags, " "),
-					"libs_to_trim":     strings.Join(a.libs_to_trim(ctx), ","),
-				},
-			})
-		} else {
-			ctx.Build(pctx, android.BuildParams{
-				Rule:        apexRule,
-				Implicits:   implicitInputs,
-				Output:      unsignedOutputFile,
-				Description: "apex (" + apexType.name() + ")",
-				Args: map[string]string{
-					"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
-					"image_dir":        imageDir.String(),
-					"copy_commands":    strings.Join(copyCommands, " && "),
-					"manifest":         a.manifestPbOut.String(),
-					"file_contexts":    fileContexts.String(),
-					"canned_fs_config": cannedFsConfig.String(),
-					"key":              a.privateKeyFile.String(),
-					"opt_flags":        strings.Join(optFlags, " "),
-				},
-			})
-		}
-
-		// TODO(jiyong): make the two rules below as separate functions
-		apexProtoFile := android.PathForModuleOut(ctx, a.Name()+".pb"+suffix)
-		bundleModuleFile := android.PathForModuleOut(ctx, a.Name()+suffix+"-base.zip")
-		a.bundleModuleFile = bundleModuleFile
-
+	defaultReadOnlyFiles := []string{"apex_manifest.json", "apex_manifest.pb"}
+	aconfigDest := imageDir.Join(ctx, "etc").String()
+	if len(a.aconfigFiles) > 0 {
+		apexAconfigFile := android.PathForModuleOut(ctx, "aconfig_flags.pb")
 		ctx.Build(pctx, android.BuildParams{
-			Rule:        apexProtoConvertRule,
-			Input:       unsignedOutputFile,
-			Output:      apexProtoFile,
-			Description: "apex proto convert",
-		})
-
-		implicitInputs = append(implicitInputs, unsignedOutputFile)
-
-		// Run coverage analysis
-		apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.txt")
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        generateAPIsUsedbyApexRule,
-			Implicits:   implicitInputs,
-			Description: "coverage",
-			Output:      apisUsedbyOutputFile,
+			Rule:        aconfig.AllDeclarationsRule,
+			Inputs:      a.aconfigFiles,
+			Output:      apexAconfigFile,
+			Description: "combine_aconfig_declarations",
 			Args: map[string]string{
-				"image_dir": imageDir.String(),
-				"readelf":   "${config.ClangBin}/llvm-readelf",
+				"cache_files": android.JoinPathsWithPrefix(a.aconfigFiles, "--cache "),
 			},
 		})
-		a.nativeApisUsedByModuleFile = apisUsedbyOutputFile
 
-		var nativeLibNames []string
-		for _, f := range a.filesInfo {
-			if f.class == nativeSharedLib {
-				nativeLibNames = append(nativeLibNames, f.stem())
-			}
+		copyCommands = append(copyCommands, "cp -f "+apexAconfigFile.String()+" "+aconfigDest)
+		implicitInputs = append(implicitInputs, apexAconfigFile)
+		defaultReadOnlyFiles = append(defaultReadOnlyFiles, "etc/"+apexAconfigFile.Base())
+
+		for _, info := range createStorageInfo {
+			outputFile := android.PathForModuleOut(ctx, info.Output_file)
+			ctx.Build(pctx, android.BuildParams{
+				Rule:        aconfig.CreateStorageRule,
+				Inputs:      a.aconfigFiles,
+				Output:      outputFile,
+				Description: info.Desc,
+				Args: map[string]string{
+					"container":   ctx.ModuleName(),
+					"file_type":   info.File_type,
+					"cache_files": android.JoinPathsWithPrefix(a.aconfigFiles, "--cache "),
+				},
+			})
+
+			copyCommands = append(copyCommands, "cp -f "+outputFile.String()+" "+aconfigDest)
+			implicitInputs = append(implicitInputs, outputFile)
+			defaultReadOnlyFiles = append(defaultReadOnlyFiles, "etc/"+outputFile.Base())
 		}
-		apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt")
-		rule := android.NewRuleBuilder(pctx, ctx)
-		rule.Command().
-			Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")).
-			Output(apisBackedbyOutputFile).
-			Flags(nativeLibNames)
-		rule.Build("ndk_backedby_list", "Generate API libraries backed by Apex")
-		a.nativeApisBackedByModuleFile = apisBackedbyOutputFile
+	}
 
-		var javaLibOrApkPath []android.Path
-		for _, f := range a.filesInfo {
-			if f.class == javaSharedLib || f.class == app {
-				javaLibOrApkPath = append(javaLibOrApkPath, f.builtFile)
-			}
-		}
-		javaApiUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.xml")
-		javaUsedByRule := android.NewRuleBuilder(pctx, ctx)
-		javaUsedByRule.Command().
-			Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")).
-			BuiltTool("dexdeps").
-			Output(javaApiUsedbyOutputFile).
-			Inputs(javaLibOrApkPath)
-		javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex")
-		a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile
+	////////////////////////////////////////////////////////////////////////////////////
+	// Step 2: create canned_fs_config which encodes filemode,uid,gid of each files
+	// in this APEX. The file will be used by apexer in later steps.
+	cannedFsConfig := a.buildCannedFsConfig(ctx, defaultReadOnlyFiles)
+	implicitInputs = append(implicitInputs, cannedFsConfig)
 
-		bundleConfig := a.buildBundleConfig(ctx)
+	////////////////////////////////////////////////////////////////////////////////////
+	// Step 3: Prepare option flags for apexer and invoke it to create an unsigned APEX.
+	// TODO(jiyong): use the RuleBuilder
+	optFlags := []string{}
 
-		var abis []string
-		for _, target := range ctx.MultiTargets() {
-			if len(target.Arch.Abi) > 0 {
-				abis = append(abis, target.Arch.Abi[0])
-			}
+	fileContexts := a.buildFileContexts(ctx)
+	implicitInputs = append(implicitInputs, fileContexts)
+
+	implicitInputs = append(implicitInputs, a.privateKeyFile, a.publicKeyFile)
+	optFlags = append(optFlags, "--pubkey "+a.publicKeyFile.String())
+
+	manifestPackageName := a.getOverrideManifestPackageName(ctx)
+	if manifestPackageName != "" {
+		optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
+	}
+
+	if a.properties.AndroidManifest != nil {
+		androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
+
+		if a.testApex {
+			androidManifestFile = markManifestTestOnly(ctx, androidManifestFile)
 		}
 
-		abis = android.FirstUniqueStrings(abis)
+		implicitInputs = append(implicitInputs, androidManifestFile)
+		optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
+	} else if a.testApex {
+		optFlags = append(optFlags, "--test_only")
+	}
 
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        apexBundleRule,
-			Input:       apexProtoFile,
-			Implicit:    bundleConfig,
-			Output:      a.bundleModuleFile,
-			Description: "apex bundle module",
-			Args: map[string]string{
-				"abi":    strings.Join(abis, "."),
-				"config": bundleConfig.String(),
-			},
+	// Determine target/min sdk version from the context
+	// TODO(jiyong): make this as a function
+	moduleMinSdkVersion := a.minSdkVersion(ctx)
+	minSdkVersion := moduleMinSdkVersion.String()
+
+	// bundletool doesn't understand what "current" is. We need to transform it to
+	// codename
+	if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() {
+		minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
+
+		if useApiFingerprint, fingerprintMinSdkVersion, fingerprintDeps :=
+			java.UseApiFingerprint(ctx); useApiFingerprint {
+			minSdkVersion = fingerprintMinSdkVersion
+			implicitInputs = append(implicitInputs, fingerprintDeps)
+		}
+	}
+	// apex module doesn't have a concept of target_sdk_version, hence for the time
+	// being targetSdkVersion == default targetSdkVersion of the branch.
+	targetSdkVersion := strconv.Itoa(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt())
+
+	if useApiFingerprint, fingerprintTargetSdkVersion, fingerprintDeps :=
+		java.UseApiFingerprint(ctx); useApiFingerprint {
+		targetSdkVersion = fingerprintTargetSdkVersion
+		implicitInputs = append(implicitInputs, fingerprintDeps)
+	}
+	optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
+	optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion)
+
+	if a.overridableProperties.Logging_parent != "" {
+		optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent)
+	}
+
+	// Create a NOTICE file, and embed it as an asset file in the APEX.
+	htmlGzNotice := android.PathForModuleOut(ctx, "NOTICE.html.gz")
+	android.BuildNoticeHtmlOutputFromLicenseMetadata(
+		ctx, htmlGzNotice, "", "",
+		[]string{
+			android.PathForModuleInstall(ctx).String() + "/",
+			android.PathForModuleInPartitionInstall(ctx, "apex").String() + "/",
 		})
-	} else { // zipApex
+	noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
+	builder := android.NewRuleBuilder(pctx, ctx)
+	builder.Command().Text("cp").
+		Input(htmlGzNotice).
+		Output(noticeAssetPath)
+	builder.Build("notice_dir", "Building notice dir")
+	implicitInputs = append(implicitInputs, noticeAssetPath)
+	optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String()))
+
+	// Apexes which are supposed to be installed in builtin dirs(/system, etc)
+	// don't need hashtree for activation. Therefore, by removing hashtree from
+	// apex bundle (filesystem image in it, to be specific), we can save storage.
+	needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) ||
+		a.shouldGenerateHashtree()
+	if ctx.Config().ApexCompressionEnabled() && a.isCompressable() {
+		needHashTree = true
+	}
+	if !needHashTree {
+		optFlags = append(optFlags, "--no_hashtree")
+	}
+
+	if a.testOnlyShouldSkipPayloadSign() {
+		optFlags = append(optFlags, "--unsigned_payload")
+	}
+
+	if moduleMinSdkVersion == android.SdkVersion_Android10 {
+		implicitInputs = append(implicitInputs, a.manifestJsonOut)
+		optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String())
+	}
+
+	optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string())
+
+	if a.dynamic_common_lib_apex() {
 		ctx.Build(pctx, android.BuildParams{
-			Rule:        zipApexRule,
+			Rule:        DCLAApexRule,
 			Implicits:   implicitInputs,
 			Output:      unsignedOutputFile,
-			Description: "apex (" + apexType.name() + ")",
+			Description: "apex",
 			Args: map[string]string{
-				"tool_path":     outHostBinDir + ":" + prebuiltSdkToolsBinDir,
-				"image_dir":     imageDir.String(),
-				"copy_commands": strings.Join(copyCommands, " && "),
-				"manifest":      a.manifestPbOut.String(),
+				"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+				"image_dir":        imageDir.String(),
+				"copy_commands":    strings.Join(copyCommands, " && "),
+				"manifest":         a.manifestPbOut.String(),
+				"file_contexts":    fileContexts.String(),
+				"canned_fs_config": cannedFsConfig.String(),
+				"key":              a.privateKeyFile.String(),
+				"opt_flags":        strings.Join(optFlags, " "),
+			},
+		})
+	} else if ctx.Config().ApexTrimEnabled() && len(a.libs_to_trim(ctx)) > 0 {
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        TrimmedApexRule,
+			Implicits:   implicitInputs,
+			Output:      unsignedOutputFile,
+			Description: "apex",
+			Args: map[string]string{
+				"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+				"image_dir":        imageDir.String(),
+				"copy_commands":    strings.Join(copyCommands, " && "),
+				"manifest":         a.manifestPbOut.String(),
+				"file_contexts":    fileContexts.String(),
+				"canned_fs_config": cannedFsConfig.String(),
+				"key":              a.privateKeyFile.String(),
+				"opt_flags":        strings.Join(optFlags, " "),
+				"libs_to_trim":     strings.Join(a.libs_to_trim(ctx), ","),
+			},
+		})
+	} else {
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        apexRule,
+			Implicits:   implicitInputs,
+			Output:      unsignedOutputFile,
+			Description: "apex",
+			Args: map[string]string{
+				"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+				"image_dir":        imageDir.String(),
+				"copy_commands":    strings.Join(copyCommands, " && "),
+				"manifest":         a.manifestPbOut.String(),
+				"file_contexts":    fileContexts.String(),
+				"canned_fs_config": cannedFsConfig.String(),
+				"key":              a.privateKeyFile.String(),
+				"opt_flags":        strings.Join(optFlags, " "),
 			},
 		})
 	}
 
+	// TODO(jiyong): make the two rules below as separate functions
+	apexProtoFile := android.PathForModuleOut(ctx, a.Name()+".pb"+suffix)
+	bundleModuleFile := android.PathForModuleOut(ctx, a.Name()+suffix+"-base.zip")
+	a.bundleModuleFile = bundleModuleFile
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        apexProtoConvertRule,
+		Input:       unsignedOutputFile,
+		Output:      apexProtoFile,
+		Description: "apex proto convert",
+	})
+
+	implicitInputs = append(implicitInputs, unsignedOutputFile)
+
+	// Run coverage analysis
+	apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.txt")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        generateAPIsUsedbyApexRule,
+		Implicits:   implicitInputs,
+		Description: "coverage",
+		Output:      apisUsedbyOutputFile,
+		Args: map[string]string{
+			"image_dir": imageDir.String(),
+			"readelf":   "${config.ClangBin}/llvm-readelf",
+		},
+	})
+	a.nativeApisUsedByModuleFile = apisUsedbyOutputFile
+
+	var nativeLibNames []string
+	for _, f := range a.filesInfo {
+		if f.class == nativeSharedLib {
+			nativeLibNames = append(nativeLibNames, f.stem())
+		}
+	}
+	apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt")
+	rb := android.NewRuleBuilder(pctx, ctx)
+	rb.Command().
+		Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")).
+		Output(apisBackedbyOutputFile).
+		Flags(nativeLibNames)
+	rb.Build("ndk_backedby_list", "Generate API libraries backed by Apex")
+	a.nativeApisBackedByModuleFile = apisBackedbyOutputFile
+
+	var javaLibOrApkPath []android.Path
+	for _, f := range a.filesInfo {
+		if f.class == javaSharedLib || f.class == app {
+			javaLibOrApkPath = append(javaLibOrApkPath, f.builtFile)
+		}
+	}
+	javaApiUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.xml")
+	javaUsedByRule := android.NewRuleBuilder(pctx, ctx)
+	javaUsedByRule.Command().
+		Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")).
+		BuiltTool("dexdeps").
+		Output(javaApiUsedbyOutputFile).
+		Inputs(javaLibOrApkPath)
+	javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex")
+	a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile
+
+	bundleConfig := a.buildBundleConfig(ctx)
+
+	var abis []string
+	for _, target := range ctx.MultiTargets() {
+		if len(target.Arch.Abi) > 0 {
+			abis = append(abis, target.Arch.Abi[0])
+		}
+	}
+
+	abis = android.FirstUniqueStrings(abis)
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        apexBundleRule,
+		Input:       apexProtoFile,
+		Implicit:    bundleConfig,
+		Output:      a.bundleModuleFile,
+		Description: "apex bundle module",
+		Args: map[string]string{
+			"abi":    strings.Join(abis, "."),
+			"config": bundleConfig.String(),
+		},
+	})
+
 	////////////////////////////////////////////////////////////////////////////////////
 	// Step 4: Sign the APEX using signapk
 	signedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix)
@@ -878,10 +942,15 @@
 		args["outCommaList"] = signedOutputFile.String()
 	}
 	var validations android.Paths
+	validations = append(validations, runApexLinkerconfigValidation(ctx, unsignedOutputFile.OutputPath, imageDir.OutputPath))
 	// TODO(b/279688635) deapexer supports [ext4]
-	if suffix == imageApexSuffix && ext4 == a.payloadFsType {
+	if !a.testApex && suffix == imageApexSuffix && ext4 == a.payloadFsType {
 		validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile.OutputPath))
 	}
+	if !a.testApex && len(a.properties.Unwanted_transitive_deps) > 0 {
+		validations = append(validations,
+			runApexElfCheckerUnwanted(ctx, unsignedOutputFile.OutputPath, a.properties.Unwanted_transitive_deps))
+	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rule,
 		Description: "signapk",
@@ -940,10 +1009,12 @@
 
 	// Install to $OUT/soong/{target,host}/.../apex.
 	a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile,
-		a.compatSymlinks.Paths()...)
+		a.compatSymlinks...)
 
 	// installed-files.txt is dist'ed
 	a.installedFilesFile = a.buildInstalledFilesFile(ctx, a.outputFile, imageDir)
+
+	a.apexKeysPath = writeApexKeys(ctx, a)
 }
 
 // getCertificateAndPrivateKey retrieves the cert and the private key that will be used to sign
@@ -972,7 +1043,7 @@
 	if a.vndkApex {
 		overrideName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(vndkApexName)
 		if overridden {
-			return overrideName + ".v" + a.vndkVersion(ctx.DeviceConfig())
+			return overrideName + ".v" + a.vndkVersion()
 		}
 		return ""
 	}
@@ -987,21 +1058,12 @@
 }
 
 func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) {
-	if !a.primaryApexType {
-		return
-	}
-
 	if a.properties.IsCoverageVariant {
 		// Otherwise, we will have duplicated rules for coverage and
 		// non-coverage variants of the same APEX
 		return
 	}
 
-	if ctx.Host() {
-		// No need to generate dependency info for host variant
-		return
-	}
-
 	depInfos := android.DepNameToDepInfoMap{}
 	a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		if from.Name() == to.Name() {
@@ -1076,8 +1138,8 @@
 	a.lintReports = java.BuildModuleLintReportZips(ctx, depSetsBuilder.Build())
 }
 
-func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.OutputPath {
-	var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"}
+func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext, defaultReadOnlyFiles []string) android.OutputPath {
+	var readOnlyPaths = defaultReadOnlyFiles
 	var executablePaths []string // this also includes dirs
 	var appSetDirs []string
 	appSetFiles := make(map[string]android.Path)
@@ -1086,7 +1148,8 @@
 		if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") {
 			executablePaths = append(executablePaths, pathInApex)
 			for _, d := range f.dataPaths {
-				readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, d.RelativeInstallPath, d.SrcPath.Rel()))
+				rel := d.ToRelativeInstallPath()
+				readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, rel))
 			}
 			for _, s := range f.symlinks {
 				executablePaths = append(executablePaths, filepath.Join(f.installDir, s))
@@ -1141,6 +1204,19 @@
 	return cannedFsConfig.OutputPath
 }
 
+func runApexLinkerconfigValidation(ctx android.ModuleContext, apexFile android.OutputPath, imageDir android.OutputPath) android.Path {
+	timestamp := android.PathForModuleOut(ctx, "apex_linkerconfig_validation.timestamp")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   apexLinkerconfigValidationRule,
+		Input:  apexFile,
+		Output: timestamp,
+		Args: map[string]string{
+			"image_dir": imageDir.String(),
+		},
+	})
+	return timestamp
+}
+
 // Runs apex_sepolicy_tests
 //
 // $ deapexer list -Z {apex_file} > {file_contexts}
@@ -1154,3 +1230,17 @@
 	})
 	return timestamp
 }
+
+func runApexElfCheckerUnwanted(ctx android.ModuleContext, apexFile android.OutputPath, unwanted []string) android.Path {
+	timestamp := android.PathForModuleOut(ctx, "apex_elf_unwanted.timestamp")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   apexElfCheckerUnwantedRule,
+		Input:  apexFile,
+		Output: timestamp,
+		Args: map[string]string{
+			"unwanted":  android.JoinWithSuffixAndSeparator(unwanted, ".so", ":"),
+			"tool_path": ctx.Config().HostToolPath(ctx, "").String() + ":${config.ClangBin}",
+		},
+	})
+	return timestamp
+}
diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go
index 9142eed..b9a9198 100644
--- a/apex/classpath_element_test.go
+++ b/apex/classpath_element_test.go
@@ -20,7 +20,6 @@
 
 	"android/soong/android"
 	"android/soong/java"
-	"github.com/google/blueprint"
 )
 
 // Contains tests for java.CreateClasspathElements logic from java/classpath_element.go that
@@ -28,19 +27,12 @@
 
 // testClasspathElementContext is a ClasspathElementContext suitable for use in tests.
 type testClasspathElementContext struct {
+	android.OtherModuleProviderContext
 	testContext *android.TestContext
 	module      android.Module
 	errs        []error
 }
 
-func (t *testClasspathElementContext) OtherModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool {
-	return t.testContext.ModuleHasProvider(module, provider)
-}
-
-func (t *testClasspathElementContext) OtherModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{} {
-	return t.testContext.ModuleProvider(module, provider)
-}
-
 func (t *testClasspathElementContext) ModuleErrorf(fmt string, args ...interface{}) {
 	t.errs = append(t.errs, t.testContext.ModuleErrorf(t.module, fmt, args...))
 }
@@ -238,7 +230,11 @@
 	}
 
 	newCtx := func() *testClasspathElementContext {
-		return &testClasspathElementContext{testContext: result.TestContext, module: bootclasspath}
+		return &testClasspathElementContext{
+			OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(),
+			testContext:                result.TestContext,
+			module:                     bootclasspath,
+		}
 	}
 
 	// Verify that CreateClasspathElements works when given valid input.
diff --git a/apex/deapexer.go b/apex/deapexer.go
index 3b7c77d..a673108 100644
--- a/apex/deapexer.go
+++ b/apex/deapexer.go
@@ -53,6 +53,10 @@
 	// all architectures, e.g. java.
 	CommonModules []string
 
+	// List of modules that use an embedded .prof to guide optimization of the equivalent dexpreopt artifact
+	// This is a subset of CommonModules
+	DexpreoptProfileGuidedModules []string
+
 	// List of files exported from the .apex file by this module
 	//
 	// Each entry is a path from the apex root, e.g. javalib/core-libart.jar.
@@ -98,6 +102,7 @@
 func (p *Deapexer) DepsMutator(ctx android.BottomUpMutatorContext) {
 	// Add dependencies from the java modules to which this exports files from the `.apex` file onto
 	// this module so that they can access the `DeapexerInfo` object that this provides.
+	// TODO: b/308174306 - Once all the mainline modules have been flagged, drop this dependency edge
 	for _, lib := range p.properties.CommonModules {
 		dep := prebuiltApexExportedModuleName(ctx, lib)
 		ctx.AddReverseDependency(ctx.Module(), android.DeapexerTag, dep)
@@ -126,8 +131,9 @@
 	// apex relative path to extracted file path available for other modules.
 	if len(exports) > 0 {
 		// Make the information available for other modules.
-		di := android.NewDeapexerInfo(apexModuleName(ctx.ModuleName()), exports)
-		ctx.SetProvider(android.DeapexerProvider, di)
+		di := android.NewDeapexerInfo(apexModuleName(ctx.ModuleName()), exports, p.properties.CommonModules)
+		di.AddDexpreoptProfileGuidedExportedModuleNames(p.properties.DexpreoptProfileGuidedModules...)
+		android.SetProvider(ctx, android.DeapexerProvider, di)
 
 		// Create a sorted list of the files that this exports.
 		exportedPaths = android.SortedUniquePaths(exportedPaths)
diff --git a/apex/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go
index 2e828ca..7a17f50 100644
--- a/apex/dexpreopt_bootjars_test.go
+++ b/apex/dexpreopt_bootjars_test.go
@@ -164,6 +164,7 @@
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar",
 		"out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof",
 		"out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof",
+		"out/soong/dexpreopt/uffd_gc_flag.txt",
 	}
 
 	expectedOutputs := []string{
@@ -199,8 +200,9 @@
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/foo.jar",
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/bar.jar",
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/baz.jar",
-		"out/soong/.intermediates/com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
+		"out/soong/.intermediates/prebuilt_com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
 		"out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof",
+		"out/soong/dexpreopt/uffd_gc_flag.txt",
 	}
 
 	expectedOutputs := []string{
@@ -252,3 +254,162 @@
 
 	testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs, false)
 }
+
+// Multiple ART apexes might exist in the tree.
+// The profile should correspond to the apex selected using release build flags
+func TestDexpreoptProfileWithMultiplePrebuiltArtApexes(t *testing.T) {
+	ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art"
+	bp := `
+		// Platform.
+
+		platform_bootclasspath {
+			name: "platform-bootclasspath",
+			fragments: [
+				{
+					apex: "com.android.art",
+					module: "art-bootclasspath-fragment",
+				},
+			],
+		}
+
+		// Source ART APEX.
+
+		java_library {
+			name: "core-oj",
+			srcs: ["core-oj.java"],
+			installable: true,
+			apex_available: [
+				"com.android.art",
+			],
+		}
+
+		bootclasspath_fragment {
+			name: "art-bootclasspath-fragment",
+			image_name: "art",
+			contents: ["core-oj"],
+			apex_available: [
+				"com.android.art",
+			],
+			hidden_api: {
+				split_packages: ["*"],
+			},
+		}
+
+		apex_key {
+			name: "com.android.art.key",
+			public_key: "com.android.art.avbpubkey",
+			private_key: "com.android.art.pem",
+		}
+
+		apex {
+			name: "com.android.art",
+			key: "com.android.art.key",
+			bootclasspath_fragments: ["art-bootclasspath-fragment"],
+			updatable: false,
+		}
+
+		// Prebuilt ART APEX.
+
+		java_import {
+			name: "core-oj",
+			jars: ["core-oj.jar"],
+			apex_available: [
+				"com.android.art",
+			],
+		}
+
+		prebuilt_bootclasspath_fragment {
+			name: "art-bootclasspath-fragment",
+			image_name: "art",
+			contents: ["core-oj"],
+			hidden_api: {
+				annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
+				metadata: "my-bootclasspath-fragment/metadata.csv",
+				index: "my-bootclasspath-fragment/index.csv",
+				stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
+				all_flags: "my-bootclasspath-fragment/all-flags.csv",
+			},
+			apex_available: [
+				"com.android.art",
+			],
+		}
+
+		prebuilt_apex {
+			name: "com.android.art",
+			apex_name: "com.android.art",
+			src: "com.android.art-arm.apex",
+			exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
+		}
+
+		// Another Prebuilt ART APEX
+		prebuilt_apex {
+			name: "com.android.art.v2",
+			apex_name: "com.android.art", // Used to determine the API domain
+			src: "com.android.art-arm.apex",
+			exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
+		}
+
+		// APEX contribution modules
+
+		apex_contributions {
+			name: "art.source.contributions",
+			api_domain: "com.android.art",
+			contents: ["com.android.art"],
+		}
+
+		apex_contributions {
+			name: "art.prebuilt.contributions",
+			api_domain: "com.android.art",
+			contents: ["prebuilt_com.android.art"],
+		}
+
+		apex_contributions {
+			name: "art.prebuilt.v2.contributions",
+			api_domain: "com.android.art",
+			contents: ["com.android.art.v2"], // prebuilt_ prefix is missing because of prebuilt_rename mutator
+		}
+
+	`
+
+	testCases := []struct {
+		desc                         string
+		selectedArtApexContributions string
+		expectedProfile              string
+	}{
+		{
+			desc:                         "Source apex com.android.art is selected, profile should come from source java library",
+			selectedArtApexContributions: "art.source.contributions",
+			expectedProfile:              "out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof",
+		},
+		{
+			desc:                         "Prebuilt apex prebuilt_com.android.art is selected, profile should come from .prof deapexed from the prebuilt",
+			selectedArtApexContributions: "art.prebuilt.contributions",
+			expectedProfile:              "out/soong/.intermediates/prebuilt_com.android.art.deapexer/android_common/deapexer/etc/boot-image.prof",
+		},
+		{
+			desc:                         "Prebuilt apex prebuilt_com.android.art.v2 is selected, profile should come from .prof deapexed from the prebuilt",
+			selectedArtApexContributions: "art.prebuilt.v2.contributions",
+			expectedProfile:              "out/soong/.intermediates/prebuilt_com.android.art.v2.deapexer/android_common/deapexer/etc/boot-image.prof",
+		},
+	}
+	for _, tc := range testCases {
+		result := android.GroupFixturePreparers(
+			java.PrepareForTestWithDexpreopt,
+			java.PrepareForTestWithJavaSdkLibraryFiles,
+			java.FixtureConfigureBootJars("com.android.art:core-oj"),
+			PrepareForTestWithApexBuildComponents,
+			prepareForTestWithArtApex,
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ART": tc.selectedArtApexContributions,
+				}
+			}),
+		).RunTestWithBp(t, bp)
+
+		dexBootJars := result.ModuleForTests("dex_bootjars", "android_common")
+		rule := dexBootJars.Output(ruleFile)
+
+		inputs := rule.Implicits.Strings()
+		android.AssertStringListContains(t, tc.desc, inputs, tc.expectedProfile)
+	}
+}
diff --git a/apex/key.go b/apex/key.go
index 3010d76..e4214f0 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -16,12 +16,8 @@
 
 import (
 	"fmt"
-	"sort"
-	"strings"
 
 	"android/soong/android"
-	"android/soong/bazel"
-
 	"github.com/google/blueprint/proptools"
 )
 
@@ -33,12 +29,10 @@
 
 func registerApexKeyBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("apex_key", ApexKeyFactory)
-	ctx.RegisterParallelSingletonType("apex_keys_text", apexKeysTextFactory)
 }
 
 type apexKey struct {
 	android.ModuleBase
-	android.BazelModuleBase
 
 	properties apexKeyProperties
 
@@ -60,8 +54,7 @@
 func ApexKeyFactory() android.Module {
 	module := &apexKey{}
 	module.AddProperties(&module.properties)
-	android.InitAndroidArchModule(module, android.HostAndDeviceDefault, android.MultilibCommon)
-	android.InitBazelModule(module)
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	return module
 }
 
@@ -102,135 +95,63 @@
 	}
 }
 
-// //////////////////////////////////////////////////////////////////////
-// apex_keys_text
-type apexKeysText struct {
-	output android.OutputPath
+type apexKeyEntry struct {
+	name                 string
+	presigned            bool
+	publicKey            string
+	privateKey           string
+	containerCertificate string
+	containerPrivateKey  string
+	partition            string
+	signTool             string
 }
 
-func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) {
-	s.output = android.PathForOutput(ctx, "apexkeys.txt")
-	type apexKeyEntry struct {
-		name                 string
-		presigned            bool
-		publicKey            string
-		privateKey           string
-		containerCertificate string
-		containerPrivateKey  string
-		partition            string
-		signTool             string
+func (e apexKeyEntry) String() string {
+	signTool := ""
+	if e.signTool != "" {
+		signTool = fmt.Sprintf(" sign_tool=%q", e.signTool)
 	}
-	toString := func(e apexKeyEntry) string {
-		signTool := ""
-		if e.signTool != "" {
-			signTool = fmt.Sprintf(" sign_tool=%q", e.signTool)
+	format := "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q%s\n"
+	if e.presigned {
+		return fmt.Sprintf(format, e.name, "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", e.partition, signTool)
+	} else {
+		return fmt.Sprintf(format, e.name, e.publicKey, e.privateKey, e.containerCertificate, e.containerPrivateKey, e.partition, signTool)
+	}
+}
+
+func apexKeyEntryFor(ctx android.ModuleContext, module android.Module) apexKeyEntry {
+	switch m := module.(type) {
+	case *apexBundle:
+		pem, key := m.getCertificateAndPrivateKey(ctx)
+		return apexKeyEntry{
+			name:                 m.Name() + ".apex",
+			presigned:            false,
+			publicKey:            m.publicKeyFile.String(),
+			privateKey:           m.privateKeyFile.String(),
+			containerCertificate: pem.String(),
+			containerPrivateKey:  key.String(),
+			partition:            m.PartitionTag(ctx.DeviceConfig()),
+			signTool:             proptools.String(m.properties.Custom_sign_tool),
 		}
-		format := "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q%s\n"
-		if e.presigned {
-			return fmt.Sprintf(format, e.name, "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", e.partition, signTool)
-		} else {
-			return fmt.Sprintf(format, e.name, e.publicKey, e.privateKey, e.containerCertificate, e.containerPrivateKey, e.partition, signTool)
+	case *Prebuilt:
+		return apexKeyEntry{
+			name:      m.InstallFilename(),
+			presigned: true,
+			partition: m.PartitionTag(ctx.DeviceConfig()),
+		}
+	case *ApexSet:
+		return apexKeyEntry{
+			name:      m.InstallFilename(),
+			presigned: true,
+			partition: m.PartitionTag(ctx.DeviceConfig()),
 		}
 	}
-
-	apexKeyMap := make(map[string]apexKeyEntry)
-	ctx.VisitAllModules(func(module android.Module) {
-		if m, ok := module.(*apexBundle); ok && m.Enabled() && m.installable() {
-			pem, key := m.getCertificateAndPrivateKey(ctx)
-			apexKeyMap[m.Name()] = apexKeyEntry{
-				name:                 m.Name() + ".apex",
-				presigned:            false,
-				publicKey:            m.publicKeyFile.String(),
-				privateKey:           m.privateKeyFile.String(),
-				containerCertificate: pem.String(),
-				containerPrivateKey:  key.String(),
-				partition:            m.PartitionTag(ctx.DeviceConfig()),
-				signTool:             proptools.String(m.properties.Custom_sign_tool),
-			}
-		}
-	})
-
-	// Find prebuilts and let them override apexBundle if they are preferred
-	ctx.VisitAllModules(func(module android.Module) {
-		if m, ok := module.(*Prebuilt); ok && m.Enabled() && m.installable() &&
-			m.Prebuilt().UsePrebuilt() {
-			apexKeyMap[m.BaseModuleName()] = apexKeyEntry{
-				name:      m.InstallFilename(),
-				presigned: true,
-				partition: m.PartitionTag(ctx.DeviceConfig()),
-			}
-		}
-	})
-
-	// Find apex_set and let them override apexBundle or prebuilts. This is done in a separate pass
-	// so that apex_set are not overridden by prebuilts.
-	ctx.VisitAllModules(func(module android.Module) {
-		if m, ok := module.(*ApexSet); ok && m.Enabled() {
-			entry := apexKeyEntry{
-				name:      m.InstallFilename(),
-				presigned: true,
-				partition: m.PartitionTag(ctx.DeviceConfig()),
-			}
-			apexKeyMap[m.BaseModuleName()] = entry
-		}
-	})
-
-	// iterating over map does not give consistent ordering in golang
-	var moduleNames []string
-	for key, _ := range apexKeyMap {
-		moduleNames = append(moduleNames, key)
-	}
-	sort.Strings(moduleNames)
-
-	var filecontent strings.Builder
-	for _, name := range moduleNames {
-		filecontent.WriteString(toString(apexKeyMap[name]))
-	}
-	android.WriteFileRule(ctx, s.output, filecontent.String())
+	panic(fmt.Errorf("unknown type(%t) for apexKeyEntry", module))
 }
 
-func apexKeysTextFactory() android.Singleton {
-	return &apexKeysText{}
-}
-
-func (s *apexKeysText) MakeVars(ctx android.MakeVarsContext) {
-	ctx.Strict("SOONG_APEX_KEYS_FILE", s.output.String())
-}
-
-// For Bazel / bp2build
-
-type bazelApexKeyAttributes struct {
-	Public_key      bazel.LabelAttribute
-	Public_key_name bazel.StringAttribute
-
-	Private_key      bazel.LabelAttribute
-	Private_key_name bazel.StringAttribute
-}
-
-// ConvertWithBp2build performs conversion apexKey for bp2build
-func (m *apexKey) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	apexKeyBp2BuildInternal(ctx, m)
-}
-
-func apexKeyBp2BuildInternal(ctx android.TopDownMutatorContext, module *apexKey) {
-	privateKeyLabelAttribute, privateKeyNameAttribute :=
-		android.BazelStringOrLabelFromProp(ctx, module.properties.Private_key)
-
-	publicKeyLabelAttribute, publicKeyNameAttribute :=
-		android.BazelStringOrLabelFromProp(ctx, module.properties.Public_key)
-
-	attrs := &bazelApexKeyAttributes{
-		Private_key:      privateKeyLabelAttribute,
-		Private_key_name: privateKeyNameAttribute,
-
-		Public_key:      publicKeyLabelAttribute,
-		Public_key_name: publicKeyNameAttribute,
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "apex_key",
-		Bzl_load_location: "//build/bazel/rules/apex:apex_key.bzl",
-	}
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
+func writeApexKeys(ctx android.ModuleContext, module android.Module) android.WritablePath {
+	path := android.PathForModuleOut(ctx, "apexkeys.txt")
+	entry := apexKeyEntryFor(ctx, module)
+	android.WriteFileRuleVerbatim(ctx, path, entry.String())
+	return path
 }
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 05bb136..2be9c10 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -86,6 +86,7 @@
 					"bar-fragment",
 				],
 				updatable: false,
+				min_sdk_version: "30", // R
 			}
 
 			apex_key {
@@ -138,6 +139,7 @@
 				sdk_version: "none",
 				compile_dex: true,
 				permitted_packages: ["bar"],
+				min_sdk_version: "30", // R
 			}
 
 			java_sdk_library {
@@ -152,22 +154,22 @@
 	).RunTest(t)
 
 	pbcp := result.Module("platform-bootclasspath", "android_common")
-	info := result.ModuleProvider(pbcp, java.MonolithicHiddenAPIInfoProvider).(java.MonolithicHiddenAPIInfo)
+	info, _ := android.SingletonModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider)
 
 	for _, category := range java.HiddenAPIFlagFileCategories {
-		name := category.PropertyName
+		name := category.PropertyName()
 		message := fmt.Sprintf("category %s", name)
 		filename := strings.ReplaceAll(name, "_", "-")
 		expected := []string{fmt.Sprintf("%s.txt", filename), fmt.Sprintf("bar-%s.txt", filename)}
 		android.AssertPathsRelativeToTopEquals(t, message, expected, info.FlagsFilesByCategory[category])
 	}
 
-	android.AssertPathsRelativeToTopEquals(t, "annotation flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/annotation-flags.csv"}, info.AnnotationFlagsPaths)
-	android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/metadata.csv"}, info.MetadataPaths)
-	android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/index.csv"}, info.IndexPaths)
+	android.AssertPathsRelativeToTopEquals(t, "annotation flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/annotation-flags.csv"}, info.AnnotationFlagsPaths)
+	android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/metadata.csv"}, info.MetadataPaths)
+	android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/index.csv"}, info.IndexPaths)
 
-	android.AssertArrayString(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/filtered-stub-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop())
-	android.AssertArrayString(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/filtered-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop())
+	android.AssertArrayString(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/filtered-stub-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop())
+	android.AssertArrayString(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/filtered-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop())
 }
 
 // TestPlatformBootclasspath_LegacyPrebuiltFragment verifies that the
@@ -234,7 +236,7 @@
 	)
 
 	pbcp := result.Module("myplatform-bootclasspath", "android_common")
-	info := result.ModuleProvider(pbcp, java.MonolithicHiddenAPIInfoProvider).(java.MonolithicHiddenAPIInfo)
+	info, _ := android.SingletonModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider)
 
 	android.AssertArrayString(t, "stub flags", []string{"prebuilt-stub-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop())
 	android.AssertArrayString(t, "all flags", []string{"prebuilt-all-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop())
@@ -252,6 +254,11 @@
 		java.FixtureWithLastReleaseApis("foo"),
 		java.PrepareForTestWithDexpreopt,
 		dexpreopt.FixtureDisableDexpreoptBootImages(false),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
 	).RunTestWithBp(t, `
 		apex {
 			name: "com.android.art",
@@ -382,11 +389,14 @@
 
 	// Make sure that the myplatform-bootclasspath has the correct dependencies.
 	CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
+		// source vs prebuilt selection metadata module
+		`platform:all_apex_contributions`,
+
 		// The following are stubs.
-		`platform:android_stubs_current`,
-		`platform:android_system_stubs_current`,
-		`platform:android_test_stubs_current`,
-		`platform:legacy.core.platform.api.stubs`,
+		`platform:android_stubs_current_exportable`,
+		`platform:android_system_stubs_current_exportable`,
+		`platform:android_test_stubs_current_exportable`,
+		`platform:legacy.core.platform.api.stubs.exportable`,
 
 		// Needed for generating the boot image.
 		`platform:dex2oatd`,
@@ -419,6 +429,9 @@
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 			variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
 		}),
 		java.FixtureWithPrebuiltApis(map[string][]string{
 			"current": {},
@@ -534,13 +547,16 @@
 
 	// Make sure that the myplatform-bootclasspath has the correct dependencies.
 	CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
+		// source vs prebuilt selection metadata module
+		`platform:all_apex_contributions`,
+
 		// The following are stubs.
 		"platform:prebuilt_sdk_public_current_android",
 		"platform:prebuilt_sdk_system_current_android",
 		"platform:prebuilt_sdk_test_current_android",
 
 		// Not a prebuilt as no prebuilt existed when it was added.
-		"platform:legacy.core.platform.api.stubs",
+		"platform:legacy.core.platform.api.stubs.exportable",
 
 		// The platform_bootclasspath intentionally adds dependencies on both source and prebuilt
 		// modules when available as it does not know which one will be preferred.
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 3509e6c..ea847e1 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -22,6 +22,7 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/dexpreopt"
 	"android/soong/java"
 	"android/soong/provenance"
 
@@ -50,6 +51,7 @@
 
 type prebuiltCommon struct {
 	android.ModuleBase
+	java.Dexpreopter
 	prebuilt android.Prebuilt
 
 	// Properties common to both prebuilt_apex and apex_set.
@@ -60,6 +62,9 @@
 	installedFile   android.InstallPath
 	outputApex      android.WritablePath
 
+	// fragment for this apex for apexkeys.txt
+	apexKeysPath android.WritablePath
+
 	// A list of apexFile objects created in prebuiltCommon.initApexFilesForAndroidMk which are used
 	// to create make modules in prebuiltCommon.AndroidMkEntries.
 	apexFilesForAndroidMk []apexFile
@@ -82,6 +87,12 @@
 	// device (/apex/<apex_name>). If unspecified, follows the name property.
 	Apex_name *string
 
+	// Name of the source APEX that gets shadowed by this prebuilt
+	// e.g. com.mycompany.android.myapex
+	// If unspecified, follows the naming convention that the source apex of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_apex_name *string
+
 	ForceDisable bool `blueprint:"mutated"`
 
 	// whether the extracted apex file is installable.
@@ -110,6 +121,11 @@
 	// List of systemserverclasspath fragments inside this prebuilt APEX bundle and for which this
 	// APEX bundle will create an APEX variant.
 	Exported_systemserverclasspath_fragments []string
+
+	// Path to the .prebuilt_info file of the prebuilt apex.
+	// In case of mainline modules, the .prebuilt_info file contains the build_id that was used to
+	// generate the prebuilt.
+	Prebuilt_info *string `android:"path"`
 }
 
 // initPrebuiltCommon initializes the prebuiltCommon structure and performs initialization of the
@@ -121,7 +137,11 @@
 }
 
 func (p *prebuiltCommon) ApexVariationName() string {
-	return proptools.StringDefault(p.prebuiltCommonProperties.Apex_name, p.ModuleBase.BaseModuleName())
+	return proptools.StringDefault(p.prebuiltCommonProperties.Apex_name, p.BaseModuleName())
+}
+
+func (p *prebuiltCommon) BaseModuleName() string {
+	return proptools.StringDefault(p.prebuiltCommonProperties.Source_apex_name, p.ModuleBase.BaseModuleName())
 }
 
 func (p *prebuiltCommon) Prebuilt() *android.Prebuilt {
@@ -167,50 +187,46 @@
 	return proptools.BoolDefault(p.prebuiltCommonProperties.Installable, true)
 }
 
-// initApexFilesForAndroidMk initializes the prebuiltCommon.apexFilesForAndroidMk field from the
-// modules that this depends upon.
+// To satisfy java.DexpreopterInterface
+func (p *prebuiltCommon) IsInstallable() bool {
+	return p.installable()
+}
+
+// initApexFilesForAndroidMk initializes the prebuiltCommon.requiredModuleNames field with the install only deps of the prebuilt apex
 func (p *prebuiltCommon) initApexFilesForAndroidMk(ctx android.ModuleContext) {
-	// Walk the dependencies of this module looking for the java modules that it exports.
-	ctx.WalkDeps(func(child, parent android.Module) bool {
-		tag := ctx.OtherModuleDependencyTag(child)
+	// If this apex contains a system server jar, then the dexpreopt artifacts should be added as required
+	for _, install := range p.Dexpreopter.DexpreoptBuiltInstalledForApex() {
+		p.requiredModuleNames = append(p.requiredModuleNames, install.FullModuleName())
+	}
+}
 
-		name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child))
-		if java.IsBootclasspathFragmentContentDepTag(tag) ||
-			java.IsSystemServerClasspathFragmentContentDepTag(tag) || tag == exportedJavaLibTag {
-			// If the exported java module provides a dex jar path then add it to the list of apexFiles.
-			path := child.(interface {
-				DexJarBuildPath() java.OptionalDexJarPath
-			}).DexJarBuildPath()
-			if path.IsSet() {
-				af := apexFile{
-					module:              child,
-					moduleDir:           ctx.OtherModuleDir(child),
-					androidMkModuleName: name,
-					builtFile:           path.Path(),
-					class:               javaSharedLib,
-				}
-				if module, ok := child.(java.DexpreopterInterface); ok {
-					for _, install := range module.DexpreoptBuiltInstalledForApex() {
-						af.requiredModuleNames = append(af.requiredModuleNames, install.FullModuleName())
-					}
-				}
-				p.apexFilesForAndroidMk = append(p.apexFilesForAndroidMk, af)
-			}
-		} else if tag == exportedBootclasspathFragmentTag {
-			_, ok := child.(*java.PrebuiltBootclasspathFragmentModule)
-			if !ok {
-				ctx.PropertyErrorf("exported_bootclasspath_fragments", "%q is not a prebuilt_bootclasspath_fragment module", name)
-				return false
-			}
-			// Visit the children of the bootclasspath_fragment.
-			return true
-		} else if tag == exportedSystemserverclasspathFragmentTag {
-			// Visit the children of the systemserver_fragment.
-			return true
+// If this prebuilt has system server jar, create the rules to dexpreopt it and install it alongside the prebuilt apex
+func (p *prebuiltCommon) dexpreoptSystemServerJars(ctx android.ModuleContext) {
+	// If this apex does not export anything, return
+	if !p.hasExportedDeps() {
+		return
+	}
+	// If this prebuilt apex has not been selected, return
+	if p.IsHideFromMake() {
+		return
+	}
+	// Use apex_name to determine the api domain of this prebuilt apex
+	apexName := p.ApexVariationName()
+	di, err := android.FindDeapexerProviderForModule(ctx)
+	if err != nil {
+		ctx.ModuleErrorf(err.Error())
+	}
+	dc := dexpreopt.GetGlobalConfig(ctx)
+	systemServerJarList := dc.AllApexSystemServerJars(ctx)
+
+	for i := 0; i < systemServerJarList.Len(); i++ {
+		sscpApex := systemServerJarList.Apex(i)
+		sscpJar := systemServerJarList.Jar(i)
+		if apexName != sscpApex {
+			continue
 		}
-
-		return false
-	})
+		p.Dexpreopter.DexpreoptPrebuiltApexSystemServerJars(ctx, sscpJar, di)
+	}
 }
 
 func (p *prebuiltCommon) addRequiredModules(entries *android.AndroidMkEntries) {
@@ -229,20 +245,28 @@
 			OutputFile:    android.OptionalPathForPath(p.outputApex),
 			Include:       "$(BUILD_PREBUILT)",
 			Host_required: p.hostRequired,
+			OverrideName:  p.BaseModuleName(),
 			ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 				func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 					entries.SetString("LOCAL_MODULE_PATH", p.installDir.String())
 					entries.SetString("LOCAL_MODULE_STEM", p.installFilename)
 					entries.SetPath("LOCAL_SOONG_INSTALLED_MODULE", p.installedFile)
 					entries.SetString("LOCAL_SOONG_INSTALL_PAIRS", p.outputApex.String()+":"+p.installedFile.String())
+					entries.AddStrings("LOCAL_SOONG_INSTALL_SYMLINKS", p.compatSymlinks.Strings()...)
 					entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable())
 					entries.AddStrings("LOCAL_OVERRIDES_MODULES", p.prebuiltCommonProperties.Overrides...)
+					entries.SetString("LOCAL_APEX_KEY_PATH", p.apexKeysPath.String())
 					p.addRequiredModules(entries)
 				},
 			},
 		},
 	}
 
+	// Add the dexpreopt artifacts to androidmk
+	for _, install := range p.Dexpreopter.DexpreoptBuiltInstalledForApex() {
+		entriesList = append(entriesList, install.ToMakeEntries())
+	}
+
 	// Iterate over the apexFilesForAndroidMk list and create an AndroidMkEntries struct for each
 	// file. This provides similar behavior to that provided in apexBundle.AndroidMk() as it makes the
 	// apex specific variants of the exported java modules available for use from within make.
@@ -423,7 +447,7 @@
 
 	// Create contents for the prebuilt_apex and store it away for later use.
 	apexContents := android.NewApexContents(contents)
-	mctx.SetProvider(ApexBundleInfoProvider, ApexBundleInfo{
+	android.SetProvider(mctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{
 		Contents: apexContents,
 	})
 
@@ -432,7 +456,7 @@
 	apexInfo := android.ApexInfo{
 		ApexVariationName: apexVariationName,
 		InApexVariants:    []string{apexVariationName},
-		InApexModules:     []string{p.ModuleBase.BaseModuleName()}, // BaseModuleName() to avoid the prebuilt_ prefix.
+		InApexModules:     []string{p.BaseModuleName()}, // BaseModuleName() to avoid the prebuilt_ prefix.
 		ApexContents:      []*android.ApexContents{apexContents},
 		ForPrebuiltApex:   true,
 	}
@@ -479,6 +503,9 @@
 	inputApex android.Path
 
 	provenanceMetaDataFile android.OutputPath
+
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
 }
 
 type ApexFileProperties struct {
@@ -607,6 +634,7 @@
 
 	// Compute the deapexer properties from the transitive dependencies of this module.
 	commonModules := []string{}
+	dexpreoptProfileGuidedModules := []string{}
 	exportedFiles := []string{}
 	ctx.WalkDeps(func(child, parent android.Module) bool {
 		tag := ctx.OtherModuleDependencyTag(child)
@@ -616,13 +644,18 @@
 			return false
 		}
 
-		name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child))
+		name := java.ModuleStemForDeapexing(child)
 		if _, ok := tag.(android.RequiresFilesFromPrebuiltApexTag); ok {
 			commonModules = append(commonModules, name)
 
-			requiredFiles := child.(android.RequiredFilesFromPrebuiltApex).RequiredFilesFromPrebuiltApex(ctx)
+			extract := child.(android.RequiredFilesFromPrebuiltApex)
+			requiredFiles := extract.RequiredFilesFromPrebuiltApex(ctx)
 			exportedFiles = append(exportedFiles, requiredFiles...)
 
+			if extract.UseProfileGuidedDexpreopt() {
+				dexpreoptProfileGuidedModules = append(dexpreoptProfileGuidedModules, name)
+			}
+
 			// Visit the dependencies of this module just in case they also require files from the
 			// prebuilt apex.
 			return true
@@ -635,7 +668,8 @@
 	deapexerProperties := &DeapexerProperties{
 		// Remove any duplicates from the common modules lists as a module may be included via a direct
 		// dependency as well as transitive ones.
-		CommonModules: android.SortedUniqueStrings(commonModules),
+		CommonModules:                 android.SortedUniqueStrings(commonModules),
+		DexpreoptProfileGuidedModules: android.SortedUniqueStrings(dexpreoptProfileGuidedModules),
 	}
 
 	// Populate the exported files property in a fixed order.
@@ -735,13 +769,11 @@
 //     V            V            V
 //     selector  <---  deapexer  <---  exported java lib
 func (p *Prebuilt) createPrebuiltApexModules(ctx android.TopDownMutatorContext) {
-	baseModuleName := p.BaseModuleName()
-
-	apexSelectorModuleName := apexSelectorModuleName(baseModuleName)
+	apexSelectorModuleName := apexSelectorModuleName(p.Name())
 	createApexSelectorModule(ctx, apexSelectorModuleName, &p.properties.ApexFileProperties)
 
 	apexFileSource := ":" + apexSelectorModuleName
-	p.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(baseModuleName), apexFileSource)
+	p.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(p.Name()), apexFileSource)
 
 	// Add a source reference to retrieve the selected apex from the selector module.
 	p.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource)
@@ -751,13 +783,63 @@
 	p.prebuiltApexContentsDeps(ctx)
 }
 
+func (p *prebuiltCommon) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if p.hasExportedDeps() {
+		// Create a dependency from the prebuilt apex (prebuilt_apex/apex_set) to the internal deapexer module
+		// The deapexer will return a provider that will be bubbled up to the rdeps of apexes (e.g. dex_bootjars)
+		ctx.AddDependency(ctx.Module(), android.DeapexerTag, deapexerModuleName(p.Name()))
+	}
+}
+
 var _ ApexInfoMutator = (*Prebuilt)(nil)
 
 func (p *Prebuilt) ApexInfoMutator(mctx android.TopDownMutatorContext) {
 	p.apexInfoMutator(mctx)
 }
 
+// Set a provider containing information about the jars and .prof provided by the apex
+// Apexes built from prebuilts retrieve this information by visiting its internal deapexer module
+// Used by dex_bootjars to generate the boot image
+func (p *prebuiltCommon) provideApexExportsInfo(ctx android.ModuleContext) {
+	if !p.hasExportedDeps() {
+		// nothing to do
+		return
+	}
+	if di, err := android.FindDeapexerProviderForModule(ctx); err == nil {
+		javaModuleToDexPath := map[string]android.Path{}
+		for _, commonModule := range di.GetExportedModuleNames() {
+			if dex := di.PrebuiltExportPath(java.ApexRootRelativePathToJavaLib(commonModule)); dex != nil {
+				javaModuleToDexPath[commonModule] = dex
+			}
+		}
+
+		exports := android.ApexExportsInfo{
+			ApexName:                      p.ApexVariationName(),
+			ProfilePathOnHost:             di.PrebuiltExportPath(java.ProfileInstallPathInApex),
+			LibraryNameToDexJarPathOnHost: javaModuleToDexPath,
+		}
+		android.SetProvider(ctx, android.ApexExportsInfoProvider, exports)
+	} else {
+		ctx.ModuleErrorf(err.Error())
+	}
+}
+
+// Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file
+// with information about whether source or prebuilt of an apex was used during the build.
+func (p *prebuiltCommon) providePrebuiltInfo(ctx android.ModuleContext) {
+	info := android.PrebuiltInfo{
+		Name:        p.BaseModuleName(),
+		Is_prebuilt: true,
+	}
+	// If Prebuilt_info information is available in the soong module definition, add it to prebuilt_info.json.
+	if p.prebuiltCommonProperties.Prebuilt_info != nil {
+		info.Prebuilt_info_file_path = android.PathForModuleSrc(ctx, *p.prebuiltCommonProperties.Prebuilt_info).String()
+	}
+	android.SetProvider(ctx, android.PrebuiltInfoProvider, info)
+}
+
 func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	p.apexKeysPath = writeApexKeys(ctx, p)
 	// TODO(jungjw): Check the key validity.
 	p.inputApex = android.OptionalPathForModuleSrc(ctx, p.prebuiltCommonProperties.Selected_apex).Path()
 	p.installDir = android.PathForModuleInstall(ctx, "apex")
@@ -777,20 +859,30 @@
 		return
 	}
 
+	// dexpreopt any system server jars if present
+	p.dexpreoptSystemServerJars(ctx)
+
+	// provide info used for generating the boot image
+	p.provideApexExportsInfo(ctx)
+
+	p.providePrebuiltInfo(ctx)
+
 	// Save the files that need to be made available to Make.
 	p.initApexFilesForAndroidMk(ctx)
 
 	// in case that prebuilt_apex replaces source apex (using prefer: prop)
-	p.compatSymlinks = makeCompatSymlinks(p.BaseModuleName(), ctx, true)
+	p.compatSymlinks = makeCompatSymlinks(p.BaseModuleName(), ctx)
 	// or that prebuilt_apex overrides other apexes (using overrides: prop)
 	for _, overridden := range p.prebuiltCommonProperties.Overrides {
-		p.compatSymlinks = append(p.compatSymlinks, makeCompatSymlinks(overridden, ctx, true)...)
+		p.compatSymlinks = append(p.compatSymlinks, makeCompatSymlinks(overridden, ctx)...)
 	}
 
 	if p.installable() {
-		p.installedFile = ctx.InstallFile(p.installDir, p.installFilename, p.inputApex, p.compatSymlinks.Paths()...)
+		p.installedFile = ctx.InstallFile(p.installDir, p.installFilename, p.inputApex, p.compatSymlinks...)
 		p.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, p.inputApex, p.installedFile)
 	}
+
+	android.CollectDependencyAconfigFiles(ctx, &p.mergedAconfigFiles)
 }
 
 func (p *Prebuilt) ProvenanceMetaDataFile() android.OutputPath {
@@ -876,12 +968,7 @@
 		srcs = append(srcs, *e.Set)
 	}
 
-	var sanitizers []string
-	if ctx.Host() {
-		sanitizers = ctx.Config().SanitizeHost()
-	} else {
-		sanitizers = ctx.Config().SanitizeDevice()
-	}
+	sanitizers := ctx.Config().SanitizeDevice()
 
 	if android.InList("address", sanitizers) && e.Sanitized.Address.Set != nil {
 		srcs = append(srcs, *e.Sanitized.Address.Set)
@@ -956,13 +1043,11 @@
 // from those provided this creates an extractor module which extracts the appropriate .apex file
 // from the zip file containing them.
 func (a *ApexSet) createPrebuiltApexModules(ctx android.TopDownMutatorContext) {
-	baseModuleName := a.BaseModuleName()
-
-	apexExtractorModuleName := apexExtractorModuleName(baseModuleName)
+	apexExtractorModuleName := apexExtractorModuleName(a.Name())
 	createApexExtractorModule(ctx, apexExtractorModuleName, &a.properties.ApexExtractorProperties)
 
 	apexFileSource := ":" + apexExtractorModuleName
-	a.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(baseModuleName), apexFileSource)
+	a.createDeapexerModuleIfNeeded(ctx, deapexerModuleName(a.Name()), apexFileSource)
 
 	// After passing the arch specific src properties to the creating the apex selector module
 	a.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource)
@@ -979,6 +1064,7 @@
 }
 
 func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	a.apexKeysPath = writeApexKeys(ctx, a)
 	a.installFilename = a.InstallFilename()
 	if !strings.HasSuffix(a.installFilename, imageApexSuffix) && !strings.HasSuffix(a.installFilename, imageCapexSuffix) {
 		ctx.ModuleErrorf("filename should end in %s or %s for apex_set", imageApexSuffix, imageCapexSuffix)
@@ -997,6 +1083,14 @@
 		return
 	}
 
+	// dexpreopt any system server jars if present
+	a.dexpreoptSystemServerJars(ctx)
+
+	// provide info used for generating the boot image
+	a.provideApexExportsInfo(ctx)
+
+	a.providePrebuiltInfo(ctx)
+
 	// Save the files that need to be made available to Make.
 	a.initApexFilesForAndroidMk(ctx)
 
@@ -1006,10 +1100,10 @@
 	}
 
 	// in case that apex_set replaces source apex (using prefer: prop)
-	a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, true)
+	a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx)
 	// or that apex_set overrides other apexes (using overrides: prop)
 	for _, overridden := range a.prebuiltCommonProperties.Overrides {
-		a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx, true)...)
+		a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx)...)
 	}
 }
 
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index f94e50f..f6c53b2 100644
--- a/apex/systemserver_classpath_fragment_test.go
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -97,7 +97,7 @@
 
 	ctx := result.TestContext
 
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"etc/classpaths/systemserverclasspath.pb",
 		"javalib/foo.jar",
 		"javalib/bar.jar",
@@ -105,7 +105,8 @@
 		"javalib/baz.jar",
 	})
 
-	java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex_image", []string{
+	java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{
+		`dex2oatd`,
 		`myapex.key`,
 		`mysystemserverclasspathfragment`,
 	})
@@ -157,11 +158,12 @@
 		}
 	`)
 
-	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex", []string{
 		"javalib/foo.jar",
 	})
 
-	java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+	java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex", []string{
+		`dex2oatd`,
 		`myapex.key`,
 		`mysystemserverclasspathfragment`,
 	})
@@ -272,24 +274,26 @@
 	ctx := result.TestContext
 
 	java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{
-		`myapex.apex.selector`,
+		`dex2oatd`,
+		`prebuilt_myapex.apex.selector`,
+		`prebuilt_myapex.deapexer`,
 		`prebuilt_mysystemserverclasspathfragment`,
 	})
 
 	java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_myapex", []string{
-		`myapex.deapexer`,
 		`prebuilt_bar`,
 		`prebuilt_foo`,
+		`prebuilt_myapex.deapexer`,
 	})
 
-	ensureExactDeapexedContents(t, ctx, "myapex", "android_common", []string{
+	ensureExactDeapexedContents(t, ctx, "prebuilt_myapex", "android_common", []string{
 		"javalib/foo.jar",
 		"javalib/bar.jar",
 		"javalib/bar.jar.prof",
 	})
 
-	assertProfileGuided(t, ctx, "foo", "android_common_myapex", false)
-	assertProfileGuided(t, ctx, "bar", "android_common_myapex", true)
+	assertProfileGuidedPrebuilt(t, ctx, "myapex", "foo", false)
+	assertProfileGuidedPrebuilt(t, ctx, "myapex", "bar", true)
 }
 
 func TestSystemserverclasspathFragmentStandaloneContents(t *testing.T) {
@@ -361,7 +365,7 @@
 
 	ctx := result.TestContext
 
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"etc/classpaths/systemserverclasspath.pb",
 		"javalib/foo.jar",
 		"javalib/bar.jar",
@@ -428,19 +432,19 @@
 	ctx := result.TestContext
 
 	java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_myapex", []string{
-		`myapex.deapexer`,
 		`prebuilt_bar`,
 		`prebuilt_foo`,
+		`prebuilt_myapex.deapexer`,
 	})
 
-	ensureExactDeapexedContents(t, ctx, "myapex", "android_common", []string{
+	ensureExactDeapexedContents(t, ctx, "prebuilt_myapex", "android_common", []string{
 		"javalib/foo.jar",
 		"javalib/bar.jar",
 		"javalib/bar.jar.prof",
 	})
 
-	assertProfileGuided(t, ctx, "foo", "android_common_myapex", false)
-	assertProfileGuided(t, ctx, "bar", "android_common_myapex", true)
+	assertProfileGuidedPrebuilt(t, ctx, "myapex", "foo", false)
+	assertProfileGuidedPrebuilt(t, ctx, "myapex", "bar", true)
 }
 
 func assertProfileGuided(t *testing.T, ctx *android.TestContext, moduleName string, variant string, expected bool) {
@@ -450,3 +454,11 @@
 		t.Fatalf("Expected profile-guided to be %v, got %v", expected, actual)
 	}
 }
+
+func assertProfileGuidedPrebuilt(t *testing.T, ctx *android.TestContext, apexName string, moduleName string, expected bool) {
+	dexpreopt := ctx.ModuleForTests(apexName, "android_common_"+apexName).Rule("dexpreopt." + moduleName)
+	actual := strings.Contains(dexpreopt.RuleParams.Command, "--profile-file=")
+	if expected != actual {
+		t.Fatalf("Expected profile-guided to be %v, got %v", expected, actual)
+	}
+}
diff --git a/apex/vndk.go b/apex/vndk.go
index 095e89d..781aa3c 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -45,16 +45,12 @@
 	return bundle
 }
 
-func (a *apexBundle) vndkVersion(config android.DeviceConfig) string {
-	vndkVersion := proptools.StringDefault(a.vndkProperties.Vndk_version, "current")
-	if vndkVersion == "current" {
-		vndkVersion = config.PlatformVndkVersion()
-	}
-	return vndkVersion
+func (a *apexBundle) vndkVersion() string {
+	return proptools.StringDefault(a.vndkProperties.Vndk_version, "current")
 }
 
 type apexVndkProperties struct {
-	// Indicates VNDK version of which this VNDK APEX bundles VNDK libs. Default is Platform VNDK Version.
+	// Indicates VNDK version of which this VNDK APEX bundles VNDK libs.
 	Vndk_version *string
 }
 
@@ -64,21 +60,20 @@
 			mctx.PropertyErrorf("native_bridge_supported", "%q doesn't support native bridge binary.", mctx.ModuleType())
 		}
 
-		vndkVersion := ab.vndkVersion(mctx.DeviceConfig())
-		apiLevel, err := android.ApiLevelFromUser(mctx, vndkVersion)
-		if err != nil {
-			mctx.PropertyErrorf("vndk_version", "%s", err.Error())
-			return
-		}
+		vndkVersion := ab.vndkVersion()
+		if vndkVersion != "" {
+			apiLevel, err := android.ApiLevelFromUser(mctx, vndkVersion)
+			if err != nil {
+				mctx.PropertyErrorf("vndk_version", "%s", err.Error())
+				return
+			}
 
-		targets := mctx.MultiTargets()
-		if len(targets) > 0 && apiLevel.LessThan(cc.MinApiForArch(mctx, targets[0].Arch.ArchType)) &&
-			vndkVersion != mctx.DeviceConfig().PlatformVndkVersion() {
-			// Disable VNDK APEXes for VNDK versions less than the minimum supported API
-			// level for the primary architecture. This validation is skipped if the VNDK
-			// version matches the platform VNDK version, which can occur when the device
-			// config targets the 'current' VNDK (see `vndkVersion`).
-			ab.Disable()
+			targets := mctx.MultiTargets()
+			if len(targets) > 0 && apiLevel.LessThan(cc.MinApiForArch(mctx, targets[0].Arch.ArchType)) {
+				// Disable VNDK APEXes for VNDK versions less than the minimum supported API
+				// level for the primary architecture.
+				ab.Disable()
+			}
 		}
 	}
 }
@@ -86,15 +81,11 @@
 func apexVndkDepsMutator(mctx android.BottomUpMutatorContext) {
 	if m, ok := mctx.Module().(*cc.Module); ok && cc.IsForVndkApex(mctx, m) {
 		vndkVersion := m.VndkVersion()
-		// For VNDK-Lite device, we gather core-variants of VNDK-Sp libraries, which doesn't have VNDK version defined
+
 		if vndkVersion == "" {
-			vndkVersion = mctx.DeviceConfig().PlatformVndkVersion()
+			return
 		}
-		if vndkVersion == mctx.DeviceConfig().PlatformVndkVersion() {
-			vndkVersion = "current"
-		} else {
-			vndkVersion = "v" + vndkVersion
-		}
+		vndkVersion = "v" + vndkVersion
 
 		vndkApexName := "com.android.vndk." + vndkVersion
 
@@ -103,19 +94,15 @@
 		}
 	} else if a, ok := mctx.Module().(*apexBundle); ok && a.vndkApex {
 		vndkVersion := proptools.StringDefault(a.vndkProperties.Vndk_version, "current")
-		mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion)...)
+		mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion, mctx)...)
 	}
 }
 
 // name is module.BaseModuleName() which is used as LOCAL_MODULE_NAME and also LOCAL_OVERRIDES_*
-func makeCompatSymlinks(name string, ctx android.ModuleContext, primaryApex bool) (symlinks android.InstallPaths) {
+func makeCompatSymlinks(name string, ctx android.ModuleContext) (symlinks android.InstallPaths) {
 	// small helper to add symlink commands
 	addSymlink := func(target string, dir android.InstallPath, linkName string) {
-		if primaryApex {
-			symlinks = append(symlinks, ctx.InstallAbsoluteSymlink(dir, linkName, target))
-		} else {
-			symlinks = append(symlinks, dir.Join(ctx, linkName))
-		}
+		symlinks = append(symlinks, ctx.InstallAbsoluteSymlink(dir, linkName, target))
 	}
 
 	// TODO(b/142911355): [VNDK APEX] Fix hard-coded references to /system/lib/vndk
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
deleted file mode 100644
index 21526c3..0000000
--- a/apex/vndk_test.go
+++ /dev/null
@@ -1,142 +0,0 @@
-package apex
-
-import (
-	"testing"
-
-	"github.com/google/blueprint/proptools"
-
-	"android/soong/android"
-)
-
-func TestVndkApexForVndkLite(t *testing.T) {
-	ctx := testApex(t, `
-		apex_vndk {
-			name: "com.android.vndk.current",
-			key: "com.android.vndk.current.key",
-			updatable: false,
-		}
-
-		apex_key {
-			name: "com.android.vndk.current.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-
-		cc_library {
-			name: "libvndk",
-			srcs: ["mylib.cpp"],
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			system_shared_libs: [],
-			stl: "none",
-			apex_available: [ "com.android.vndk.current" ],
-		}
-
-		cc_library {
-			name: "libvndksp",
-			srcs: ["mylib.cpp"],
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			system_shared_libs: [],
-			stl: "none",
-			apex_available: [ "com.android.vndk.current" ],
-		}
-	`+vndkLibrariesTxtFiles("current"),
-		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-			variables.DeviceVndkVersion = proptools.StringPtr("")
-		}),
-	)
-	// VNDK-Lite contains only core variants of VNDK-Sp libraries
-	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
-		"lib/libvndksp.so",
-		"lib/libc++.so",
-		"lib64/libvndksp.so",
-		"lib64/libc++.so",
-		"etc/llndk.libraries.29.txt",
-		"etc/vndkcore.libraries.29.txt",
-		"etc/vndksp.libraries.29.txt",
-		"etc/vndkprivate.libraries.29.txt",
-		"etc/vndkproduct.libraries.29.txt",
-	})
-}
-
-func TestVndkApexUsesVendorVariant(t *testing.T) {
-	bp := `
-		apex_vndk {
-			name: "com.android.vndk.current",
-			key: "mykey",
-			updatable: false,
-		}
-		apex_key {
-			name: "mykey",
-		}
-		cc_library {
-			name: "libfoo",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			system_shared_libs: [],
-			stl: "none",
-		}
-		` + vndkLibrariesTxtFiles("current")
-
-	ensureFileSrc := func(t *testing.T, files []fileInApex, path, src string) {
-		t.Helper()
-		for _, f := range files {
-			if f.path == path {
-				ensureContains(t, f.src, src)
-				return
-			}
-		}
-		t.Errorf("expected path %q not found", path)
-	}
-
-	t.Run("VNDK lib doesn't have an apex variant", func(t *testing.T) {
-		ctx := testApex(t, bp)
-
-		// libfoo doesn't have apex variants
-		for _, variant := range ctx.ModuleVariantsForTests("libfoo") {
-			ensureNotContains(t, variant, "_myapex")
-		}
-
-		// VNDK APEX doesn't create apex variant
-		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
-		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
-	})
-
-	t.Run("VNDK APEX gathers only vendor variants even if product variants are available", func(t *testing.T) {
-		ctx := testApex(t, bp,
-			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-				// Now product variant is available
-				variables.ProductVndkVersion = proptools.StringPtr("current")
-			}),
-		)
-
-		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
-		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
-	})
-
-	t.Run("VNDK APEX supports coverage variants", func(t *testing.T) {
-		ctx := testApex(t, bp,
-			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-				variables.GcovCoverage = proptools.BoolPtr(true)
-				variables.Native_coverage = proptools.BoolPtr(true)
-			}),
-		)
-
-		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
-		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
-
-		files = getFiles(t, ctx, "com.android.vndk.current", "android_common_cov_image")
-		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared_cov/libfoo.so")
-	})
-}
diff --git a/bazel/aquery.go b/bazel/aquery.go
index d77d59a..35942bc 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -18,14 +18,16 @@
 	"crypto/sha256"
 	"encoding/base64"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"path/filepath"
-	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
 	"reflect"
 	"sort"
 	"strings"
 	"sync"
 
+	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
+
 	"github.com/google/blueprint/metrics"
 	"github.com/google/blueprint/proptools"
 	"google.golang.org/protobuf/proto"
@@ -35,19 +37,6 @@
 type depsetId int
 type pathFragmentId int
 
-// artifact contains relevant portions of Bazel's aquery proto, Artifact.
-// Represents a single artifact, whether it's a source file or a derived output file.
-type artifact struct {
-	Id             artifactId
-	PathFragmentId pathFragmentId
-}
-
-type pathFragment struct {
-	Id       pathFragmentId
-	Label    string
-	ParentId pathFragmentId
-}
-
 // KeyValuePair represents Bazel's aquery proto, KeyValuePair.
 type KeyValuePair struct {
 	Key   string
@@ -68,37 +57,6 @@
 	TransitiveDepSetHashes []string
 }
 
-// depSetOfFiles contains relevant portions of Bazel's aquery proto, DepSetOfFiles.
-// Represents a data structure containing one or more files. Depsets in Bazel are an efficient
-// data structure for storing large numbers of file paths.
-type depSetOfFiles struct {
-	Id                  depsetId
-	DirectArtifactIds   []artifactId
-	TransitiveDepSetIds []depsetId
-}
-
-// action contains relevant portions of Bazel's aquery proto, Action.
-// Represents a single command line invocation in the Bazel build graph.
-type action struct {
-	Arguments            []string
-	EnvironmentVariables []KeyValuePair
-	InputDepSetIds       []depsetId
-	Mnemonic             string
-	OutputIds            []artifactId
-	TemplateContent      string
-	Substitutions        []KeyValuePair
-	FileContents         string
-}
-
-// actionGraphContainer contains relevant portions of Bazel's aquery proto, ActionGraphContainer.
-// An aquery response from Bazel contains a single ActionGraphContainer proto.
-type actionGraphContainer struct {
-	Artifacts     []artifact
-	Actions       []action
-	DepSetOfFiles []depSetOfFiles
-	PathFragments []pathFragment
-}
-
 // BuildStatement contains information to register a build statement corresponding (one to one)
 // with a Bazel action from Bazel's action graph.
 type BuildStatement struct {
@@ -123,6 +81,7 @@
 	// Unlike most properties in BuildStatement, these paths must be relative to the root of
 	// the whole out/ folder, instead of relative to ctx.Config().BazelContext.OutputBase()
 	ImplicitDeps []string
+	IsExecutable bool
 }
 
 // A helper type for aquery processing which facilitates retrieval of path IDs from their
@@ -176,6 +135,21 @@
 		if err != nil {
 			return nil, err
 		}
+		if artifact.IsTreeArtifact &&
+			!strings.HasPrefix(artifactPath, "bazel-out/io_bazel_rules_go/") &&
+			!strings.HasPrefix(artifactPath, "bazel-out/rules_java_builtin/") {
+			// Since we're using ninja as an executor, we can't use tree artifacts. Ninja only
+			// considers a file/directory "dirty" when it's mtime changes. Directories' mtimes will
+			// only change when a file in the directory is added/removed, but not when files in
+			// the directory are changed, or when files in subdirectories are changed/added/removed.
+			// Bazel handles this by walking the directory and generating a hash for it after the
+			// action runs, which we would have to do as well if we wanted to support these
+			// artifacts in mixed builds.
+			//
+			// However, there are some bazel built-in rules that use tree artifacts. Allow those,
+			// but keep in mind that they'll have incrementality issues.
+			return nil, fmt.Errorf("tree artifacts are currently not supported in mixed builds: " + artifactPath)
+		}
 		artifactIdToPath[artifactId(artifact.Id)] = artifactPath
 	}
 
@@ -354,13 +328,20 @@
 		defer eventHandler.End("build_statements")
 		wg := sync.WaitGroup{}
 		var errOnce sync.Once
-
+		id2targets := make(map[uint32]string, len(aqueryProto.Targets))
+		for _, t := range aqueryProto.Targets {
+			id2targets[t.GetId()] = t.GetLabel()
+		}
 		for i, actionEntry := range aqueryProto.Actions {
 			wg.Add(1)
 			go func(i int, actionEntry *analysis_v2_proto.Action) {
-				buildStatement, aErr := aqueryHandler.actionToBuildStatement(actionEntry)
-				if aErr != nil {
+				if strings.HasPrefix(id2targets[actionEntry.TargetId], "@bazel_tools//") {
+					// bazel_tools are removed depsets in `populateDepsetMaps()` so skipping
+					// conversion to build statements as well
+					buildStatements[i] = nil
+				} else if buildStatement, aErr := aqueryHandler.actionToBuildStatement(actionEntry); aErr != nil {
 					errOnce.Do(func() {
+						aErr = fmt.Errorf("%s: [%s] [%s]", aErr.Error(), actionEntry.GetMnemonic(), id2targets[actionEntry.TargetId])
 						err = aErr
 					})
 				} else {
@@ -462,26 +443,21 @@
 
 // escapes the args received from aquery and creates a command string
 func commandString(actionEntry *analysis_v2_proto.Action) string {
-	switch actionEntry.Mnemonic {
-	case "GoCompilePkg", "GoStdlib":
-		argsEscaped := []string{}
-		for _, arg := range actionEntry.Arguments {
-			if arg == "" {
-				// If this is an empty string, add ''
-				// And not
-				// 1. (literal empty)
-				// 2. `''\'''\'''` (escaped version of '')
-				//
-				// If we had used (1), then this would appear as a whitespace when we strings.Join
-				argsEscaped = append(argsEscaped, "''")
-			} else {
-				argsEscaped = append(argsEscaped, proptools.ShellEscapeIncludingSpaces(arg))
-			}
+	argsEscaped := make([]string, len(actionEntry.Arguments))
+	for i, arg := range actionEntry.Arguments {
+		if arg == "" {
+			// If this is an empty string, add ''
+			// And not
+			// 1. (literal empty)
+			// 2. `''\'''\'''` (escaped version of '')
+			//
+			// If we had used (1), then this would appear as a whitespace when we strings.Join
+			argsEscaped[i] = "''"
+		} else {
+			argsEscaped[i] = proptools.ShellEscapeIncludingSpaces(arg)
 		}
-		return strings.Join(argsEscaped, " ")
-	default:
-		return strings.Join(proptools.ShellEscapeListIncludingSpaces(actionEntry.Arguments), " ")
 	}
+	return strings.Join(argsEscaped, " ")
 }
 
 func (a *aqueryArtifactHandler) normalActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
@@ -560,6 +536,7 @@
 		Mnemonic:          actionEntry.Mnemonic,
 		InputDepsetHashes: depsetHashes,
 		FileContents:      actionEntry.FileContents,
+		IsExecutable:      actionEntry.IsExecutable,
 	}, nil
 }
 
@@ -765,7 +742,7 @@
 	}
 
 	if len(actionEntry.Arguments) < 1 {
-		return nil, fmt.Errorf("received action with no command: [%s]", actionEntry.Mnemonic)
+		return nil, errors.New("received action with no command")
 	}
 	return a.normalActionBuildStatement(actionEntry)
 
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 32c87a0..cbd2791 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -178,8 +178,8 @@
    { "id": 2, "path_fragment_id": 2 }],
  "actions": [{
    "target_id": 1,
-   "action_key": "x",
-   "mnemonic": "x",
+   "action_key": "action_x",
+   "mnemonic": "X",
    "arguments": ["touch", "foo"],
    "input_dep_set_ids": [1],
    "output_ids": [3],
@@ -198,7 +198,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, "undefined outputId 3")
+	assertError(t, err, "undefined outputId 3: [X] []")
 }
 
 func TestInvalidInputDepsetIdFromAction(t *testing.T) {
@@ -209,13 +209,17 @@
    { "id": 2, "path_fragment_id": 2 }],
  "actions": [{
    "target_id": 1,
-   "action_key": "x",
-   "mnemonic": "x",
+   "action_key": "action_x",
+   "mnemonic": "X",
    "arguments": ["touch", "foo"],
    "input_dep_set_ids": [2],
    "output_ids": [1],
    "primary_output_id": 1
  }],
+ "targets": [{
+   "id": 1,
+   "label": "target_x"
+ }],
  "dep_set_of_files": [
    { "id": 1, "direct_artifact_ids": [1, 2] }],
  "path_fragments": [
@@ -229,7 +233,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, "undefined (not even empty) input depsetId 2")
+	assertError(t, err, "undefined (not even empty) input depsetId 2: [X] [target_x]")
 }
 
 func TestInvalidInputDepsetIdFromDepset(t *testing.T) {
@@ -383,8 +387,8 @@
    { "id": 4, "path_fragment_id": 4 }],
  "actions": [{
    "target_id": 1,
-   "action_key": "x",
-   "mnemonic": "x",
+   "action_key": "action_x",
+   "mnemonic": "X",
    "arguments": ["touch", "foo"],
    "input_dep_set_ids": [1],
    "output_ids": [2,3,4],
@@ -407,7 +411,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, `found multiple potential depfiles "two.d", "other.d"`)
+	assertError(t, err, `found multiple potential depfiles "two.d", "other.d": [X] []`)
 }
 
 func TestTransitiveInputDepsets(t *testing.T) {
@@ -559,7 +563,7 @@
 	}, actual)
 }
 
-func TestBazelOutRemovalFromInputDepsets(t *testing.T) {
+func TestBazelToolsRemovalFromInputDepsets(t *testing.T) {
 	const inputString = `{
  "artifacts": [
    { "id": 1, "path_fragment_id": 10 },
@@ -637,7 +641,55 @@
 	}
 }
 
-func TestBazelOutRemovalFromTransitiveInputDepsets(t *testing.T) {
+func TestBazelToolsRemovalFromTargets(t *testing.T) {
+	const inputString = `{
+ "artifacts": [{ "id": 1, "path_fragment_id": 10 }],
+ "targets": [
+   { "id": 100, "label": "targetX" },
+   { "id": 200, "label": "@bazel_tools//tool_y" }
+],
+ "actions": [{
+   "target_id": 100,
+   "action_key": "actionX",
+   "arguments": ["bogus", "command"],
+   "mnemonic" : "x",
+   "output_ids": [1]
+ }, {
+   "target_id": 200,
+   "action_key": "y"
+ }],
+ "path_fragments": [{ "id": 10, "label": "outputX"}]
+}`
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actualBuildStatements, actualDepsets, _ := AqueryBuildStatements(data, &metrics.EventHandler{})
+	if len(actualDepsets) != 0 {
+		t.Errorf("expected 0 depset but found %#v", actualDepsets)
+		return
+	}
+	expectedBuildStatement := &BuildStatement{
+		Command:      "bogus command",
+		OutputPaths:  []string{"outputX"},
+		Mnemonic:     "x",
+		SymlinkPaths: []string{},
+	}
+	buildStatementFound := false
+	for _, actualBuildStatement := range actualBuildStatements {
+		if buildStatementEquals(actualBuildStatement, expectedBuildStatement) == "" {
+			buildStatementFound = true
+			break
+		}
+	}
+	if !buildStatementFound {
+		t.Errorf("expected but missing %#v in %#v build statements", expectedBuildStatement, len(actualBuildStatements))
+		return
+	}
+}
+
+func TestBazelToolsRemovalFromTransitiveInputDepsets(t *testing.T) {
 	const inputString = `{
  "artifacts": [
    { "id": 1, "path_fragment_id": 10 },
@@ -939,7 +991,7 @@
    { "id": 3, "path_fragment_id": 3 }],
  "actions": [{
    "target_id": 1,
-   "action_key": "x",
+   "action_key": "action_x",
    "mnemonic": "Symlink",
    "input_dep_set_ids": [1],
    "output_ids": [3],
@@ -958,7 +1010,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]`)
+	assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]: [Symlink] []`)
 }
 
 func TestSymlinkMultipleOutputs(t *testing.T) {
@@ -989,7 +1041,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, "undefined outputId 2")
+	assertError(t, err, "undefined outputId 2: [Symlink] []")
 }
 
 func TestTemplateExpandActionSubstitutions(t *testing.T) {
@@ -1066,7 +1118,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, `Expect 1 output to template expand action, got: output []`)
+	assertError(t, err, `Expect 1 output to template expand action, got: output []: [TemplateExpand] []`)
 }
 
 func TestFileWrite(t *testing.T) {
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 671e5c1..2c9a536 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -39,7 +39,7 @@
 
 	// Targets in arch.go
 	osArchAndroidArm        = "android_arm"
-	osArchAndroidArm64      = "android_arm64"
+	OsArchAndroidArm64      = "android_arm64"
 	osArchAndroidRiscv64    = "android_riscv64"
 	osArchAndroidX86        = "android_x86"
 	osArchAndroidX86_64     = "android_x86_64"
@@ -71,11 +71,14 @@
 
 	AndroidAndInApex = "android-in_apex"
 	AndroidPlatform  = "system"
+	Unbundled_app    = "unbundled_app"
 
 	InApex  = "in_apex"
 	NonApex = "non_apex"
 
 	ErrorproneDisabled = "errorprone_disabled"
+	// TODO: b/294868620 - Remove when completing the bug
+	SanitizersEnabled = "sanitizers_enabled"
 )
 
 func PowerSetWithoutEmptySet[T any](items []T) [][]T {
@@ -130,7 +133,7 @@
 	}
 	result := make(map[string]string)
 	for arch, allFeatures := range archFeatures {
-		result[arch] = "//build/bazel/platforms/arch:" + arch
+		result[arch] = "//build/bazel_common_rules/platforms/arch:" + arch
 		// Sometimes we want to select on multiple features being active, so
 		// add the power set of all possible features to the map. More details
 		// in android.ModuleBase.GetArchVariantProperties
@@ -157,33 +160,33 @@
 	// 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{
-		OsAndroid:                  "//build/bazel/platforms/os:android",
-		OsDarwin:                   "//build/bazel/platforms/os:darwin",
-		OsLinux:                    "//build/bazel/platforms/os:linux_glibc",
-		osLinuxMusl:                "//build/bazel/platforms/os:linux_musl",
-		osLinuxBionic:              "//build/bazel/platforms/os:linux_bionic",
-		OsWindows:                  "//build/bazel/platforms/os:windows",
+		OsAndroid:                  "//build/bazel_common_rules/platforms/os:android",
+		OsDarwin:                   "//build/bazel_common_rules/platforms/os:darwin",
+		OsLinux:                    "//build/bazel_common_rules/platforms/os:linux_glibc",
+		osLinuxMusl:                "//build/bazel_common_rules/platforms/os:linux_musl",
+		osLinuxBionic:              "//build/bazel_common_rules/platforms/os:linux_bionic",
+		OsWindows:                  "//build/bazel_common_rules/platforms/os:windows",
 		ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
 	}
 
 	platformOsArchMap = map[string]string{
-		osArchAndroidArm:           "//build/bazel/platforms/os_arch:android_arm",
-		osArchAndroidArm64:         "//build/bazel/platforms/os_arch:android_arm64",
-		osArchAndroidRiscv64:       "//build/bazel/platforms/os_arch:android_riscv64",
-		osArchAndroidX86:           "//build/bazel/platforms/os_arch:android_x86",
-		osArchAndroidX86_64:        "//build/bazel/platforms/os_arch:android_x86_64",
-		osArchDarwinArm64:          "//build/bazel/platforms/os_arch:darwin_arm64",
-		osArchDarwinX86_64:         "//build/bazel/platforms/os_arch:darwin_x86_64",
-		osArchLinuxX86:             "//build/bazel/platforms/os_arch:linux_glibc_x86",
-		osArchLinuxX86_64:          "//build/bazel/platforms/os_arch:linux_glibc_x86_64",
-		osArchLinuxMuslArm:         "//build/bazel/platforms/os_arch:linux_musl_arm",
-		osArchLinuxMuslArm64:       "//build/bazel/platforms/os_arch:linux_musl_arm64",
-		osArchLinuxMuslX86:         "//build/bazel/platforms/os_arch:linux_musl_x86",
-		osArchLinuxMuslX86_64:      "//build/bazel/platforms/os_arch:linux_musl_x86_64",
-		osArchLinuxBionicArm64:     "//build/bazel/platforms/os_arch:linux_bionic_arm64",
-		osArchLinuxBionicX86_64:    "//build/bazel/platforms/os_arch:linux_bionic_x86_64",
-		osArchWindowsX86:           "//build/bazel/platforms/os_arch:windows_x86",
-		osArchWindowsX86_64:        "//build/bazel/platforms/os_arch:windows_x86_64",
+		osArchAndroidArm:           "//build/bazel_common_rules/platforms/os_arch:android_arm",
+		OsArchAndroidArm64:         "//build/bazel_common_rules/platforms/os_arch:android_arm64",
+		osArchAndroidRiscv64:       "//build/bazel_common_rules/platforms/os_arch:android_riscv64",
+		osArchAndroidX86:           "//build/bazel_common_rules/platforms/os_arch:android_x86",
+		osArchAndroidX86_64:        "//build/bazel_common_rules/platforms/os_arch:android_x86_64",
+		osArchDarwinArm64:          "//build/bazel_common_rules/platforms/os_arch:darwin_arm64",
+		osArchDarwinX86_64:         "//build/bazel_common_rules/platforms/os_arch:darwin_x86_64",
+		osArchLinuxX86:             "//build/bazel_common_rules/platforms/os_arch:linux_glibc_x86",
+		osArchLinuxX86_64:          "//build/bazel_common_rules/platforms/os_arch:linux_glibc_x86_64",
+		osArchLinuxMuslArm:         "//build/bazel_common_rules/platforms/os_arch:linux_musl_arm",
+		osArchLinuxMuslArm64:       "//build/bazel_common_rules/platforms/os_arch:linux_musl_arm64",
+		osArchLinuxMuslX86:         "//build/bazel_common_rules/platforms/os_arch:linux_musl_x86",
+		osArchLinuxMuslX86_64:      "//build/bazel_common_rules/platforms/os_arch:linux_musl_x86_64",
+		osArchLinuxBionicArm64:     "//build/bazel_common_rules/platforms/os_arch:linux_bionic_arm64",
+		osArchLinuxBionicX86_64:    "//build/bazel_common_rules/platforms/os_arch:linux_bionic_x86_64",
+		osArchWindowsX86:           "//build/bazel_common_rules/platforms/os_arch:windows_x86",
+		osArchWindowsX86_64:        "//build/bazel_common_rules/platforms/os_arch:windows_x86_64",
 		ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
 	}
 
@@ -205,11 +208,12 @@
 	osAndInApexMap = map[string]string{
 		AndroidAndInApex:           "//build/bazel/rules/apex:android-in_apex",
 		AndroidPlatform:            "//build/bazel/rules/apex:system",
-		OsDarwin:                   "//build/bazel/platforms/os:darwin",
-		OsLinux:                    "//build/bazel/platforms/os:linux_glibc",
-		osLinuxMusl:                "//build/bazel/platforms/os:linux_musl",
-		osLinuxBionic:              "//build/bazel/platforms/os:linux_bionic",
-		OsWindows:                  "//build/bazel/platforms/os:windows",
+		Unbundled_app:              "//build/bazel/rules/apex:unbundled_app",
+		OsDarwin:                   "//build/bazel_common_rules/platforms/os:darwin",
+		OsLinux:                    "//build/bazel_common_rules/platforms/os:linux_glibc",
+		osLinuxMusl:                "//build/bazel_common_rules/platforms/os:linux_musl",
+		osLinuxBionic:              "//build/bazel_common_rules/platforms/os:linux_bionic",
+		OsWindows:                  "//build/bazel_common_rules/platforms/os:windows",
 		ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
 	}
 
@@ -223,6 +227,12 @@
 		ErrorproneDisabled:         "//build/bazel/rules/java/errorprone:errorprone_globally_disabled",
 		ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
 	}
+
+	// TODO: b/294868620 - Remove when completing the bug
+	sanitizersEnabledMap = map[string]string{
+		SanitizersEnabled:          "//build/bazel/rules/cc:sanitizers_enabled",
+		ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
+	}
 )
 
 // basic configuration types
@@ -237,6 +247,8 @@
 	osAndInApex
 	inApex
 	errorProneDisabled
+	// TODO: b/294868620 - Remove when completing the bug
+	sanitizersEnabled
 )
 
 func osArchString(os string, arch string) string {
@@ -253,6 +265,8 @@
 		osAndInApex:        "os_in_apex",
 		inApex:             "in_apex",
 		errorProneDisabled: "errorprone_disabled",
+		// TODO: b/294868620 - Remove when completing the bug
+		sanitizersEnabled: "sanitizers_enabled",
 	}[ct]
 }
 
@@ -287,6 +301,11 @@
 		if _, ok := errorProneMap[config]; !ok {
 			panic(fmt.Errorf("Unknown errorprone config: %s", config))
 		}
+	// TODO: b/294868620 - Remove when completing the bug
+	case sanitizersEnabled:
+		if _, ok := sanitizersEnabledMap[config]; !ok {
+			panic(fmt.Errorf("Unknown sanitizers_enabled config: %s", config))
+		}
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
 	}
@@ -318,6 +337,9 @@
 		return inApexMap[config]
 	case errorProneDisabled:
 		return errorProneMap[config]
+	// TODO: b/294868620 - Remove when completing the bug
+	case sanitizersEnabled:
+		return sanitizersEnabledMap[config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
 	}
@@ -338,6 +360,9 @@
 	InApexAxis = ConfigurationAxis{configurationType: inApex}
 
 	ErrorProneAxis = ConfigurationAxis{configurationType: errorProneDisabled}
+
+	// TODO: b/294868620 - Remove when completing the bug
+	SanitizersEnabledAxis = ConfigurationAxis{configurationType: sanitizersEnabled}
 )
 
 // ProductVariableConfigurationAxis returns an axis for the given product variable
diff --git a/bazel/properties.go b/bazel/properties.go
index 702c31c..9c63bc0 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -194,14 +194,7 @@
 // UniqueSortedBazelLabels takes a []Label and deduplicates the labels, and returns
 // the slice in a sorted order.
 func UniqueSortedBazelLabels(originalLabels []Label) []Label {
-	uniqueLabelsSet := make(map[Label]bool)
-	for _, l := range originalLabels {
-		uniqueLabelsSet[l] = true
-	}
-	var uniqueLabels []Label
-	for l, _ := range uniqueLabelsSet {
-		uniqueLabels = append(uniqueLabels, l)
-	}
+	uniqueLabels := FirstUniqueBazelLabels(originalLabels)
 	sort.SliceStable(uniqueLabels, func(i, j int) bool {
 		return uniqueLabels[i].Label < uniqueLabels[j].Label
 	})
@@ -210,13 +203,13 @@
 
 func FirstUniqueBazelLabels(originalLabels []Label) []Label {
 	var labels []Label
-	found := make(map[Label]bool, len(originalLabels))
+	found := make(map[string]bool, len(originalLabels))
 	for _, l := range originalLabels {
-		if _, ok := found[l]; ok {
+		if _, ok := found[l.Label]; ok {
 			continue
 		}
 		labels = append(labels, l)
-		found[l] = true
+		found[l.Label] = true
 	}
 	return labels
 }
@@ -433,7 +426,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		la.Value = &value
-	case arch, os, osArch, productVariables, osAndInApex:
+	case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
 		if la.ConfigurableValues == nil {
 			la.ConfigurableValues = make(configurableLabels)
 		}
@@ -449,7 +442,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return la.Value
-	case arch, os, osArch, productVariables, osAndInApex:
+	case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
 		return la.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -519,7 +512,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		ba.Value = value
-	case arch, os, osArch, productVariables, osAndInApex:
+	case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
 		if ba.ConfigurableValues == nil {
 			ba.ConfigurableValues = make(configurableBools)
 		}
@@ -666,7 +659,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return ba.Value
-	case arch, os, osArch, productVariables, osAndInApex:
+	case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
 		if v, ok := ba.ConfigurableValues[axis][config]; ok {
 			return &v
 		} else {
@@ -801,7 +794,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		lla.Value = list
-	case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled:
+	case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled, sanitizersEnabled:
 		if lla.ConfigurableValues == nil {
 			lla.ConfigurableValues = make(configurableLabelLists)
 		}
@@ -817,7 +810,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return lla.Value
-	case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled:
+	case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled, sanitizersEnabled:
 		return lla.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -1175,7 +1168,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		sa.Value = str
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, productVariables, sanitizersEnabled:
 		if sa.ConfigurableValues == nil {
 			sa.ConfigurableValues = make(configurableStrings)
 		}
@@ -1191,7 +1184,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return sa.Value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, productVariables, sanitizersEnabled:
 		if v, ok := sa.ConfigurableValues[axis][config]; ok {
 			return v
 		} else {
@@ -1381,7 +1374,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		sla.Value = list
-	case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled:
+	case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled, sanitizersEnabled:
 		if sla.ConfigurableValues == nil {
 			sla.ConfigurableValues = make(configurableStringLists)
 		}
@@ -1397,7 +1390,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return sla.Value
-	case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled:
+	case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled, sanitizersEnabled:
 		return sla.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
index c98ae0e..751cb8b 100644
--- a/bazel/properties_test.go
+++ b/bazel/properties_test.go
@@ -33,8 +33,12 @@
 				{Label: "b"},
 				{Label: "a"},
 				{Label: "c"},
+				// namespaces
+				{Label: "//foo:bar", OriginalModuleName: "bar"},       // when referenced from foo namespace
+				{Label: "//foo:bar", OriginalModuleName: "//foo:bar"}, // when reference from root namespace
 			},
 			expectedUniqueLabels: []Label{
+				{Label: "//foo:bar", OriginalModuleName: "bar"},
 				{Label: "a"},
 				{Label: "b"},
 				{Label: "c"},
@@ -194,6 +198,9 @@
 					{Label: "b"},
 					{Label: "a"},
 					{Label: "c"},
+					// namespaces
+					{Label: "//foo:bar", OriginalModuleName: "bar"},       // when referenced from foo namespace
+					{Label: "//foo:bar", OriginalModuleName: "//foo:bar"}, // when referenced from root namespace
 				},
 				Excludes: []Label{
 					{Label: "x"},
@@ -207,6 +214,7 @@
 					{Label: "a"},
 					{Label: "b"},
 					{Label: "c"},
+					{Label: "//foo:bar", OriginalModuleName: "bar"},
 				},
 				Excludes: []Label{
 					{Label: "x"},
diff --git a/bin/build-flag b/bin/build-flag
new file mode 100755
index 0000000..dc404bc
--- /dev/null
+++ b/bin/build-flag
@@ -0,0 +1,28 @@
+#!/bin/bash -eu
+#
+# Copyright 2017 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils.sh
+require_top
+
+# Save the current PWD for use in soong_ui
+export ORIGINAL_PWD=${PWD}
+export TOP=$(gettop)
+source ${TOP}/build/soong/scripts/microfactory.bash
+
+soong_build_go build-flag android/soong/cmd/release_config/build_flag
+
+cd ${TOP}
+exec "$(getoutdir)/build-flag" "$@"
diff --git a/bin/soongdbg b/bin/soongdbg
new file mode 100755
index 0000000..bfdbbde
--- /dev/null
+++ b/bin/soongdbg
@@ -0,0 +1,424 @@
+#!/usr/bin/env python3
+
+import argparse
+import fnmatch
+import html
+import io
+import json
+import os
+import pathlib
+import subprocess
+import types
+import sys
+
+
+class Graph:
+    def __init__(self, modules):
+        def get_or_make_node(dictionary, id, module):
+            node = dictionary.get(id)
+            if node:
+                if module and not node.module:
+                    node.module = module
+                return node
+            node = Node(id, module)
+            dictionary[id] = node
+            return node
+        self.nodes = dict()
+        for module in modules.values():
+            node = get_or_make_node(self.nodes, module.id, module)
+            for d in module.deps:
+                dep = get_or_make_node(self.nodes, d.id, None)
+                node.deps.add(dep)
+                dep.rdeps.add(node)
+                node.dep_tags.setdefault(dep, list()).append(d)
+
+    def find_paths(self, id1, id2):
+        # Throws KeyError if one of the names isn't found
+        def recurse(node1, node2, visited):
+            result = set()
+            for dep in node1.rdeps:
+                if dep == node2:
+                    result.add(node2)
+                if dep not in visited:
+                    visited.add(dep)
+                    found = recurse(dep, node2, visited)
+                    if found:
+                        result |= found
+                        result.add(dep)
+            return result
+        node1 = self.nodes[id1]
+        node2 = self.nodes[id2]
+        # Take either direction
+        p = recurse(node1, node2, set())
+        if p:
+            p.add(node1)
+            return p
+        p = recurse(node2, node1, set())
+        p.add(node2)
+        return p
+
+
+class Node:
+    def __init__(self, id, module):
+        self.id = id
+        self.module = module
+        self.deps = set()
+        self.rdeps = set()
+        self.dep_tags = {}
+
+
+PROVIDERS = [
+    "android/soong/java.JarJarProviderData",
+    "android/soong/java.BaseJarJarProviderData",
+]
+
+
+def format_dep_label(node, dep):
+    tags = node.dep_tags.get(dep)
+    labels = []
+    if tags:
+        labels = [tag.tag_type.split("/")[-1] for tag in tags]
+        labels = sorted(set(labels))
+    if labels:
+        result = "<<table border=\"0\" cellborder=\"0\" cellspacing=\"0\" cellpadding=\"0\">"
+        for label in labels:
+            result += f"<tr><td>{label}</td></tr>"
+        result += "</table>>"
+        return result
+
+
+def format_node_label(node, module_formatter):
+    result = "<<table border=\"0\" cellborder=\"0\" cellspacing=\"0\" cellpadding=\"0\">"
+
+    # node name
+    result += f"<tr><td><b>{node.module.name if node.module else node.id}</b></td></tr>"
+
+    if node.module:
+        # node_type
+        result += f"<tr><td>{node.module.type}</td></tr>"
+
+        # module_formatter will return a list of rows
+        for row in module_formatter(node.module):
+            row = html.escape(row)
+            result += f"<tr><td><font color=\"#666666\">{row}</font></td></tr>"
+
+    result += "</table>>"
+    return result
+
+
+def format_source_pos(file, lineno):
+    result = file
+    if lineno:
+        result += f":{lineno}"
+    return result
+
+
+STRIP_TYPE_PREFIXES = [
+    "android/soong/",
+    "github.com/google/",
+]
+
+
+def format_provider(provider):
+    result = ""
+    for prefix in STRIP_TYPE_PREFIXES:
+        if provider.type.startswith(prefix):
+            result = provider.type[len(prefix):]
+            break
+    if not result:
+        result = provider.type
+    if True and provider.debug:
+        result += " (" + provider.debug + ")"
+    return result
+
+
+def load_soong_debug():
+    # Read the json
+    try:
+        with open(SOONG_DEBUG_DATA_FILENAME) as f:
+            info = json.load(f, object_hook=lambda d: types.SimpleNamespace(**d))
+    except IOError:
+        sys.stderr.write(f"error: Unable to open {SOONG_DEBUG_DATA_FILENAME}. Make sure you have"
+                         + " built with GENERATE_SOONG_DEBUG.\n")
+        sys.exit(1)
+
+    # Construct IDs, which are name + variant if the
+    name_counts = dict()
+    for m in info.modules:
+        name_counts[m.name] = name_counts.get(m.name, 0) + 1
+    def get_id(m):
+        result = m.name
+        if name_counts[m.name] > 1 and m.variant:
+            result += "@@" + m.variant
+        return result
+    for m in info.modules:
+        m.id = get_id(m)
+        for dep in m.deps:
+            dep.id = get_id(dep)
+
+    return info
+
+
+def load_modules():
+    info = load_soong_debug()
+
+    # Filter out unnamed modules
+    modules = dict()
+    for m in info.modules:
+        if not m.name:
+            continue
+        modules[m.id] = m
+
+    return modules
+
+
+def load_graph():
+    modules=load_modules()
+    return Graph(modules)
+
+
+def module_selection_args(parser):
+    parser.add_argument("modules", nargs="*",
+                        help="Modules to match. Can be glob-style wildcards.")
+    parser.add_argument("--provider", nargs="+",
+                        help="Match the given providers.")
+    parser.add_argument("--dep", nargs="+",
+                        help="Match the given providers.")
+
+
+def load_and_filter_modules(args):
+    # Which modules are printed
+    matchers = []
+    if args.modules:
+        matchers.append(lambda m: [True for pattern in args.modules
+                                   if fnmatch.fnmatchcase(m.name, pattern)])
+    if args.provider:
+        matchers.append(lambda m: [True for pattern in args.provider
+                                   if [True for p in m.providers if p.type.endswith(pattern)]])
+    if args.dep:
+        matchers.append(lambda m: [True for pattern in args.dep
+                                   if [True for d in m.deps if d.id == pattern]])
+
+    if not matchers:
+        sys.stderr.write("error: At least one module matcher must be supplied\n")
+        sys.exit(1)
+
+    info = load_soong_debug()
+    for m in sorted(info.modules, key=lambda m: (m.name, m.variant)):
+        if len([matcher for matcher in matchers if matcher(m)]) == len(matchers):
+            yield m
+
+
+def print_args(parser):
+    parser.add_argument("--label", action="append", metavar="JQ_FILTER",
+                        help="jq query for each module metadata")
+    parser.add_argument("--deptags", action="store_true",
+                        help="show dependency tags (makes the graph much more complex)")
+
+    group = parser.add_argument_group("output formats",
+                                      "If no format is provided, a dot file will be written to"
+                                      + " stdout.")
+    output = group.add_mutually_exclusive_group()
+    output.add_argument("--dot", type=str, metavar="FILENAME",
+                        help="Write the graph to this file as dot (graphviz format)")
+    output.add_argument("--svg", type=str, metavar="FILENAME",
+                        help="Write the graph to this file as svg")
+
+
+def print_nodes(args, nodes, module_formatter):
+    # Generate the graphviz
+    dep_tag_id = 0
+    dot = io.StringIO()
+    dot.write("digraph {\n")
+    dot.write("node [shape=box];")
+
+    for node in nodes:
+        dot.write(f"\"{node.id}\" [label={format_node_label(node, module_formatter)}];\n")
+        for dep in node.deps:
+            if dep in nodes:
+                if args.deptags:
+                    dot.write(f"\"{node.id}\" -> \"__dep_tag_{dep_tag_id}\" [ arrowhead=none ];\n")
+                    dot.write(f"\"__dep_tag_{dep_tag_id}\" -> \"{dep.id}\";\n")
+                    dot.write(f"\"__dep_tag_{dep_tag_id}\""
+                                  + f"[label={format_dep_label(node, dep)} shape=ellipse"
+                                  + " color=\"#666666\" fontcolor=\"#666666\"];\n")
+                else:
+                    dot.write(f"\"{node.id}\" -> \"{dep.id}\";\n")
+                dep_tag_id += 1
+    dot.write("}\n")
+    text = dot.getvalue()
+
+    # Write it somewhere
+    if args.dot:
+        with open(args.dot, "w") as f:
+            f.write(text)
+    elif args.svg:
+        subprocess.run(["dot", "-Tsvg", "-o", args.svg],
+                              input=text, text=True, check=True)
+    else:
+        sys.stdout.write(text)
+
+
+def get_deps(nodes, root, maxdepth, reverse):
+    if root in nodes:
+        return
+    nodes.add(root)
+    if maxdepth != 0:
+        for dep in (root.rdeps if reverse else root.deps):
+            get_deps(nodes, dep, maxdepth-1, reverse)
+
+
+def new_module_formatter(args):
+    def module_formatter(module):
+        if not args.label:
+            return []
+        result = []
+        text = json.dumps(module, default=lambda o: o.__dict__)
+        for jq_filter in args.label:
+            proc = subprocess.run(["jq", jq_filter],
+                                  input=text, text=True, check=True, stdout=subprocess.PIPE)
+            if proc.stdout:
+                o = json.loads(proc.stdout)
+                if type(o) == list:
+                    for row in o:
+                        if row:
+                            result.append(row)
+                elif type(o) == dict:
+                    result.append(str(proc.stdout).strip())
+                else:
+                    if o:
+                        result.append(str(o).strip())
+        return result
+    return module_formatter
+
+
+class BetweenCommand:
+    help = "Print the module graph between two nodes."
+
+    def args(self, parser):
+        parser.add_argument("module", nargs=2,
+                            help="the two modules")
+        print_args(parser)
+
+    def run(self, args):
+        graph = load_graph()
+        print_nodes(args, graph.find_paths(args.module[0], args.module[1]),
+                    new_module_formatter(args))
+
+
+class DepsCommand:
+    help = "Print the module graph of dependencies of one or more modules"
+
+    def args(self, parser):
+        parser.add_argument("module", nargs="+",
+                            help="Module to print dependencies of")
+        parser.add_argument("--reverse", action="store_true",
+                            help="traverse reverse dependencies")
+        parser.add_argument("--depth", type=int, default=-1,
+                            help="max depth of dependencies (can keep the graph size reasonable)")
+        print_args(parser)
+
+    def run(self, args):
+        graph = load_graph()
+        nodes = set()
+        err = False
+        for id in args.module:
+            root = graph.nodes.get(id)
+            if not root:
+                sys.stderr.write(f"error: Can't find root: {id}\n")
+                err = True
+                continue
+            get_deps(nodes, root, args.depth, args.reverse)
+        if err:
+            sys.exit(1)
+        print_nodes(args, nodes, new_module_formatter(args))
+
+
+class IdCommand:
+    help = "Print the id (name + variant) of matching modules"
+
+    def args(self, parser):
+        module_selection_args(parser)
+
+    def run(self, args):
+        for m in load_and_filter_modules(args):
+            print(m.id)
+
+
+class JsonCommand:
+    help = "Print metadata about modules in json format"
+
+    def args(self, parser):
+        module_selection_args(parser)
+        parser.add_argument("--list", action="store_true",
+                            help="Print the results in a json list. If not set and multiple"
+                            + " modules are matched, the output won't be valid json.")
+
+    def run(self, args):
+        modules = load_and_filter_modules(args)
+        if args.list:
+            json.dump([m for m in modules], sys.stdout, indent=4, default=lambda o: o.__dict__)
+        else:
+            for m in modules:
+                json.dump(m, sys.stdout, indent=4, default=lambda o: o.__dict__)
+                print()
+
+
+class QueryCommand:
+    help = "Query details about modules"
+
+    def args(self, parser):
+        module_selection_args(parser)
+
+    def run(self, args):
+        for m in load_and_filter_modules(args):
+            print(m.id)
+            print(f"    type:     {m.type}")
+            print(f"    location: {format_source_pos(m.source_file, m.source_line)}")
+            for p in m.providers:
+                print(f"    provider: {format_provider(p)}")
+            for d in m.deps:
+                print(f"    dep:      {d.id}")
+
+
+COMMANDS = {
+    "between": BetweenCommand(),
+    "deps": DepsCommand(),
+    "id": IdCommand(),
+    "json": JsonCommand(),
+    "query": QueryCommand(),
+}
+
+
+def assert_env(name):
+    val = os.getenv(name)
+    if not val:
+        sys.stderr.write(f"{name} not set. please make sure you've run lunch.")
+    return val
+
+ANDROID_BUILD_TOP = assert_env("ANDROID_BUILD_TOP")
+
+TARGET_PRODUCT = assert_env("TARGET_PRODUCT")
+OUT_DIR = os.getenv("OUT_DIR")
+if not OUT_DIR:
+    OUT_DIR = "out"
+if OUT_DIR[0] != "/":
+    OUT_DIR = pathlib.Path(ANDROID_BUILD_TOP).joinpath(OUT_DIR)
+SOONG_DEBUG_DATA_FILENAME = pathlib.Path(OUT_DIR).joinpath("soong/soong-debug-info.json")
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    subparsers = parser.add_subparsers(required=True, dest="command")
+    for name in sorted(COMMANDS.keys()):
+        command = COMMANDS[name]
+        subparser = subparsers.add_parser(name, help=command.help)
+        command.args(subparser)
+    args = parser.parse_args()
+    COMMANDS[args.command].run(args)
+    sys.exit(0)
+
+
+if __name__ == "__main__":
+    main()
+
diff --git a/bloaty/bloaty.go b/bloaty/bloaty.go
index 3cff60f..b72b6d3 100644
--- a/bloaty/bloaty.go
+++ b/bloaty/bloaty.go
@@ -26,7 +26,7 @@
 const protoFilename = "binary_sizes.pb.gz"
 
 var (
-	fileSizeMeasurerKey blueprint.ProviderKey
+	fileSizeMeasurerKey blueprint.ProviderKey[measuredFiles]
 	pctx                = android.NewPackageContext("android/soong/bloaty")
 
 	// bloaty is used to measure a binary section sizes.
@@ -52,7 +52,7 @@
 	pctx.SourcePathVariable("bloaty", "prebuilts/build-tools/${hostPrebuiltTag}/bin/bloaty")
 	pctx.HostBinToolVariable("bloatyMerger", "bloaty_merger")
 	android.RegisterParallelSingletonType("file_metrics", fileSizesSingleton)
-	fileSizeMeasurerKey = blueprint.NewProvider(measuredFiles{})
+	fileSizeMeasurerKey = blueprint.NewProvider[measuredFiles]()
 }
 
 // measuredFiles contains the paths of the files measured by a module.
@@ -73,7 +73,7 @@
 			mf.paths = append(mf.paths, p)
 		}
 	}
-	ctx.SetProvider(fileSizeMeasurerKey, mf)
+	android.SetProvider(ctx, fileSizeMeasurerKey, mf)
 }
 
 type sizesSingleton struct{}
@@ -85,10 +85,13 @@
 func (singleton *sizesSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	var deps android.Paths
 	ctx.VisitAllModules(func(m android.Module) {
-		if !ctx.ModuleHasProvider(m, fileSizeMeasurerKey) {
+		if !m.ExportedToMake() {
 			return
 		}
-		filePaths := ctx.ModuleProvider(m, fileSizeMeasurerKey).(measuredFiles)
+		filePaths, ok := android.SingletonModuleProvider(ctx, m, fileSizeMeasurerKey)
+		if !ok {
+			return
+		}
 		for _, path := range filePaths.paths {
 			filePath := path.(android.ModuleOutPath)
 			sizeFile := filePath.InSameDir(ctx, filePath.Base()+bloatyDescriptorExt)
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 4a3786f..ba12682 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -7,20 +7,16 @@
     pkgPath: "android/soong/bp2build",
     srcs: [
         "androidbp_to_build_templates.go",
-        "bp2build.go",
-        "bp2build_product_config.go",
         "build_conversion.go",
         "bzl_conversion.go",
         "configurability.go",
         "constants.go",
         "conversion.go",
-        "metrics.go",
-        "symlink_forest.go",
-        "testing.go",
     ],
     deps: [
         "blueprint-bootstrap",
         "soong-aidl-library",
+        "soong-aconfig",
         "soong-android",
         "soong-android-allowlists",
         "soong-android-soongconfig",
@@ -32,58 +28,14 @@
         "soong-genrule",
         "soong-linkerconfig",
         "soong-python",
+        "soong-rust",
         "soong-sh",
         "soong-shared",
         "soong-starlark-format",
         "soong-ui-metrics",
     ],
     testSrcs: [
-        "go_conversion_test.go",
-        "aar_conversion_test.go",
-        "aidl_library_conversion_test.go",
-        "android_app_certificate_conversion_test.go",
-        "android_app_conversion_test.go",
-        "apex_conversion_test.go",
-        "apex_key_conversion_test.go",
-        "build_conversion_test.go",
-        "bp2build_product_config_test.go",
-        "bzl_conversion_test.go",
-        "cc_binary_conversion_test.go",
-        "cc_library_conversion_test.go",
-        "cc_library_headers_conversion_test.go",
-        "cc_library_shared_conversion_test.go",
-        "cc_library_static_conversion_test.go",
-        "cc_object_conversion_test.go",
-        "cc_prebuilt_library_conversion_test.go",
-        "cc_prebuilt_library_shared_test.go",
-        "cc_prebuilt_library_static_test.go",
-        "cc_prebuilt_object_conversion_test.go",
-        "cc_test_conversion_test.go",
-        "cc_yasm_conversion_test.go",
         "conversion_test.go",
-        "droidstubs_conversion_test.go",
-        "filegroup_conversion_test.go",
-        "genrule_conversion_test.go",
-        "gensrcs_conversion_test.go",
-        "java_binary_host_conversion_test.go",
-        "java_host_for_device_conversion_test.go",
-        "java_import_conversion_test.go",
-        "java_library_conversion_test.go",
-        "java_library_host_conversion_test.go",
-        "java_plugin_conversion_test.go",
-        "java_proto_conversion_test.go",
-        "license_conversion_test.go",
-        "license_kind_conversion_test.go",
-        "linker_config_conversion_test.go",
-        "package_conversion_test.go",
-        "performance_test.go",
-        "platform_compat_config_conversion_test.go",
-        "prebuilt_etc_conversion_test.go",
-        "python_binary_conversion_test.go",
-        "python_library_conversion_test.go",
-        "python_test_conversion_test.go",
-        "sh_conversion_test.go",
-        "soong_config_module_type_conversion_test.go",
     ],
     pluginFor: [
         "soong_build",
diff --git a/bp2build/aar_conversion_test.go b/bp2build/aar_conversion_test.go
deleted file mode 100644
index 09d9dc1..0000000
--- a/bp2build/aar_conversion_test.go
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"android/soong/android"
-	"android/soong/java"
-	"fmt"
-
-	"testing"
-)
-
-func TestConvertAndroidLibrary(t *testing.T) {
-	t.Helper()
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
-		Description:                "Android Library - simple example",
-		ModuleTypeUnderTest:        "android_library",
-		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
-		Filesystem: map[string]string{
-			"lib.java":                     "",
-			"arm.java":                     "",
-			"x86.java":                     "",
-			"res/res.png":                  "",
-			"manifest/AndroidManifest.xml": "",
-		},
-		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
-android_library {
-        name: "TestLib",
-        srcs: ["lib.java"],
-        arch: {
-			arm: {
-				srcs: ["arm.java"],
-			},
-			x86: {
-				srcs: ["x86.java"],
-			}
-		},
-        manifest: "manifest/AndroidManifest.xml",
-        static_libs: ["static_lib_dep"],
-        java_version: "7",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget(
-				"android_library",
-				"TestLib",
-				AttrNameToString{
-					"srcs": `["lib.java"] + select({
-        "//build/bazel/platforms/arch:arm": ["arm.java"],
-        "//build/bazel/platforms/arch:x86": ["x86.java"],
-        "//conditions:default": [],
-    })`,
-					"manifest":       `"manifest/AndroidManifest.xml"`,
-					"resource_files": `["res/res.png"]`,
-					"deps":           `[":static_lib_dep"]`,
-					"exports":        `[":static_lib_dep"]`,
-					"java_version":   `"7"`,
-				}),
-			MakeNeverlinkDuplicateTargetWithAttrs(
-				"android_library",
-				"TestLib",
-				AttrNameToString{"java_version": `"7"`}),
-		}})
-}
-
-func TestConvertAndroidLibraryWithNoSources(t *testing.T) {
-	t.Helper()
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
-		Description:                "Android Library - modules with deps must have sources",
-		ModuleTypeUnderTest:        "android_library",
-		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
-		Filesystem: map[string]string{
-			"res/res.png":         "",
-			"AndroidManifest.xml": "",
-		},
-		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "lib_dep") + `
-android_library {
-        name: "TestLib",
-        srcs: [],
-        manifest: "AndroidManifest.xml",
-        libs: ["lib_dep"],
-}
-`,
-		ExpectedErr:          fmt.Errorf("Module has direct dependencies but no sources. Bazel will not allow this."),
-		ExpectedBazelTargets: []string{},
-	})
-}
-
-func TestConvertAndroidLibraryImport(t *testing.T) {
-	t.Helper()
-	RunBp2BuildTestCase(
-		t,
-		func(ctx android.RegistrationContext) {
-			ctx.RegisterModuleType("android_library", java.AndroidLibraryFactory)
-		},
-		Bp2buildTestCase{
-			Description:                "Android Library Import",
-			ModuleTypeUnderTest:        "android_library_import",
-			ModuleTypeUnderTestFactory: java.AARImportFactory,
-			Filesystem: map[string]string{
-				"import.aar": "",
-			},
-			// Bazel's aar_import can only export *_import targets, so we expect
-			// only "static_import_dep" in exports, but both "static_lib_dep" and
-			// "static_import_dep" in deps
-			Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") +
-				simpleModuleDoNotConvertBp2build("android_library_import", "static_import_dep") + `
-android_library_import {
-        name: "TestImport",
-        aars: ["import.aar"],
-        static_libs: ["static_lib_dep", "static_import_dep"],
-}
-`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget(
-					"aar_import",
-					"TestImport",
-					AttrNameToString{
-						"aar": `"import.aar"`,
-						"deps": `[
-        ":static_lib_dep",
-        ":static_import_dep",
-    ]`,
-						"exports": `[":static_import_dep"]`,
-					},
-				),
-				MakeNeverlinkDuplicateTarget("android_library", "TestImport"),
-			},
-		},
-	)
-}
-
-func TestConvertAndroidLibraryKotlin(t *testing.T) {
-	t.Helper()
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
-		Description:                "Android Library with .kt srcs and common_srcs attribute",
-		ModuleTypeUnderTest:        "android_library",
-		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
-		Filesystem: map[string]string{
-			"AndroidManifest.xml": "",
-		},
-		Blueprint: `
-android_library {
-        name: "TestLib",
-        srcs: ["a.java", "b.kt"],
-        common_srcs: ["c.kt"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget(
-				"android_library",
-				"TestLib",
-				AttrNameToString{
-					"srcs": `[
-        "a.java",
-        "b.kt",
-    ]`,
-					"common_srcs":    `["c.kt"]`,
-					"manifest":       `"AndroidManifest.xml"`,
-					"resource_files": `[]`,
-				}),
-			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
-		}})
-}
-
-func TestConvertAndroidLibraryKotlinCflags(t *testing.T) {
-	t.Helper()
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
-		Description:                "Android Library with .kt srcs and kotlincflags ",
-		ModuleTypeUnderTest:        "android_library",
-		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
-		Filesystem: map[string]string{
-			"AndroidManifest.xml": "",
-		},
-		Blueprint: `
-android_library {
-        name: "TestLib",
-        srcs: ["a.java", "b.kt"],
-        kotlincflags: ["-flag1", "-flag2"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget(
-				"android_library",
-				"TestLib",
-				AttrNameToString{
-					"srcs": `[
-        "a.java",
-        "b.kt",
-    ]`,
-					"kotlincflags": `[
-        "-flag1",
-        "-flag2",
-    ]`,
-					"manifest":       `"AndroidManifest.xml"`,
-					"resource_files": `[]`,
-				}),
-			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
-		}})
-}
diff --git a/bp2build/aidl_library_conversion_test.go b/bp2build/aidl_library_conversion_test.go
deleted file mode 100644
index 0522da4..0000000
--- a/bp2build/aidl_library_conversion_test.go
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/aidl_library"
-	"android/soong/android"
-)
-
-func runAidlLibraryTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "aidl_library"
-	(&tc).ModuleTypeUnderTestFactory = aidl_library.AidlLibraryFactory
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
-}
-
-func TestAidlLibrary(t *testing.T) {
-	testcases := []struct {
-		name               string
-		bp                 string
-		expectedBazelAttrs AttrNameToString
-	}{
-		{
-			name: "aidl_library with strip_import_prefix",
-			bp: `
-	aidl_library {
-		name: "foo",
-		srcs: ["aidl/foo.aidl"],
-		hdrs: ["aidl/header.aidl"],
-		strip_import_prefix: "aidl",
-	}`,
-			expectedBazelAttrs: AttrNameToString{
-				"srcs":                `["aidl/foo.aidl"]`,
-				"hdrs":                `["aidl/header.aidl"]`,
-				"strip_import_prefix": `"aidl"`,
-				"tags":                `["apex_available=//apex_available:anyapex"]`,
-			},
-		},
-		{
-			name: "aidl_library without strip_import_prefix",
-			bp: `
-	aidl_library {
-		name: "foo",
-		srcs: ["aidl/foo.aidl"],
-		hdrs: ["aidl/header.aidl"],
-	}`,
-			expectedBazelAttrs: AttrNameToString{
-				"srcs": `["aidl/foo.aidl"]`,
-				"hdrs": `["aidl/header.aidl"]`,
-				"tags": `["apex_available=//apex_available:anyapex"]`,
-			},
-		},
-	}
-
-	for _, test := range testcases {
-		t.Run(test.name, func(t *testing.T) {
-			expectedBazelTargets := []string{
-				MakeBazelTargetNoRestrictions("aidl_library", "foo", test.expectedBazelAttrs),
-			}
-			runAidlLibraryTestCase(t, Bp2buildTestCase{
-				Description:          test.name,
-				Blueprint:            test.bp,
-				ExpectedBazelTargets: expectedBazelTargets,
-			})
-		})
-	}
-}
-
-func TestAidlLibraryWithDeps(t *testing.T) {
-	bp := `
-	aidl_library {
-		name: "bar",
-		srcs: ["Bar.aidl"],
-		hdrs: ["aidl/BarHeader.aidl"],
-	}
-	aidl_library {
-		name: "foo",
-		srcs: ["aidl/Foo.aidl"],
-		hdrs: ["aidl/FooHeader.aidl"],
-		strip_import_prefix: "aidl",
-		deps: ["bar"],
-	}`
-
-	t.Run("aidl_library with deps", func(t *testing.T) {
-		expectedBazelTargets := []string{
-			MakeBazelTargetNoRestrictions("aidl_library", "bar", AttrNameToString{
-				"srcs": `["Bar.aidl"]`,
-				"hdrs": `["aidl/BarHeader.aidl"]`,
-				"tags": `["apex_available=//apex_available:anyapex"]`,
-			}),
-			MakeBazelTargetNoRestrictions("aidl_library", "foo", AttrNameToString{
-				"srcs":                `["aidl/Foo.aidl"]`,
-				"hdrs":                `["aidl/FooHeader.aidl"]`,
-				"strip_import_prefix": `"aidl"`,
-				"deps":                `[":bar"]`,
-				"tags":                `["apex_available=//apex_available:anyapex"]`,
-			}),
-		}
-		runAidlLibraryTestCase(t, Bp2buildTestCase{
-			Description:          "aidl_library with deps",
-			Blueprint:            bp,
-			ExpectedBazelTargets: expectedBazelTargets,
-		})
-	})
-}
diff --git a/bp2build/android_app_certificate_conversion_test.go b/bp2build/android_app_certificate_conversion_test.go
deleted file mode 100644
index 0104513..0000000
--- a/bp2build/android_app_certificate_conversion_test.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"android/soong/android"
-	"android/soong/java"
-
-	"testing"
-)
-
-func runAndroidAppCertificateTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	RunBp2BuildTestCase(t, registerAndroidAppCertificateModuleTypes, tc)
-}
-
-func registerAndroidAppCertificateModuleTypes(ctx android.RegistrationContext) {
-}
-
-func TestAndroidAppCertificateSimple(t *testing.T) {
-	runAndroidAppCertificateTestCase(t, Bp2buildTestCase{
-		Description:                "Android app certificate - simple example",
-		ModuleTypeUnderTest:        "android_app_certificate",
-		ModuleTypeUnderTestFactory: java.AndroidAppCertificateFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: `
-android_app_certificate {
-        name: "com.android.apogee.cert",
-        certificate: "chamber_of_secrets_dir",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTargetNoRestrictions("android_app_certificate", "com.android.apogee.cert", AttrNameToString{
-				"certificate": `"chamber_of_secrets_dir"`,
-			}),
-		}})
-}
diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go
deleted file mode 100644
index d1b4d40..0000000
--- a/bp2build/android_app_conversion_test.go
+++ /dev/null
@@ -1,404 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"android/soong/android"
-	"android/soong/java"
-
-	"testing"
-)
-
-func runAndroidAppTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	RunBp2BuildTestCase(t, registerAndroidAppModuleTypes, tc)
-}
-
-func registerAndroidAppModuleTypes(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
-	ctx.RegisterModuleType("java_library", java.LibraryFactory)
-}
-
-func TestMinimalAndroidApp(t *testing.T) {
-	runAndroidAppTestCase(t, Bp2buildTestCase{
-		Description:                "Android app - simple example",
-		ModuleTypeUnderTest:        "android_app",
-		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
-		Filesystem: map[string]string{
-			"app.java":            "",
-			"res/res.png":         "",
-			"AndroidManifest.xml": "",
-		},
-		Blueprint: `
-android_app {
-        name: "TestApp",
-        srcs: ["app.java"],
-        sdk_version: "current",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("android_binary", "TestApp", AttrNameToString{
-				"srcs":           `["app.java"]`,
-				"manifest":       `"AndroidManifest.xml"`,
-				"resource_files": `["res/res.png"]`,
-				"sdk_version":    `"current"`,
-			}),
-		}})
-}
-
-func TestAndroidAppAllSupportedFields(t *testing.T) {
-	runAndroidAppTestCase(t, Bp2buildTestCase{
-		Description:                "Android app - all supported fields",
-		ModuleTypeUnderTest:        "android_app",
-		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
-		Filesystem: map[string]string{
-			"app.java":                     "",
-			"resa/res.png":                 "",
-			"resb/res.png":                 "",
-			"manifest/AndroidManifest.xml": "",
-		},
-		Blueprint: simpleModuleDoNotConvertBp2build("android_app", "static_lib_dep") + `
-android_app {
-        name: "TestApp",
-        srcs: ["app.java"],
-        sdk_version: "current",
-        package_name: "com.google",
-        resource_dirs: ["resa", "resb"],
-        manifest: "manifest/AndroidManifest.xml",
-        static_libs: ["static_lib_dep"],
-        java_version: "7",
-        certificate: "foocert",
-        required: ["static_lib_dep"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("android_binary", "TestApp", AttrNameToString{
-				"srcs":     `["app.java"]`,
-				"manifest": `"manifest/AndroidManifest.xml"`,
-				"resource_files": `[
-        "resa/res.png",
-        "resb/res.png",
-    ]`,
-				"custom_package":   `"com.google"`,
-				"deps":             `[":static_lib_dep"]`,
-				"java_version":     `"7"`,
-				"sdk_version":      `"current"`,
-				"certificate_name": `"foocert"`,
-			}),
-		}})
-}
-
-func TestAndroidAppArchVariantSrcs(t *testing.T) {
-	runAndroidAppTestCase(t, Bp2buildTestCase{
-		Description:                "Android app - arch variant srcs",
-		ModuleTypeUnderTest:        "android_app",
-		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
-		Filesystem: map[string]string{
-			"arm.java":            "",
-			"x86.java":            "",
-			"res/res.png":         "",
-			"AndroidManifest.xml": "",
-		},
-		Blueprint: `
-android_app {
-        name: "TestApp",
-        sdk_version: "current",
-        arch: {
-			arm: {
-				srcs: ["arm.java"],
-			},
-			x86: {
-				srcs: ["x86.java"],
-			}
-		}
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("android_binary", "TestApp", AttrNameToString{
-				"srcs": `select({
-        "//build/bazel/platforms/arch:arm": ["arm.java"],
-        "//build/bazel/platforms/arch:x86": ["x86.java"],
-        "//conditions:default": [],
-    })`,
-				"manifest":       `"AndroidManifest.xml"`,
-				"resource_files": `["res/res.png"]`,
-				"sdk_version":    `"current"`,
-			}),
-		}})
-}
-
-func TestAndroidAppCertIsModule(t *testing.T) {
-	runAndroidAppTestCase(t, Bp2buildTestCase{
-		Description:                "Android app - cert is module",
-		ModuleTypeUnderTest:        "android_app",
-		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
-android_app {
-        name: "TestApp",
-        certificate: ":foocert",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("android_binary", "TestApp", AttrNameToString{
-				"certificate":    `":foocert"`,
-				"manifest":       `"AndroidManifest.xml"`,
-				"resource_files": `[]`,
-			}),
-		}})
-}
-
-func TestAndroidAppCertIsSrcFile(t *testing.T) {
-	runAndroidAppTestCase(t, Bp2buildTestCase{
-		Description:                "Android app - cert is src file",
-		ModuleTypeUnderTest:        "android_app",
-		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
-		Filesystem: map[string]string{
-			"foocert": "",
-		},
-		Blueprint: `
-android_app {
-        name: "TestApp",
-        certificate: "foocert",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("android_binary", "TestApp", AttrNameToString{
-				"certificate":    `"foocert"`,
-				"manifest":       `"AndroidManifest.xml"`,
-				"resource_files": `[]`,
-			}),
-		}})
-}
-
-func TestAndroidAppCertIsNotSrcOrModule(t *testing.T) {
-	runAndroidAppTestCase(t, Bp2buildTestCase{
-		Description:                "Android app - cert is not src or module",
-		ModuleTypeUnderTest:        "android_app",
-		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
-		Filesystem:                 map[string]string{
-			// deliberate empty
-		},
-		Blueprint: `
-android_app {
-        name: "TestApp",
-        certificate: "foocert",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("android_binary", "TestApp", AttrNameToString{
-				"certificate_name": `"foocert"`,
-				"manifest":         `"AndroidManifest.xml"`,
-				"resource_files":   `[]`,
-			}),
-		}})
-}
-
-func TestAndroidAppLibs(t *testing.T) {
-	runAndroidAppTestCase(t, Bp2buildTestCase{
-		Description:                "Android app with libs",
-		ModuleTypeUnderTest:        "android_app",
-		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
-android_app {
-        name: "foo",
-				libs: ["barLib"]
-}
-java_library{
-       name: "barLib",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "barLib", AttrNameToString{}),
-			MakeNeverlinkDuplicateTarget("java_library", "barLib"),
-			MakeBazelTarget("android_binary", "foo", AttrNameToString{
-				"manifest":       `"AndroidManifest.xml"`,
-				"resource_files": `[]`,
-				"deps":           `[":barLib-neverlink"]`,
-			}),
-		}})
-}
-
-func TestAndroidAppKotlinSrcs(t *testing.T) {
-	runAndroidAppTestCase(t, Bp2buildTestCase{
-		Description:                "Android app with kotlin sources and common_srcs",
-		ModuleTypeUnderTest:        "android_app",
-		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
-		Filesystem: map[string]string{
-			"res/res.png": "",
-		},
-		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
-android_app {
-        name: "foo",
-        srcs: ["a.java", "b.kt"],
-        certificate: ":foocert",
-        manifest: "fooManifest.xml",
-        libs: ["barLib"]
-}
-java_library{
-      name:   "barLib",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "barLib", AttrNameToString{}),
-			MakeNeverlinkDuplicateTarget("java_library", "barLib"),
-			MakeBazelTarget("android_library", "foo_kt", AttrNameToString{
-				"srcs": `[
-        "a.java",
-        "b.kt",
-    ]`,
-				"manifest":       `"fooManifest.xml"`,
-				"resource_files": `["res/res.png"]`,
-				"deps":           `[":barLib-neverlink"]`,
-			}),
-			MakeBazelTarget("android_binary", "foo", AttrNameToString{
-				"deps":        `[":foo_kt"]`,
-				"certificate": `":foocert"`,
-				"manifest":    `"fooManifest.xml"`,
-			}),
-		}})
-}
-
-func TestAndroidAppCommonSrcs(t *testing.T) {
-	runAndroidAppTestCase(t, Bp2buildTestCase{
-		Description:                "Android app with common_srcs",
-		ModuleTypeUnderTest:        "android_app",
-		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
-		Filesystem: map[string]string{
-			"res/res.png": "",
-		},
-		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
-android_app {
-        name: "foo",
-        srcs: ["a.java"],
-        common_srcs: ["b.kt"],
-        certificate: "foocert",
-        manifest: "fooManifest.xml",
-        libs:        ["barLib"],
-}
-java_library{
-      name:   "barLib",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "barLib", AttrNameToString{}),
-			MakeNeverlinkDuplicateTarget("java_library", "barLib"),
-			MakeBazelTarget("android_library", "foo_kt", AttrNameToString{
-				"srcs":           `["a.java"]`,
-				"common_srcs":    `["b.kt"]`,
-				"manifest":       `"fooManifest.xml"`,
-				"resource_files": `["res/res.png"]`,
-				"deps":           `[":barLib-neverlink"]`,
-			}),
-			MakeBazelTarget("android_binary", "foo", AttrNameToString{
-				"deps":             `[":foo_kt"]`,
-				"certificate_name": `"foocert"`,
-				"manifest":         `"fooManifest.xml"`,
-			}),
-		}})
-}
-
-func TestAndroidAppKotlinCflags(t *testing.T) {
-	runAndroidAppTestCase(t, Bp2buildTestCase{
-		Description:                "Android app with kotlincflags",
-		ModuleTypeUnderTest:        "android_app",
-		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
-		Filesystem: map[string]string{
-			"res/res.png": "",
-		},
-		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
-android_app {
-        name: "foo",
-        srcs: ["a.java", "b.kt"],
-        certificate: ":foocert",
-        manifest: "fooManifest.xml",
-        kotlincflags: ["-flag1", "-flag2"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("android_library", "foo_kt", AttrNameToString{
-				"srcs": `[
-        "a.java",
-        "b.kt",
-    ]`,
-				"manifest":       `"fooManifest.xml"`,
-				"resource_files": `["res/res.png"]`,
-				"kotlincflags": `[
-        "-flag1",
-        "-flag2",
-    ]`,
-			}),
-			MakeBazelTarget("android_binary", "foo", AttrNameToString{
-				"deps":        `[":foo_kt"]`,
-				"certificate": `":foocert"`,
-				"manifest":    `"fooManifest.xml"`,
-			}),
-		}})
-}
-
-func TestAndroidAppManifestSdkVersionsProvided(t *testing.T) {
-	runAndroidAppTestCase(t, Bp2buildTestCase{
-		Description:                "Android app with value for min_sdk_version",
-		ModuleTypeUnderTest:        "android_app",
-		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
-android_app {
-        name: "foo",
-        sdk_version: "current",
-        min_sdk_version: "24",
-        max_sdk_version: "30",
-        target_sdk_version: "29",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("android_binary", "foo", AttrNameToString{
-				"manifest":       `"AndroidManifest.xml"`,
-				"resource_files": `[]`,
-				"manifest_values": `{
-        "maxSdkVersion": "30",
-        "minSdkVersion": "24",
-        "targetSdkVersion": "29",
-    }`,
-				"sdk_version": `"current"`,
-			}),
-		}})
-}
-
-func TestAndroidAppMinAndTargetSdkDefaultToSdkVersion(t *testing.T) {
-	runAndroidAppTestCase(t, Bp2buildTestCase{
-		Description:                "Android app with value for sdk_version",
-		ModuleTypeUnderTest:        "android_app",
-		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
-android_app {
-        name: "foo",
-        sdk_version: "30",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("android_binary", "foo", AttrNameToString{
-				"manifest":       `"AndroidManifest.xml"`,
-				"resource_files": `[]`,
-				"manifest_values": `{
-        "minSdkVersion": "30",
-        "targetSdkVersion": "30",
-    }`,
-				"sdk_version": `"30"`,
-			}),
-		}})
-}
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
deleted file mode 100644
index 2383247..0000000
--- a/bp2build/apex_conversion_test.go
+++ /dev/null
@@ -1,1595 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"android/soong/android"
-	"android/soong/apex"
-	"android/soong/cc"
-	"android/soong/etc"
-	"android/soong/java"
-	"android/soong/sh"
-
-	"fmt"
-	"testing"
-)
-
-func runApexTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	RunBp2BuildTestCase(t, registerApexModuleTypes, tc)
-}
-
-func registerApexModuleTypes(ctx android.RegistrationContext) {
-	// CC module types needed as they can be APEX dependencies
-	cc.RegisterCCBuildComponents(ctx)
-
-	ctx.RegisterModuleType("sh_binary", sh.ShBinaryFactory)
-	ctx.RegisterModuleType("cc_binary", cc.BinaryFactory)
-	ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
-	ctx.RegisterModuleType("apex_key", apex.ApexKeyFactory)
-	ctx.RegisterModuleType("android_app_certificate", java.AndroidAppCertificateFactory)
-	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
-	ctx.RegisterModuleType("prebuilt_etc", etc.PrebuiltEtcFactory)
-	ctx.RegisterModuleType("cc_test", cc.TestFactory)
-}
-
-func runOverrideApexTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	RunBp2BuildTestCase(t, registerOverrideApexModuleTypes, tc)
-}
-
-func registerOverrideApexModuleTypes(ctx android.RegistrationContext) {
-	// CC module types needed as they can be APEX dependencies
-	cc.RegisterCCBuildComponents(ctx)
-
-	ctx.RegisterModuleType("sh_binary", sh.ShBinaryFactory)
-	ctx.RegisterModuleType("cc_binary", cc.BinaryFactory)
-	ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
-	ctx.RegisterModuleType("apex_key", apex.ApexKeyFactory)
-	ctx.RegisterModuleType("apex_test", apex.TestApexBundleFactory)
-	ctx.RegisterModuleType("android_app_certificate", java.AndroidAppCertificateFactory)
-	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
-	ctx.RegisterModuleType("apex", apex.BundleFactory)
-	ctx.RegisterModuleType("apex_defaults", apex.DefaultsFactory)
-	ctx.RegisterModuleType("prebuilt_etc", etc.PrebuiltEtcFactory)
-	ctx.RegisterModuleType("soong_config_module_type", android.SoongConfigModuleTypeFactory)
-	ctx.RegisterModuleType("soong_config_string_variable", android.SoongConfigStringVariableDummyFactory)
-}
-
-func TestApexBundleSimple(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - example with all props, file_context is a module in same Android.bp",
-		ModuleTypeUnderTest:        "apex",
-		ModuleTypeUnderTestFactory: apex.BundleFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: `
-apex_key {
-	name: "com.android.apogee.key",
-	public_key: "com.android.apogee.avbpubkey",
-	private_key: "com.android.apogee.pem",
-	bazel_module: { bp2build_available: false },
-}
-
-android_app_certificate {
-	name: "com.android.apogee.certificate",
-	certificate: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-	name: "native_shared_lib_1",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-	name: "native_shared_lib_2",
-	bazel_module: { bp2build_available: false },
-}
-
-prebuilt_etc {
-	name: "prebuilt_1",
-	bazel_module: { bp2build_available: false },
-}
-
-prebuilt_etc {
-	name: "prebuilt_2",
-	bazel_module: { bp2build_available: false },
-}
-
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [
-		"com.android.apogee-file_contexts",
-	],
-	bazel_module: { bp2build_available: false },
-}
-
-cc_binary { name: "cc_binary_1", bazel_module: { bp2build_available: false } }
-sh_binary { name: "sh_binary_2", bazel_module: { bp2build_available: false } }
-
-apex {
-	name: "com.android.apogee",
-	manifest: "apogee_manifest.json",
-	androidManifest: "ApogeeAndroidManifest.xml",
-	apex_available_name: "apogee_apex_name",
-	file_contexts: ":com.android.apogee-file_contexts",
-	min_sdk_version: "29",
-	key: "com.android.apogee.key",
-	certificate: ":com.android.apogee.certificate",
-	updatable: false,
-	installable: false,
-	compressible: false,
-	native_shared_libs: [
-	    "native_shared_lib_1",
-	    "native_shared_lib_2",
-	],
-	binaries: [
-		"cc_binary_1",
-		"sh_binary_2",
-	],
-	prebuilts: [
-	    "prebuilt_1",
-	    "prebuilt_2",
-	],
-	package_name: "com.android.apogee.test.package",
-	logging_parent: "logging.parent",
-	variant_version: "3",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
-				"android_manifest":    `"ApogeeAndroidManifest.xml"`,
-				"apex_available_name": `"apogee_apex_name"`,
-				"binaries": `[
-        ":cc_binary_1",
-        ":sh_binary_2",
-    ]`,
-				"certificate":     `":com.android.apogee.certificate"`,
-				"file_contexts":   `":com.android.apogee-file_contexts"`,
-				"installable":     "False",
-				"key":             `":com.android.apogee.key"`,
-				"manifest":        `"apogee_manifest.json"`,
-				"min_sdk_version": `"29"`,
-				"native_shared_libs_32": `select({
-        "//build/bazel/platforms/arch:arm": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_2",
-        ],
-        "//build/bazel/platforms/arch:x86": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_2",
-        ],
-        "//conditions:default": [],
-    })`,
-				"native_shared_libs_64": `select({
-        "//build/bazel/platforms/arch:arm64": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_2",
-        ],
-        "//build/bazel/platforms/arch:x86_64": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_2",
-        ],
-        "//conditions:default": [],
-    })`,
-				"prebuilts": `[
-        ":prebuilt_1",
-        ":prebuilt_2",
-    ]`,
-				"updatable":       "False",
-				"compressible":    "False",
-				"package_name":    `"com.android.apogee.test.package"`,
-				"logging_parent":  `"logging.parent"`,
-				"variant_version": `"3"`,
-			}),
-		}})
-}
-
-func TestApexBundleSimple_fileContextsInAnotherAndroidBp(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - file contexts is a module in another Android.bp",
-		ModuleTypeUnderTest:        "apex",
-		ModuleTypeUnderTestFactory: apex.BundleFactory,
-		Filesystem: map[string]string{
-			"a/b/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [
-		"com.android.apogee-file_contexts",
-	],
-	bazel_module: { bp2build_available: false },
-}
-`,
-		},
-		Blueprint: `
-apex {
-	name: "com.android.apogee",
-	file_contexts: ":com.android.apogee-file_contexts",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
-				"file_contexts": `"//a/b:com.android.apogee-file_contexts"`,
-				"manifest":      `"apex_manifest.json"`,
-			}),
-		}})
-}
-
-func TestApexBundleSimple_fileContextsIsFile(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - file contexts is a file",
-		ModuleTypeUnderTest:        "apex",
-		ModuleTypeUnderTestFactory: apex.BundleFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: `
-apex {
-	name: "com.android.apogee",
-	file_contexts: "file_contexts_file",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
-				"file_contexts": `"file_contexts_file"`,
-				"manifest":      `"apex_manifest.json"`,
-			}),
-		}})
-}
-
-func TestApexBundleSimple_fileContextsIsNotSpecified(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - file contexts is not specified",
-		ModuleTypeUnderTest:        "apex",
-		ModuleTypeUnderTestFactory: apex.BundleFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [
-		"com.android.apogee-file_contexts",
-	],
-	bazel_module: { bp2build_available: false },
-}
-`,
-		},
-		Blueprint: `
-apex {
-	name: "com.android.apogee",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
-				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":      `"apex_manifest.json"`,
-			}),
-		}})
-}
-
-func TestApexBundleCompileMultilibBoth(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - example with compile_multilib=both",
-		ModuleTypeUnderTest:        "apex",
-		ModuleTypeUnderTestFactory: apex.BundleFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}
-`,
-		},
-		Blueprint: createMultilibBlueprint(`compile_multilib: "both",`),
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
-				"native_shared_libs_32": `[
-        ":unnested_native_shared_lib",
-        ":native_shared_lib_for_both",
-        ":native_shared_lib_for_lib32",
-    ] + select({
-        "//build/bazel/platforms/arch:arm": [":native_shared_lib_for_first"],
-        "//build/bazel/platforms/arch:x86": [":native_shared_lib_for_first"],
-        "//conditions:default": [],
-    })`,
-				"native_shared_libs_64": `select({
-        "//build/bazel/platforms/arch:arm64": [
-            ":unnested_native_shared_lib",
-            ":native_shared_lib_for_both",
-            ":native_shared_lib_for_lib64",
-            ":native_shared_lib_for_first",
-        ],
-        "//build/bazel/platforms/arch:x86_64": [
-            ":unnested_native_shared_lib",
-            ":native_shared_lib_for_both",
-            ":native_shared_lib_for_lib64",
-            ":native_shared_lib_for_first",
-        ],
-        "//conditions:default": [],
-    })`,
-				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":      `"apex_manifest.json"`,
-			}),
-		}})
-}
-
-func TestApexBundleCompileMultilibFirstAndDefaultValue(t *testing.T) {
-	expectedBazelTargets := []string{
-		MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
-			"native_shared_libs_32": `select({
-        "//build/bazel/platforms/arch:arm": [
-            ":unnested_native_shared_lib",
-            ":native_shared_lib_for_both",
-            ":native_shared_lib_for_lib32",
-            ":native_shared_lib_for_first",
-        ],
-        "//build/bazel/platforms/arch:x86": [
-            ":unnested_native_shared_lib",
-            ":native_shared_lib_for_both",
-            ":native_shared_lib_for_lib32",
-            ":native_shared_lib_for_first",
-        ],
-        "//conditions:default": [],
-    })`,
-			"native_shared_libs_64": `select({
-        "//build/bazel/platforms/arch:arm64": [
-            ":unnested_native_shared_lib",
-            ":native_shared_lib_for_both",
-            ":native_shared_lib_for_lib64",
-            ":native_shared_lib_for_first",
-        ],
-        "//build/bazel/platforms/arch:x86_64": [
-            ":unnested_native_shared_lib",
-            ":native_shared_lib_for_both",
-            ":native_shared_lib_for_lib64",
-            ":native_shared_lib_for_first",
-        ],
-        "//conditions:default": [],
-    })`,
-			"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-			"manifest":      `"apex_manifest.json"`,
-		}),
-	}
-
-	// "first" is the default value of compile_multilib prop so `compile_multilib_: "first"` and unset compile_multilib
-	// should result to the same bp2build output
-	compileMultiLibPropValues := []string{`compile_multilib: "first",`, ""}
-	for _, compileMultiLibProp := range compileMultiLibPropValues {
-		descriptionSuffix := compileMultiLibProp
-		if descriptionSuffix == "" {
-			descriptionSuffix = "compile_multilib unset"
-		}
-		runApexTestCase(t, Bp2buildTestCase{
-			Description:                "apex - example with " + compileMultiLibProp,
-			ModuleTypeUnderTest:        "apex",
-			ModuleTypeUnderTestFactory: apex.BundleFactory,
-			Filesystem: map[string]string{
-				"system/sepolicy/apex/Android.bp": `
-    filegroup {
-        name: "com.android.apogee-file_contexts",
-        srcs: [ "apogee-file_contexts", ],
-        bazel_module: { bp2build_available: false },
-    }
-    `,
-			},
-			Blueprint:            createMultilibBlueprint(compileMultiLibProp),
-			ExpectedBazelTargets: expectedBazelTargets,
-		})
-	}
-}
-
-func TestApexBundleCompileMultilib32(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - example with compile_multilib=32",
-		ModuleTypeUnderTest:        "apex",
-		ModuleTypeUnderTestFactory: apex.BundleFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}
-`,
-		},
-		Blueprint: createMultilibBlueprint(`compile_multilib: "32",`),
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
-				"native_shared_libs_32": `[
-        ":unnested_native_shared_lib",
-        ":native_shared_lib_for_both",
-        ":native_shared_lib_for_lib32",
-    ] + select({
-        "//build/bazel/platforms/arch:arm": [":native_shared_lib_for_first"],
-        "//build/bazel/platforms/arch:x86": [":native_shared_lib_for_first"],
-        "//conditions:default": [],
-    })`,
-				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":      `"apex_manifest.json"`,
-			}),
-		}})
-}
-
-func TestApexBundleCompileMultilib64(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - example with compile_multilib=64",
-		ModuleTypeUnderTest:        "apex",
-		ModuleTypeUnderTestFactory: apex.BundleFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}
-`,
-		},
-		Blueprint: createMultilibBlueprint(`compile_multilib: "64",`),
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
-				"native_shared_libs_64": `select({
-        "//build/bazel/platforms/arch:arm64": [
-            ":unnested_native_shared_lib",
-            ":native_shared_lib_for_both",
-            ":native_shared_lib_for_lib64",
-            ":native_shared_lib_for_first",
-        ],
-        "//build/bazel/platforms/arch:x86_64": [
-            ":unnested_native_shared_lib",
-            ":native_shared_lib_for_both",
-            ":native_shared_lib_for_lib64",
-            ":native_shared_lib_for_first",
-        ],
-        "//conditions:default": [],
-    })`,
-				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":      `"apex_manifest.json"`,
-			}),
-		}})
-}
-
-func createMultilibBlueprint(compile_multilib string) string {
-	return fmt.Sprintf(`
-cc_library {
-	name: "native_shared_lib_for_both",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-	name: "native_shared_lib_for_first",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-	name: "native_shared_lib_for_lib32",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-	name: "native_shared_lib_for_lib64",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-	name: "unnested_native_shared_lib",
-	bazel_module: { bp2build_available: false },
-}
-
-apex {
-	name: "com.android.apogee",
-	%s
-	native_shared_libs: ["unnested_native_shared_lib"],
-	multilib: {
-		both: {
-			native_shared_libs: [
-				"native_shared_lib_for_both",
-			],
-		},
-		first: {
-			native_shared_libs: [
-				"native_shared_lib_for_first",
-			],
-		},
-		lib32: {
-			native_shared_libs: [
-				"native_shared_lib_for_lib32",
-			],
-		},
-		lib64: {
-			native_shared_libs: [
-				"native_shared_lib_for_lib64",
-			],
-		},
-	},
-}`, compile_multilib)
-}
-
-func TestApexBundleDefaultPropertyValues(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - default property values",
-		ModuleTypeUnderTest:        "apex",
-		ModuleTypeUnderTestFactory: apex.BundleFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}
-`,
-		},
-		Blueprint: `
-apex {
-	name: "com.android.apogee",
-	manifest: "apogee_manifest.json",
-}
-`,
-		ExpectedBazelTargets: []string{MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
-			"manifest":      `"apogee_manifest.json"`,
-			"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-		}),
-		}})
-}
-
-func TestApexBundleHasBazelModuleProps(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - has bazel module props",
-		ModuleTypeUnderTest:        "apex",
-		ModuleTypeUnderTestFactory: apex.BundleFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}
-`,
-		},
-		Blueprint: `
-apex {
-	name: "apogee",
-	manifest: "manifest.json",
-	bazel_module: { bp2build_available: true },
-}
-`,
-		ExpectedBazelTargets: []string{MakeBazelTarget("apex", "apogee", AttrNameToString{
-			"manifest":      `"manifest.json"`,
-			"file_contexts": `"//system/sepolicy/apex:apogee-file_contexts"`,
-		}),
-		}})
-}
-
-func TestBp2BuildOverrideApex(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: `
-apex_key {
-	name: "com.android.apogee.key",
-	public_key: "com.android.apogee.avbpubkey",
-	private_key: "com.android.apogee.pem",
-	bazel_module: { bp2build_available: false },
-}
-
-android_app_certificate {
-	name: "com.android.apogee.certificate",
-	certificate: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-	name: "native_shared_lib_1",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-	name: "native_shared_lib_2",
-	bazel_module: { bp2build_available: false },
-}
-
-prebuilt_etc {
-	name: "prebuilt_1",
-	bazel_module: { bp2build_available: false },
-}
-
-prebuilt_etc {
-	name: "prebuilt_2",
-	bazel_module: { bp2build_available: false },
-}
-
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [
-		"com.android.apogee-file_contexts",
-	],
-	bazel_module: { bp2build_available: false },
-}
-
-cc_binary { name: "cc_binary_1", bazel_module: { bp2build_available: false } }
-sh_binary { name: "sh_binary_2", bazel_module: { bp2build_available: false } }
-
-apex {
-	name: "com.android.apogee",
-	manifest: "apogee_manifest.json",
-	androidManifest: "ApogeeAndroidManifest.xml",
-	file_contexts: ":com.android.apogee-file_contexts",
-	min_sdk_version: "29",
-	key: "com.android.apogee.key",
-	certificate: ":com.android.apogee.certificate",
-	updatable: false,
-	installable: false,
-	compressible: false,
-	native_shared_libs: [
-	    "native_shared_lib_1",
-	    "native_shared_lib_2",
-	],
-	binaries: [
-		"cc_binary_1",
-		"sh_binary_2",
-	],
-	prebuilts: [
-	    "prebuilt_1",
-	    "prebuilt_2",
-	],
-	bazel_module: { bp2build_available: false },
-}
-
-apex_key {
-	name: "com.google.android.apogee.key",
-	public_key: "com.google.android.apogee.avbpubkey",
-	private_key: "com.google.android.apogee.pem",
-	bazel_module: { bp2build_available: false },
-}
-
-android_app_certificate {
-	name: "com.google.android.apogee.certificate",
-	certificate: "com.google.android.apogee",
-	bazel_module: { bp2build_available: false },
-}
-
-override_apex {
-	name: "com.google.android.apogee",
-	base: ":com.android.apogee",
-	key: "com.google.android.apogee.key",
-	certificate: ":com.google.android.apogee.certificate",
-	prebuilts: [],
-	compressible: true,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"android_manifest": `"ApogeeAndroidManifest.xml"`,
-				"base_apex_name":   `"com.android.apogee"`,
-				"binaries": `[
-        ":cc_binary_1",
-        ":sh_binary_2",
-    ]`,
-				"certificate":     `":com.google.android.apogee.certificate"`,
-				"file_contexts":   `":com.android.apogee-file_contexts"`,
-				"installable":     "False",
-				"key":             `":com.google.android.apogee.key"`,
-				"manifest":        `"apogee_manifest.json"`,
-				"min_sdk_version": `"29"`,
-				"native_shared_libs_32": `select({
-        "//build/bazel/platforms/arch:arm": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_2",
-        ],
-        "//build/bazel/platforms/arch:x86": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_2",
-        ],
-        "//conditions:default": [],
-    })`,
-				"native_shared_libs_64": `select({
-        "//build/bazel/platforms/arch:arm64": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_2",
-        ],
-        "//build/bazel/platforms/arch:x86_64": [
-            ":native_shared_lib_1",
-            ":native_shared_lib_2",
-        ],
-        "//conditions:default": [],
-    })`,
-				"prebuilts":    `[]`,
-				"updatable":    "False",
-				"compressible": "True",
-			}),
-		}})
-}
-
-func TestOverrideApexTest(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: `
-apex_key {
-	name: "com.android.apogee.key",
-	public_key: "com.android.apogee.avbpubkey",
-	private_key: "com.android.apogee.pem",
-	bazel_module: { bp2build_available: false },
-}
-
-android_app_certificate {
-	name: "com.android.apogee.certificate",
-	certificate: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-	name: "native_shared_lib_1",
-	bazel_module: { bp2build_available: false },
-}
-
-prebuilt_etc {
-	name: "prebuilt_1",
-	bazel_module: { bp2build_available: false },
-}
-
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [
-		"com.android.apogee-file_contexts",
-	],
-	bazel_module: { bp2build_available: false },
-}
-
-cc_binary { name: "cc_binary_1", bazel_module: { bp2build_available: false } }
-sh_binary { name: "sh_binary_2", bazel_module: { bp2build_available: false } }
-
-apex_test {
-	name: "com.android.apogee",
-	manifest: "apogee_manifest.json",
-	androidManifest: "ApogeeAndroidManifest.xml",
-	file_contexts: ":com.android.apogee-file_contexts",
-	min_sdk_version: "29",
-	key: "com.android.apogee.key",
-	certificate: ":com.android.apogee.certificate",
-	updatable: false,
-	installable: false,
-	compressible: false,
-	native_shared_libs: [
-	    "native_shared_lib_1",
-	],
-	binaries: [
-		"cc_binary_1",
-		"sh_binary_2",
-	],
-	prebuilts: [
-	    "prebuilt_1",
-	],
-	bazel_module: { bp2build_available: false },
-}
-
-apex_key {
-	name: "com.google.android.apogee.key",
-	public_key: "com.google.android.apogee.avbpubkey",
-	private_key: "com.google.android.apogee.pem",
-	bazel_module: { bp2build_available: false },
-}
-
-android_app_certificate {
-	name: "com.google.android.apogee.certificate",
-	certificate: "com.google.android.apogee",
-	bazel_module: { bp2build_available: false },
-}
-
-override_apex {
-	name: "com.google.android.apogee",
-	base: ":com.android.apogee",
-	key: "com.google.android.apogee.key",
-	certificate: ":com.google.android.apogee.certificate",
-	prebuilts: [],
-	compressible: true,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"android_manifest": `"ApogeeAndroidManifest.xml"`,
-				"base_apex_name":   `"com.android.apogee"`,
-				"binaries": `[
-        ":cc_binary_1",
-        ":sh_binary_2",
-    ]`,
-				"certificate":     `":com.google.android.apogee.certificate"`,
-				"file_contexts":   `":com.android.apogee-file_contexts"`,
-				"installable":     "False",
-				"key":             `":com.google.android.apogee.key"`,
-				"manifest":        `"apogee_manifest.json"`,
-				"min_sdk_version": `"29"`,
-				"native_shared_libs_32": `select({
-        "//build/bazel/platforms/arch:arm": [":native_shared_lib_1"],
-        "//build/bazel/platforms/arch:x86": [":native_shared_lib_1"],
-        "//conditions:default": [],
-    })`,
-				"native_shared_libs_64": `select({
-        "//build/bazel/platforms/arch:arm64": [":native_shared_lib_1"],
-        "//build/bazel/platforms/arch:x86_64": [":native_shared_lib_1"],
-        "//conditions:default": [],
-    })`,
-				"testonly":     "True",
-				"prebuilts":    `[]`,
-				"updatable":    "False",
-				"compressible": "True",
-			}),
-		}})
-}
-
-func TestApexBundleSimple_manifestIsEmpty_baseApexOverrideApexInDifferentAndroidBp(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex - manifest of base apex is empty, base apex and override_apex is in different Android.bp",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}`,
-			"a/b/Android.bp": `
-apex {
-	name: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-}
-`,
-		},
-		Blueprint: `
-override_apex {
-	name: "com.google.android.apogee",
-	base: ":com.android.apogee",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"base_apex_name": `"com.android.apogee"`,
-				"file_contexts":  `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":       `"//a/b:apex_manifest.json"`,
-			}),
-		}})
-}
-
-func TestApexBundleSimple_manifestIsSet_baseApexOverrideApexInDifferentAndroidBp(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex - manifest of base apex is set, base apex and override_apex is in different Android.bp",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}`,
-			"a/b/Android.bp": `
-apex {
-	name: "com.android.apogee",
-  manifest: "apogee_manifest.json",
-	bazel_module: { bp2build_available: false },
-}
-`,
-		},
-		Blueprint: `
-override_apex {
-	name: "com.google.android.apogee",
-  base: ":com.android.apogee",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"base_apex_name": `"com.android.apogee"`,
-				"file_contexts":  `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":       `"//a/b:apogee_manifest.json"`,
-			}),
-		}})
-}
-
-func TestApexBundleSimple_manifestIsEmpty_baseApexOverrideApexInSameAndroidBp(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex - manifest of base apex is empty, base apex and override_apex is in same Android.bp",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}`,
-		},
-		Blueprint: `
-apex {
-	name: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-}
-
-override_apex {
-	name: "com.google.android.apogee",
-  base: ":com.android.apogee",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"base_apex_name": `"com.android.apogee"`,
-				"file_contexts":  `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":       `"apex_manifest.json"`,
-			}),
-		}})
-}
-
-func TestApexBundleSimple_manifestIsSet_baseApexOverrideApexInSameAndroidBp(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex - manifest of base apex is set, base apex and override_apex is in same Android.bp",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}`,
-		},
-		Blueprint: `
-apex {
-	name: "com.android.apogee",
-  manifest: "apogee_manifest.json",
-	bazel_module: { bp2build_available: false },
-}
-
-override_apex {
-	name: "com.google.android.apogee",
-  base: ":com.android.apogee",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"base_apex_name": `"com.android.apogee"`,
-				"file_contexts":  `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":       `"apogee_manifest.json"`,
-			}),
-		}})
-}
-
-func TestApexBundleSimple_packageNameOverride(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex - override package name",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}`,
-		},
-		Blueprint: `
-apex {
-	name: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-}
-
-override_apex {
-	name: "com.google.android.apogee",
-	base: ":com.android.apogee",
-	package_name: "com.google.android.apogee",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"base_apex_name": `"com.android.apogee"`,
-				"file_contexts":  `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":       `"apex_manifest.json"`,
-				"package_name":   `"com.google.android.apogee"`,
-			}),
-		}})
-}
-
-func TestApexBundleSimple_NoPrebuiltsOverride(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex - no override",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}`,
-		},
-		Blueprint: `
-prebuilt_etc {
-	name: "prebuilt_file",
-	bazel_module: { bp2build_available: false },
-}
-
-apex {
-	name: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-    prebuilts: ["prebuilt_file"]
-}
-
-override_apex {
-	name: "com.google.android.apogee",
-	base: ":com.android.apogee",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"base_apex_name": `"com.android.apogee"`,
-				"file_contexts":  `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":       `"apex_manifest.json"`,
-				"prebuilts":      `[":prebuilt_file"]`,
-			}),
-		}})
-}
-
-func TestApexBundleSimple_PrebuiltsOverride(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex - ooverride",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}`,
-		},
-		Blueprint: `
-prebuilt_etc {
-	name: "prebuilt_file",
-	bazel_module: { bp2build_available: false },
-}
-
-prebuilt_etc {
-	name: "prebuilt_file2",
-	bazel_module: { bp2build_available: false },
-}
-
-apex {
-	name: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-    prebuilts: ["prebuilt_file"]
-}
-
-override_apex {
-	name: "com.google.android.apogee",
-	base: ":com.android.apogee",
-    prebuilts: ["prebuilt_file2"]
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"base_apex_name": `"com.android.apogee"`,
-				"file_contexts":  `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":       `"apex_manifest.json"`,
-				"prebuilts":      `[":prebuilt_file2"]`,
-			}),
-		}})
-}
-
-func TestApexBundleSimple_PrebuiltsOverrideEmptyList(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex - override with empty list",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}`,
-		},
-		Blueprint: `
-prebuilt_etc {
-	name: "prebuilt_file",
-	bazel_module: { bp2build_available: false },
-}
-
-apex {
-	name: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-    prebuilts: ["prebuilt_file"]
-}
-
-override_apex {
-	name: "com.google.android.apogee",
-	base: ":com.android.apogee",
-    prebuilts: [],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"base_apex_name": `"com.android.apogee"`,
-				"file_contexts":  `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":       `"apex_manifest.json"`,
-				"prebuilts":      `[]`,
-			}),
-		}})
-}
-
-func TestApexBundleSimple_NoLoggingParentOverride(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex - logging_parent - no override",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}`,
-		},
-		Blueprint: `
-apex {
-	name: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-	logging_parent: "foo.bar.baz",
-}
-
-override_apex {
-	name: "com.google.android.apogee",
-	base: ":com.android.apogee",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"base_apex_name": `"com.android.apogee"`,
-				"file_contexts":  `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":       `"apex_manifest.json"`,
-				"logging_parent": `"foo.bar.baz"`,
-			}),
-		}})
-}
-
-func TestApexBundleSimple_LoggingParentOverride(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex - logging_parent - override",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem: map[string]string{
-			"system/sepolicy/apex/Android.bp": `
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [ "apogee-file_contexts", ],
-	bazel_module: { bp2build_available: false },
-}`,
-		},
-		Blueprint: `
-apex {
-	name: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-	logging_parent: "foo.bar.baz",
-}
-
-override_apex {
-	name: "com.google.android.apogee",
-	base: ":com.android.apogee",
-	logging_parent: "foo.bar.baz.override",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"base_apex_name": `"com.android.apogee"`,
-				"file_contexts":  `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
-				"manifest":       `"apex_manifest.json"`,
-				"logging_parent": `"foo.bar.baz.override"`,
-			}),
-		}})
-}
-
-func TestBp2BuildOverrideApex_CertificateNil(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex - don't set default certificate",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: `
-android_app_certificate {
-	name: "com.android.apogee.certificate",
-	certificate: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-}
-
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [
-		"com.android.apogee-file_contexts",
-	],
-	bazel_module: { bp2build_available: false },
-}
-
-apex {
-	name: "com.android.apogee",
-	manifest: "apogee_manifest.json",
-	file_contexts: ":com.android.apogee-file_contexts",
-	certificate: ":com.android.apogee.certificate",
-	bazel_module: { bp2build_available: false },
-}
-
-override_apex {
-	name: "com.google.android.apogee",
-	base: ":com.android.apogee",
-	// certificate is deliberately omitted, and not converted to bazel,
-	// because the overridden apex shouldn't be using the base apex's cert.
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"base_apex_name": `"com.android.apogee"`,
-				"file_contexts":  `":com.android.apogee-file_contexts"`,
-				"manifest":       `"apogee_manifest.json"`,
-			}),
-		}})
-}
-
-func TestApexCertificateIsModule(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - certificate is module",
-		ModuleTypeUnderTest:        "apex",
-		ModuleTypeUnderTestFactory: apex.BundleFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: `
-android_app_certificate {
-	name: "com.android.apogee.certificate",
-	certificate: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-}
-
-apex {
-	name: "com.android.apogee",
-	manifest: "apogee_manifest.json",
-	file_contexts: ":com.android.apogee-file_contexts",
-	certificate: ":com.android.apogee.certificate",
-}
-` + simpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee-file_contexts"),
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
-				"certificate":   `":com.android.apogee.certificate"`,
-				"file_contexts": `":com.android.apogee-file_contexts"`,
-				"manifest":      `"apogee_manifest.json"`,
-			}),
-		}})
-}
-
-func TestApexWithStubLib(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - static variant of stub lib should not have apex_available tag",
-		ModuleTypeUnderTest:        "apex",
-		ModuleTypeUnderTestFactory: apex.BundleFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: `
-cc_library{
-	name: "foo",
-	stubs: { symbol_file: "foo.map.txt", versions: ["28", "29", "current"] },
-	apex_available: ["myapex"],
-}
-
-cc_binary{
-	name: "bar",
-	static_libs: ["foo"],
-	apex_available: ["myapex"],
-}
-
-apex {
-	name: "myapex",
-	manifest: "myapex_manifest.json",
-	file_contexts: ":myapex-file_contexts",
-	binaries: ["bar"],
-	native_shared_libs: ["foo"],
-}
-` + simpleModuleDoNotConvertBp2build("filegroup", "myapex-file_contexts"),
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_binary", "bar", AttrNameToString{
-				"local_includes": `["."]`,
-				"deps":           `[":foo_bp2build_cc_library_static"]`,
-				"tags":           `["apex_available=myapex"]`,
-			}),
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"local_includes":    `["."]`,
-				"stubs_symbol_file": `"foo.map.txt"`,
-				"tags":              `["apex_available=myapex"]`,
-			}),
-			MakeBazelTarget("cc_stub_suite", "foo_stub_libs", AttrNameToString{
-				"soname":               `"foo.so"`,
-				"source_library_label": `"//:foo"`,
-				"symbol_file":          `"foo.map.txt"`,
-				"versions": `[
-        "28",
-        "29",
-        "current",
-    ]`,
-			}),
-			MakeBazelTarget("apex", "myapex", AttrNameToString{
-				"file_contexts": `":myapex-file_contexts"`,
-				"manifest":      `"myapex_manifest.json"`,
-				"binaries":      `[":bar"]`,
-				"native_shared_libs_32": `select({
-        "//build/bazel/platforms/arch:arm": [":foo"],
-        "//build/bazel/platforms/arch:x86": [":foo"],
-        "//conditions:default": [],
-    })`,
-				"native_shared_libs_64": `select({
-        "//build/bazel/platforms/arch:arm64": [":foo"],
-        "//build/bazel/platforms/arch:x86_64": [":foo"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestApexCertificateIsSrc(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - certificate is src",
-		ModuleTypeUnderTest:        "apex",
-		ModuleTypeUnderTestFactory: apex.BundleFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: `
-apex {
-	name: "com.android.apogee",
-	manifest: "apogee_manifest.json",
-	file_contexts: ":com.android.apogee-file_contexts",
-	certificate: "com.android.apogee.certificate",
-}
-` + simpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee-file_contexts"),
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
-				"certificate_name": `"com.android.apogee.certificate"`,
-				"file_contexts":    `":com.android.apogee-file_contexts"`,
-				"manifest":         `"apogee_manifest.json"`,
-			}),
-		}})
-}
-
-func TestBp2BuildOverrideApex_CertificateIsModule(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex - certificate is module",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: `
-android_app_certificate {
-	name: "com.android.apogee.certificate",
-	certificate: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-}
-
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [
-		"com.android.apogee-file_contexts",
-	],
-	bazel_module: { bp2build_available: false },
-}
-
-apex {
-	name: "com.android.apogee",
-	manifest: "apogee_manifest.json",
-	file_contexts: ":com.android.apogee-file_contexts",
-	certificate: ":com.android.apogee.certificate",
-	bazel_module: { bp2build_available: false },
-}
-
-android_app_certificate {
-	name: "com.google.android.apogee.certificate",
-	certificate: "com.google.android.apogee",
-	bazel_module: { bp2build_available: false },
-}
-
-override_apex {
-	name: "com.google.android.apogee",
-	base: ":com.android.apogee",
-	certificate: ":com.google.android.apogee.certificate",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"base_apex_name": `"com.android.apogee"`,
-				"file_contexts":  `":com.android.apogee-file_contexts"`,
-				"certificate":    `":com.google.android.apogee.certificate"`,
-				"manifest":       `"apogee_manifest.json"`,
-			}),
-		}})
-}
-
-func TestBp2BuildOverrideApex_CertificateIsSrc(t *testing.T) {
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "override_apex - certificate is src",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: `
-android_app_certificate {
-	name: "com.android.apogee.certificate",
-	certificate: "com.android.apogee",
-	bazel_module: { bp2build_available: false },
-}
-
-filegroup {
-	name: "com.android.apogee-file_contexts",
-	srcs: [
-		"com.android.apogee-file_contexts",
-	],
-	bazel_module: { bp2build_available: false },
-}
-
-apex {
-	name: "com.android.apogee",
-	manifest: "apogee_manifest.json",
-	file_contexts: ":com.android.apogee-file_contexts",
-	certificate: ":com.android.apogee.certificate",
-	bazel_module: { bp2build_available: false },
-}
-
-override_apex {
-	name: "com.google.android.apogee",
-	base: ":com.android.apogee",
-	certificate: "com.google.android.apogee.certificate",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.google.android.apogee", AttrNameToString{
-				"base_apex_name":   `"com.android.apogee"`,
-				"file_contexts":    `":com.android.apogee-file_contexts"`,
-				"certificate_name": `"com.google.android.apogee.certificate"`,
-				"manifest":         `"apogee_manifest.json"`,
-			}),
-		}})
-}
-
-func TestApexTestBundleSimple(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex_test - simple",
-		ModuleTypeUnderTest:        "apex_test",
-		ModuleTypeUnderTestFactory: apex.TestApexBundleFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: `
-cc_test { name: "cc_test_1", bazel_module: { bp2build_available: false } }
-
-apex_test {
-	name: "test_com.android.apogee",
-	file_contexts: "file_contexts_file",
-	tests: ["cc_test_1"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "test_com.android.apogee", AttrNameToString{
-				"file_contexts":  `"file_contexts_file"`,
-				"base_apex_name": `"com.android.apogee"`,
-				"manifest":       `"apex_manifest.json"`,
-				"testonly":       `True`,
-				"tests":          `[":cc_test_1"]`,
-			}),
-		}})
-}
-
-func TestApexBundle_overridePlusProductVars(t *testing.T) {
-	// Reproduction of b/271424349
-	// Tests that overriding an apex that uses product variables correctly copies the product var
-	// selects over to the override.
-	runOverrideApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - overriding a module that uses product vars",
-		ModuleTypeUnderTest:        "override_apex",
-		ModuleTypeUnderTestFactory: apex.OverrideApexFactory,
-		Blueprint: `
-soong_config_string_variable {
-    name: "library_linking_strategy",
-    values: [
-        "prefer_static",
-    ],
-}
-
-soong_config_module_type {
-    name: "library_linking_strategy_apex_defaults",
-    module_type: "apex_defaults",
-    config_namespace: "ANDROID",
-    variables: ["library_linking_strategy"],
-    properties: [
-        "manifest",
-        "min_sdk_version",
-    ],
-}
-
-library_linking_strategy_apex_defaults {
-    name: "higher_min_sdk_when_prefer_static",
-    soong_config_variables: {
-        library_linking_strategy: {
-            // Use the R min_sdk_version
-            prefer_static: {},
-            // Override the R min_sdk_version to min_sdk_version that supports dcla
-            conditions_default: {
-                min_sdk_version: "31",
-            },
-        },
-    },
-}
-
-filegroup {
-	name: "foo-file_contexts",
-	srcs: [
-		"com.android.apogee-file_contexts",
-	],
-	bazel_module: { bp2build_available: false },
-}
-
-apex {
-	name: "foo",
-	defaults: ["higher_min_sdk_when_prefer_static"],
-	min_sdk_version: "30",
-	package_name: "pkg_name",
-	file_contexts: ":foo-file_contexts",
-}
-override_apex {
-	name: "override_foo",
-	base: ":foo",
-	package_name: "override_pkg_name",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "foo", AttrNameToString{
-				"file_contexts": `":foo-file_contexts"`,
-				"manifest":      `"apex_manifest.json"`,
-				"min_sdk_version": `select({
-        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": "30",
-        "//conditions:default": "31",
-    })`,
-				"package_name": `"pkg_name"`,
-			}), MakeBazelTarget("apex", "override_foo", AttrNameToString{
-				"base_apex_name": `"foo"`,
-				"file_contexts":  `":foo-file_contexts"`,
-				"manifest":       `"apex_manifest.json"`,
-				"min_sdk_version": `select({
-        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": "30",
-        "//conditions:default": "31",
-    })`,
-				"package_name": `"override_pkg_name"`,
-			}),
-		}})
-}
-
-func TestApexBundleSimple_customCannedFsConfig(t *testing.T) {
-	runApexTestCase(t, Bp2buildTestCase{
-		Description:                "apex - custom canned_fs_config",
-		ModuleTypeUnderTest:        "apex",
-		ModuleTypeUnderTestFactory: apex.BundleFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: `
-apex {
-	name: "com.android.apogee",
-	canned_fs_config: "custom.canned_fs_config",
-	file_contexts: "file_contexts_file",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
-				"canned_fs_config": `"custom.canned_fs_config"`,
-				"file_contexts":    `"file_contexts_file"`,
-				"manifest":         `"apex_manifest.json"`,
-			}),
-		}})
-}
diff --git a/bp2build/apex_key_conversion_test.go b/bp2build/apex_key_conversion_test.go
deleted file mode 100644
index f9a68c9..0000000
--- a/bp2build/apex_key_conversion_test.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"android/soong/android"
-	"android/soong/apex"
-
-	"testing"
-)
-
-func runApexKeyTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	RunBp2BuildTestCase(t, registerApexKeyModuleTypes, tc)
-}
-
-func registerApexKeyModuleTypes(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
-}
-
-func TestApexKeySimple_KeysAreSrcFilesInSameDir(t *testing.T) {
-	runApexKeyTestCase(t, Bp2buildTestCase{
-		Description:                "apex key - keys are src files, use key attributes",
-		ModuleTypeUnderTest:        "apex_key",
-		ModuleTypeUnderTestFactory: apex.ApexKeyFactory,
-		Filesystem: map[string]string{
-			"com.android.apogee.avbpubkey": "",
-			"com.android.apogee.pem":       "",
-		},
-		Blueprint: `
-apex_key {
-        name: "com.android.apogee.key",
-        public_key: "com.android.apogee.avbpubkey",
-        private_key: "com.android.apogee.pem",
-}
-`,
-		ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{
-			"private_key": `"com.android.apogee.pem"`,
-			"public_key":  `"com.android.apogee.avbpubkey"`,
-		}),
-		}})
-}
-
-func TestApexKeySimple_KeysAreSrcFilesNotInDir(t *testing.T) {
-	runApexKeyTestCase(t, Bp2buildTestCase{
-		Description:                "apex key - keys are not src or module, use key_name attributes",
-		ModuleTypeUnderTest:        "apex_key",
-		ModuleTypeUnderTestFactory: apex.ApexKeyFactory,
-		Filesystem:                 map[string]string{
-			// deliberately left empty
-		},
-		Blueprint: `
-apex_key {
-        name: "com.android.apogee.key",
-        public_key: "com.android.apogee.avbpubkey",
-        private_key: "com.android.apogee.pem",
-}
-`,
-		ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{
-			"private_key_name": `"com.android.apogee.pem"`,
-			"public_key_name":  `"com.android.apogee.avbpubkey"`,
-		}),
-		}})
-}
-
-func TestApexKey_KeysAreModules(t *testing.T) {
-	runApexKeyTestCase(t, Bp2buildTestCase{
-		Description:                "apex key - keys are modules, use key attributes",
-		ModuleTypeUnderTest:        "apex_key",
-		ModuleTypeUnderTestFactory: apex.ApexKeyFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: `
-apex_key {
-        name: "com.android.apogee.key",
-        public_key: ":com.android.apogee.avbpubkey",
-        private_key: ":com.android.apogee.pem",
-}
-` + simpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee.avbpubkey") +
-			simpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee.pem"),
-		ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{
-			"private_key": `":com.android.apogee.pem"`,
-			"public_key":  `":com.android.apogee.avbpubkey"`,
-		}),
-		}})
-}
diff --git a/bp2build/api_domain_conversion_test.go b/bp2build/api_domain_conversion_test.go
deleted file mode 100644
index 224008f..0000000
--- a/bp2build/api_domain_conversion_test.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/cc"
-)
-
-func registerApiDomainModuleTypes(ctx android.RegistrationContext) {
-	android.RegisterApiDomainBuildComponents(ctx)
-	cc.RegisterNdkModuleTypes(ctx)
-	cc.RegisterLibraryBuildComponents(ctx)
-}
-
-func TestApiDomainContributionsTest(t *testing.T) {
-	bp := `
-	api_domain {
-		name: "system",
-		cc_api_contributions: [
-			"libfoo.ndk",
-			"libbar",
-		],
-	}
-	`
-	fs := map[string]string{
-		"libfoo/Android.bp": `
-		ndk_library {
-			name: "libfoo",
-		}
-		`,
-		"libbar/Android.bp": `
-		cc_library {
-			name: "libbar",
-		}
-		`,
-	}
-	expectedBazelTarget := MakeBazelTargetNoRestrictions(
-		"api_domain",
-		"system",
-		AttrNameToString{
-			"cc_api_contributions": `[
-        "//libfoo:libfoo.ndk.contribution",
-        "//libbar:libbar.contribution",
-    ]`,
-			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-		},
-	)
-	RunApiBp2BuildTestCase(t, registerApiDomainModuleTypes, Bp2buildTestCase{
-		Blueprint:            bp,
-		ExpectedBazelTargets: []string{expectedBazelTarget},
-		Filesystem:           fs,
-	})
-}
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
deleted file mode 100644
index 5f7b382..0000000
--- a/bp2build/bp2build.go
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2020 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"fmt"
-	"os"
-	"path/filepath"
-	"strings"
-
-	"android/soong/android"
-	"android/soong/bazel"
-	"android/soong/shared"
-	"android/soong/starlark_import"
-)
-
-func deleteFilesExcept(ctx *CodegenContext, rootOutputPath android.OutputPath, except []BazelFile) {
-	// Delete files that should no longer be present.
-	bp2buildDirAbs := shared.JoinPath(ctx.topDir, rootOutputPath.String())
-
-	filesToDelete := make(map[string]struct{})
-	err := filepath.Walk(bp2buildDirAbs,
-		func(path string, info os.FileInfo, err error) error {
-			if err != nil {
-				return err
-			}
-			if !info.IsDir() {
-				relPath, err := filepath.Rel(bp2buildDirAbs, path)
-				if err != nil {
-					return err
-				}
-				filesToDelete[relPath] = struct{}{}
-			}
-			return nil
-		})
-	if err != nil {
-		fmt.Printf("ERROR reading %s: %s", bp2buildDirAbs, err)
-		os.Exit(1)
-	}
-
-	for _, bazelFile := range except {
-		filePath := filepath.Join(bazelFile.Dir, bazelFile.Basename)
-		delete(filesToDelete, filePath)
-	}
-	for f, _ := range filesToDelete {
-		absPath := shared.JoinPath(bp2buildDirAbs, f)
-		if err := os.RemoveAll(absPath); err != nil {
-			fmt.Printf("ERROR deleting %s: %s", absPath, err)
-			os.Exit(1)
-		}
-	}
-}
-
-// Codegen is the backend of bp2build. The code generator is responsible for
-// writing .bzl files that are equivalent to Android.bp files that are capable
-// of being built with Bazel.
-func Codegen(ctx *CodegenContext) *CodegenMetrics {
-	ctx.Context().BeginEvent("Codegen")
-	defer ctx.Context().EndEvent("Codegen")
-	// This directory stores BUILD files that could be eventually checked-in.
-	bp2buildDir := android.PathForOutput(ctx, "bp2build")
-
-	res, errs := GenerateBazelTargets(ctx, true)
-	if len(errs) > 0 {
-		errMsgs := make([]string, len(errs))
-		for i, err := range errs {
-			errMsgs[i] = fmt.Sprintf("%q", err)
-		}
-		fmt.Printf("ERROR: Encountered %d error(s): \nERROR: %s", len(errs), strings.Join(errMsgs, "\n"))
-		os.Exit(1)
-	}
-	var bp2buildFiles []BazelFile
-	ctx.Context().EventHandler.Do("CreateBazelFile", func() {
-		bp2buildFiles = CreateBazelFiles(nil, res.buildFileToTargets, ctx.mode)
-	})
-	injectionFiles, additionalBp2buildFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics)
-	if err != nil {
-		fmt.Printf("%s\n", err.Error())
-		os.Exit(1)
-	}
-	bp2buildFiles = append(bp2buildFiles, additionalBp2buildFiles...)
-	writeFiles(ctx, bp2buildDir, bp2buildFiles)
-	// Delete files under the bp2build root which weren't just written. An
-	// alternative would have been to delete the whole directory and write these
-	// files. However, this would regenerate files which were otherwise unchanged
-	// since the last bp2build run, which would have negative incremental
-	// performance implications.
-	deleteFilesExcept(ctx, bp2buildDir, bp2buildFiles)
-
-	writeFiles(ctx, android.PathForOutput(ctx, bazel.SoongInjectionDirName), injectionFiles)
-	starlarkDeps, err := starlark_import.GetNinjaDeps()
-	if err != nil {
-		fmt.Fprintf(os.Stderr, "%s\n", err)
-		os.Exit(1)
-	}
-	ctx.AddNinjaFileDeps(starlarkDeps...)
-	return &res.metrics
-}
-
-// Wrapper function that will be responsible for all files in soong_injection directory
-// This includes
-// 1. config value(s) that are hardcoded in Soong
-// 2. product_config variables
-func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) {
-	var ret []BazelFile
-
-	productConfigInjectionFiles, productConfigBp2BuildDirFiles, err := CreateProductConfigFiles(ctx, metrics)
-	if err != nil {
-		return nil, nil, err
-	}
-	ret = append(ret, productConfigInjectionFiles...)
-	injectionFiles, err := soongInjectionFiles(ctx.Config(), metrics)
-	if err != nil {
-		return nil, nil, err
-	}
-	ret = append(injectionFiles, ret...)
-	return ret, productConfigBp2BuildDirFiles, nil
-}
-
-// Get the output directory and create it if it doesn't exist.
-func getOrCreateOutputDir(outputDir android.OutputPath, ctx android.PathContext, dir string) android.OutputPath {
-	dirPath := outputDir.Join(ctx, dir)
-	if err := android.CreateOutputDirIfNonexistent(dirPath, os.ModePerm); err != nil {
-		fmt.Printf("ERROR: path %s: %s", dirPath, err.Error())
-	}
-	return dirPath
-}
-
-// writeFiles materializes a list of BazelFile rooted at outputDir.
-func writeFiles(ctx android.PathContext, outputDir android.OutputPath, files []BazelFile) {
-	for _, f := range files {
-		p := getOrCreateOutputDir(outputDir, ctx, f.Dir).Join(ctx, f.Basename)
-		if err := writeFile(p, f.Contents); err != nil {
-			panic(fmt.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err))
-		}
-	}
-}
-
-func writeFile(pathToFile android.OutputPath, content string) error {
-	// These files are made editable to allow users to modify and iterate on them
-	// in the source tree.
-	return android.WriteFileToOutputDir(pathToFile, []byte(content), 0644)
-}
diff --git a/bp2build/bp2build_product_config.go b/bp2build/bp2build_product_config.go
deleted file mode 100644
index e8c2ef7..0000000
--- a/bp2build/bp2build_product_config.go
+++ /dev/null
@@ -1,400 +0,0 @@
-package bp2build
-
-import (
-	"android/soong/android"
-	"android/soong/android/soongconfig"
-	"android/soong/starlark_import"
-	"encoding/json"
-	"fmt"
-	"os"
-	"path/filepath"
-	"reflect"
-	"strings"
-
-	"github.com/google/blueprint/proptools"
-	"go.starlark.net/starlark"
-)
-
-func CreateProductConfigFiles(
-	ctx *CodegenContext,
-	metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) {
-	cfg := &ctx.config
-	targetProduct := "unknown"
-	if cfg.HasDeviceProduct() {
-		targetProduct = cfg.DeviceProduct()
-	}
-	targetBuildVariant := "user"
-	if cfg.Eng() {
-		targetBuildVariant = "eng"
-	} else if cfg.Debuggable() {
-		targetBuildVariant = "userdebug"
-	}
-
-	productVariablesFileName := cfg.ProductVariablesFileName
-	if !strings.HasPrefix(productVariablesFileName, "/") {
-		productVariablesFileName = filepath.Join(ctx.topDir, productVariablesFileName)
-	}
-	productVariablesBytes, err := os.ReadFile(productVariablesFileName)
-	if err != nil {
-		return nil, nil, err
-	}
-	productVariables := android.ProductVariables{}
-	err = json.Unmarshal(productVariablesBytes, &productVariables)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	// TODO(b/249685973): the name is product_config_platforms because product_config
-	// was already used for other files. Deduplicate them.
-	currentProductFolder := fmt.Sprintf("product_config_platforms/products/%s-%s", targetProduct, targetBuildVariant)
-
-	productReplacer := strings.NewReplacer(
-		"{PRODUCT}", targetProduct,
-		"{VARIANT}", targetBuildVariant,
-		"{PRODUCT_FOLDER}", currentProductFolder)
-
-	platformMappingContent, err := platformMappingContent(
-		productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"),
-		&productVariables,
-		ctx.Config().Bp2buildSoongConfigDefinitions,
-		metrics.convertedModulePathMap)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	productsForTestingMap, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing")
-	if err != nil {
-		return nil, nil, err
-	}
-	productsForTesting := android.SortedKeys(productsForTestingMap)
-	for i := range productsForTesting {
-		productsForTesting[i] = fmt.Sprintf("  \"@//build/bazel/tests/products:%s\",", productsForTesting[i])
-	}
-
-	injectionDirFiles := []BazelFile{
-		newFile(
-			currentProductFolder,
-			"soong.variables.bzl",
-			`variables = json.decode("""`+strings.ReplaceAll(string(productVariablesBytes), "\\", "\\\\")+`""")`),
-		newFile(
-			currentProductFolder,
-			"BUILD",
-			productReplacer.Replace(`
-package(default_visibility=[
-    "@soong_injection//product_config_platforms:__subpackages__",
-    "@//build/bazel/product_config:__subpackages__",
-])
-load(":soong.variables.bzl", _soong_variables = "variables")
-load("@//build/bazel/product_config:android_product.bzl", "android_product")
-
-android_product(
-    name = "{PRODUCT}-{VARIANT}",
-    soong_variables = _soong_variables,
-)
-`)),
-		newFile(
-			"product_config_platforms",
-			"BUILD.bazel",
-			productReplacer.Replace(`
-package(default_visibility = [
-	"@//build/bazel/product_config:__subpackages__",
-	"@soong_injection//product_config_platforms:__subpackages__",
-])
-
-load("//{PRODUCT_FOLDER}:soong.variables.bzl", _soong_variables = "variables")
-load("@//build/bazel/product_config:android_product.bzl", "android_product")
-
-# Bazel will qualify its outputs by the platform name. When switching between products, this
-# means that soong-built files that depend on bazel-built files will suddenly get different
-# dependency files, because the path changes, and they will be rebuilt. In order to avoid this
-# extra rebuilding, make mixed builds always use a single platform so that the bazel artifacts
-# are always under the same path.
-android_product(
-    name = "mixed_builds_product-{VARIANT}",
-    soong_variables = _soong_variables,
-    extra_constraints = ["@//build/bazel/platforms:mixed_builds"],
-)
-`)),
-		newFile(
-			"product_config_platforms",
-			"product_labels.bzl",
-			productReplacer.Replace(`
-# This file keeps a list of all the products in the android source tree, because they're
-# discovered as part of a preprocessing step before bazel runs.
-# TODO: When we start generating the platforms for more than just the
-# currently lunched product, they should all be listed here
-product_labels = [
-  "@soong_injection//product_config_platforms:mixed_builds_product-{VARIANT}",
-  "@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}",
-`)+strings.Join(productsForTesting, "\n")+"\n]\n"),
-		newFile(
-			"product_config_platforms",
-			"common.bazelrc",
-			productReplacer.Replace(`
-build --platform_mappings=platform_mappings
-build --platforms @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
-
-build:android --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}
-build:linux_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86
-build:linux_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
-build:linux_bionic_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_bionic_x86_64
-build:linux_musl_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86
-build:linux_musl_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86_64
-`)),
-		newFile(
-			"product_config_platforms",
-			"linux.bazelrc",
-			productReplacer.Replace(`
-build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
-`)),
-		newFile(
-			"product_config_platforms",
-			"darwin.bazelrc",
-			productReplacer.Replace(`
-build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_darwin_x86_64
-`)),
-	}
-	bp2buildDirFiles := []BazelFile{
-		newFile(
-			"",
-			"platform_mappings",
-			platformMappingContent),
-	}
-	return injectionDirFiles, bp2buildDirFiles, nil
-}
-
-func platformMappingContent(
-	mainProductLabel string,
-	mainProductVariables *android.ProductVariables,
-	soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions,
-	convertedModulePathMap map[string]string) (string, error) {
-	productsForTesting, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing")
-	if err != nil {
-		return "", err
-	}
-	var result strings.Builder
-
-	mergedConvertedModulePathMap := make(map[string]string)
-	for k, v := range convertedModulePathMap {
-		mergedConvertedModulePathMap[k] = v
-	}
-	additionalModuleNamesToPackages, err := starlark_import.GetStarlarkValue[map[string]string]("additional_module_names_to_packages")
-	if err != nil {
-		return "", err
-	}
-	for k, v := range additionalModuleNamesToPackages {
-		mergedConvertedModulePathMap[k] = v
-	}
-
-	result.WriteString("platforms:\n")
-	platformMappingSingleProduct(mainProductLabel, mainProductVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result)
-	for product, productVariablesStarlark := range productsForTesting {
-		productVariables, err := starlarkMapToProductVariables(productVariablesStarlark)
-		if err != nil {
-			return "", err
-		}
-		platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result)
-	}
-	return result.String(), nil
-}
-
-var bazelPlatformSuffixes = []string{
-	"",
-	"_darwin_arm64",
-	"_darwin_x86_64",
-	"_linux_bionic_arm64",
-	"_linux_bionic_x86_64",
-	"_linux_musl_x86",
-	"_linux_musl_x86_64",
-	"_linux_x86",
-	"_linux_x86_64",
-	"_windows_x86",
-	"_windows_x86_64",
-}
-
-func platformMappingSingleProduct(
-	label string,
-	productVariables *android.ProductVariables,
-	soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions,
-	convertedModulePathMap map[string]string,
-	result *strings.Builder) {
-	targetBuildVariant := "user"
-	if proptools.Bool(productVariables.Eng) {
-		targetBuildVariant = "eng"
-	} else if proptools.Bool(productVariables.Debuggable) {
-		targetBuildVariant = "userdebug"
-	}
-
-	platform_sdk_version := -1
-	if productVariables.Platform_sdk_version != nil {
-		platform_sdk_version = *productVariables.Platform_sdk_version
-	}
-
-	defaultAppCertificateFilegroup := "//build/bazel/utils:empty_filegroup"
-	if proptools.String(productVariables.DefaultAppCertificate) != "" {
-		defaultAppCertificateFilegroup = "@//" + filepath.Dir(proptools.String(productVariables.DefaultAppCertificate)) + ":android_certificate_directory"
-	}
-
-	for _, suffix := range bazelPlatformSuffixes {
-		result.WriteString("  ")
-		result.WriteString(label)
-		result.WriteString(suffix)
-		result.WriteString("\n")
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:always_use_prebuilt_sdks=%t\n", proptools.Bool(productVariables.Always_use_prebuilt_sdks)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:arc=%t\n", proptools.Bool(productVariables.Arc)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:apex_global_min_sdk_version_override=%s\n", proptools.String(productVariables.ApexGlobalMinSdkVersionOverride)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:binder32bit=%t\n", proptools.Bool(productVariables.Binder32bit)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:build_from_text_stub=%t\n", proptools.Bool(productVariables.Build_from_text_stub)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:build_id=%s\n", proptools.String(productVariables.BuildId)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:build_version_tags=%s\n", strings.Join(productVariables.BuildVersionTags, ",")))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:cfi_exclude_paths=%s\n", strings.Join(productVariables.CFIExcludePaths, ",")))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:cfi_include_paths=%s\n", strings.Join(productVariables.CFIIncludePaths, ",")))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:compressed_apex=%t\n", proptools.Bool(productVariables.CompressedApex)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:debuggable=%t\n", proptools.Bool(productVariables.Debuggable)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:default_app_certificate=%s\n", proptools.String(productVariables.DefaultAppCertificate)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:default_app_certificate_filegroup=%s\n", defaultAppCertificateFilegroup))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_abi=%s\n", strings.Join(productVariables.DeviceAbi, ",")))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_max_page_size_supported=%s\n", proptools.String(productVariables.DeviceMaxPageSizeSupported)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_name=%s\n", proptools.String(productVariables.DeviceName)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_page_size_agnostic=%t\n", proptools.Bool(productVariables.DevicePageSizeAgnostic)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_product=%s\n", proptools.String(productVariables.DeviceProduct)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:enable_cfi=%t\n", proptools.BoolDefault(productVariables.EnableCFI, true)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:enforce_vintf_manifest=%t\n", proptools.Bool(productVariables.Enforce_vintf_manifest)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:eng=%t\n", proptools.Bool(productVariables.Eng)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:malloc_not_svelte=%t\n", proptools.Bool(productVariables.Malloc_not_svelte)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:malloc_pattern_fill_contents=%t\n", proptools.Bool(productVariables.Malloc_pattern_fill_contents)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:malloc_zero_contents=%t\n", proptools.Bool(productVariables.Malloc_zero_contents)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:manifest_package_name_overrides=%s\n", strings.Join(productVariables.ManifestPackageNameOverrides, ",")))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:native_coverage=%t\n", proptools.Bool(productVariables.Native_coverage)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:platform_version_name=%s\n", proptools.String(productVariables.Platform_version_name)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:product_brand=%s\n", productVariables.ProductBrand))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:product_manufacturer=%s\n", productVariables.ProductManufacturer))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:platform_sdk_version=%d\n", platform_sdk_version))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:safestack=%t\n", proptools.Bool(productVariables.Safestack)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:target_build_variant=%s\n", targetBuildVariant))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:treble_linker_namespaces=%t\n", proptools.Bool(productVariables.Treble_linker_namespaces)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:tidy_checks=%s\n", proptools.String(productVariables.TidyChecks)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:uml=%t\n", proptools.Bool(productVariables.Uml)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:unbundled_build=%t\n", proptools.Bool(productVariables.Unbundled_build)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:unbundled_build_apps=%s\n", strings.Join(productVariables.Unbundled_build_apps, ",")))
-
-		for _, override := range productVariables.CertificateOverrides {
-			parts := strings.SplitN(override, ":", 2)
-			if apexPath, ok := convertedModulePathMap[parts[0]]; ok {
-				if overrideCertPath, ok := convertedModulePathMap[parts[1]]; ok {
-					result.WriteString(fmt.Sprintf("    --%s:%s_certificate_override=%s:%s\n", apexPath, parts[0], overrideCertPath, parts[1]))
-				}
-			}
-		}
-
-		for namespace, namespaceContents := range productVariables.VendorVars {
-			for variable, value := range namespaceContents {
-				key := namespace + "__" + variable
-				_, hasBool := soongConfigDefinitions.BoolVars[key]
-				_, hasString := soongConfigDefinitions.StringVars[key]
-				_, hasValue := soongConfigDefinitions.ValueVars[key]
-				if !hasBool && !hasString && !hasValue {
-					// Not all soong config variables are defined in Android.bp files. For example,
-					// prebuilt_bootclasspath_fragment uses soong config variables in a nonstandard
-					// way, that causes them to be present in the soong.variables file but not
-					// defined in an Android.bp file. There's also nothing stopping you from setting
-					// a variable in make that doesn't exist in soong. We only generate build
-					// settings for the ones that exist in soong, so skip all others.
-					continue
-				}
-				if hasBool && hasString || hasBool && hasValue || hasString && hasValue {
-					panic(fmt.Sprintf("Soong config variable %s:%s appears to be of multiple types. bool? %t, string? %t, value? %t", namespace, variable, hasBool, hasString, hasValue))
-				}
-				if hasBool {
-					// Logic copied from soongConfig.Bool()
-					value = strings.ToLower(value)
-					if value == "1" || value == "y" || value == "yes" || value == "on" || value == "true" {
-						value = "true"
-					} else {
-						value = "false"
-					}
-				}
-				result.WriteString(fmt.Sprintf("    --//build/bazel/product_config/soong_config_variables:%s=%s\n", strings.ToLower(key), value))
-			}
-		}
-	}
-}
-
-func starlarkMapToProductVariables(in map[string]starlark.Value) (android.ProductVariables, error) {
-	result := android.ProductVariables{}
-	productVarsReflect := reflect.ValueOf(&result).Elem()
-	for i := 0; i < productVarsReflect.NumField(); i++ {
-		field := productVarsReflect.Field(i)
-		fieldType := productVarsReflect.Type().Field(i)
-		name := fieldType.Name
-		if name == "BootJars" || name == "ApexBootJars" || name == "VendorSnapshotModules" ||
-			name == "RecoverySnapshotModules" {
-			// These variables have more complicated types, and we don't need them right now
-			continue
-		}
-		if _, ok := in[name]; ok {
-			if name == "VendorVars" {
-				vendorVars, err := starlark_import.Unmarshal[map[string]map[string]string](in[name])
-				if err != nil {
-					return result, err
-				}
-				field.Set(reflect.ValueOf(vendorVars))
-				continue
-			}
-			switch field.Type().Kind() {
-			case reflect.Bool:
-				val, err := starlark_import.Unmarshal[bool](in[name])
-				if err != nil {
-					return result, err
-				}
-				field.SetBool(val)
-			case reflect.String:
-				val, err := starlark_import.Unmarshal[string](in[name])
-				if err != nil {
-					return result, err
-				}
-				field.SetString(val)
-			case reflect.Slice:
-				if field.Type().Elem().Kind() != reflect.String {
-					return result, fmt.Errorf("slices of types other than strings are unimplemented")
-				}
-				val, err := starlark_import.UnmarshalReflect(in[name], field.Type())
-				if err != nil {
-					return result, err
-				}
-				field.Set(val)
-			case reflect.Pointer:
-				switch field.Type().Elem().Kind() {
-				case reflect.Bool:
-					val, err := starlark_import.UnmarshalNoneable[bool](in[name])
-					if err != nil {
-						return result, err
-					}
-					field.Set(reflect.ValueOf(val))
-				case reflect.String:
-					val, err := starlark_import.UnmarshalNoneable[string](in[name])
-					if err != nil {
-						return result, err
-					}
-					field.Set(reflect.ValueOf(val))
-				case reflect.Int:
-					val, err := starlark_import.UnmarshalNoneable[int](in[name])
-					if err != nil {
-						return result, err
-					}
-					field.Set(reflect.ValueOf(val))
-				default:
-					return result, fmt.Errorf("pointers of types other than strings/bools are unimplemented: %s", field.Type().Elem().Kind().String())
-				}
-			default:
-				return result, fmt.Errorf("unimplemented type: %s", field.Type().String())
-			}
-		}
-	}
-
-	result.Native_coverage = proptools.BoolPtr(
-		proptools.Bool(result.GcovCoverage) ||
-			proptools.Bool(result.ClangCoverage))
-
-	return result, nil
-}
diff --git a/bp2build/bp2build_product_config_test.go b/bp2build/bp2build_product_config_test.go
deleted file mode 100644
index 02d83b4..0000000
--- a/bp2build/bp2build_product_config_test.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package bp2build
-
-import (
-	"android/soong/android"
-	"android/soong/starlark_import"
-	"encoding/json"
-	"reflect"
-	"testing"
-
-	"github.com/google/blueprint/proptools"
-	"go.starlark.net/starlark"
-)
-
-func createStarlarkValue(t *testing.T, code string) starlark.Value {
-	t.Helper()
-	result, err := starlark.ExecFile(&starlark.Thread{}, "main.bzl", "x = "+code, nil)
-	if err != nil {
-		t.Error(err)
-	}
-	return result["x"]
-}
-
-func createStarlarkProductVariablesMap(t *testing.T, code string) map[string]starlark.Value {
-	t.Helper()
-	rawValue := createStarlarkValue(t, code)
-	value, err := starlark_import.Unmarshal[map[string]starlark.Value](rawValue)
-	if err != nil {
-		t.Error(err)
-	}
-	return value
-}
-
-func TestStarlarkMapToProductVariables(t *testing.T) {
-	thirty := 30
-	cases := []struct {
-		starlark string
-		result   android.ProductVariables
-	}{
-		{
-			starlark: `{"CompressedApex": True}`,
-			result:   android.ProductVariables{CompressedApex: proptools.BoolPtr(true)},
-		},
-		{
-			starlark: `{"ApexGlobalMinSdkVersionOverride": "Tiramisu"}`,
-			result:   android.ProductVariables{ApexGlobalMinSdkVersionOverride: proptools.StringPtr("Tiramisu")},
-		},
-		{
-			starlark: `{"ProductManufacturer": "Google"}`,
-			result:   android.ProductVariables{ProductManufacturer: "Google"},
-		},
-		{
-			starlark: `{"Unbundled_build_apps": ["app1", "app2"]}`,
-			result:   android.ProductVariables{Unbundled_build_apps: []string{"app1", "app2"}},
-		},
-		{
-			starlark: `{"Platform_sdk_version": 30}`,
-			result:   android.ProductVariables{Platform_sdk_version: &thirty},
-		},
-		{
-			starlark: `{"HostFakeSnapshotEnabled": True}`,
-			result:   android.ProductVariables{HostFakeSnapshotEnabled: true},
-		},
-	}
-
-	for _, testCase := range cases {
-		productVariables, err := starlarkMapToProductVariables(createStarlarkProductVariablesMap(t,
-			testCase.starlark))
-		if err != nil {
-			t.Error(err)
-			continue
-		}
-		testCase.result.Native_coverage = proptools.BoolPtr(false)
-		if !reflect.DeepEqual(testCase.result, productVariables) {
-			expected, err := json.Marshal(testCase.result)
-			if err != nil {
-				t.Error(err)
-				continue
-			}
-			actual, err := json.Marshal(productVariables)
-			if err != nil {
-				t.Error(err)
-				continue
-			}
-			expectedStr := string(expected)
-			actualStr := string(actual)
-			t.Errorf("expected %q, but got %q", expectedStr, actualStr)
-		}
-	}
-}
diff --git a/bp2build/bpf_conversion_test.go b/bp2build/bpf_conversion_test.go
deleted file mode 100644
index 1259f9e..0000000
--- a/bp2build/bpf_conversion_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"android/soong/android"
-	"android/soong/bpf"
-
-	"testing"
-)
-
-func runBpfTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "bpf"
-	(&tc).ModuleTypeUnderTestFactory = bpf.BpfFactory
-	RunBp2BuildTestCase(t, registerBpfModuleTypes, tc)
-}
-
-func registerBpfModuleTypes(ctx android.RegistrationContext) {}
-
-func TestBpfSupportedAttrs(t *testing.T) {
-	runBpfTestCase(t, Bp2buildTestCase{
-		Description: "Bpf module only converts supported attributes",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-bpf {
-    name: "bpfTestOut.o",
-    srcs: ["bpfTestSrcOne.c",
-           "bpfTestSrcTwo.c"],
-    btf: true,
-    cflags: ["-bpfCflagOne",
-             "-bpfCflagTwo"],
-    include_dirs: ["ia/ib/ic"],
-    sub_dir: "sa/ab",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("bpf", "bpfTestOut.o", AttrNameToString{
-				"absolute_includes": `["ia/ib/ic"]`,
-				"btf":               `True`,
-				"copts": `[
-        "-bpfCflagOne",
-        "-bpfCflagTwo",
-    ]`,
-				"srcs": `[
-        "bpfTestSrcOne.c",
-        "bpfTestSrcTwo.c",
-    ]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 6ca4bb4..bd56768 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -28,10 +28,7 @@
 	"android/soong/android"
 	"android/soong/bazel"
 	"android/soong/starlark_fmt"
-	"android/soong/ui/metrics/bp2build_metrics_proto"
-
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -39,18 +36,24 @@
 	Attrs map[string]string
 }
 
-type BazelTarget struct {
-	name            string
-	packageName     string
-	content         string
-	ruleClass       string
-	bzlLoadLocation string
+type BazelLoadSymbol struct {
+	// The name of the symbol in the file being loaded
+	symbol string
+	// The name the symbol wil have in this file. Can be left blank to use the same name as symbol.
+	alias string
 }
 
-// IsLoadedFromStarlark determines if the BazelTarget's rule class is loaded from a .bzl file,
-// as opposed to a native rule built into Bazel.
-func (t BazelTarget) IsLoadedFromStarlark() bool {
-	return t.bzlLoadLocation != ""
+type BazelLoad struct {
+	file    string
+	symbols []BazelLoadSymbol
+}
+
+type BazelTarget struct {
+	name        string
+	packageName string
+	content     string
+	ruleClass   string
+	loads       []BazelLoad
 }
 
 // Label is the fully qualified Bazel label constructed from the BazelTarget's
@@ -110,30 +113,62 @@
 // LoadStatements return the string representation of the sorted and deduplicated
 // Starlark rule load statements needed by a group of BazelTargets.
 func (targets BazelTargets) LoadStatements() string {
-	bzlToLoadedSymbols := map[string][]string{}
+	// First, merge all the load statements from all the targets onto one list
+	bzlToLoadedSymbols := map[string][]BazelLoadSymbol{}
 	for _, target := range targets {
-		if target.IsLoadedFromStarlark() {
-			bzlToLoadedSymbols[target.bzlLoadLocation] =
-				append(bzlToLoadedSymbols[target.bzlLoadLocation], target.ruleClass)
+		for _, load := range target.loads {
+		outer:
+			for _, symbol := range load.symbols {
+				alias := symbol.alias
+				if alias == "" {
+					alias = symbol.symbol
+				}
+				for _, otherSymbol := range bzlToLoadedSymbols[load.file] {
+					otherAlias := otherSymbol.alias
+					if otherAlias == "" {
+						otherAlias = otherSymbol.symbol
+					}
+					if symbol.symbol == otherSymbol.symbol && alias == otherAlias {
+						continue outer
+					} else if alias == otherAlias {
+						panic(fmt.Sprintf("Conflicting destination (%s) for loads of %s and %s", alias, symbol.symbol, otherSymbol.symbol))
+					}
+				}
+				bzlToLoadedSymbols[load.file] = append(bzlToLoadedSymbols[load.file], symbol)
+			}
 		}
 	}
 
-	var loadStatements []string
-	for bzl, ruleClasses := range bzlToLoadedSymbols {
-		loadStatement := "load(\""
-		loadStatement += bzl
-		loadStatement += "\", "
-		ruleClasses = android.SortedUniqueStrings(ruleClasses)
-		for i, ruleClass := range ruleClasses {
-			loadStatement += "\"" + ruleClass + "\""
-			if i != len(ruleClasses)-1 {
-				loadStatement += ", "
+	var loadStatements strings.Builder
+	for i, bzl := range android.SortedKeys(bzlToLoadedSymbols) {
+		symbols := bzlToLoadedSymbols[bzl]
+		loadStatements.WriteString("load(\"")
+		loadStatements.WriteString(bzl)
+		loadStatements.WriteString("\", ")
+		sort.Slice(symbols, func(i, j int) bool {
+			if symbols[i].symbol < symbols[j].symbol {
+				return true
+			}
+			return symbols[i].alias < symbols[j].alias
+		})
+		for j, symbol := range symbols {
+			if symbol.alias != "" && symbol.alias != symbol.symbol {
+				loadStatements.WriteString(symbol.alias)
+				loadStatements.WriteString(" = ")
+			}
+			loadStatements.WriteString("\"")
+			loadStatements.WriteString(symbol.symbol)
+			loadStatements.WriteString("\"")
+			if j != len(symbols)-1 {
+				loadStatements.WriteString(", ")
 			}
 		}
-		loadStatement += ")"
-		loadStatements = append(loadStatements, loadStatement)
+		loadStatements.WriteString(")")
+		if i != len(bzlToLoadedSymbols)-1 {
+			loadStatements.WriteString("\n")
+		}
 	}
-	return strings.Join(android.SortedUniqueStrings(loadStatements), "\n")
+	return loadStatements.String()
 }
 
 type bpToBuildContext interface {
@@ -163,21 +198,13 @@
 type CodegenMode int
 
 const (
-	// Bp2Build - generate BUILD files with targets buildable by Bazel directly.
-	//
-	// This mode is used for the Soong->Bazel build definition conversion.
-	Bp2Build CodegenMode = iota
-
 	// QueryView - generate BUILD files with targets representing fully mutated
 	// Soong modules, representing the fully configured Soong module graph with
 	// variants and dependency edges.
 	//
 	// This mode is used for discovering and introspecting the existing Soong
 	// module graph.
-	QueryView
-
-	// ApiBp2build - generate BUILD files for API contribution targets
-	ApiBp2build
+	QueryView CodegenMode = iota
 )
 
 type unconvertedDepsMode int
@@ -192,12 +219,8 @@
 
 func (mode CodegenMode) String() string {
 	switch mode {
-	case Bp2Build:
-		return "Bp2Build"
 	case QueryView:
 		return "QueryView"
-	case ApiBp2build:
-		return "ApiBp2build"
 	default:
 		return fmt.Sprintf("%d", mode)
 	}
@@ -223,9 +246,6 @@
 // writing BUILD files in the output directory.
 func NewCodegenContext(config android.Config, context *android.Context, mode CodegenMode, topDir string) *CodegenContext {
 	var unconvertedDeps unconvertedDepsMode
-	if config.IsEnvTrue("BP2BUILD_ERROR_UNCONVERTED") {
-		unconvertedDeps = errorModulesUnconvertedDeps
-	}
 	return &CodegenContext{
 		context:            context,
 		config:             config,
@@ -246,519 +266,32 @@
 }
 
 type conversionResults struct {
-	buildFileToTargets map[string]BazelTargets
-	metrics            CodegenMetrics
+	buildFileToTargets    map[string]BazelTargets
+	moduleNameToPartition map[string]string
 }
 
 func (r conversionResults) BuildDirToTargets() map[string]BazelTargets {
 	return r.buildFileToTargets
 }
 
-// struct to store state of go bazel targets
-// this implements bp2buildModule interface and is passed to generateBazelTargets
-type goBazelTarget struct {
-	targetName            string
-	targetPackage         string
-	bazelRuleClass        string
-	bazelRuleLoadLocation string
-	bazelAttributes       []interface{}
-}
-
-var _ bp2buildModule = (*goBazelTarget)(nil)
-
-func (g goBazelTarget) TargetName() string {
-	return g.targetName
-}
-
-func (g goBazelTarget) TargetPackage() string {
-	return g.targetPackage
-}
-
-func (g goBazelTarget) BazelRuleClass() string {
-	return g.bazelRuleClass
-}
-
-func (g goBazelTarget) BazelRuleLoadLocation() string {
-	return g.bazelRuleLoadLocation
-}
-
-func (g goBazelTarget) BazelAttributes() []interface{} {
-	return g.bazelAttributes
-}
-
-// Creates a target_compatible_with entry that is *not* compatible with android
-func targetNotCompatibleWithAndroid() bazel.LabelListAttribute {
-	ret := bazel.LabelListAttribute{}
-	ret.SetSelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid,
-		bazel.MakeLabelList(
-			[]bazel.Label{
-				bazel.Label{
-					Label: "@platforms//:incompatible",
-				},
-			},
-		),
-	)
-	return ret
-}
-
-// helper function to return labels for srcs used in bootstrap_go_package and bootstrap_go_binary
-// this function has the following limitations which make it unsuitable for widespread use
-// - wildcard patterns in srcs
-// This is ok for go since build/blueprint does not support it.
-//
-// Prefer to use `BazelLabelForModuleSrc` instead
-func goSrcLabels(cfg android.Config, moduleDir string, srcs []string, linuxSrcs, darwinSrcs []string) bazel.LabelListAttribute {
-	labels := func(srcs []string) bazel.LabelList {
-		ret := []bazel.Label{}
-		for _, src := range srcs {
-			srcLabel := bazel.Label{
-				Label: src,
-			}
-			ret = append(ret, srcLabel)
-		}
-		// Respect package boundaries
-		return android.TransformSubpackagePaths(
-			cfg,
-			moduleDir,
-			bazel.MakeLabelList(ret),
-		)
-	}
-
-	ret := bazel.LabelListAttribute{}
-	// common
-	ret.SetSelectValue(bazel.NoConfigAxis, "", labels(srcs))
-	// linux
-	ret.SetSelectValue(bazel.OsConfigurationAxis, bazel.OsLinux, labels(linuxSrcs))
-	// darwin
-	ret.SetSelectValue(bazel.OsConfigurationAxis, bazel.OsDarwin, labels(darwinSrcs))
-	return ret
-}
-
-func goDepLabels(deps []string, goModulesMap nameToGoLibraryModule) bazel.LabelListAttribute {
-	labels := []bazel.Label{}
-	for _, dep := range deps {
-		moduleDir := goModulesMap[dep].Dir
-		if moduleDir == "." {
-			moduleDir = ""
-		}
-		label := bazel.Label{
-			Label: fmt.Sprintf("//%s:%s", moduleDir, dep),
-		}
-		labels = append(labels, label)
-	}
-	return bazel.MakeLabelListAttribute(bazel.MakeLabelList(labels))
-}
-
-// attributes common to blueprint_go_binary and bootstap_go_package
-type goAttributes struct {
-	Importpath             bazel.StringAttribute
-	Srcs                   bazel.LabelListAttribute
-	Deps                   bazel.LabelListAttribute
-	Data                   bazel.LabelListAttribute
-	Target_compatible_with bazel.LabelListAttribute
-
-	// attributes for the dynamically generated go_test target
-	Embed bazel.LabelListAttribute
-}
-
-type goTestProperties struct {
-	name           string
-	dir            string
-	testSrcs       []string
-	linuxTestSrcs  []string
-	darwinTestSrcs []string
-	testData       []string
-	// Name of the target that should be compiled together with the test
-	embedName string
-}
-
-// Creates a go_test target for bootstrap_go_package / blueprint_go_binary
-func generateBazelTargetsGoTest(ctx *android.Context, goModulesMap nameToGoLibraryModule, gp goTestProperties) (BazelTarget, error) {
-	ca := android.CommonAttributes{
-		Name: gp.name,
-	}
-	ga := goAttributes{
-		Srcs: goSrcLabels(ctx.Config(), gp.dir, gp.testSrcs, gp.linuxTestSrcs, gp.darwinTestSrcs),
-		Data: goSrcLabels(ctx.Config(), gp.dir, gp.testData, []string{}, []string{}),
-		Embed: bazel.MakeLabelListAttribute(
-			bazel.MakeLabelList(
-				[]bazel.Label{bazel.Label{Label: ":" + gp.embedName}},
-			),
-		),
-		Target_compatible_with: targetNotCompatibleWithAndroid(),
-	}
-
-	libTest := goBazelTarget{
-		targetName:            gp.name,
-		targetPackage:         gp.dir,
-		bazelRuleClass:        "go_test",
-		bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl",
-		bazelAttributes:       []interface{}{&ca, &ga},
-	}
-	return generateBazelTarget(ctx, libTest)
-}
-
-// TODO - b/288491147: testSrcs of certain bootstrap_go_package/blueprint_go_binary are not hermetic and depend on
-// testdata checked into the filesystem.
-// Denylist the generation of go_test targets for these Soong modules.
-// The go_library/go_binary will still be generated, since those are hermitic.
-var (
-	goTestsDenylist = []string{
-		"android-archive-zip",
-		"bazel_notice_gen",
-		"blueprint-bootstrap-bpdoc",
-		"blueprint-microfactory",
-		"blueprint-pathtools",
-		"bssl_ar",
-		"compliance_checkmetadata",
-		"compliance_checkshare",
-		"compliance_dumpgraph",
-		"compliance_dumpresolutions",
-		"compliance_listshare",
-		"compliance-module",
-		"compliancenotice_bom",
-		"compliancenotice_shippedlibs",
-		"compliance_rtrace",
-		"compliance_sbom",
-		"golang-protobuf-internal-fuzz-jsonfuzz",
-		"golang-protobuf-internal-fuzz-textfuzz",
-		"golang-protobuf-internal-fuzz-wirefuzz",
-		"htmlnotice",
-		"protoc-gen-go",
-		"rbcrun-module",
-		"spdx-tools-builder",
-		"spdx-tools-builder2v1",
-		"spdx-tools-builder2v2",
-		"spdx-tools-builder2v3",
-		"spdx-tools-idsearcher",
-		"spdx-tools-spdx-json",
-		"spdx-tools-utils",
-		"soong-ui-build",
-		"textnotice",
-		"xmlnotice",
-	}
-)
-
-func testOfGoPackageIsIncompatible(g *bootstrap.GoPackage) bool {
-	return android.InList(g.Name(), goTestsDenylist) ||
-		// Denylist tests of soong_build
-		// Theses tests have a guard that prevent usage outside a test environment
-		// The guard (`ensureTestOnly`) looks for a `-test` in os.Args, which is present in soong's gotestrunner, but missing in `b test`
-		g.IsPluginFor("soong_build") ||
-		// soong-android is a dep of soong_build
-		// This dependency is created by soong_build by listing it in its deps explicitly in Android.bp, and not via `plugin_for` in `soong-android`
-		g.Name() == "soong-android"
-}
-
-func testOfGoBinaryIsIncompatible(g *bootstrap.GoBinary) bool {
-	return android.InList(g.Name(), goTestsDenylist)
-}
-
-func generateBazelTargetsGoPackage(ctx *android.Context, g *bootstrap.GoPackage, goModulesMap nameToGoLibraryModule) ([]BazelTarget, []error) {
-	ca := android.CommonAttributes{
-		Name: g.Name(),
-	}
-
-	// For this bootstrap_go_package dep chain,
-	// A --> B --> C ( ---> depends on)
-	// Soong provides the convenience of only listing B as deps of A even if a src file of A imports C
-	// Bazel OTOH
-	// 1. requires C to be listed in `deps` expllicity.
-	// 2. does not require C to be listed if src of A does not import C
-	//
-	// bp2build does not have sufficient info on whether C is a direct dep of A or not, so for now collect all transitive deps and add them to deps
-	transitiveDeps := transitiveGoDeps(g.Deps(), goModulesMap)
-
-	ga := goAttributes{
-		Importpath: bazel.StringAttribute{
-			Value: proptools.StringPtr(g.GoPkgPath()),
-		},
-		Srcs: goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs()),
-		Deps: goDepLabels(
-			android.FirstUniqueStrings(transitiveDeps),
-			goModulesMap,
-		),
-		Target_compatible_with: targetNotCompatibleWithAndroid(),
-	}
-
-	lib := goBazelTarget{
-		targetName:            g.Name(),
-		targetPackage:         ctx.ModuleDir(g),
-		bazelRuleClass:        "go_library",
-		bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl",
-		bazelAttributes:       []interface{}{&ca, &ga},
-	}
-	retTargets := []BazelTarget{}
-	var retErrs []error
-	if libTarget, err := generateBazelTarget(ctx, lib); err == nil {
-		retTargets = append(retTargets, libTarget)
-	} else {
-		retErrs = []error{err}
-	}
-
-	// If the library contains test srcs, create an additional go_test target
-	if !testOfGoPackageIsIncompatible(g) && (len(g.TestSrcs()) > 0 || len(g.LinuxTestSrcs()) > 0 || len(g.DarwinTestSrcs()) > 0) {
-		gp := goTestProperties{
-			name:           g.Name() + "-test",
-			dir:            ctx.ModuleDir(g),
-			testSrcs:       g.TestSrcs(),
-			linuxTestSrcs:  g.LinuxTestSrcs(),
-			darwinTestSrcs: g.DarwinTestSrcs(),
-			testData:       g.TestData(),
-			embedName:      g.Name(), // embed the source go_library in the test so that its .go files are included in the compilation unit
-		}
-		if libTestTarget, err := generateBazelTargetsGoTest(ctx, goModulesMap, gp); err == nil {
-			retTargets = append(retTargets, libTestTarget)
-		} else {
-			retErrs = append(retErrs, err)
-		}
-	}
-
-	return retTargets, retErrs
-}
-
-type goLibraryModule struct {
-	Dir  string
-	Deps []string
-}
-
-type nameToGoLibraryModule map[string]goLibraryModule
-
-// Visit each module in the graph
-// If a module is of type `bootstrap_go_package`, return a map containing metadata like its dir and deps
-func createGoLibraryModuleMap(ctx *android.Context) nameToGoLibraryModule {
-	ret := nameToGoLibraryModule{}
-	ctx.VisitAllModules(func(m blueprint.Module) {
-		moduleType := ctx.ModuleType(m)
-		// We do not need to store information about blueprint_go_binary since it does not have any rdeps
-		if moduleType == "bootstrap_go_package" {
-			ret[m.Name()] = goLibraryModule{
-				Dir:  ctx.ModuleDir(m),
-				Deps: m.(*bootstrap.GoPackage).Deps(),
-			}
-		}
-	})
-	return ret
-}
-
-// Returns the deps in the transitive closure of a go target
-func transitiveGoDeps(directDeps []string, goModulesMap nameToGoLibraryModule) []string {
-	allDeps := directDeps
-	i := 0
-	for i < len(allDeps) {
-		curr := allDeps[i]
-		allDeps = append(allDeps, goModulesMap[curr].Deps...)
-		i += 1
-	}
-	allDeps = android.SortedUniqueStrings(allDeps)
-	return allDeps
-}
-
-func generateBazelTargetsGoBinary(ctx *android.Context, g *bootstrap.GoBinary, goModulesMap nameToGoLibraryModule) ([]BazelTarget, []error) {
-	ca := android.CommonAttributes{
-		Name: g.Name(),
-	}
-
-	retTargets := []BazelTarget{}
-	var retErrs []error
-
-	// For this bootstrap_go_package dep chain,
-	// A --> B --> C ( ---> depends on)
-	// Soong provides the convenience of only listing B as deps of A even if a src file of A imports C
-	// Bazel OTOH
-	// 1. requires C to be listed in `deps` expllicity.
-	// 2. does not require C to be listed if src of A does not import C
-	//
-	// bp2build does not have sufficient info on whether C is a direct dep of A or not, so for now collect all transitive deps and add them to deps
-	transitiveDeps := transitiveGoDeps(g.Deps(), goModulesMap)
-
-	goSource := ""
-	// If the library contains test srcs, create an additional go_test target
-	// The go_test target will embed a go_source containining the source .go files it tests
-	if !testOfGoBinaryIsIncompatible(g) && (len(g.TestSrcs()) > 0 || len(g.LinuxTestSrcs()) > 0 || len(g.DarwinTestSrcs()) > 0) {
-		// Create a go_source containing the source .go files of go_library
-		// This target will be an `embed` of the go_binary and go_test
-		goSource = g.Name() + "-source"
-		ca := android.CommonAttributes{
-			Name: goSource,
-		}
-		ga := goAttributes{
-			Srcs:                   goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs()),
-			Deps:                   goDepLabels(transitiveDeps, goModulesMap),
-			Target_compatible_with: targetNotCompatibleWithAndroid(),
-		}
-		libTestSource := goBazelTarget{
-			targetName:            goSource,
-			targetPackage:         ctx.ModuleDir(g),
-			bazelRuleClass:        "go_source",
-			bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl",
-			bazelAttributes:       []interface{}{&ca, &ga},
-		}
-		if libSourceTarget, err := generateBazelTarget(ctx, libTestSource); err == nil {
-			retTargets = append(retTargets, libSourceTarget)
-		} else {
-			retErrs = append(retErrs, err)
-		}
-
-		// Create a go_test target
-		gp := goTestProperties{
-			name:           g.Name() + "-test",
-			dir:            ctx.ModuleDir(g),
-			testSrcs:       g.TestSrcs(),
-			linuxTestSrcs:  g.LinuxTestSrcs(),
-			darwinTestSrcs: g.DarwinTestSrcs(),
-			testData:       g.TestData(),
-			// embed the go_source in the test
-			embedName: g.Name() + "-source",
-		}
-		if libTestTarget, err := generateBazelTargetsGoTest(ctx, goModulesMap, gp); err == nil {
-			retTargets = append(retTargets, libTestTarget)
-		} else {
-			retErrs = append(retErrs, err)
-		}
-
-	}
-
-	// Create a go_binary target
-	ga := goAttributes{
-		Deps:                   goDepLabels(transitiveDeps, goModulesMap),
-		Target_compatible_with: targetNotCompatibleWithAndroid(),
-	}
-
-	// If the binary has testSrcs, embed the common `go_source`
-	if goSource != "" {
-		ga.Embed = bazel.MakeLabelListAttribute(
-			bazel.MakeLabelList(
-				[]bazel.Label{bazel.Label{Label: ":" + goSource}},
-			),
-		)
-	} else {
-		ga.Srcs = goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs())
-	}
-
-	bin := goBazelTarget{
-		targetName:            g.Name(),
-		targetPackage:         ctx.ModuleDir(g),
-		bazelRuleClass:        "go_binary",
-		bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl",
-		bazelAttributes:       []interface{}{&ca, &ga},
-	}
-
-	if binTarget, err := generateBazelTarget(ctx, bin); err == nil {
-		retTargets = append(retTargets, binTarget)
-	} else {
-		retErrs = []error{err}
-	}
-
-	return retTargets, retErrs
-}
-
 func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (conversionResults, []error) {
 	ctx.Context().BeginEvent("GenerateBazelTargets")
 	defer ctx.Context().EndEvent("GenerateBazelTargets")
 	buildFileToTargets := make(map[string]BazelTargets)
 
-	// Simple metrics tracking for bp2build
-	metrics := CreateCodegenMetrics()
-
 	dirs := make(map[string]bool)
+	moduleNameToPartition := make(map[string]string)
 
 	var errs []error
 
-	// Visit go libraries in a pre-run and store its state in a map
-	// The time complexity remains O(N), and this does not add significant wall time.
-	nameToGoLibMap := createGoLibraryModuleMap(ctx.Context())
-
 	bpCtx := ctx.Context()
 	bpCtx.VisitAllModules(func(m blueprint.Module) {
 		dir := bpCtx.ModuleDir(m)
-		moduleType := bpCtx.ModuleType(m)
 		dirs[dir] = true
 
 		var targets []BazelTarget
-		var targetErrs []error
 
 		switch ctx.Mode() {
-		case Bp2Build:
-			// There are two main ways of converting a Soong module to Bazel:
-			// 1) Manually handcrafting a Bazel target and associating the module with its label
-			// 2) Automatically generating with bp2build converters
-			//
-			// bp2build converters are used for the majority of modules.
-			if b, ok := m.(android.Bazelable); ok && b.HasHandcraftedLabel() {
-				// Handle modules converted to handcrafted targets.
-				//
-				// Since these modules are associated with some handcrafted
-				// target in a BUILD file, we don't autoconvert them.
-
-				// Log the module.
-				metrics.AddUnconvertedModule(m, moduleType, dir,
-					android.UnconvertedReason{
-						ReasonType: int(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE),
-					})
-			} else if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() {
-				// Handle modules converted to generated targets.
-
-				// Log the module.
-				metrics.AddConvertedModule(aModule, moduleType, dir)
-
-				// Handle modules with unconverted deps. By default, emit a warning.
-				if unconvertedDeps := aModule.GetUnconvertedBp2buildDeps(); len(unconvertedDeps) > 0 {
-					msg := fmt.Sprintf("%s %s:%s depends on unconverted modules: %s",
-						moduleType, bpCtx.ModuleDir(m), m.Name(), strings.Join(unconvertedDeps, ", "))
-					switch ctx.unconvertedDepMode {
-					case warnUnconvertedDeps:
-						metrics.moduleWithUnconvertedDepsMsgs = append(metrics.moduleWithUnconvertedDepsMsgs, msg)
-					case errorModulesUnconvertedDeps:
-						errs = append(errs, fmt.Errorf(msg))
-						return
-					}
-				}
-				if unconvertedDeps := aModule.GetMissingBp2buildDeps(); len(unconvertedDeps) > 0 {
-					msg := fmt.Sprintf("%s %s:%s depends on missing modules: %s",
-						moduleType, bpCtx.ModuleDir(m), m.Name(), strings.Join(unconvertedDeps, ", "))
-					switch ctx.unconvertedDepMode {
-					case warnUnconvertedDeps:
-						metrics.moduleWithMissingDepsMsgs = append(metrics.moduleWithMissingDepsMsgs, msg)
-					case errorModulesUnconvertedDeps:
-						errs = append(errs, fmt.Errorf(msg))
-						return
-					}
-				}
-				targets, targetErrs = generateBazelTargets(bpCtx, aModule)
-				errs = append(errs, targetErrs...)
-				for _, t := range targets {
-					// A module can potentially generate more than 1 Bazel
-					// target, each of a different rule class.
-					metrics.IncrementRuleClassCount(t.ruleClass)
-				}
-			} else if _, ok := ctx.Config().BazelModulesForceEnabledByFlag()[m.Name()]; ok && m.Name() != "" {
-				err := fmt.Errorf("Force Enabled Module %s not converted", m.Name())
-				errs = append(errs, err)
-			} else if aModule, ok := m.(android.Module); ok {
-				reason := aModule.GetUnconvertedReason()
-				if reason == nil {
-					panic(fmt.Errorf("module '%s' was neither converted nor marked unconvertible with bp2build", aModule.Name()))
-				} else {
-					metrics.AddUnconvertedModule(m, moduleType, dir, *reason)
-				}
-				return
-			} else if glib, ok := m.(*bootstrap.GoPackage); ok {
-				targets, targetErrs = generateBazelTargetsGoPackage(bpCtx, glib, nameToGoLibMap)
-				errs = append(errs, targetErrs...)
-				metrics.IncrementRuleClassCount("go_library")
-				metrics.AddConvertedModule(glib, "go_library", dir)
-			} else if gbin, ok := m.(*bootstrap.GoBinary); ok {
-				targets, targetErrs = generateBazelTargetsGoBinary(bpCtx, gbin, nameToGoLibMap)
-				errs = append(errs, targetErrs...)
-				metrics.IncrementRuleClassCount("go_binary")
-				metrics.AddConvertedModule(gbin, "go_binary", dir)
-			} else {
-				metrics.AddUnconvertedModule(m, moduleType, dir, android.UnconvertedReason{
-					ReasonType: int(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED),
-				})
-				return
-			}
 		case QueryView:
 			// Blocklist certain module types from being generated.
 			if canonicalizeModuleType(bpCtx.ModuleType(m)) == "package" {
@@ -771,10 +304,6 @@
 				errs = append(errs, err)
 			}
 			targets = append(targets, t)
-		case ApiBp2build:
-			if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() {
-				targets, errs = generateBazelTargets(bpCtx, aModule)
-			}
 		default:
 			errs = append(errs, fmt.Errorf("Unknown code-generation mode: %s", ctx.Mode()))
 			return
@@ -805,73 +334,18 @@
 		for dir := range dirs {
 			buildFileToTargets[dir] = append(buildFileToTargets[dir], BazelTarget{
 				name:      "bp2build_all_srcs",
-				content:   `filegroup(name = "bp2build_all_srcs", srcs = glob(["**/*"]))`,
+				content:   `filegroup(name = "bp2build_all_srcs", srcs = glob(["**/*"]), tags = ["manual"])`,
 				ruleClass: "filegroup",
 			})
 		}
 	}
 
 	return conversionResults{
-		buildFileToTargets: buildFileToTargets,
-		metrics:            metrics,
+		buildFileToTargets:    buildFileToTargets,
+		moduleNameToPartition: moduleNameToPartition,
 	}, errs
 }
 
-func generateBazelTargets(ctx bpToBuildContext, m android.Module) ([]BazelTarget, []error) {
-	var targets []BazelTarget
-	var errs []error
-	for _, m := range m.Bp2buildTargets() {
-		target, err := generateBazelTarget(ctx, m)
-		if err != nil {
-			errs = append(errs, err)
-			return targets, errs
-		}
-		targets = append(targets, target)
-	}
-	return targets, errs
-}
-
-type bp2buildModule interface {
-	TargetName() string
-	TargetPackage() string
-	BazelRuleClass() string
-	BazelRuleLoadLocation() string
-	BazelAttributes() []interface{}
-}
-
-func generateBazelTarget(ctx bpToBuildContext, m bp2buildModule) (BazelTarget, error) {
-	ruleClass := m.BazelRuleClass()
-	bzlLoadLocation := m.BazelRuleLoadLocation()
-
-	// extract the bazel attributes from the module.
-	attrs := m.BazelAttributes()
-	props, err := extractModuleProperties(attrs, true)
-	if err != nil {
-		return BazelTarget{}, err
-	}
-
-	// name is handled in a special manner
-	delete(props.Attrs, "name")
-
-	// Return the Bazel target with rule class and attributes, ready to be
-	// code-generated.
-	attributes := propsToAttributes(props.Attrs)
-	var content string
-	targetName := m.TargetName()
-	if targetName != "" {
-		content = fmt.Sprintf(ruleTargetTemplate, ruleClass, targetName, attributes)
-	} else {
-		content = fmt.Sprintf(unnamedRuleTargetTemplate, ruleClass, attributes)
-	}
-	return BazelTarget{
-		name:            targetName,
-		packageName:     m.TargetPackage(),
-		ruleClass:       ruleClass,
-		bzlLoadLocation: bzlLoadLocation,
-		content:         content,
-	}, nil
-}
-
 // Convert a module and its deps and props into a Bazel macro/rule
 // representation in the BUILD file.
 func generateSoongModuleTarget(ctx bpToBuildContext, m blueprint.Module) (BazelTarget, error) {
@@ -972,7 +446,7 @@
 	if !emitZeroValues && isZero(propertyValue) {
 		// A property value being set or unset actually matters -- Soong does set default
 		// values for unset properties, like system_shared_libs = ["libc", "libm", "libdl"] at
-		// https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=281-287;drc=f70926eef0b9b57faf04c17a1062ce50d209e480
+		// https://cs.android.com/android/platform/superproject/+/main:build/soong/cc/linker.go;l=281-287;drc=f70926eef0b9b57faf04c17a1062ce50d209e480
 		//
 		// In Bazel-parlance, we would use "attr.<type>(default = <default
 		// value>)" to set the default value of unset attributes. In the cases
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
deleted file mode 100644
index 8ee0439..0000000
--- a/bp2build/build_conversion_test.go
+++ /dev/null
@@ -1,1994 +0,0 @@
-// Copyright 2020 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"fmt"
-	"strings"
-	"testing"
-
-	"android/soong/android"
-	"android/soong/android/allowlists"
-	"android/soong/bazel"
-	"android/soong/python"
-)
-
-func TestGenerateSoongModuleTargets(t *testing.T) {
-	testCases := []struct {
-		description         string
-		bp                  string
-		expectedBazelTarget string
-	}{
-		{
-			description: "only name",
-			bp: `custom { name: "foo" }
-    `,
-			expectedBazelTarget: `soong_module(
-    name = "foo",
-    soong_module_name = "foo",
-    soong_module_type = "custom",
-    soong_module_variant = "",
-    soong_module_deps = [
-    ],
-    bool_prop = False,
-    string_prop = "",
-)`,
-		},
-		{
-			description: "handles bool",
-			bp: `custom {
-  name: "foo",
-  bool_prop: true,
-}
-    `,
-			expectedBazelTarget: `soong_module(
-    name = "foo",
-    soong_module_name = "foo",
-    soong_module_type = "custom",
-    soong_module_variant = "",
-    soong_module_deps = [
-    ],
-    bool_prop = True,
-    string_prop = "",
-)`,
-		},
-		{
-			description: "string escaping",
-			bp: `custom {
-  name: "foo",
-  owner: "a_string_with\"quotes\"_and_\\backslashes\\\\",
-}
-    `,
-			expectedBazelTarget: `soong_module(
-    name = "foo",
-    soong_module_name = "foo",
-    soong_module_type = "custom",
-    soong_module_variant = "",
-    soong_module_deps = [
-    ],
-    bool_prop = False,
-    owner = "a_string_with\"quotes\"_and_\\backslashes\\\\",
-    string_prop = "",
-)`,
-		},
-		{
-			description: "single item string list",
-			bp: `custom {
-  name: "foo",
-  required: ["bar"],
-}
-    `,
-			expectedBazelTarget: `soong_module(
-    name = "foo",
-    soong_module_name = "foo",
-    soong_module_type = "custom",
-    soong_module_variant = "",
-    soong_module_deps = [
-    ],
-    bool_prop = False,
-    required = ["bar"],
-    string_prop = "",
-)`,
-		},
-		{
-			description: "list of strings",
-			bp: `custom {
-  name: "foo",
-  target_required: ["qux", "bazqux"],
-}
-    `,
-			expectedBazelTarget: `soong_module(
-    name = "foo",
-    soong_module_name = "foo",
-    soong_module_type = "custom",
-    soong_module_variant = "",
-    soong_module_deps = [
-    ],
-    bool_prop = False,
-    string_prop = "",
-    target_required = [
-        "qux",
-        "bazqux",
-    ],
-)`,
-		},
-		{
-			description: "dist/dists",
-			bp: `custom {
-  name: "foo",
-  dist: {
-    targets: ["goal_foo"],
-    tag: ".foo",
-  },
-  dists: [{
-    targets: ["goal_bar"],
-    tag: ".bar",
-  }],
-}
-    `,
-			expectedBazelTarget: `soong_module(
-    name = "foo",
-    soong_module_name = "foo",
-    soong_module_type = "custom",
-    soong_module_variant = "",
-    soong_module_deps = [
-    ],
-    bool_prop = False,
-    dist = {
-        "tag": ".foo",
-        "targets": ["goal_foo"],
-    },
-    dists = [{
-        "tag": ".bar",
-        "targets": ["goal_bar"],
-    }],
-    string_prop = "",
-)`,
-		},
-		{
-			description: "put it together",
-			bp: `custom {
-  name: "foo",
-  required: ["bar"],
-  target_required: ["qux", "bazqux"],
-  bool_prop: true,
-  owner: "custom_owner",
-  dists: [
-    {
-      tag: ".tag",
-      targets: ["my_goal"],
-    },
-  ],
-}
-    `,
-			expectedBazelTarget: `soong_module(
-    name = "foo",
-    soong_module_name = "foo",
-    soong_module_type = "custom",
-    soong_module_variant = "",
-    soong_module_deps = [
-    ],
-    bool_prop = True,
-    dists = [{
-        "tag": ".tag",
-        "targets": ["my_goal"],
-    }],
-    owner = "custom_owner",
-    required = ["bar"],
-    string_prop = "",
-    target_required = [
-        "qux",
-        "bazqux",
-    ],
-)`,
-		},
-	}
-
-	dir := "."
-	for _, testCase := range testCases {
-		t.Run(testCase.description, func(t *testing.T) {
-			config := android.TestConfig(buildDir, nil, testCase.bp, nil)
-			ctx := android.NewTestContext(config)
-
-			ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
-			ctx.Register()
-
-			_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
-			android.FailIfErrored(t, errs)
-			_, errs = ctx.PrepareBuildActions(config)
-			android.FailIfErrored(t, errs)
-
-			codegenCtx := NewCodegenContext(config, ctx.Context, QueryView, "")
-			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
-			android.FailIfErrored(t, err)
-			if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
-				t.Fatalf("Expected %d bazel target, got %d", expectedCount, actualCount)
-			}
-
-			actualBazelTarget := bazelTargets[0]
-			if actualBazelTarget.content != testCase.expectedBazelTarget {
-				t.Errorf(
-					"Expected generated Bazel target to be '%s', got '%s'",
-					testCase.expectedBazelTarget,
-					actualBazelTarget.content,
-				)
-			}
-		})
-	}
-}
-
-func TestGenerateBazelTargetModules(t *testing.T) {
-	testCases := []Bp2buildTestCase{
-		{
-			Description: "string prop empty",
-			Blueprint: `custom {
-	name: "foo",
-    string_literal_prop: "",
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("custom", "foo", AttrNameToString{
-					"string_literal_prop": `""`,
-				}),
-			},
-		},
-		{
-			Description: `string prop "PROP"`,
-			Blueprint: `custom {
-	name: "foo",
-    string_literal_prop: "PROP",
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("custom", "foo", AttrNameToString{
-					"string_literal_prop": `"PROP"`,
-				}),
-			},
-		},
-		{
-			Description: `string prop arch variant`,
-			Blueprint: `custom {
-    name: "foo",
-    arch: {
-        arm: { string_literal_prop: "ARM" },
-        arm64: { string_literal_prop: "ARM64" },
-    },
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("custom", "foo", AttrNameToString{
-					"string_literal_prop": `select({
-        "//build/bazel/platforms/arch:arm": "ARM",
-        "//build/bazel/platforms/arch:arm64": "ARM64",
-        "//conditions:default": None,
-    })`,
-				}),
-			},
-		},
-		{
-			Description: "string ptr props",
-			Blueprint: `custom {
-	name: "foo",
-    string_ptr_prop: "",
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("custom", "foo", AttrNameToString{
-					"string_ptr_prop": `""`,
-				}),
-			},
-		},
-		{
-			Description: "string list props",
-			Blueprint: `custom {
-  name: "foo",
-    string_list_prop: ["a", "b"],
-    string_ptr_prop: "a",
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("custom", "foo", AttrNameToString{
-					"string_list_prop": `[
-        "a",
-        "b",
-    ]`,
-					"string_ptr_prop": `"a"`,
-				}),
-			},
-		},
-		{
-			Description: "control characters",
-			Blueprint: `custom {
-    name: "foo",
-    string_list_prop: ["\t", "\n"],
-    string_ptr_prop: "a\t\n\r",
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("custom", "foo", AttrNameToString{
-					"string_list_prop": `[
-        "\t",
-        "\n",
-    ]`,
-					"string_ptr_prop": `"a\t\n\r"`,
-				}),
-			},
-		},
-		{
-			Description: "handles dep",
-			Blueprint: `custom {
-  name: "has_dep",
-  arch_paths: [":dep"],
-  bazel_module: { bp2build_available: true },
-}
-
-custom {
-  name: "dep",
-  arch_paths: ["abc"],
-  bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("custom", "dep", AttrNameToString{
-					"arch_paths": `["abc"]`,
-				}),
-				MakeBazelTarget("custom", "has_dep", AttrNameToString{
-					"arch_paths": `[":dep"]`,
-				}),
-			},
-		},
-		{
-			Description: "non-existent dep",
-			Blueprint: `custom {
-  name: "has_dep",
-  arch_paths: [":dep"],
-  bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("custom", "has_dep", AttrNameToString{
-					"arch_paths": `[":dep__BP2BUILD__MISSING__DEP"]`,
-				}),
-			},
-		},
-		{
-			Description: "arch-variant srcs",
-			Blueprint: `custom {
-    name: "arch_paths",
-    arch: {
-      x86: { arch_paths: ["x86.txt"] },
-      x86_64:  { arch_paths: ["x86_64.txt"] },
-      arm:  { arch_paths: ["arm.txt"] },
-      arm64:  { arch_paths: ["arm64.txt"] },
-      riscv64: { arch_paths: ["riscv64.txt"] },
-    },
-    target: {
-      linux: { arch_paths: ["linux.txt"] },
-      bionic: { arch_paths: ["bionic.txt"] },
-      host: { arch_paths: ["host.txt"] },
-      not_windows: { arch_paths: ["not_windows.txt"] },
-      android: { arch_paths: ["android.txt"] },
-      linux_musl: { arch_paths: ["linux_musl.txt"] },
-      musl: { arch_paths: ["musl.txt"] },
-      linux_glibc: { arch_paths: ["linux_glibc.txt"] },
-      glibc: { arch_paths: ["glibc.txt"] },
-      linux_bionic: { arch_paths: ["linux_bionic.txt"] },
-      darwin: { arch_paths: ["darwin.txt"] },
-      windows: { arch_paths: ["windows.txt"] },
-    },
-    multilib: {
-        lib32: { arch_paths: ["lib32.txt"] },
-        lib64: { arch_paths: ["lib64.txt"] },
-    },
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("custom", "arch_paths", AttrNameToString{
-					"arch_paths": `select({
-        "//build/bazel/platforms/arch:arm": [
-            "arm.txt",
-            "lib32.txt",
-        ],
-        "//build/bazel/platforms/arch:arm64": [
-            "arm64.txt",
-            "lib64.txt",
-        ],
-        "//build/bazel/platforms/arch:riscv64": [
-            "riscv64.txt",
-            "lib64.txt",
-        ],
-        "//build/bazel/platforms/arch:x86": [
-            "x86.txt",
-            "lib32.txt",
-        ],
-        "//build/bazel/platforms/arch:x86_64": [
-            "x86_64.txt",
-            "lib64.txt",
-        ],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/os:android": [
-            "linux.txt",
-            "bionic.txt",
-            "android.txt",
-        ],
-        "//build/bazel/platforms/os:darwin": [
-            "host.txt",
-            "darwin.txt",
-            "not_windows.txt",
-        ],
-        "//build/bazel/platforms/os:linux_bionic": [
-            "host.txt",
-            "linux.txt",
-            "bionic.txt",
-            "linux_bionic.txt",
-            "not_windows.txt",
-        ],
-        "//build/bazel/platforms/os:linux_glibc": [
-            "host.txt",
-            "linux.txt",
-            "glibc.txt",
-            "linux_glibc.txt",
-            "not_windows.txt",
-        ],
-        "//build/bazel/platforms/os:linux_musl": [
-            "host.txt",
-            "linux.txt",
-            "musl.txt",
-            "linux_musl.txt",
-            "not_windows.txt",
-        ],
-        "//build/bazel/platforms/os:windows": [
-            "host.txt",
-            "windows.txt",
-        ],
-        "//conditions:default": [],
-    })`,
-				}),
-			},
-		},
-		{
-			Description: "arch-variant deps",
-			Blueprint: `custom {
-  name: "has_dep",
-  arch: {
-    x86: {
-      arch_paths: [":dep"],
-    },
-  },
-  bazel_module: { bp2build_available: true },
-}
-
-custom {
-    name: "dep",
-    arch_paths: ["abc"],
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("custom", "dep", AttrNameToString{
-					"arch_paths": `["abc"]`,
-				}),
-				MakeBazelTarget("custom", "has_dep", AttrNameToString{
-					"arch_paths": `select({
-        "//build/bazel/platforms/arch:x86": [":dep"],
-        "//conditions:default": [],
-    })`,
-				}),
-			},
-		},
-		{
-			Description: "embedded props",
-			Blueprint: `custom {
-    name: "embedded_props",
-    embedded_prop: "abc",
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("custom", "embedded_props", AttrNameToString{
-					"embedded_attr": `"abc"`,
-				}),
-			},
-		},
-		{
-			Description: "ptr to embedded props",
-			Blueprint: `custom {
-    name: "ptr_to_embedded_props",
-    other_embedded_prop: "abc",
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("custom", "ptr_to_embedded_props", AttrNameToString{
-					"other_embedded_attr": `"abc"`,
-				}),
-			},
-		},
-	}
-
-	dir := "."
-	for _, testCase := range testCases {
-		t.Run(testCase.Description, func(t *testing.T) {
-			config := android.TestConfig(buildDir, nil, testCase.Blueprint, nil)
-			ctx := android.NewTestContext(config)
-
-			registerCustomModuleForBp2buildConversion(ctx)
-
-			_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
-			if errored(t, testCase, errs) {
-				return
-			}
-			_, errs = ctx.ResolveDependencies(config)
-			if errored(t, testCase, errs) {
-				return
-			}
-
-			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
-			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
-			android.FailIfErrored(t, err)
-
-			if actualCount, expectedCount := len(bazelTargets), len(testCase.ExpectedBazelTargets); actualCount != expectedCount {
-				t.Errorf("Expected %d bazel target (%s),\ngot %d (%s)", expectedCount, testCase.ExpectedBazelTargets, actualCount, bazelTargets)
-			} else {
-				for i, expectedBazelTarget := range testCase.ExpectedBazelTargets {
-					actualBazelTarget := bazelTargets[i]
-					if actualBazelTarget.content != expectedBazelTarget {
-						t.Errorf(
-							"Expected generated Bazel target to be '%s', got '%s'",
-							expectedBazelTarget,
-							actualBazelTarget.content,
-						)
-					}
-				}
-			}
-		})
-	}
-}
-
-func TestBp2buildHostAndDevice(t *testing.T) {
-	testCases := []Bp2buildTestCase{
-		{
-			Description:                "host and device, device only",
-			ModuleTypeUnderTest:        "custom",
-			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			Blueprint: `custom {
-		name: "foo",
-		bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
-			},
-		},
-		{
-			Description:                "host and device, both",
-			ModuleTypeUnderTest:        "custom",
-			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			Blueprint: `custom {
-		name: "foo",
-		host_supported: true,
-		bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{}),
-			},
-		},
-		{
-			Description:                "host and device, host explicitly disabled",
-			ModuleTypeUnderTest:        "custom",
-			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			Blueprint: `custom {
-		name: "foo",
-		host_supported: false,
-		bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
-			},
-		},
-		{
-			Description:                "host and device, neither",
-			ModuleTypeUnderTest:        "custom",
-			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			Blueprint: `custom {
-		name: "foo",
-		host_supported: false,
-		device_supported: false,
-		bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
-					"target_compatible_with": `["@platforms//:incompatible"]`,
-				}),
-			},
-		},
-		{
-			Description:                "host and device, neither, cannot override with product_var",
-			ModuleTypeUnderTest:        "custom",
-			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			Blueprint: `custom {
-		name: "foo",
-		host_supported: false,
-		device_supported: false,
-		product_variables: { unbundled_build: { enabled: true } },
-		bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
-					"target_compatible_with": `["@platforms//:incompatible"]`,
-				}),
-			},
-		},
-		{
-			Description:                "host and device, both, disabled overrided with product_var",
-			ModuleTypeUnderTest:        "custom",
-			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			Blueprint: `custom {
-		name: "foo",
-		host_supported: true,
-		device_supported: true,
-		enabled: false,
-		product_variables: { unbundled_build: { enabled: true } },
-		bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
-					"target_compatible_with": `select({
-        "//build/bazel/product_config/config_settings:unbundled_build": [],
-        "//conditions:default": ["@platforms//:incompatible"],
-    })`,
-				}),
-			},
-		},
-		{
-			Description:                "host and device, neither, cannot override with arch enabled",
-			ModuleTypeUnderTest:        "custom",
-			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			Blueprint: `custom {
-		name: "foo",
-		host_supported: false,
-		device_supported: false,
-		arch: { x86: { enabled: true } },
-		bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
-					"target_compatible_with": `["@platforms//:incompatible"]`,
-				}),
-			},
-		},
-		{
-			Description:                "host and device, host only",
-			ModuleTypeUnderTest:        "custom",
-			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			Blueprint: `custom {
-		name: "foo",
-		host_supported: true,
-		device_supported: false,
-		bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported),
-			},
-		},
-		{
-			Description:                "host only",
-			ModuleTypeUnderTest:        "custom",
-			ModuleTypeUnderTestFactory: customModuleFactoryHostSupported,
-			Blueprint: `custom {
-		name: "foo",
-		bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported),
-			},
-		},
-		{
-			Description:                "device only",
-			ModuleTypeUnderTest:        "custom",
-			ModuleTypeUnderTestFactory: customModuleFactoryDeviceSupported,
-			Blueprint: `custom {
-		name: "foo",
-		bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
-			},
-		},
-		{
-			Description:                "host and device default, default",
-			ModuleTypeUnderTest:        "custom",
-			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
-			Blueprint: `custom {
-		name: "foo",
-		bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{}),
-			},
-		},
-		{
-			Description:                "host and device default, device only",
-			ModuleTypeUnderTest:        "custom",
-			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
-			Blueprint: `custom {
-		name: "foo",
-		host_supported: false,
-		bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
-			},
-		},
-		{
-			Description:                "host and device default, host only",
-			ModuleTypeUnderTest:        "custom",
-			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
-			Blueprint: `custom {
-		name: "foo",
-		device_supported: false,
-		bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported),
-			},
-		},
-		{
-			Description:                "host and device default, neither",
-			ModuleTypeUnderTest:        "custom",
-			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
-			Blueprint: `custom {
-		name: "foo",
-		host_supported: false,
-		device_supported: false,
-		bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
-					"target_compatible_with": `["@platforms//:incompatible"]`,
-				}),
-			},
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.Description, func(t *testing.T) {
-			RunBp2BuildTestCaseSimple(t, tc)
-		})
-	}
-}
-
-func TestLoadStatements(t *testing.T) {
-	testCases := []struct {
-		bazelTargets           BazelTargets
-		expectedLoadStatements string
-	}{
-		{
-			bazelTargets: BazelTargets{
-				BazelTarget{
-					name:            "foo",
-					ruleClass:       "cc_library",
-					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
-				},
-			},
-			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_library")`,
-		},
-		{
-			bazelTargets: BazelTargets{
-				BazelTarget{
-					name:            "foo",
-					ruleClass:       "cc_library",
-					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
-				},
-				BazelTarget{
-					name:            "bar",
-					ruleClass:       "cc_library",
-					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
-				},
-			},
-			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_library")`,
-		},
-		{
-			bazelTargets: BazelTargets{
-				BazelTarget{
-					name:            "foo",
-					ruleClass:       "cc_library",
-					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
-				},
-				BazelTarget{
-					name:            "bar",
-					ruleClass:       "cc_binary",
-					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
-				},
-			},
-			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary", "cc_library")`,
-		},
-		{
-			bazelTargets: BazelTargets{
-				BazelTarget{
-					name:            "foo",
-					ruleClass:       "cc_library",
-					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
-				},
-				BazelTarget{
-					name:            "bar",
-					ruleClass:       "cc_binary",
-					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
-				},
-				BazelTarget{
-					name:            "baz",
-					ruleClass:       "java_binary",
-					bzlLoadLocation: "//build/bazel/rules:java.bzl",
-				},
-			},
-			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary", "cc_library")
-load("//build/bazel/rules:java.bzl", "java_binary")`,
-		},
-		{
-			bazelTargets: BazelTargets{
-				BazelTarget{
-					name:            "foo",
-					ruleClass:       "cc_binary",
-					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
-				},
-				BazelTarget{
-					name:            "bar",
-					ruleClass:       "java_binary",
-					bzlLoadLocation: "//build/bazel/rules:java.bzl",
-				},
-				BazelTarget{
-					name:      "baz",
-					ruleClass: "genrule",
-					// Note: no bzlLoadLocation for native rules
-				},
-			},
-			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary")
-load("//build/bazel/rules:java.bzl", "java_binary")`,
-		},
-	}
-
-	for _, testCase := range testCases {
-		actual := testCase.bazelTargets.LoadStatements()
-		expected := testCase.expectedLoadStatements
-		if actual != expected {
-			t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
-		}
-	}
-
-}
-
-func TestGenerateBazelTargetModules_OneToMany_LoadedFromStarlark(t *testing.T) {
-	testCases := []struct {
-		bp                       string
-		expectedBazelTarget      string
-		expectedBazelTargetCount int
-		expectedLoadStatements   string
-	}{
-		{
-			bp: `custom {
-    name: "bar",
-    host_supported: true,
-    one_to_many_prop: true,
-    bazel_module: { bp2build_available: true  },
-}`,
-			expectedBazelTarget: `my_library(
-    name = "bar",
-)
-
-proto_library(
-    name = "bar_proto_library_deps",
-)
-
-my_proto_library(
-    name = "bar_my_proto_library_deps",
-)`,
-			expectedBazelTargetCount: 3,
-			expectedLoadStatements: `load("//build/bazel/rules:proto.bzl", "my_proto_library", "proto_library")
-load("//build/bazel/rules:rules.bzl", "my_library")`,
-		},
-	}
-
-	dir := "."
-	for _, testCase := range testCases {
-		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
-		ctx := android.NewTestContext(config)
-		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
-		ctx.RegisterForBazelConversion()
-
-		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
-		android.FailIfErrored(t, errs)
-		_, errs = ctx.ResolveDependencies(config)
-		android.FailIfErrored(t, errs)
-
-		codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
-		bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
-		android.FailIfErrored(t, err)
-		if actualCount := len(bazelTargets); actualCount != testCase.expectedBazelTargetCount {
-			t.Fatalf("Expected %d bazel target, got %d", testCase.expectedBazelTargetCount, actualCount)
-		}
-
-		actualBazelTargets := bazelTargets.String()
-		if actualBazelTargets != testCase.expectedBazelTarget {
-			t.Errorf(
-				"Expected generated Bazel target to be '%s', got '%s'",
-				testCase.expectedBazelTarget,
-				actualBazelTargets,
-			)
-		}
-
-		actualLoadStatements := bazelTargets.LoadStatements()
-		if actualLoadStatements != testCase.expectedLoadStatements {
-			t.Errorf(
-				"Expected generated load statements to be '%s', got '%s'",
-				testCase.expectedLoadStatements,
-				actualLoadStatements,
-			)
-		}
-	}
-}
-
-func TestModuleTypeBp2Build(t *testing.T) {
-	testCases := []Bp2buildTestCase{
-		{
-			Description:                "filegroup with does not specify srcs",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: `filegroup {
-    name: "fg_foo",
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
-			},
-		},
-		{
-			Description:                "filegroup with no srcs",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: `filegroup {
-    name: "fg_foo",
-    srcs: [],
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
-			},
-		},
-		{
-			Description:                "filegroup with srcs",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: `filegroup {
-    name: "fg_foo",
-    srcs: ["a", "b"],
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `[
-        "a",
-        "b",
-    ]`,
-				}),
-			},
-		},
-		{
-			Description:                "filegroup with dot-slash-prefixed srcs",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: `filegroup {
-    name: "fg_foo",
-    srcs: ["./a", "./b"],
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `[
-        "a",
-        "b",
-    ]`,
-				}),
-			},
-		},
-		{
-			Description:                "filegroup with excludes srcs",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: `filegroup {
-    name: "fg_foo",
-    srcs: ["a", "b"],
-    exclude_srcs: ["a"],
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `["b"]`,
-				}),
-			},
-		},
-		{
-			Description:                "depends_on_other_dir_module",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: `filegroup {
-    name: "fg_foo",
-    srcs: [
-        ":foo",
-        "c",
-    ],
-    bazel_module: { bp2build_available: true },
-}`,
-			Filesystem: map[string]string{
-				"other/Android.bp": `filegroup {
-    name: "foo",
-    srcs: ["a", "b"],
-    bazel_module: { bp2build_available: true },
-}`,
-			},
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `[
-        "//other:foo",
-        "c",
-    ]`,
-				}),
-			},
-		},
-		{
-			Description:                "depends_on_other_unconverted_module_error",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			UnconvertedDepsMode:        errorModulesUnconvertedDeps,
-			Blueprint: `filegroup {
-    name: "foobar",
-    srcs: [
-        ":foo",
-        "c",
-    ],
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedErr: fmt.Errorf(`filegroup .:foobar depends on unconverted modules: foo`),
-			Filesystem: map[string]string{
-				"other/Android.bp": `filegroup {
-    name: "foo",
-    srcs: ["a", "b"],
-}`,
-			},
-		},
-		{
-			Description:                "depends_on_other_missing_module_error",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			UnconvertedDepsMode:        errorModulesUnconvertedDeps,
-			Blueprint: `filegroup {
-    name: "foobar",
-    srcs: [
-        "c",
-        "//other:foo",
-        "//other:goo",
-    ],
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedErr: fmt.Errorf(`filegroup .:foobar depends on missing modules: //other:goo`),
-			Filesystem: map[string]string{"other/Android.bp": `filegroup {
-    name: "foo",
-    srcs: ["a"],
-    bazel_module: { bp2build_available: true },
-}
-`,
-			},
-		},
-	}
-
-	for _, testCase := range testCases {
-		t.Run(testCase.Description, func(t *testing.T) {
-			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, testCase)
-		})
-	}
-}
-
-func TestAllowlistingBp2buildTargetsExplicitly(t *testing.T) {
-	testCases := []struct {
-		moduleTypeUnderTest        string
-		moduleTypeUnderTestFactory android.ModuleFactory
-		bp                         string
-		expectedCount              int
-		description                string
-	}{
-		{
-			description:                "explicitly unavailable",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			bp: `filegroup {
-    name: "foo",
-    srcs: ["a", "b"],
-    bazel_module: { bp2build_available: false },
-}`,
-			expectedCount: 0,
-		},
-		{
-			description:                "implicitly unavailable",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			bp: `filegroup {
-    name: "foo",
-    srcs: ["a", "b"],
-}`,
-			expectedCount: 0,
-		},
-		{
-			description:                "explicitly available",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			bp: `filegroup {
-    name: "foo",
-    srcs: ["a", "b"],
-    bazel_module: { bp2build_available: true },
-}`,
-			expectedCount: 1,
-		},
-		{
-			description:                "generates more than 1 target if needed",
-			moduleTypeUnderTest:        "custom",
-			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
-			bp: `custom {
-    name: "foo",
-    one_to_many_prop: true,
-    bazel_module: { bp2build_available: true },
-}`,
-			expectedCount: 3,
-		},
-	}
-
-	dir := "."
-	for _, testCase := range testCases {
-		t.Run(testCase.description, func(t *testing.T) {
-			config := android.TestConfig(buildDir, nil, testCase.bp, nil)
-			ctx := android.NewTestContext(config)
-			ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
-			ctx.RegisterForBazelConversion()
-
-			_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
-			android.FailIfErrored(t, errs)
-			_, errs = ctx.ResolveDependencies(config)
-			android.FailIfErrored(t, errs)
-
-			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
-			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
-			android.FailIfErrored(t, err)
-			if actualCount := len(bazelTargets); actualCount != testCase.expectedCount {
-				t.Fatalf("%s: Expected %d bazel target, got %d", testCase.description, testCase.expectedCount, actualCount)
-			}
-		})
-	}
-}
-
-func TestAllowlistingBp2buildTargetsWithConfig(t *testing.T) {
-	testCases := []struct {
-		moduleTypeUnderTest        string
-		moduleTypeUnderTestFactory android.ModuleFactory
-		expectedCount              map[string]int
-		description                string
-		bp2buildConfig             allowlists.Bp2BuildConfig
-		checkDir                   string
-		fs                         map[string]string
-		forceEnabledModules        []string
-		expectedErrorMessages      []string
-	}{
-		{
-			description:                "test bp2build config package and subpackages config",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			expectedCount: map[string]int{
-				"migrated":                           1,
-				"migrated/but_not_really":            0,
-				"migrated/but_not_really/but_really": 1,
-				"not_migrated":                       0,
-				"also_not_migrated":                  0,
-			},
-			bp2buildConfig: allowlists.Bp2BuildConfig{
-				"migrated":                allowlists.Bp2BuildDefaultTrueRecursively,
-				"migrated/but_not_really": allowlists.Bp2BuildDefaultFalse,
-				"not_migrated":            allowlists.Bp2BuildDefaultFalse,
-			},
-			fs: map[string]string{
-				"migrated/Android.bp":                           `filegroup { name: "a" }`,
-				"migrated/but_not_really/Android.bp":            `filegroup { name: "b" }`,
-				"migrated/but_not_really/but_really/Android.bp": `filegroup { name: "c" }`,
-				"not_migrated/Android.bp":                       `filegroup { name: "d" }`,
-				"also_not_migrated/Android.bp":                  `filegroup { name: "e" }`,
-			},
-		},
-		{
-			description:                "test bp2build config opt-in and opt-out",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			expectedCount: map[string]int{
-				"package-opt-in":             2,
-				"package-opt-in/subpackage":  0,
-				"package-opt-out":            1,
-				"package-opt-out/subpackage": 0,
-			},
-			bp2buildConfig: allowlists.Bp2BuildConfig{
-				"package-opt-in":  allowlists.Bp2BuildDefaultFalse,
-				"package-opt-out": allowlists.Bp2BuildDefaultTrueRecursively,
-			},
-			fs: map[string]string{
-				"package-opt-in/Android.bp": `
-filegroup { name: "opt-in-a" }
-filegroup { name: "opt-in-b", bazel_module: { bp2build_available: true } }
-filegroup { name: "opt-in-c", bazel_module: { bp2build_available: true } }
-`,
-
-				"package-opt-in/subpackage/Android.bp": `
-filegroup { name: "opt-in-d" } // parent package not configured to DefaultTrueRecursively
-`,
-
-				"package-opt-out/Android.bp": `
-filegroup { name: "opt-out-a" }
-filegroup { name: "opt-out-b", bazel_module: { bp2build_available: false } }
-filegroup { name: "opt-out-c", bazel_module: { bp2build_available: false } }
-`,
-
-				"package-opt-out/subpackage/Android.bp": `
-filegroup { name: "opt-out-g", bazel_module: { bp2build_available: false } }
-filegroup { name: "opt-out-h", bazel_module: { bp2build_available: false } }
-`,
-			},
-		},
-		{
-			description:                "test force-enabled errors out",
-			moduleTypeUnderTest:        "filegroup",
-			moduleTypeUnderTestFactory: android.FileGroupFactory,
-			expectedCount: map[string]int{
-				"migrated":     0,
-				"not_migrated": 0,
-			},
-			bp2buildConfig: allowlists.Bp2BuildConfig{
-				"migrated/but_not_really": allowlists.Bp2BuildDefaultFalse,
-				"not_migrated":            allowlists.Bp2BuildDefaultFalse,
-			},
-			fs: map[string]string{
-				"migrated/Android.bp": `filegroup { name: "a" }`,
-			},
-			forceEnabledModules:   []string{"a"},
-			expectedErrorMessages: []string{"Force Enabled Module a not converted"},
-		},
-	}
-
-	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, "", fs)
-		config.AddForceEnabledModules(testCase.forceEnabledModules)
-		ctx := android.NewTestContext(config)
-		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
-		allowlist := android.NewBp2BuildAllowlist().SetDefaultConfig(testCase.bp2buildConfig)
-		ctx.RegisterBp2BuildConfig(allowlist)
-		ctx.RegisterForBazelConversion()
-
-		_, errs := ctx.ParseFileList(dir, toParse)
-		android.FailIfErrored(t, errs)
-		_, errs = ctx.ResolveDependencies(config)
-		android.FailIfErrored(t, errs)
-
-		codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
-
-		// For each directory, test that the expected number of generated targets is correct.
-		for dir, expectedCount := range testCase.expectedCount {
-			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
-			android.CheckErrorsAgainstExpectations(t, err, testCase.expectedErrorMessages)
-			if actualCount := len(bazelTargets); actualCount != expectedCount {
-				t.Fatalf(
-					"%s: Expected %d bazel target for %s package, got %d",
-					testCase.description,
-					expectedCount,
-					dir,
-					actualCount)
-			}
-
-		}
-	}
-}
-
-func TestCombineBuildFilesBp2buildTargets(t *testing.T) {
-	testCases := []Bp2buildTestCase{
-		{
-			Description:                "filegroup bazel_module.label",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: `filegroup {
-    name: "fg_foo",
-    bazel_module: { label: "//other:fg_foo" },
-}`,
-			ExpectedBazelTargets: []string{},
-			Filesystem: map[string]string{
-				"other/BUILD.bazel": `// BUILD file`,
-			},
-		},
-		{
-			Description:                "multiple bazel_module.label same BUILD",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: `filegroup {
-        name: "fg_foo",
-        bazel_module: { label: "//other:fg_foo" },
-    }
-
-    filegroup {
-        name: "foo",
-        bazel_module: { label: "//other:foo" },
-    }`,
-			ExpectedBazelTargets: []string{},
-			Filesystem: map[string]string{
-				"other/BUILD.bazel": `// BUILD file`,
-			},
-		},
-		{
-			Description:                "filegroup bazel_module.label and bp2build in subdir",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Dir:                        "other",
-			Blueprint:                  ``,
-			Filesystem: map[string]string{
-				"other/Android.bp": `filegroup {
-        name: "fg_foo",
-        bazel_module: {
-          bp2build_available: true,
-        },
-      }
-      filegroup {
-        name: "fg_bar",
-        bazel_module: {
-          label: "//other:fg_bar"
-        },
-      }`,
-				"other/BUILD.bazel": `// definition for fg_bar`,
-			},
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
-			},
-		},
-		{
-			Description:                "filegroup bazel_module.label and filegroup bp2build",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-
-			Filesystem: map[string]string{
-				"other/BUILD.bazel": `// BUILD file`,
-			},
-			Blueprint: `filegroup {
-        name: "fg_foo",
-        bazel_module: {
-          label: "//other:fg_foo",
-        },
-    }
-
-    filegroup {
-        name: "fg_bar",
-        bazel_module: {
-          bp2build_available: true,
-        },
-    }`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_bar", map[string]string{}),
-			},
-		},
-	}
-
-	dir := "."
-	for _, testCase := range testCases {
-		t.Run(testCase.Description, func(t *testing.T) {
-			fs := make(map[string][]byte)
-			toParse := []string{
-				"Android.bp",
-			}
-			for f, content := range testCase.Filesystem {
-				if strings.HasSuffix(f, "Android.bp") {
-					toParse = append(toParse, f)
-				}
-				fs[f] = []byte(content)
-			}
-			config := android.TestConfig(buildDir, nil, testCase.Blueprint, fs)
-			ctx := android.NewTestContext(config)
-			ctx.RegisterModuleType(testCase.ModuleTypeUnderTest, testCase.ModuleTypeUnderTestFactory)
-			ctx.RegisterForBazelConversion()
-
-			_, errs := ctx.ParseFileList(dir, toParse)
-			if errored(t, testCase, errs) {
-				return
-			}
-			_, errs = ctx.ResolveDependencies(config)
-			if errored(t, testCase, errs) {
-				return
-			}
-
-			checkDir := dir
-			if testCase.Dir != "" {
-				checkDir = testCase.Dir
-			}
-			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
-			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir)
-			android.FailIfErrored(t, err)
-			bazelTargets.sort()
-			actualCount := len(bazelTargets)
-			expectedCount := len(testCase.ExpectedBazelTargets)
-			if actualCount != expectedCount {
-				t.Errorf("Expected %d bazel target, got %d\n%s", expectedCount, actualCount, bazelTargets)
-			}
-			for i, target := range bazelTargets {
-				actualContent := target.content
-				expectedContent := testCase.ExpectedBazelTargets[i]
-				if expectedContent != actualContent {
-					t.Errorf(
-						"Expected generated Bazel target to be '%s', got '%s'",
-						expectedContent,
-						actualContent,
-					)
-				}
-			}
-		})
-	}
-}
-
-func TestGlob(t *testing.T) {
-	testCases := []Bp2buildTestCase{
-		{
-			Description:                "filegroup with glob",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: `filegroup {
-    name: "fg_foo",
-    srcs: ["**/*.txt"],
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `[
-        "other/a.txt",
-        "other/b.txt",
-        "other/subdir/a.txt",
-    ]`,
-				}),
-			},
-			Filesystem: map[string]string{
-				"other/a.txt":        "",
-				"other/b.txt":        "",
-				"other/subdir/a.txt": "",
-				"other/file":         "",
-			},
-		},
-		{
-			Description:                "filegroup with glob in subdir",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Dir:                        "other",
-			Filesystem: map[string]string{
-				"other/Android.bp": `filegroup {
-    name: "fg_foo",
-    srcs: ["**/*.txt"],
-    bazel_module: { bp2build_available: true },
-}`,
-				"other/a.txt":        "",
-				"other/b.txt":        "",
-				"other/subdir/a.txt": "",
-				"other/file":         "",
-			},
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `[
-        "a.txt",
-        "b.txt",
-        "subdir/a.txt",
-    ]`,
-				}),
-			},
-		},
-		{
-			Description:                "filegroup with glob with no kept BUILD files",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			KeepBuildFileForDirs:       []string{
-				// empty
-			},
-			Blueprint: `filegroup {
-    name: "fg_foo",
-    srcs: ["**/*.txt"],
-    bazel_module: { bp2build_available: true },
-}`,
-			Filesystem: map[string]string{
-				"a.txt":         "",
-				"b.txt":         "",
-				"foo/BUILD":     "",
-				"foo/a.txt":     "",
-				"foo/bar/BUILD": "",
-				"foo/bar/b.txt": "",
-			},
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `[
-        "a.txt",
-        "b.txt",
-        "foo/a.txt",
-        "foo/bar/b.txt",
-    ]`,
-				}),
-			},
-		},
-		{
-			Description:                "filegroup with glob with kept BUILD file",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			KeepBuildFileForDirs: []string{
-				"foo",
-			},
-			Blueprint: `filegroup {
-    name: "fg_foo",
-    srcs: ["**/*.txt"],
-    bazel_module: { bp2build_available: true },
-}`,
-			Filesystem: map[string]string{
-				"a.txt":         "",
-				"b.txt":         "",
-				"foo/BUILD":     "",
-				"foo/a.txt":     "",
-				"foo/bar/BUILD": "",
-				"foo/bar/b.txt": "",
-			},
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `[
-        "a.txt",
-        "b.txt",
-        "//foo:a.txt",
-        "//foo:bar/b.txt",
-    ]`,
-				}),
-			},
-		},
-		{
-			Description:                "filegroup with glob with kept BUILD.bazel file",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			KeepBuildFileForDirs: []string{
-				"foo",
-			},
-			Blueprint: `filegroup {
-    name: "fg_foo",
-    srcs: ["**/*.txt"],
-    bazel_module: { bp2build_available: true },
-}`,
-			Filesystem: map[string]string{
-				"a.txt":               "",
-				"b.txt":               "",
-				"foo/BUILD.bazel":     "",
-				"foo/a.txt":           "",
-				"foo/bar/BUILD.bazel": "",
-				"foo/bar/b.txt":       "",
-			},
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `[
-        "a.txt",
-        "b.txt",
-        "//foo:a.txt",
-        "//foo:bar/b.txt",
-    ]`,
-				}),
-			},
-		},
-		{
-			Description:                "filegroup with glob with Android.bp file as boundary",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: `filegroup {
-    name: "fg_foo",
-    srcs: ["**/*.txt"],
-    bazel_module: { bp2build_available: true },
-}`,
-			Filesystem: map[string]string{
-				"a.txt":              "",
-				"b.txt":              "",
-				"foo/Android.bp":     "",
-				"foo/a.txt":          "",
-				"foo/bar/Android.bp": "",
-				"foo/bar/b.txt":      "",
-			},
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `[
-        "a.txt",
-        "b.txt",
-        "//foo:a.txt",
-        "//foo/bar:b.txt",
-    ]`,
-				}),
-			},
-		},
-		{
-			Description:                "filegroup with glob in subdir with kept BUILD and BUILD.bazel file",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Dir:                        "other",
-			KeepBuildFileForDirs: []string{
-				"other/foo",
-				"other/foo/bar",
-				// deliberately not other/foo/baz/BUILD.
-			},
-			Filesystem: map[string]string{
-				"other/Android.bp": `filegroup {
-    name: "fg_foo",
-    srcs: ["**/*.txt"],
-    bazel_module: { bp2build_available: true },
-}`,
-				"other/a.txt":               "",
-				"other/b.txt":               "",
-				"other/foo/BUILD":           "",
-				"other/foo/a.txt":           "",
-				"other/foo/bar/BUILD.bazel": "",
-				"other/foo/bar/b.txt":       "",
-				"other/foo/baz/BUILD":       "",
-				"other/foo/baz/c.txt":       "",
-			},
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `[
-        "a.txt",
-        "b.txt",
-        "//other/foo:a.txt",
-        "//other/foo/bar:b.txt",
-        "//other/foo:baz/c.txt",
-    ]`,
-				}),
-			},
-		},
-	}
-
-	for _, testCase := range testCases {
-		t.Run(testCase.Description, func(t *testing.T) {
-			RunBp2BuildTestCaseSimple(t, testCase)
-		})
-	}
-}
-
-func TestGlobExcludeSrcs(t *testing.T) {
-	testCases := []Bp2buildTestCase{
-		{
-			Description:                "filegroup top level exclude_srcs",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: `filegroup {
-    name: "fg_foo",
-    srcs: ["**/*.txt"],
-    exclude_srcs: ["c.txt"],
-    bazel_module: { bp2build_available: true },
-}`,
-			Filesystem: map[string]string{
-				"a.txt":          "",
-				"b.txt":          "",
-				"c.txt":          "",
-				"dir/Android.bp": "",
-				"dir/e.txt":      "",
-				"dir/f.txt":      "",
-			},
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `[
-        "a.txt",
-        "b.txt",
-        "//dir:e.txt",
-        "//dir:f.txt",
-    ]`,
-				}),
-			},
-		},
-		{
-			Description:                "filegroup in subdir exclude_srcs",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint:                  "",
-			Dir:                        "dir",
-			Filesystem: 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{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"srcs": `[
-        "a.txt",
-        "//dir/subdir:e.txt",
-        "//dir/subdir:f.txt",
-    ]`,
-				}),
-			},
-		},
-	}
-
-	for _, testCase := range testCases {
-		t.Run(testCase.Description, func(t *testing.T) {
-			RunBp2BuildTestCaseSimple(t, testCase)
-		})
-	}
-}
-
-func TestCommonBp2BuildModuleAttrs(t *testing.T) {
-	testCases := []Bp2buildTestCase{
-		{
-			Description:                "Required into data test",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
-filegroup {
-    name: "fg_foo",
-    required: ["reqd"],
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"data": `[":reqd"]`,
-				}),
-			},
-		},
-		{
-			Description:                "Required into data test, cyclic self reference is filtered out",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
-filegroup {
-    name: "fg_foo",
-    required: ["reqd", "fg_foo"],
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"data": `[":reqd"]`,
-				}),
-			},
-		},
-		{
-			Description:                "Required via arch into data test",
-			ModuleTypeUnderTest:        "python_library",
-			ModuleTypeUnderTestFactory: python.PythonLibraryFactory,
-			Blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqdx86") +
-				simpleModuleDoNotConvertBp2build("python_library", "reqdarm") + `
-python_library {
-    name: "fg_foo",
-    arch: {
-       arm: {
-         required: ["reqdarm"],
-       },
-       x86: {
-         required: ["reqdx86"],
-       },
-    },
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("py_library", "fg_foo", map[string]string{
-					"data": `select({
-        "//build/bazel/platforms/arch:arm": [":reqdarm"],
-        "//build/bazel/platforms/arch:x86": [":reqdx86"],
-        "//conditions:default": [],
-    })`,
-					"srcs_version": `"PY3"`,
-					"imports":      `["."]`,
-				}),
-			},
-		},
-		{
-			Description:                "Required appended to data test",
-			ModuleTypeUnderTest:        "python_library",
-			ModuleTypeUnderTestFactory: python.PythonLibraryFactory,
-			Filesystem: map[string]string{
-				"data.bin": "",
-				"src.py":   "",
-			},
-			Blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqd") + `
-python_library {
-    name: "fg_foo",
-    data: ["data.bin"],
-    required: ["reqd"],
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("py_library", "fg_foo", map[string]string{
-					"data": `[
-        "data.bin",
-        ":reqd",
-    ]`,
-					"srcs_version": `"PY3"`,
-					"imports":      `["."]`,
-				}),
-			},
-		},
-		{
-			Description:                "All props-to-attrs at once together test",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
-filegroup {
-    name: "fg_foo",
-    required: ["reqd"],
-    bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
-					"data": `[":reqd"]`,
-				}),
-			},
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.Description, func(t *testing.T) {
-			RunBp2BuildTestCaseSimple(t, tc)
-		})
-	}
-}
-
-func TestLicensesAttrConversion(t *testing.T) {
-	RunBp2BuildTestCase(t,
-		func(ctx android.RegistrationContext) {
-			ctx.RegisterModuleType("license", android.LicenseFactory)
-		},
-		Bp2buildTestCase{
-			Description:                "Test that licenses: attribute is converted",
-			ModuleTypeUnderTest:        "filegroup",
-			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: `
-license {
-    name: "my_license",
-}
-filegroup {
-    name: "my_filegroup",
-    licenses: ["my_license"],
-}
-`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("filegroup", "my_filegroup", AttrNameToString{
-					"applicable_licenses": `[":my_license"]`,
-				}),
-				MakeBazelTargetNoRestrictions("android_license", "my_license", AttrNameToString{}),
-			},
-		})
-}
-
-func TestGenerateApiBazelTargets(t *testing.T) {
-	bp := `
-	custom {
-		name: "foo",
-		api: "foo.txt",
-	}
-	`
-	expectedBazelTarget := MakeBazelTarget(
-		"custom_api_contribution",
-		"foo",
-		AttrNameToString{
-			"api": `"foo.txt"`,
-		},
-	)
-	registerCustomModule := func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
-	}
-	RunApiBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
-		Blueprint:            bp,
-		ExpectedBazelTargets: []string{expectedBazelTarget},
-		Description:          "Generating API contribution Bazel targets for custom module",
-	})
-}
-
-func TestGenerateConfigSetting(t *testing.T) {
-	bp := `
-	custom {
-		name: "foo",
-		test_config_setting: true,
-	}
-	`
-	expectedBazelTargets := []string{
-		MakeBazelTargetNoRestrictions(
-			"config_setting",
-			"foo_config_setting",
-			AttrNameToString{
-				"flag_values": `{
-        "//build/bazel/rules/my_string_setting": "foo",
-    }`,
-			},
-		),
-		MakeBazelTarget(
-			"custom",
-			"foo",
-			AttrNameToString{},
-		),
-	}
-	registerCustomModule := func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
-	}
-	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
-		Blueprint:            bp,
-		ExpectedBazelTargets: expectedBazelTargets,
-		Description:          "Generating API contribution Bazel targets for custom module",
-	})
-}
-
-// If values of all keys in an axis are equal to //conditions:default, drop the axis and print the common value
-func TestPrettyPrintSelectMapEqualValues(t *testing.T) {
-	lla := bazel.LabelListAttribute{
-		Value: bazel.LabelList{},
-	}
-	libFooImplLabel := bazel.Label{
-		Label: ":libfoo.impl",
-	}
-	lla.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidPlatform, bazel.MakeLabelList([]bazel.Label{libFooImplLabel}))
-	lla.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.MakeLabelList([]bazel.Label{libFooImplLabel}))
-	actual, _ := prettyPrintAttribute(lla, 0)
-	android.AssertStringEquals(t, "Print the common value if all keys in an axis have the same value", `[":libfoo.impl"]`, actual)
-}
-
-// If CommonAttributes.Dir is set, the bazel target should be created in that dir
-func TestCreateBazelTargetInDifferentDir(t *testing.T) {
-	t.Parallel()
-	bp := `
-	custom {
-		name: "foo",
-		dir: "subdir",
-	}
-	`
-	registerCustomModule := func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
-	}
-	// Check that foo is not created in root dir
-	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
-		Description: "foo is not created in root dir because it sets dir explicitly",
-		Blueprint:   bp,
-		Filesystem: map[string]string{
-			"subdir/Android.bp": "",
-		},
-		ExpectedBazelTargets: []string{},
-	})
-	// Check that foo is created in `subdir`
-	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
-		Description: "foo is created in `subdir` because it sets dir explicitly",
-		Blueprint:   bp,
-		Filesystem: map[string]string{
-			"subdir/Android.bp": "",
-		},
-		Dir: "subdir",
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("custom", "foo", AttrNameToString{}),
-		},
-	})
-	// Check that we cannot create target in different dir if it is does not an Android.bp
-	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
-		Description: "foo cannot be created in `subdir` because it does not contain an Android.bp file",
-		Blueprint:   bp,
-		Dir:         "subdir",
-		ExpectedErr: fmt.Errorf("Cannot use ca.Dir to create a BazelTarget in dir: subdir since it does not contain an Android.bp file"),
-	})
-
-}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
deleted file mode 100644
index 402d4b0..0000000
--- a/bp2build/bzl_conversion_test.go
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright 2020 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"io/ioutil"
-	"os"
-	"strings"
-	"testing"
-
-	"android/soong/android"
-)
-
-func setUp() {
-	var err error
-	buildDir, err = ioutil.TempDir("", "bazel_queryview_test")
-	if err != nil {
-		panic(err)
-	}
-}
-
-func tearDown() {
-	os.RemoveAll(buildDir)
-}
-
-func TestMain(m *testing.M) {
-	run := func() int {
-		setUp()
-		defer tearDown()
-
-		return m.Run()
-	}
-
-	os.Exit(run())
-}
-
-func TestGenerateModuleRuleShims(t *testing.T) {
-	moduleTypeFactories := map[string]android.ModuleFactory{
-		"custom":          customModuleFactoryBase,
-		"custom_test":     customTestModuleFactoryBase,
-		"custom_defaults": customDefaultsModuleFactoryBasic,
-	}
-	ruleShims := CreateRuleShims(moduleTypeFactories)
-
-	if len(ruleShims) != 1 {
-		t.Errorf("Expected to generate 1 rule shim, but got %d", len(ruleShims))
-	}
-
-	ruleShim := ruleShims["bp2build"]
-	expectedRules := []string{
-		"custom",
-		"custom_defaults",
-		"custom_test_",
-	}
-
-	if len(ruleShim.rules) != len(expectedRules) {
-		t.Errorf("Expected %d rules, but got %d", len(expectedRules), len(ruleShim.rules))
-	}
-
-	for i, rule := range ruleShim.rules {
-		if rule != expectedRules[i] {
-			t.Errorf("Expected rule shim to contain %s, but got %s", expectedRules[i], rule)
-		}
-	}
-	expectedBzl := `load("//build/bazel/queryview_rules:providers.bzl", "SoongModuleInfo")
-
-def _custom_impl(ctx):
-    return [SoongModuleInfo()]
-
-custom = rule(
-    implementation = _custom_impl,
-    attrs = {
-        "soong_module_name": attr.string(mandatory = True),
-        "soong_module_variant": attr.string(),
-        "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
-        "api": attr.string(),
-        "arch_paths": attr.string_list(),
-        "arch_paths_exclude": attr.string_list(),
-        # bazel_module start
-#         "label": attr.string(),
-#         "bp2build_available": attr.bool(),
-        # bazel_module end
-        "bool_prop": attr.bool(),
-        "bool_ptr_prop": attr.bool(),
-        "dir": attr.string(),
-        "embedded_prop": attr.string(),
-        "int64_ptr_prop": attr.int(),
-        # nested_props start
-#         "nested_prop": attr.string(),
-        # nested_props end
-        # nested_props_ptr start
-#         "nested_prop": attr.string(),
-        # nested_props_ptr end
-        "one_to_many_prop": attr.bool(),
-        "other_embedded_prop": attr.string(),
-        "string_list_prop": attr.string_list(),
-        "string_literal_prop": attr.string(),
-        "string_prop": attr.string(),
-        "string_ptr_prop": attr.string(),
-        "test_config_setting": attr.bool(),
-    },
-)
-
-def _custom_defaults_impl(ctx):
-    return [SoongModuleInfo()]
-
-custom_defaults = rule(
-    implementation = _custom_defaults_impl,
-    attrs = {
-        "soong_module_name": attr.string(mandatory = True),
-        "soong_module_variant": attr.string(),
-        "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
-        "api": attr.string(),
-        "arch_paths": attr.string_list(),
-        "arch_paths_exclude": attr.string_list(),
-        "bool_prop": attr.bool(),
-        "bool_ptr_prop": attr.bool(),
-        "dir": attr.string(),
-        "embedded_prop": attr.string(),
-        "int64_ptr_prop": attr.int(),
-        # nested_props start
-#         "nested_prop": attr.string(),
-        # nested_props end
-        # nested_props_ptr start
-#         "nested_prop": attr.string(),
-        # nested_props_ptr end
-        "one_to_many_prop": attr.bool(),
-        "other_embedded_prop": attr.string(),
-        "string_list_prop": attr.string_list(),
-        "string_literal_prop": attr.string(),
-        "string_prop": attr.string(),
-        "string_ptr_prop": attr.string(),
-        "test_config_setting": attr.bool(),
-    },
-)
-
-def _custom_test__impl(ctx):
-    return [SoongModuleInfo()]
-
-custom_test_ = rule(
-    implementation = _custom_test__impl,
-    attrs = {
-        "soong_module_name": attr.string(mandatory = True),
-        "soong_module_variant": attr.string(),
-        "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
-        "api": attr.string(),
-        "arch_paths": attr.string_list(),
-        "arch_paths_exclude": attr.string_list(),
-        "bool_prop": attr.bool(),
-        "bool_ptr_prop": attr.bool(),
-        "dir": attr.string(),
-        "embedded_prop": attr.string(),
-        "int64_ptr_prop": attr.int(),
-        # nested_props start
-#         "nested_prop": attr.string(),
-        # nested_props end
-        # nested_props_ptr start
-#         "nested_prop": attr.string(),
-        # nested_props_ptr end
-        "one_to_many_prop": attr.bool(),
-        "other_embedded_prop": attr.string(),
-        "string_list_prop": attr.string_list(),
-        "string_literal_prop": attr.string(),
-        "string_prop": attr.string(),
-        "string_ptr_prop": attr.string(),
-        "test_config_setting": attr.bool(),
-        # test_prop start
-#         "test_string_prop": attr.string(),
-        # test_prop end
-    },
-)
-`
-
-	if ruleShim.content != expectedBzl {
-		t.Errorf(
-			"Expected the generated rule shim bzl to be:\n%s\nbut got:\n%s",
-			expectedBzl,
-			ruleShim.content)
-	}
-}
-
-func TestGenerateSoongModuleBzl(t *testing.T) {
-	ruleShims := map[string]RuleShim{
-		"file1": RuleShim{
-			rules:   []string{"a", "b"},
-			content: "irrelevant",
-		},
-		"file2": RuleShim{
-			rules:   []string{"c", "d"},
-			content: "irrelevant",
-		},
-	}
-	files := CreateBazelFiles(ruleShims, make(map[string]BazelTargets), QueryView)
-
-	var actualSoongModuleBzl BazelFile
-	for _, f := range files {
-		if f.Basename == "soong_module.bzl" {
-			actualSoongModuleBzl = f
-		}
-	}
-
-	expectedLoad := `load("//build/bazel/queryview_rules:file1.bzl", "a", "b")
-load("//build/bazel/queryview_rules:file2.bzl", "c", "d")
-`
-	expectedRuleMap := `soong_module_rule_map = {
-    "a": a,
-    "b": b,
-    "c": c,
-    "d": d,
-}`
-	if !strings.Contains(actualSoongModuleBzl.Contents, expectedLoad) {
-		t.Errorf(
-			"Generated soong_module.bzl:\n\n%s\n\n"+
-				"Could not find the load statement in the generated soong_module.bzl:\n%s",
-			actualSoongModuleBzl.Contents,
-			expectedLoad)
-	}
-
-	if !strings.Contains(actualSoongModuleBzl.Contents, expectedRuleMap) {
-		t.Errorf(
-			"Generated soong_module.bzl:\n\n%s\n\n"+
-				"Could not find the module -> rule map in the generated soong_module.bzl:\n%s",
-			actualSoongModuleBzl.Contents,
-			expectedRuleMap)
-	}
-}
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
deleted file mode 100644
index d9a7860..0000000
--- a/bp2build/cc_binary_conversion_test.go
+++ /dev/null
@@ -1,1295 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"fmt"
-	"strings"
-	"testing"
-
-	"android/soong/android"
-	"android/soong/cc"
-	"android/soong/genrule"
-)
-
-const (
-	ccBinaryTypePlaceHolder = "{rule_name}"
-)
-
-type testBazelTarget struct {
-	typ   string
-	name  string
-	attrs AttrNameToString
-}
-
-func generateBazelTargetsForTest(targets []testBazelTarget, hod android.HostOrDeviceSupported) []string {
-	ret := make([]string, 0, len(targets))
-	for _, t := range targets {
-		attrs := t.attrs.clone()
-		ret = append(ret, makeBazelTargetHostOrDevice(t.typ, t.name, attrs, hod))
-	}
-	return ret
-}
-
-type ccBinaryBp2buildTestCase struct {
-	description string
-	filesystem  map[string]string
-	blueprint   string
-	targets     []testBazelTarget
-}
-
-func registerCcBinaryModuleTypes(ctx android.RegistrationContext) {
-	cc.RegisterCCBuildComponents(ctx)
-	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
-	ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
-	ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
-	ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
-}
-
-var binaryReplacer = strings.NewReplacer(ccBinaryTypePlaceHolder, "cc_binary")
-var hostBinaryReplacer = strings.NewReplacer(ccBinaryTypePlaceHolder, "cc_binary_host")
-
-func runCcBinaryTests(t *testing.T, tc ccBinaryBp2buildTestCase) {
-	t.Helper()
-	runCcBinaryTestCase(t, tc)
-	runCcHostBinaryTestCase(t, tc)
-}
-
-func runCcBinaryTestCase(t *testing.T, testCase ccBinaryBp2buildTestCase) {
-	t.Helper()
-	moduleTypeUnderTest := "cc_binary"
-
-	description := fmt.Sprintf("%s %s", moduleTypeUnderTest, testCase.description)
-	t.Run(description, func(t *testing.T) {
-		t.Helper()
-		RunBp2BuildTestCase(t, registerCcBinaryModuleTypes, Bp2buildTestCase{
-			ExpectedBazelTargets:       generateBazelTargetsForTest(testCase.targets, android.DeviceSupported),
-			ModuleTypeUnderTest:        moduleTypeUnderTest,
-			ModuleTypeUnderTestFactory: cc.BinaryFactory,
-			Description:                description,
-			Blueprint:                  binaryReplacer.Replace(testCase.blueprint),
-			Filesystem:                 testCase.filesystem,
-		})
-	})
-}
-
-func runCcHostBinaryTestCase(t *testing.T, testCase ccBinaryBp2buildTestCase) {
-	t.Helper()
-	moduleTypeUnderTest := "cc_binary_host"
-	description := fmt.Sprintf("%s %s", moduleTypeUnderTest, testCase.description)
-	t.Run(description, func(t *testing.T) {
-		RunBp2BuildTestCase(t, registerCcBinaryModuleTypes, Bp2buildTestCase{
-			ExpectedBazelTargets:       generateBazelTargetsForTest(testCase.targets, android.HostSupported),
-			ModuleTypeUnderTest:        moduleTypeUnderTest,
-			ModuleTypeUnderTestFactory: cc.BinaryHostFactory,
-			Description:                description,
-			Blueprint:                  hostBinaryReplacer.Replace(testCase.blueprint),
-			Filesystem:                 testCase.filesystem,
-		})
-	})
-}
-
-func TestBasicCcBinary(t *testing.T) {
-	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-		description: "basic -- properties -> attrs with little/no transformation",
-		filesystem: map[string]string{
-			soongCcVersionLibBpPath: soongCcVersionLibBp,
-		},
-		blueprint: `
-{rule_name} {
-    name: "foo",
-    srcs: ["a.cc"],
-    local_include_dirs: ["dir"],
-    include_dirs: ["absolute_dir"],
-    cflags: ["-Dcopt"],
-    cppflags: ["-Dcppflag"],
-    conlyflags: ["-Dconlyflag"],
-    asflags: ["-Dasflag"],
-    ldflags: ["ld-flag"],
-    rtti: true,
-    strip: {
-        all: true,
-        keep_symbols: true,
-        keep_symbols_and_debug_frame: true,
-        keep_symbols_list: ["symbol"],
-        none: true,
-    },
-    sdk_version: "current",
-    min_sdk_version: "29",
-    use_version_lib: true,
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"absolute_includes": `["absolute_dir"]`,
-				"asflags":           `["-Dasflag"]`,
-				"conlyflags":        `["-Dconlyflag"]`,
-				"copts":             `["-Dcopt"]`,
-				"cppflags":          `["-Dcppflag"]`,
-				"linkopts":          `["ld-flag"]`,
-				"local_includes": `[
-        "dir",
-        ".",
-    ]`,
-				"rtti": `True`,
-				"srcs": `["a.cc"]`,
-				"strip": `{
-        "all": True,
-        "keep_symbols": True,
-        "keep_symbols_and_debug_frame": True,
-        "keep_symbols_list": ["symbol"],
-        "none": True,
-    }`,
-				"sdk_version":        `"current"`,
-				"min_sdk_version":    `"29"`,
-				"use_version_lib":    `True`,
-				"whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
-			},
-			},
-		},
-	})
-}
-
-func TestCcBinaryWithSharedLdflagDisableFeature(t *testing.T) {
-	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-		description: `ldflag "-shared" disables static_flag feature`,
-		blueprint: `
-{rule_name} {
-    name: "foo",
-    ldflags: ["-shared"],
-    include_build_directory: false,
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"features": `["-static_flag"]`,
-				"linkopts": `["-shared"]`,
-			},
-			},
-		},
-	})
-}
-
-func TestCcBinaryWithLinkStatic(t *testing.T) {
-	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-		description: "link static",
-		blueprint: `
-{rule_name} {
-    name: "foo",
-    static_executable: true,
-    include_build_directory: false,
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"linkshared": `False`,
-			},
-			},
-		},
-	})
-}
-
-func TestCcBinaryVersionScriptAndDynamicList(t *testing.T) {
-	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-		description: `version script and dynamic list`,
-		blueprint: `
-{rule_name} {
-    name: "foo",
-    include_build_directory: false,
-    version_script: "vs",
-    dynamic_list: "dynamic.list",
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"additional_linker_inputs": `[
-        "vs",
-        "dynamic.list",
-    ]`,
-				"linkopts": `[
-        "-Wl,--version-script,$(location vs)",
-        "-Wl,--dynamic-list,$(location dynamic.list)",
-    ]`,
-				"features": `["android_cfi_exports_map"]`,
-			},
-			},
-		},
-	})
-}
-
-func TestCcBinaryLdflagsSplitBySpaceExceptSoongAdded(t *testing.T) {
-	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-		description: "ldflags are split by spaces except for the ones added by soong (version script and dynamic list)",
-		blueprint: `
-{rule_name} {
-    name: "foo",
-		ldflags: [
-			"--nospace_flag",
-			"-z spaceflag",
-		],
-		version_script: "version_script",
-		dynamic_list: "dynamic.list",
-    include_build_directory: false,
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"additional_linker_inputs": `[
-        "version_script",
-        "dynamic.list",
-    ]`,
-				"features": `["android_cfi_exports_map"]`,
-				"linkopts": `[
-        "--nospace_flag",
-        "-z",
-        "spaceflag",
-        "-Wl,--version-script,$(location version_script)",
-        "-Wl,--dynamic-list,$(location dynamic.list)",
-    ]`,
-			}}},
-	})
-}
-
-func TestCcBinarySplitSrcsByLang(t *testing.T) {
-	runCcHostBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "split srcs by lang",
-		blueprint: `
-{rule_name} {
-    name: "foo",
-    srcs: [
-        "asonly.S",
-        "conly.c",
-        "cpponly.cpp",
-        ":fg_foo",
-    ],
-    include_build_directory: false,
-}
-` + simpleModuleDoNotConvertBp2build("filegroup", "fg_foo"),
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"srcs": `[
-        "cpponly.cpp",
-        ":fg_foo_cpp_srcs",
-    ]`,
-				"srcs_as": `[
-        "asonly.S",
-        ":fg_foo_as_srcs",
-    ]`,
-				"srcs_c": `[
-        "conly.c",
-        ":fg_foo_c_srcs",
-    ]`,
-			},
-			},
-		},
-	})
-}
-
-func TestCcBinaryDoNotDistinguishBetweenDepsAndImplementationDeps(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "no implementation deps",
-		blueprint: `
-genrule {
-    name: "generated_hdr",
-    cmd: "nothing to see here",
-    bazel_module: { bp2build_available: false },
-}
-
-genrule {
-    name: "export_generated_hdr",
-    cmd: "nothing to see here",
-    bazel_module: { bp2build_available: false },
-}
-
-{rule_name} {
-    name: "foo",
-    srcs: ["foo.cpp"],
-    shared_libs: ["implementation_shared_dep", "shared_dep"],
-    export_shared_lib_headers: ["shared_dep"],
-    static_libs: ["implementation_static_dep", "static_dep"],
-    export_static_lib_headers: ["static_dep", "whole_static_dep"],
-    whole_static_libs: ["not_explicitly_exported_whole_static_dep", "whole_static_dep"],
-    include_build_directory: false,
-    generated_headers: ["generated_hdr", "export_generated_hdr"],
-    export_generated_headers: ["export_generated_hdr"],
-}
-` +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep") +
-			simpleModuleDoNotConvertBp2build("cc_library", "shared_dep") +
-			simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep"),
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"deps": `[
-        ":implementation_static_dep",
-        ":static_dep",
-    ]`,
-				"dynamic_deps": `[
-        ":implementation_shared_dep",
-        ":shared_dep",
-    ]`,
-				"srcs": `[
-        "foo.cpp",
-        ":generated_hdr",
-        ":export_generated_hdr",
-    ]`,
-				"whole_archive_deps": `[
-        ":not_explicitly_exported_whole_static_dep",
-        ":whole_static_dep",
-    ]`,
-				"local_includes": `["."]`,
-			},
-			},
-		},
-	})
-}
-
-func TestCcBinaryNocrtTests(t *testing.T) {
-	baseTestCases := []struct {
-		description   string
-		soongProperty string
-		bazelAttr     AttrNameToString
-	}{
-		{
-			description:   "nocrt: true",
-			soongProperty: `nocrt: true,`,
-			bazelAttr:     AttrNameToString{"features": `["-link_crt"]`},
-		},
-		{
-			description:   "nocrt: false",
-			soongProperty: `nocrt: false,`,
-			bazelAttr:     AttrNameToString{},
-		},
-		{
-			description: "nocrt: not set",
-			bazelAttr:   AttrNameToString{},
-		},
-	}
-
-	baseBlueprint := `{rule_name} {
-    name: "foo",%s
-    include_build_directory: false,
-}
-`
-
-	for _, btc := range baseTestCases {
-		prop := btc.soongProperty
-		if len(prop) > 0 {
-			prop = "\n" + prop
-		}
-		runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-			description: btc.description,
-			blueprint:   fmt.Sprintf(baseBlueprint, prop),
-			targets: []testBazelTarget{
-				{"cc_binary", "foo", btc.bazelAttr},
-			},
-		})
-	}
-}
-
-func TestCcBinaryNo_libcrtTests(t *testing.T) {
-	baseTestCases := []struct {
-		description   string
-		soongProperty string
-		bazelAttr     AttrNameToString
-	}{
-		{
-			description:   "no_libcrt: true",
-			soongProperty: `no_libcrt: true,`,
-			bazelAttr:     AttrNameToString{"features": `["-use_libcrt"]`},
-		},
-		{
-			description:   "no_libcrt: false",
-			soongProperty: `no_libcrt: false,`,
-			bazelAttr:     AttrNameToString{},
-		},
-		{
-			description: "no_libcrt: not set",
-			bazelAttr:   AttrNameToString{},
-		},
-	}
-
-	baseBlueprint := `{rule_name} {
-    name: "foo",%s
-    include_build_directory: false,
-}
-`
-
-	for _, btc := range baseTestCases {
-		prop := btc.soongProperty
-		if len(prop) > 0 {
-			prop = "\n" + prop
-		}
-		runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-			description: btc.description,
-			blueprint:   fmt.Sprintf(baseBlueprint, prop),
-			targets: []testBazelTarget{
-				{"cc_binary", "foo", btc.bazelAttr},
-			},
-		})
-	}
-}
-
-func TestCcBinaryPropertiesToFeatures(t *testing.T) {
-	baseTestCases := []struct {
-		description   string
-		soongProperty string
-		bazelAttr     AttrNameToString
-	}{
-		{
-			description:   "pack_relocation: true",
-			soongProperty: `pack_relocations: true,`,
-			bazelAttr:     AttrNameToString{},
-		},
-		{
-			description:   "pack_relocations: false",
-			soongProperty: `pack_relocations: false,`,
-			bazelAttr:     AttrNameToString{"features": `["disable_pack_relocations"]`},
-		},
-		{
-			description: "pack_relocations: not set",
-			bazelAttr:   AttrNameToString{},
-		},
-		{
-			description:   "pack_relocation: true",
-			soongProperty: `allow_undefined_symbols: true,`,
-			bazelAttr:     AttrNameToString{"features": `["-no_undefined_symbols"]`},
-		},
-		{
-			description:   "allow_undefined_symbols: false",
-			soongProperty: `allow_undefined_symbols: false,`,
-			bazelAttr:     AttrNameToString{},
-		},
-		{
-			description: "allow_undefined_symbols: not set",
-			bazelAttr:   AttrNameToString{},
-		},
-	}
-
-	baseBlueprint := `{rule_name} {
-    name: "foo",%s
-    include_build_directory: false,
-}
-`
-	for _, btc := range baseTestCases {
-		prop := btc.soongProperty
-		if len(prop) > 0 {
-			prop = "\n" + prop
-		}
-		runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-			description: btc.description,
-			blueprint:   fmt.Sprintf(baseBlueprint, prop),
-			targets: []testBazelTarget{
-				{"cc_binary", "foo", btc.bazelAttr},
-			},
-		})
-	}
-}
-
-func TestCcBinarySharedProto(t *testing.T) {
-	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-		blueprint: soongCcProtoLibraries + `{rule_name} {
-	name: "foo",
-	srcs: ["foo.proto"],
-	proto: {
-	},
-	include_build_directory: false,
-}`,
-		targets: []testBazelTarget{
-			{"proto_library", "foo_proto", AttrNameToString{
-				"srcs": `["foo.proto"]`,
-			}}, {"cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
-				"deps": `[":foo_proto"]`,
-			}}, {"cc_binary", "foo", AttrNameToString{
-				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":foo_cc_proto_lite"]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryStaticProto(t *testing.T) {
-	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-		blueprint: soongCcProtoLibraries + `{rule_name} {
-	name: "foo",
-	srcs: ["foo.proto"],
-	static_executable: true,
-	proto: {
-	},
-	include_build_directory: false,
-}`,
-		targets: []testBazelTarget{
-			{"proto_library", "foo_proto", AttrNameToString{
-				"srcs": `["foo.proto"]`,
-			}}, {"cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
-				"deps": `[":foo_proto"]`,
-			}}, {"cc_binary", "foo", AttrNameToString{
-				"deps":               `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":foo_cc_proto_lite"]`,
-				"linkshared":         `False`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryConvertLex(t *testing.T) {
-	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-		description: `.l and .ll sources converted to .c and .cc`,
-		blueprint: `
-{rule_name} {
-    name: "foo",
-		srcs: ["foo.c", "bar.cc", "foo1.l", "foo2.l", "bar1.ll", "bar2.ll"],
-		lex: { flags: ["--foo_opt", "--bar_opt"] },
-		include_build_directory: false,
-}
-`,
-		targets: []testBazelTarget{
-			{"genlex", "foo_genlex_l", AttrNameToString{
-				"srcs": `[
-        "foo1.l",
-        "foo2.l",
-    ]`,
-				"lexopts": `[
-        "--foo_opt",
-        "--bar_opt",
-    ]`,
-			}},
-			{"genlex", "foo_genlex_ll", AttrNameToString{
-				"srcs": `[
-        "bar1.ll",
-        "bar2.ll",
-    ]`,
-				"lexopts": `[
-        "--foo_opt",
-        "--bar_opt",
-    ]`,
-			}},
-			{"cc_binary", "foo", AttrNameToString{
-				"srcs": `[
-        "bar.cc",
-        ":foo_genlex_ll",
-    ]`,
-				"srcs_c": `[
-        "foo.c",
-        ":foo_genlex_l",
-    ]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryRuntimeLibs(t *testing.T) {
-	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary with runtime libs",
-		blueprint: `
-cc_library {
-    name: "bar",
-    srcs: ["b.cc"],
-}
-
-{rule_name} {
-    name: "foo",
-    srcs: ["a.cc"],
-    runtime_libs: ["bar"],
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_library_static", "bar_bp2build_cc_library_static", AttrNameToString{
-				"local_includes":         `["."]`,
-				"srcs":                   `["b.cc"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-			},
-			},
-			{"cc_library_shared", "bar", AttrNameToString{
-				"local_includes":         `["."]`,
-				"srcs":                   `["b.cc"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-			},
-			},
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"srcs":           `["a.cc"]`,
-				"runtime_deps":   `[":bar"]`,
-			},
-			},
-		},
-	})
-}
-
-func TestCcBinaryWithInstructionSet(t *testing.T) {
-	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-		description: "instruction set",
-		blueprint: `
-{rule_name} {
-    name: "foo",
-    arch: {
-      arm: {
-        instruction_set: "arm",
-      }
-    }
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"features": `select({
-        "//build/bazel/platforms/arch:arm": ["arm_isa_arm"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryEmptySuffix(t *testing.T) {
-	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-		description: "binary with empty suffix",
-		blueprint: `
-{rule_name} {
-    name: "foo",
-    suffix: "",
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"suffix":         `""`,
-			}},
-		},
-	})
-}
-
-func TestCcBinarySuffix(t *testing.T) {
-	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-		description: "binary with suffix",
-		blueprint: `
-{rule_name} {
-    name: "foo",
-    suffix: "-suf",
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"suffix":         `"-suf"`,
-			}},
-		},
-	})
-}
-
-func TestCcArchVariantBinarySuffix(t *testing.T) {
-	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-		description: "binary with suffix",
-		blueprint: `
-{rule_name} {
-    name: "foo",
-    arch: {
-        arm64: { suffix: "-64" },
-        arm:   { suffix: "-32" },
-		},
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"suffix": `select({
-        "//build/bazel/platforms/arch:arm": "-32",
-        "//build/bazel/platforms/arch:arm64": "-64",
-        "//conditions:default": None,
-    })`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryWithSyspropSrcs(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary with sysprop sources",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	srcs: [
-		"bar.sysprop",
-		"baz.sysprop",
-		"blah.cpp",
-	],
-	min_sdk_version: "5",
-}`,
-		targets: []testBazelTarget{
-			{"sysprop_library", "foo_sysprop_library", AttrNameToString{
-				"srcs": `[
-        "bar.sysprop",
-        "baz.sysprop",
-    ]`,
-			}},
-			{"cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
-				"dep":             `":foo_sysprop_library"`,
-				"min_sdk_version": `"5"`,
-			}},
-			{"cc_binary", "foo", AttrNameToString{
-				"srcs":               `["blah.cpp"]`,
-				"local_includes":     `["."]`,
-				"min_sdk_version":    `"5"`,
-				"whole_archive_deps": `[":foo_cc_sysprop_library_static"]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryWithSyspropSrcsSomeConfigs(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary with sysprop sources in some configs but not others",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	srcs: [
-		"blah.cpp",
-	],
-	target: {
-		android: {
-			srcs: ["bar.sysprop"],
-		},
-	},
-	min_sdk_version: "5",
-}`,
-		targets: []testBazelTarget{
-			{"sysprop_library", "foo_sysprop_library", AttrNameToString{
-				"srcs": `select({
-        "//build/bazel/platforms/os:android": ["bar.sysprop"],
-        "//conditions:default": [],
-    })`,
-			}},
-			{"cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
-				"dep":             `":foo_sysprop_library"`,
-				"min_sdk_version": `"5"`,
-			}},
-			{"cc_binary", "foo", AttrNameToString{
-				"srcs":            `["blah.cpp"]`,
-				"local_includes":  `["."]`,
-				"min_sdk_version": `"5"`,
-				"whole_archive_deps": `select({
-        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
-        "//conditions:default": [],
-    })`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryWithIntegerOverflowProperty(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary with integer overflow property specified",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	sanitize: {
-		integer_overflow: true,
-	},
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features":       `["ubsan_integer_overflow"]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryWithMiscUndefinedProperty(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary with miscellaneous properties specified",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	sanitize: {
-		misc_undefined: ["undefined", "nullability"],
-	},
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features": `[
-        "ubsan_undefined",
-        "ubsan_nullability",
-    ]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryWithUBSanPropertiesArchSpecific(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary has correct feature select when UBSan props are specified in arch specific blocks",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	sanitize: {
-		misc_undefined: ["undefined", "nullability"],
-	},
-	target: {
-			android: {
-					sanitize: {
-							misc_undefined: ["alignment"],
-					},
-			},
-			linux_glibc: {
-					sanitize: {
-							integer_overflow: true,
-					},
-			},
-	},
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features": `[
-        "ubsan_undefined",
-        "ubsan_nullability",
-    ] + select({
-        "//build/bazel/platforms/os:android": ["ubsan_alignment"],
-        "//build/bazel/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
-        "//conditions:default": [],
-    })`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryWithSanitizerBlocklist(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary has the correct feature when sanitize.blocklist is provided",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	sanitize: {
-		blocklist: "foo_blocklist.txt",
-	},
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryWithThinLto(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary has correct features when thin LTO is enabled",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	lto: {
-		thin: true,
-	},
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features":       `["android_thin_lto"]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryWithLtoNever(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary has correct features when LTO is explicitly disabled",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	lto: {
-		never: true,
-	},
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features":       `["-android_thin_lto"]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryWithThinLtoArchSpecific(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary has correct features when LTO differs across arch and os variants",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	target: {
-		android: {
-			lto: {
-				thin: true,
-			},
-		},
-	},
-	arch: {
-		riscv64: {
-			lto: {
-				thin: false,
-			},
-		},
-	},
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
-        "//conditions:default": [],
-    })`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryWithThinLtoDisabledDefaultEnabledVariant(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary has correct features when LTO disabled by default but enabled on a particular variant",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	lto: {
-		never: true,
-	},
-	target: {
-		android: {
-			lto: {
-				thin: true,
-				never: false,
-			},
-		},
-	},
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_thin_lto"],
-        "//conditions:default": ["-android_thin_lto"],
-    })`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryWithThinLtoAndWholeProgramVtables(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary has correct features when thin LTO is enabled with whole_program_vtables",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	lto: {
-		thin: true,
-	},
-	whole_program_vtables: true,
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features": `[
-        "android_thin_lto",
-        "android_thin_lto_whole_program_vtables",
-    ]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryHiddenVisibilityConvertedToFeature(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary changes hidden visibility to feature",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	cflags: ["-fvisibility=hidden"],
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features":       `["visibility_hidden"]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary changes hidden visibility to feature for specific os",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	target: {
-		android: {
-			cflags: ["-fvisibility=hidden"],
-		},
-	},
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["visibility_hidden"],
-        "//conditions:default": [],
-    })`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryWithCfi(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary has correct features when cfi is enabled",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	sanitize: {
-		cfi: true,
-	},
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"features":       `["android_cfi"]`,
-				"local_includes": `["."]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryWithCfiOsSpecific(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary has correct features when cfi is enabled for specific variants",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	target: {
-		android: {
-			sanitize: {
-				cfi: true,
-			},
-		},
-	},
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_cfi"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryWithCfiAndCfiAssemblySupport(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary has correct features when cfi is enabled with cfi assembly support",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	sanitize: {
-		cfi: true,
-		config: {
-			cfi_assembly_support: true,
-		},
-	},
-}`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"features": `[
-        "android_cfi",
-        "android_cfi_assembly_support",
-    ]`,
-				"local_includes": `["."]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryExplicitlyDisablesCfiWhenFalse(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary disables cfi when explciitly set to false in the bp",
-		blueprint: `
-{rule_name} {
-	name: "foo",
-	sanitize: {
-		cfi: false,
-	},
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo", AttrNameToString{
-				"features":       `["-android_cfi"]`,
-				"local_includes": `["."]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryStem(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_binary with stem property",
-		blueprint: `
-cc_binary {
-	name: "foo_with_stem_simple",
-	stem: "foo",
-}
-cc_binary {
-	name: "foo_with_arch_variant_stem",
-	arch: {
-		arm: {
-			stem: "foo-arm",
-		},
-		arm64: {
-			stem: "foo-arm64",
-		},
-	},
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_binary", "foo_with_stem_simple", AttrNameToString{
-				"stem":           `"foo"`,
-				"local_includes": `["."]`,
-			}},
-			{"cc_binary", "foo_with_arch_variant_stem", AttrNameToString{
-				"stem": `select({
-        "//build/bazel/platforms/arch:arm": "foo-arm",
-        "//build/bazel/platforms/arch:arm64": "foo-arm64",
-        "//conditions:default": None,
-    })`,
-				"local_includes": `["."]`,
-			}},
-		},
-	})
-}
-
-func TestCCBinaryRscriptSrc(t *testing.T) {
-	runCcBinaryTests(t, ccBinaryBp2buildTestCase{
-		description: `cc_binary with rscript files in sources`,
-		blueprint: `
-{rule_name} {
-    name : "foo",
-    srcs : [
-        "ccSrc.cc",
-        "rsSrc.rscript",
-    ],
-    include_build_directory: false,
-}
-`,
-		targets: []testBazelTarget{
-			{"rscript_to_cpp", "foo_renderscript", AttrNameToString{
-				"srcs": `["rsSrc.rscript"]`,
-			}},
-			{"cc_binary", "foo", AttrNameToString{
-				"absolute_includes": `[
-        "frameworks/rs",
-        "frameworks/rs/cpp",
-    ]`,
-				"local_includes": `["."]`,
-				"srcs": `[
-        "ccSrc.cc",
-        "foo_renderscript",
-    ]`,
-			}},
-		},
-	})
-}
-
-func TestCcBinaryStatic_SystemSharedLibUsedAsDep(t *testing.T) {
-	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
-		description: "cc_library_static system_shared_lib empty for linux_bionic variant",
-		blueprint: soongCcLibraryStaticPreamble +
-			simpleModuleDoNotConvertBp2build("cc_library", "libc") + `
-
-cc_library {
-    name: "libm",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_binary {
-    name: "used_in_bionic_oses",
-    target: {
-        android: {
-            static_libs: ["libc"],
-        },
-        linux_bionic: {
-            static_libs: ["libc"],
-        },
-    },
-    include_build_directory: false,
-    static_executable: true,
-}
-
-cc_binary {
-    name: "all",
-    static_libs: ["libc"],
-    include_build_directory: false,
-    static_executable: true,
-}
-
-cc_binary {
-    name: "keep_for_empty_system_shared_libs",
-    static_libs: ["libc"],
-    system_shared_libs: [],
-    include_build_directory: false,
-    static_executable: true,
-}
-
-cc_binary {
-    name: "used_with_stubs",
-    static_libs: ["libm"],
-    include_build_directory: false,
-    static_executable: true,
-}
-
-cc_binary {
-    name: "keep_with_stubs",
-    static_libs: ["libm"],
-    system_shared_libs: [],
-    include_build_directory: false,
-    static_executable: true,
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_binary", "all", AttrNameToString{
-				"linkshared": "False",
-			}},
-			{"cc_binary", "keep_for_empty_system_shared_libs", AttrNameToString{
-				"deps":        `[":libc_bp2build_cc_library_static"]`,
-				"system_deps": `[]`,
-				"linkshared":  "False",
-			}},
-			{"cc_binary", "keep_with_stubs", AttrNameToString{
-				"linkshared":  "False",
-				"deps":        `[":libm_bp2build_cc_library_static"]`,
-				"system_deps": `[]`,
-			}},
-			{"cc_binary", "used_in_bionic_oses", AttrNameToString{
-				"linkshared": "False",
-			}},
-			{"cc_binary", "used_with_stubs", AttrNameToString{
-				"linkshared": "False",
-			}},
-		},
-	})
-}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
deleted file mode 100644
index e5ae73e..0000000
--- a/bp2build/cc_library_conversion_test.go
+++ /dev/null
@@ -1,5052 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"fmt"
-	"testing"
-
-	"android/soong/aidl_library"
-	"android/soong/android"
-	"android/soong/cc"
-)
-
-const (
-	// See cc/testing.go for more context
-	soongCcLibraryPreamble = `
-cc_defaults {
-    name: "linux_bionic_supported",
-}
-`
-
-	soongCcVersionLibBpPath = "build/soong/cc/libbuildversion/Android.bp"
-	soongCcVersionLibBp     = `
-cc_library_static {
-	name: "libbuildversion",
-	bazel_module: { bp2build_available: false },
-}
-`
-
-	soongCcProtoLibraries = `
-cc_library {
-	name: "libprotobuf-cpp-lite",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-	name: "libprotobuf-cpp-full",
-	bazel_module: { bp2build_available: false },
-}`
-
-	soongCcProtoPreamble = soongCcLibraryPreamble + soongCcProtoLibraries
-)
-
-func runCcLibraryTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	RunBp2BuildTestCase(t, registerCcLibraryModuleTypes, tc)
-}
-
-func registerCcLibraryModuleTypes(ctx android.RegistrationContext) {
-	cc.RegisterCCBuildComponents(ctx)
-	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
-	ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
-	ctx.RegisterModuleType("cc_prebuilt_library_static", cc.PrebuiltStaticLibraryFactory)
-	ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
-	ctx.RegisterModuleType("aidl_library", aidl_library.AidlLibraryFactory)
-}
-
-func TestCcLibrarySimple(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library - simple example",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			soongCcVersionLibBpPath: soongCcVersionLibBp,
-			"android.cpp":           "",
-			"bionic.cpp":            "",
-			"darwin.cpp":            "",
-			// Refer to cc.headerExts for the supported header extensions in Soong.
-			"header.h":         "",
-			"header.hh":        "",
-			"header.hpp":       "",
-			"header.hxx":       "",
-			"header.h++":       "",
-			"header.inl":       "",
-			"header.inc":       "",
-			"header.ipp":       "",
-			"header.h.generic": "",
-			"impl.cpp":         "",
-			"linux.cpp":        "",
-			"x86.cpp":          "",
-			"x86_64.cpp":       "",
-			"foo-dir/a.h":      "",
-		},
-		Blueprint: soongCcLibraryPreamble +
-			simpleModuleDoNotConvertBp2build("cc_library_headers", "some-headers") + `
-cc_library {
-    name: "foo-lib",
-    srcs: ["impl.cpp"],
-    cflags: ["-Wall"],
-    header_libs: ["some-headers"],
-    export_include_dirs: ["foo-dir"],
-    ldflags: ["-Wl,--exclude-libs=bar.a"],
-    arch: {
-        x86: {
-            ldflags: ["-Wl,--exclude-libs=baz.a"],
-            srcs: ["x86.cpp"],
-        },
-        x86_64: {
-            ldflags: ["-Wl,--exclude-libs=qux.a"],
-            srcs: ["x86_64.cpp"],
-        },
-    },
-    target: {
-        android: {
-            srcs: ["android.cpp"],
-        },
-        linux_glibc: {
-            srcs: ["linux.cpp"],
-        },
-        darwin: {
-            srcs: ["darwin.cpp"],
-        },
-        bionic: {
-          srcs: ["bionic.cpp"]
-        },
-    },
-    include_build_directory: false,
-    sdk_version: "current",
-    min_sdk_version: "29",
-    use_version_lib: true,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
-			"copts":               `["-Wall"]`,
-			"export_includes":     `["foo-dir"]`,
-			"implementation_deps": `[":some-headers"]`,
-			"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"] + select({
-        "//build/bazel/platforms/arch:x86": ["x86.cpp"],
-        "//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/os:android": [
-            "bionic.cpp",
-            "android.cpp",
-        ],
-        "//build/bazel/platforms/os:darwin": ["darwin.cpp"],
-        "//build/bazel/platforms/os:linux_bionic": ["bionic.cpp"],
-        "//build/bazel/platforms/os:linux_glibc": ["linux.cpp"],
-        "//conditions:default": [],
-    })`,
-			"sdk_version":        `"current"`,
-			"min_sdk_version":    `"29"`,
-			"use_version_lib":    `True`,
-			"whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
-		}),
-	})
-}
-
-func TestCcLibraryTrimmedLdAndroid(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library - trimmed example of //bionic/linker:ld-android",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"ld-android.cpp":           "",
-			"linked_list.h":            "",
-			"linker.h":                 "",
-			"linker_block_allocator.h": "",
-			"linker_cfi.h":             "",
-		},
-		Blueprint: soongCcLibraryPreamble +
-			simpleModuleDoNotConvertBp2build("cc_library_headers", "libc_headers") + `
-cc_library {
-    name: "fake-ld-android",
-    srcs: ["ld_android.cpp"],
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Wunused",
-        "-Werror",
-    ],
-    header_libs: ["libc_headers"],
-    ldflags: [
-        "-Wl,--exclude-libs=libgcc.a",
-        "-Wl,--exclude-libs=libgcc_stripped.a",
-        "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
-        "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
-        "-Wl,--exclude-libs=libclang_rt.builtins-i686-android.a",
-        "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
-    ],
-    arch: {
-        x86: {
-            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
-        },
-        x86_64: {
-            ldflags: ["-Wl,--exclude-libs=libgcc_eh.a"],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("fake-ld-android", AttrNameToString{
-			"srcs": `["ld_android.cpp"]`,
-			"copts": `[
-        "-Wall",
-        "-Wextra",
-        "-Wunused",
-        "-Werror",
-    ]`,
-			"implementation_deps": `[":libc_headers"]`,
-			"linkopts": `[
-        "-Wl,--exclude-libs=libgcc.a",
-        "-Wl,--exclude-libs=libgcc_stripped.a",
-        "-Wl,--exclude-libs=libclang_rt.builtins-arm-android.a",
-        "-Wl,--exclude-libs=libclang_rt.builtins-aarch64-android.a",
-        "-Wl,--exclude-libs=libclang_rt.builtins-i686-android.a",
-        "-Wl,--exclude-libs=libclang_rt.builtins-x86_64-android.a",
-    ] + select({
-        "//build/bazel/platforms/arch:x86": ["-Wl,--exclude-libs=libgcc_eh.a"],
-        "//build/bazel/platforms/arch:x86_64": ["-Wl,--exclude-libs=libgcc_eh.a"],
-        "//conditions:default": [],
-    })`,
-		}),
-	})
-}
-
-func TestCcLibraryExcludeSrcs(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library exclude_srcs - trimmed example of //external/arm-optimized-routines:libarm-optimized-routines-math",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		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 },
-}
-`,
-		},
-		Blueprint: soongCcLibraryPreamble,
-		ExpectedBazelTargets: makeCcLibraryTargets("fake-libarm-optimized-routines-math", AttrNameToString{
-			"copts": `select({
-        "//build/bazel/platforms/arch:arm64": ["-DHAVE_FAST_FMA=1"],
-        "//conditions:default": [],
-    })`,
-			"local_includes": `["."]`,
-			"srcs_c":         `["math/cosf.c"]`,
-		}),
-	})
-}
-
-func TestCcLibrarySharedStaticProps(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library shared/static props",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"both.cpp":       "",
-			"sharedonly.cpp": "",
-			"staticonly.cpp": "",
-		},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "a",
-    srcs: ["both.cpp"],
-    cflags: ["bothflag"],
-    shared_libs: ["shared_dep_for_both"],
-    static_libs: ["static_dep_for_both", "whole_and_static_lib_for_both"],
-    whole_static_libs: ["whole_static_lib_for_both", "whole_and_static_lib_for_both"],
-    static: {
-        srcs: ["staticonly.cpp"],
-        cflags: ["staticflag"],
-        shared_libs: ["shared_dep_for_static"],
-        static_libs: ["static_dep_for_static"],
-        whole_static_libs: ["whole_static_lib_for_static"],
-    },
-    shared: {
-        srcs: ["sharedonly.cpp"],
-        cflags: ["sharedflag"],
-        shared_libs: ["shared_dep_for_shared"],
-        static_libs: ["static_dep_for_shared"],
-        whole_static_libs: ["whole_static_lib_for_shared"],
-    },
-    include_build_directory: false,
-}
-
-cc_library_static {
-    name: "static_dep_for_shared",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "static_dep_for_static",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "static_dep_for_both",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "whole_static_lib_for_shared",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "whole_static_lib_for_static",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "whole_static_lib_for_both",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "whole_and_static_lib_for_both",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "shared_dep_for_shared",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "shared_dep_for_static",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "shared_dep_for_both",
-    bazel_module: { bp2build_available: false },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
-				"copts": `[
-        "bothflag",
-        "staticflag",
-    ]`,
-				"implementation_deps": `[
-        ":static_dep_for_both",
-        ":static_dep_for_static",
-    ]`,
-				"implementation_dynamic_deps": `[
-        ":shared_dep_for_both",
-        ":shared_dep_for_static",
-    ]`,
-				"srcs": `[
-        "both.cpp",
-        "staticonly.cpp",
-    ]`,
-				"whole_archive_deps": `[
-        ":whole_static_lib_for_both",
-        ":whole_and_static_lib_for_both",
-        ":whole_static_lib_for_static",
-    ]`}),
-			MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
-				"copts": `[
-        "bothflag",
-        "sharedflag",
-    ]`,
-				"implementation_deps": `[
-        ":static_dep_for_both",
-        ":static_dep_for_shared",
-    ]`,
-				"implementation_dynamic_deps": `[
-        ":shared_dep_for_both",
-        ":shared_dep_for_shared",
-    ]`,
-				"srcs": `[
-        "both.cpp",
-        "sharedonly.cpp",
-    ]`,
-				"whole_archive_deps": `[
-        ":whole_static_lib_for_both",
-        ":whole_and_static_lib_for_both",
-        ":whole_static_lib_for_shared",
-    ]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryDeps(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library shared/static props",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"both.cpp":       "",
-			"sharedonly.cpp": "",
-			"staticonly.cpp": "",
-		},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "a",
-    srcs: ["both.cpp"],
-    cflags: ["bothflag"],
-    shared_libs: ["implementation_shared_dep_for_both", "shared_dep_for_both"],
-    export_shared_lib_headers: ["shared_dep_for_both"],
-    static_libs: ["implementation_static_dep_for_both", "static_dep_for_both"],
-    export_static_lib_headers: ["static_dep_for_both", "whole_static_dep_for_both"],
-    whole_static_libs: ["not_explicitly_exported_whole_static_dep_for_both", "whole_static_dep_for_both"],
-    static: {
-        srcs: ["staticonly.cpp"],
-        cflags: ["staticflag"],
-        shared_libs: ["implementation_shared_dep_for_static", "shared_dep_for_static"],
-        export_shared_lib_headers: ["shared_dep_for_static"],
-        static_libs: ["implementation_static_dep_for_static", "static_dep_for_static"],
-        export_static_lib_headers: ["static_dep_for_static", "whole_static_dep_for_static"],
-        whole_static_libs: ["not_explicitly_exported_whole_static_dep_for_static", "whole_static_dep_for_static"],
-    },
-    shared: {
-        srcs: ["sharedonly.cpp"],
-        cflags: ["sharedflag"],
-        shared_libs: ["implementation_shared_dep_for_shared", "shared_dep_for_shared"],
-        export_shared_lib_headers: ["shared_dep_for_shared"],
-        static_libs: ["implementation_static_dep_for_shared", "static_dep_for_shared"],
-        export_static_lib_headers: ["static_dep_for_shared", "whole_static_dep_for_shared"],
-        whole_static_libs: ["not_explicitly_exported_whole_static_dep_for_shared", "whole_static_dep_for_shared"],
-    },
-    include_build_directory: false,
-}
-` + simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_shared") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_shared") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_static") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_static") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_both") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_both") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_shared") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_shared") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_static") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_static") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_both") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_both") +
-			simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_shared") +
-			simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_shared") +
-			simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_static") +
-			simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_static") +
-			simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_both") +
-			simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_both"),
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
-				"copts": `[
-        "bothflag",
-        "staticflag",
-    ]`,
-				"deps": `[
-        ":static_dep_for_both",
-        ":static_dep_for_static",
-    ]`,
-				"dynamic_deps": `[
-        ":shared_dep_for_both",
-        ":shared_dep_for_static",
-    ]`,
-				"implementation_deps": `[
-        ":implementation_static_dep_for_both",
-        ":implementation_static_dep_for_static",
-    ]`,
-				"implementation_dynamic_deps": `[
-        ":implementation_shared_dep_for_both",
-        ":implementation_shared_dep_for_static",
-    ]`,
-				"srcs": `[
-        "both.cpp",
-        "staticonly.cpp",
-    ]`,
-				"whole_archive_deps": `[
-        ":not_explicitly_exported_whole_static_dep_for_both",
-        ":whole_static_dep_for_both",
-        ":not_explicitly_exported_whole_static_dep_for_static",
-        ":whole_static_dep_for_static",
-    ]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
-				"copts": `[
-        "bothflag",
-        "sharedflag",
-    ]`,
-				"deps": `[
-        ":static_dep_for_both",
-        ":static_dep_for_shared",
-    ]`,
-				"dynamic_deps": `[
-        ":shared_dep_for_both",
-        ":shared_dep_for_shared",
-    ]`,
-				"implementation_deps": `[
-        ":implementation_static_dep_for_both",
-        ":implementation_static_dep_for_shared",
-    ]`,
-				"implementation_dynamic_deps": `[
-        ":implementation_shared_dep_for_both",
-        ":implementation_shared_dep_for_shared",
-    ]`,
-				"srcs": `[
-        "both.cpp",
-        "sharedonly.cpp",
-    ]`,
-				"whole_archive_deps": `[
-        ":not_explicitly_exported_whole_static_dep_for_both",
-        ":whole_static_dep_for_both",
-        ":not_explicitly_exported_whole_static_dep_for_shared",
-        ":whole_static_dep_for_shared",
-    ]`,
-			})},
-	},
-	)
-}
-
-func TestCcLibraryWholeStaticLibsAlwaysLink(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Dir:                        "foo/bar",
-		Filesystem: map[string]string{
-			"foo/bar/Android.bp": `
-cc_library {
-    name: "a",
-    whole_static_libs: ["whole_static_lib_for_both"],
-    static: {
-        whole_static_libs: ["whole_static_lib_for_static"],
-    },
-    shared: {
-        whole_static_libs: ["whole_static_lib_for_shared"],
-    },
-    bazel_module: { bp2build_available: true },
-    include_build_directory: false,
-}
-
-cc_prebuilt_library_static { name: "whole_static_lib_for_shared" }
-
-cc_prebuilt_library_static { name: "whole_static_lib_for_static" }
-
-cc_prebuilt_library_static { name: "whole_static_lib_for_both" }
-`,
-		},
-		Blueprint: soongCcLibraryPreamble,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
-				"whole_archive_deps": `[
-        ":whole_static_lib_for_both_alwayslink",
-        ":whole_static_lib_for_static_alwayslink",
-    ]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
-				"whole_archive_deps": `[
-        ":whole_static_lib_for_both_alwayslink",
-        ":whole_static_lib_for_shared_alwayslink",
-    ]`,
-			}),
-		},
-	},
-	)
-}
-
-func TestCcLibrarySharedStaticPropsInArch(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library shared/static props in arch",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Dir:                        "foo/bar",
-		Filesystem: map[string]string{
-			"foo/bar/arm.cpp":        "",
-			"foo/bar/x86.cpp":        "",
-			"foo/bar/sharedonly.cpp": "",
-			"foo/bar/staticonly.cpp": "",
-			"foo/bar/Android.bp": `
-cc_library {
-    name: "a",
-    arch: {
-        arm: {
-            shared: {
-                srcs: ["arm_shared.cpp"],
-                cflags: ["-DARM_SHARED"],
-                static_libs: ["arm_static_dep_for_shared"],
-                whole_static_libs: ["arm_whole_static_dep_for_shared"],
-                shared_libs: ["arm_shared_dep_for_shared"],
-            },
-        },
-        x86: {
-            static: {
-                srcs: ["x86_static.cpp"],
-                cflags: ["-DX86_STATIC"],
-                static_libs: ["x86_dep_for_static"],
-            },
-        },
-    },
-    target: {
-        android: {
-            shared: {
-                srcs: ["android_shared.cpp"],
-                cflags: ["-DANDROID_SHARED"],
-                static_libs: ["android_dep_for_shared"],
-            },
-        },
-        android_arm: {
-            shared: {
-                cflags: ["-DANDROID_ARM_SHARED"],
-            },
-        },
-    },
-    srcs: ["both.cpp"],
-    cflags: ["bothflag"],
-    static_libs: ["static_dep_for_both"],
-    static: {
-        srcs: ["staticonly.cpp"],
-        cflags: ["staticflag"],
-        static_libs: ["static_dep_for_static"],
-    },
-    shared: {
-        srcs: ["sharedonly.cpp"],
-        cflags: ["sharedflag"],
-        static_libs: ["static_dep_for_shared"],
-    },
-    bazel_module: { bp2build_available: true },
-}
-
-cc_library_static { name: "static_dep_for_shared" }
-cc_library_static { name: "static_dep_for_static" }
-cc_library_static { name: "static_dep_for_both" }
-
-cc_library_static { name: "arm_static_dep_for_shared" }
-cc_library_static { name: "arm_whole_static_dep_for_shared" }
-cc_library_static { name: "arm_shared_dep_for_shared" }
-
-cc_library_static { name: "x86_dep_for_static" }
-
-cc_library_static { name: "android_dep_for_shared" }
-`,
-		},
-		Blueprint: soongCcLibraryPreamble,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
-				"copts": `[
-        "bothflag",
-        "staticflag",
-    ] + select({
-        "//build/bazel/platforms/arch:x86": ["-DX86_STATIC"],
-        "//conditions:default": [],
-    })`,
-				"implementation_deps": `[
-        ":static_dep_for_both",
-        ":static_dep_for_static",
-    ] + select({
-        "//build/bazel/platforms/arch:x86": [":x86_dep_for_static"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-				"srcs": `[
-        "both.cpp",
-        "staticonly.cpp",
-    ] + select({
-        "//build/bazel/platforms/arch:x86": ["x86_static.cpp"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
-				"copts": `[
-        "bothflag",
-        "sharedflag",
-    ] + select({
-        "//build/bazel/platforms/arch:arm": ["-DARM_SHARED"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/os:android": ["-DANDROID_SHARED"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/os_arch:android_arm": ["-DANDROID_ARM_SHARED"],
-        "//conditions:default": [],
-    })`,
-				"implementation_deps": `[
-        ":static_dep_for_both",
-        ":static_dep_for_shared",
-    ] + select({
-        "//build/bazel/platforms/arch:arm": [":arm_static_dep_for_shared"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/os:android": [":android_dep_for_shared"],
-        "//conditions:default": [],
-    })`,
-				"implementation_dynamic_deps": `select({
-        "//build/bazel/platforms/arch:arm": [":arm_shared_dep_for_shared"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-				"srcs": `[
-        "both.cpp",
-        "sharedonly.cpp",
-    ] + select({
-        "//build/bazel/platforms/arch:arm": ["arm_shared.cpp"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/os:android": ["android_shared.cpp"],
-        "//conditions:default": [],
-    })`,
-				"whole_archive_deps": `select({
-        "//build/bazel/platforms/arch:arm": [":arm_whole_static_dep_for_shared"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	},
-	)
-}
-
-func TestCcLibrarySharedStaticPropsWithMixedSources(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library shared/static props with c/cpp/s mixed sources",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Dir:                        "foo/bar",
-		Filesystem: map[string]string{
-			"foo/bar/both_source.cpp":   "",
-			"foo/bar/both_source.cc":    "",
-			"foo/bar/both_source.c":     "",
-			"foo/bar/both_source.s":     "",
-			"foo/bar/both_source.S":     "",
-			"foo/bar/shared_source.cpp": "",
-			"foo/bar/shared_source.cc":  "",
-			"foo/bar/shared_source.c":   "",
-			"foo/bar/shared_source.s":   "",
-			"foo/bar/shared_source.S":   "",
-			"foo/bar/static_source.cpp": "",
-			"foo/bar/static_source.cc":  "",
-			"foo/bar/static_source.c":   "",
-			"foo/bar/static_source.s":   "",
-			"foo/bar/static_source.S":   "",
-			"foo/bar/Android.bp": `
-cc_library {
-    name: "a",
-    srcs: [
-    "both_source.cpp",
-    "both_source.cc",
-    "both_source.c",
-    "both_source.s",
-    "both_source.S",
-    ":both_filegroup",
-  ],
-    static: {
-        srcs: [
-          "static_source.cpp",
-          "static_source.cc",
-          "static_source.c",
-          "static_source.s",
-          "static_source.S",
-          ":static_filegroup",
-        ],
-    },
-    shared: {
-        srcs: [
-          "shared_source.cpp",
-          "shared_source.cc",
-          "shared_source.c",
-          "shared_source.s",
-          "shared_source.S",
-          ":shared_filegroup",
-        ],
-    },
-    bazel_module: { bp2build_available: true },
-}
-
-filegroup {
-    name: "both_filegroup",
-    srcs: [
-        // Not relevant, handled by filegroup macro
-  ],
-}
-
-filegroup {
-    name: "shared_filegroup",
-    srcs: [
-        // Not relevant, handled by filegroup macro
-  ],
-}
-
-filegroup {
-    name: "static_filegroup",
-    srcs: [
-        // Not relevant, handled by filegroup macro
-  ],
-}
-`,
-		},
-		Blueprint: soongCcLibraryPreamble,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
-				"local_includes": `["."]`,
-				"srcs": `[
-        "both_source.cpp",
-        "both_source.cc",
-        ":both_filegroup_cpp_srcs",
-        "static_source.cpp",
-        "static_source.cc",
-        ":static_filegroup_cpp_srcs",
-    ]`,
-				"srcs_as": `[
-        "both_source.s",
-        "both_source.S",
-        ":both_filegroup_as_srcs",
-        "static_source.s",
-        "static_source.S",
-        ":static_filegroup_as_srcs",
-    ]`,
-				"srcs_c": `[
-        "both_source.c",
-        ":both_filegroup_c_srcs",
-        "static_source.c",
-        ":static_filegroup_c_srcs",
-    ]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
-				"local_includes": `["."]`,
-				"srcs": `[
-        "both_source.cpp",
-        "both_source.cc",
-        ":both_filegroup_cpp_srcs",
-        "shared_source.cpp",
-        "shared_source.cc",
-        ":shared_filegroup_cpp_srcs",
-    ]`,
-				"srcs_as": `[
-        "both_source.s",
-        "both_source.S",
-        ":both_filegroup_as_srcs",
-        "shared_source.s",
-        "shared_source.S",
-        ":shared_filegroup_as_srcs",
-    ]`,
-				"srcs_c": `[
-        "both_source.c",
-        ":both_filegroup_c_srcs",
-        "shared_source.c",
-        ":shared_filegroup_c_srcs",
-    ]`,
-			})}})
-}
-
-func TestCcLibraryNonConfiguredVersionScriptAndDynamicList(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library non-configured version script and dynamic list",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Dir:                        "foo/bar",
-		Filesystem: map[string]string{
-			"foo/bar/Android.bp": `
-cc_library {
-    name: "a",
-    srcs: ["a.cpp"],
-    version_script: "v.map",
-    dynamic_list: "dynamic.list",
-    bazel_module: { bp2build_available: true },
-    include_build_directory: false,
-}
-`,
-		},
-		Blueprint: soongCcLibraryPreamble,
-		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
-			"additional_linker_inputs": `[
-        "v.map",
-        "dynamic.list",
-    ]`,
-			"linkopts": `[
-        "-Wl,--version-script,$(location v.map)",
-        "-Wl,--dynamic-list,$(location dynamic.list)",
-    ]`,
-			"srcs":     `["a.cpp"]`,
-			"features": `["android_cfi_exports_map"]`,
-		}),
-	},
-	)
-}
-
-func TestCcLibraryConfiguredVersionScriptAndDynamicList(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library configured version script and dynamic list",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Dir:                        "foo/bar",
-		Filesystem: map[string]string{
-			"foo/bar/Android.bp": `
-cc_library {
-   name: "a",
-   srcs: ["a.cpp"],
-   arch: {
-     arm: {
-       version_script: "arm.map",
-       dynamic_list: "dynamic_arm.list",
-     },
-     arm64: {
-       version_script: "arm64.map",
-       dynamic_list: "dynamic_arm64.list",
-     },
-   },
-
-   bazel_module: { bp2build_available: true },
-    include_build_directory: false,
-}
-    `,
-		},
-		Blueprint: soongCcLibraryPreamble,
-		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
-			"additional_linker_inputs": `select({
-        "//build/bazel/platforms/arch:arm": [
-            "arm.map",
-            "dynamic_arm.list",
-        ],
-        "//build/bazel/platforms/arch:arm64": [
-            "arm64.map",
-            "dynamic_arm64.list",
-        ],
-        "//conditions:default": [],
-    })`,
-			"linkopts": `select({
-        "//build/bazel/platforms/arch:arm": [
-            "-Wl,--version-script,$(location arm.map)",
-            "-Wl,--dynamic-list,$(location dynamic_arm.list)",
-        ],
-        "//build/bazel/platforms/arch:arm64": [
-            "-Wl,--version-script,$(location arm64.map)",
-            "-Wl,--dynamic-list,$(location dynamic_arm64.list)",
-        ],
-        "//conditions:default": [],
-    })`,
-			"srcs": `["a.cpp"]`,
-			"features": `select({
-        "//build/bazel/platforms/arch:arm": ["android_cfi_exports_map"],
-        "//build/bazel/platforms/arch:arm64": ["android_cfi_exports_map"],
-        "//conditions:default": [],
-    })`,
-		}),
-	},
-	)
-}
-
-func TestCcLibraryLdflagsSplitBySpaceExceptSoongAdded(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "ldflags are split by spaces except for the ones added by soong (version script and dynamic list)",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"version_script": "",
-			"dynamic.list":   "",
-		},
-		Blueprint: `
-cc_library {
-    name: "foo",
-    ldflags: [
-        "--nospace_flag",
-        "-z spaceflag",
-    ],
-    version_script: "version_script",
-    dynamic_list: "dynamic.list",
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features": `["android_cfi_exports_map"]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"additional_linker_inputs": `[
-        "version_script",
-        "dynamic.list",
-    ]`,
-				"features": `["android_cfi_exports_map"]`,
-				"linkopts": `[
-        "--nospace_flag",
-        "-z",
-        "spaceflag",
-        "-Wl,--version-script,$(location version_script)",
-        "-Wl,--dynamic-list,$(location dynamic.list)",
-    ]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedLibs(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library shared_libs",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "mylib",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "a",
-    shared_libs: ["mylib",],
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
-			"implementation_dynamic_deps": `[":mylib"]`,
-		}),
-	},
-	)
-}
-
-func TestCcLibraryFeatures(t *testing.T) {
-	expected_targets := []string{}
-	expected_targets = append(expected_targets, makeCcLibraryTargets("a", AttrNameToString{
-		"features": `[
-        "disable_pack_relocations",
-        "-no_undefined_symbols",
-    ]`,
-		"native_coverage": `False`,
-		"srcs":            `["a.cpp"]`,
-	})...)
-	expected_targets = append(expected_targets, makeCcLibraryTargets("b", AttrNameToString{
-		"features": `select({
-        "//build/bazel/platforms/arch:x86_64": [
-            "disable_pack_relocations",
-            "-no_undefined_symbols",
-        ],
-        "//conditions:default": [],
-    })`,
-		"native_coverage": `False`,
-		"srcs":            `["b.cpp"]`,
-	})...)
-	expected_targets = append(expected_targets, makeCcLibraryTargets("c", AttrNameToString{
-		"features": `select({
-        "//build/bazel/platforms/os:darwin": [
-            "disable_pack_relocations",
-            "-no_undefined_symbols",
-        ],
-        "//conditions:default": [],
-    })`,
-		"srcs": `["c.cpp"]`,
-	})...)
-
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library pack_relocations test",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "a",
-    srcs: ["a.cpp"],
-    pack_relocations: false,
-    allow_undefined_symbols: true,
-    include_build_directory: false,
-    native_coverage: false,
-}
-
-cc_library {
-    name: "b",
-    srcs: ["b.cpp"],
-    arch: {
-        x86_64: {
-            pack_relocations: false,
-            allow_undefined_symbols: true,
-        },
-    },
-    include_build_directory: false,
-    native_coverage: false,
-}
-
-cc_library {
-    name: "c",
-    srcs: ["c.cpp"],
-    target: {
-        darwin: {
-            pack_relocations: false,
-            allow_undefined_symbols: true,
-        },
-    },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: expected_targets,
-	})
-}
-
-func TestCcLibrarySpacesInCopts(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library spaces in copts",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "a",
-    cflags: ["-include header.h",],
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
-			"copts": `[
-        "-include",
-        "header.h",
-    ]`,
-		}),
-	},
-	)
-}
-
-func TestCcLibraryCppFlagsGoesIntoCopts(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library cppflags usage",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `cc_library {
-    name: "a",
-    srcs: ["a.cpp"],
-    cflags: ["-Wall"],
-    cppflags: [
-        "-fsigned-char",
-        "-pedantic",
-    ],
-    arch: {
-        arm64: {
-            cppflags: ["-DARM64=1"],
-        },
-    },
-    target: {
-        android: {
-            cppflags: ["-DANDROID=1"],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
-			"copts": `["-Wall"]`,
-			"cppflags": `[
-        "-fsigned-char",
-        "-pedantic",
-    ] + select({
-        "//build/bazel/platforms/arch:arm64": ["-DARM64=1"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/os:android": ["-DANDROID=1"],
-        "//conditions:default": [],
-    })`,
-			"srcs": `["a.cpp"]`,
-		}),
-	},
-	)
-}
-
-func TestCcLibraryExcludeLibs(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library {
-    name: "foo_static",
-    srcs: ["common.c"],
-    whole_static_libs: [
-        "arm_whole_static_lib_excludes",
-        "malloc_not_svelte_whole_static_lib_excludes"
-    ],
-    static_libs: [
-        "arm_static_lib_excludes",
-        "malloc_not_svelte_static_lib_excludes"
-    ],
-    shared_libs: [
-        "arm_shared_lib_excludes",
-    ],
-    arch: {
-        arm: {
-            exclude_shared_libs: [
-                 "arm_shared_lib_excludes",
-            ],
-            exclude_static_libs: [
-                "arm_static_lib_excludes",
-                "arm_whole_static_lib_excludes",
-            ],
-        },
-    },
-    product_variables: {
-        malloc_not_svelte: {
-            shared_libs: ["malloc_not_svelte_shared_lib"],
-            whole_static_libs: ["malloc_not_svelte_whole_static_lib"],
-            exclude_static_libs: [
-                "malloc_not_svelte_static_lib_excludes",
-                "malloc_not_svelte_whole_static_lib_excludes",
-            ],
-        },
-    },
-    include_build_directory: false,
-}
-
-cc_library {
-    name: "arm_whole_static_lib_excludes",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "malloc_not_svelte_whole_static_lib",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "malloc_not_svelte_whole_static_lib_excludes",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "arm_static_lib_excludes",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "malloc_not_svelte_static_lib_excludes",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "arm_shared_lib_excludes",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "malloc_not_svelte_shared_lib",
-    bazel_module: { bp2build_available: false },
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo_static", AttrNameToString{
-			"implementation_deps": `select({
-        "//build/bazel/platforms/arch:arm": [],
-        "//conditions:default": [":arm_static_lib_excludes_bp2build_cc_library_static"],
-    }) + select({
-        "//build/bazel/product_config/config_settings:malloc_not_svelte": [],
-        "//conditions:default": [":malloc_not_svelte_static_lib_excludes_bp2build_cc_library_static"],
-    })`,
-			"implementation_dynamic_deps": `select({
-        "//build/bazel/platforms/arch:arm": [],
-        "//conditions:default": [":arm_shared_lib_excludes"],
-    }) + select({
-        "//build/bazel/product_config/config_settings:malloc_not_svelte": [":malloc_not_svelte_shared_lib"],
-        "//conditions:default": [],
-    })`,
-			"srcs_c": `["common.c"]`,
-			"whole_archive_deps": `select({
-        "//build/bazel/platforms/arch:arm": [],
-        "//conditions:default": [":arm_whole_static_lib_excludes_bp2build_cc_library_static"],
-    }) + select({
-        "//build/bazel/product_config/config_settings:malloc_not_svelte": [":malloc_not_svelte_whole_static_lib_bp2build_cc_library_static"],
-        "//conditions:default": [":malloc_not_svelte_whole_static_lib_excludes_bp2build_cc_library_static"],
-    })`,
-		}),
-	},
-	)
-}
-
-func TestCcLibraryProductVariablesHeaderLibs(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library {
-    name: "foo_static",
-    srcs: ["common.c"],
-    product_variables: {
-        malloc_not_svelte: {
-            header_libs: ["malloc_not_svelte_header_lib"],
-        },
-    },
-    include_build_directory: false,
-}
-
-cc_library {
-    name: "malloc_not_svelte_header_lib",
-    bazel_module: { bp2build_available: false },
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo_static", AttrNameToString{
-			"implementation_deps": `select({
-        "//build/bazel/product_config/config_settings:malloc_not_svelte": [":malloc_not_svelte_header_lib"],
-        "//conditions:default": [],
-    })`,
-			"srcs_c":                 `["common.c"]`,
-			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-		}),
-	},
-	)
-}
-
-func TestCCLibraryNoCrtTrue(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library - nocrt: true disables feature",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"impl.cpp": "",
-		},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "foo-lib",
-    srcs: ["impl.cpp"],
-    nocrt: true,
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
-			"features": `["-link_crt"]`,
-			"srcs":     `["impl.cpp"]`,
-		}),
-	},
-	)
-}
-
-func TestCCLibraryNoCrtFalse(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library - nocrt: false - does not emit attribute",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"impl.cpp": "",
-		},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "foo-lib",
-    srcs: ["impl.cpp"],
-    nocrt: false,
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
-			"srcs": `["impl.cpp"]`,
-		}),
-	})
-}
-
-func TestCCLibraryNoCrtArchVariant(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library - nocrt in select",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"impl.cpp": "",
-		},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "foo-lib",
-    srcs: ["impl.cpp"],
-    arch: {
-        arm: {
-            nocrt: true,
-        },
-        x86: {
-            nocrt: false,
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
-			"features": `select({
-        "//build/bazel/platforms/arch:arm": ["-link_crt"],
-        "//conditions:default": [],
-    })`,
-			"srcs": `["impl.cpp"]`,
-		}),
-	})
-}
-
-func TestCCLibraryNoLibCrtTrue(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"impl.cpp": "",
-		},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "foo-lib",
-    srcs: ["impl.cpp"],
-    no_libcrt: true,
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
-			"features": `["-use_libcrt"]`,
-			"srcs":     `["impl.cpp"]`,
-		}),
-	})
-}
-
-func makeCcLibraryTargets(name string, attrs AttrNameToString) []string {
-	STATIC_ONLY_ATTRS := map[string]bool{}
-	SHARED_ONLY_ATTRS := map[string]bool{
-		"link_crt":                 true,
-		"additional_linker_inputs": true,
-		"linkopts":                 true,
-		"strip":                    true,
-		"inject_bssl_hash":         true,
-		"stubs_symbol_file":        true,
-		"use_version_lib":          true,
-	}
-
-	sharedAttrs := AttrNameToString{}
-	staticAttrs := AttrNameToString{}
-	for key, val := range attrs {
-		if _, staticOnly := STATIC_ONLY_ATTRS[key]; !staticOnly {
-			sharedAttrs[key] = val
-		}
-		if _, sharedOnly := SHARED_ONLY_ATTRS[key]; !sharedOnly {
-			staticAttrs[key] = val
-		}
-	}
-	sharedTarget := MakeBazelTarget("cc_library_shared", name, sharedAttrs)
-	staticTarget := MakeBazelTarget("cc_library_static", name+"_bp2build_cc_library_static", staticAttrs)
-
-	return []string{staticTarget, sharedTarget}
-}
-
-func TestCCLibraryNoLibCrtFalse(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"impl.cpp": "",
-		},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "foo-lib",
-    srcs: ["impl.cpp"],
-    no_libcrt: false,
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
-			"srcs": `["impl.cpp"]`,
-		}),
-	})
-}
-
-func TestCCLibraryNoLibCrtArchVariant(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"impl.cpp": "",
-		},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "foo-lib",
-    srcs: ["impl.cpp"],
-    arch: {
-        arm: {
-            no_libcrt: true,
-        },
-        x86: {
-            no_libcrt: true,
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
-			"srcs": `["impl.cpp"]`,
-			"features": `select({
-        "//build/bazel/platforms/arch:arm": ["-use_libcrt"],
-        "//build/bazel/platforms/arch:x86": ["-use_libcrt"],
-        "//conditions:default": [],
-    })`,
-		}),
-	})
-}
-
-func TestCCLibraryNoLibCrtArchAndTargetVariant(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"impl.cpp": "",
-		},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "foo-lib",
-    srcs: ["impl.cpp"],
-    arch: {
-        arm: {
-            no_libcrt: true,
-        },
-        x86: {
-            no_libcrt: true,
-        },
-    },
-    target: {
-        darwin: {
-            no_libcrt: true,
-        }
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
-			"features": `select({
-        "//build/bazel/platforms/arch:arm": ["-use_libcrt"],
-        "//build/bazel/platforms/arch:x86": ["-use_libcrt"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/os:darwin": ["-use_libcrt"],
-        "//conditions:default": [],
-    })`,
-			"srcs": `["impl.cpp"]`,
-		}),
-	})
-}
-
-func TestCCLibraryNoLibCrtArchAndTargetVariantConflict(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"impl.cpp": "",
-		},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "foo-lib",
-    srcs: ["impl.cpp"],
-    arch: {
-        arm: {
-            no_libcrt: true,
-        },
-        // This is expected to override the value for darwin_x86_64.
-        x86_64: {
-            no_libcrt: true,
-        },
-    },
-    target: {
-        darwin: {
-            no_libcrt: false,
-        }
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
-			"srcs": `["impl.cpp"]`,
-			"features": `select({
-        "//build/bazel/platforms/arch:arm": ["-use_libcrt"],
-        "//build/bazel/platforms/arch:x86_64": ["-use_libcrt"],
-        "//conditions:default": [],
-    })`,
-		}),
-	})
-}
-
-func TestCcLibraryStrip(t *testing.T) {
-	expectedTargets := []string{}
-	expectedTargets = append(expectedTargets, makeCcLibraryTargets("all", AttrNameToString{
-		"strip": `{
-        "all": True,
-    }`,
-	})...)
-	expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols", AttrNameToString{
-		"strip": `{
-        "keep_symbols": True,
-    }`,
-	})...)
-	expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols_and_debug_frame", AttrNameToString{
-		"strip": `{
-        "keep_symbols_and_debug_frame": True,
-    }`,
-	})...)
-	expectedTargets = append(expectedTargets, makeCcLibraryTargets("keep_symbols_list", AttrNameToString{
-		"strip": `{
-        "keep_symbols_list": ["symbol"],
-    }`,
-	})...)
-	expectedTargets = append(expectedTargets, makeCcLibraryTargets("none", AttrNameToString{
-		"strip": `{
-        "none": True,
-    }`,
-	})...)
-	expectedTargets = append(expectedTargets, makeCcLibraryTargets("nothing", AttrNameToString{})...)
-
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library strip args",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "nothing",
-    include_build_directory: false,
-}
-cc_library {
-    name: "keep_symbols",
-    strip: {
-        keep_symbols: true,
-    },
-    include_build_directory: false,
-}
-cc_library {
-    name: "keep_symbols_and_debug_frame",
-    strip: {
-        keep_symbols_and_debug_frame: true,
-    },
-    include_build_directory: false,
-}
-cc_library {
-    name: "none",
-    strip: {
-        none: true,
-    },
-    include_build_directory: false,
-}
-cc_library {
-    name: "keep_symbols_list",
-    strip: {
-        keep_symbols_list: ["symbol"],
-    },
-    include_build_directory: false,
-}
-cc_library {
-    name: "all",
-    strip: {
-        all: true,
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: expectedTargets,
-	})
-}
-
-func TestCcLibraryStripWithArch(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library strip args",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "multi-arch",
-    target: {
-        darwin: {
-            strip: {
-                keep_symbols_list: ["foo", "bar"]
-            }
-        },
-    },
-    arch: {
-        arm: {
-            strip: {
-                keep_symbols_and_debug_frame: true,
-            },
-        },
-        arm64: {
-            strip: {
-                keep_symbols: true,
-            },
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("multi-arch", AttrNameToString{
-			"strip": `{
-        "keep_symbols": select({
-            "//build/bazel/platforms/arch:arm64": True,
-            "//conditions:default": None,
-        }),
-        "keep_symbols_and_debug_frame": select({
-            "//build/bazel/platforms/arch:arm": True,
-            "//conditions:default": None,
-        }),
-        "keep_symbols_list": select({
-            "//build/bazel/platforms/os:darwin": [
-                "foo",
-                "bar",
-            ],
-            "//conditions:default": [],
-        }),
-    }`,
-		}),
-	},
-	)
-}
-
-func TestCcLibrary_SystemSharedLibsRootEmpty(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library system_shared_libs empty at root",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "root_empty",
-    system_shared_libs: [],
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("root_empty", AttrNameToString{
-			"system_dynamic_deps": `[]`,
-		}),
-	},
-	)
-}
-
-func TestCcLibrary_SystemSharedLibsStaticEmpty(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library system_shared_libs empty for static variant",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "static_empty",
-    static: {
-        system_shared_libs: [],
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "static_empty_bp2build_cc_library_static", AttrNameToString{
-				"system_dynamic_deps": "[]",
-			}),
-			MakeBazelTarget("cc_library_shared", "static_empty", AttrNameToString{}),
-		},
-	})
-}
-
-func TestCcLibrary_SystemSharedLibsSharedEmpty(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library system_shared_libs empty for shared variant",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "shared_empty",
-    shared: {
-        system_shared_libs: [],
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "shared_empty_bp2build_cc_library_static", AttrNameToString{}),
-			MakeBazelTarget("cc_library_shared", "shared_empty", AttrNameToString{
-				"system_dynamic_deps": "[]",
-			}),
-		},
-	})
-}
-
-func TestCcLibrary_SystemSharedLibsSharedBionicEmpty(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library system_shared_libs empty for shared, bionic variant",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "shared_empty",
-    target: {
-        bionic: {
-            shared: {
-                system_shared_libs: [],
-            }
-        }
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "shared_empty_bp2build_cc_library_static", AttrNameToString{}),
-			MakeBazelTarget("cc_library_shared", "shared_empty", AttrNameToString{
-				"system_dynamic_deps": "[]",
-			}),
-		},
-	})
-}
-
-func TestCcLibrary_SystemSharedLibsLinuxBionicEmpty(t *testing.T) {
-	// Note that this behavior is technically incorrect (it's a simplification).
-	// The correct behavior would be if bp2build wrote `system_dynamic_deps = []`
-	// only for linux_bionic, but `android` had `["libc", "libdl", "libm"].
-	// b/195791252 tracks the fix.
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library system_shared_libs empty for linux_bionic variant",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-	name: "libc_musl",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "target_linux_bionic_empty",
-    target: {
-        linux_bionic: {
-            system_shared_libs: [],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("target_linux_bionic_empty", AttrNameToString{
-			"system_dynamic_deps": `select({
-        "//build/bazel/platforms/os:linux_musl": [":libc_musl"],
-        "//conditions:default": [],
-    })`,
-		}),
-	},
-	)
-}
-
-func TestCcLibrary_SystemSharedLibsBionicEmpty(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library system_shared_libs empty for bionic variant",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-	name: "libc_musl",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "target_bionic_empty",
-    target: {
-        bionic: {
-            system_shared_libs: [],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("target_bionic_empty", AttrNameToString{
-			"system_dynamic_deps": `select({
-        "//build/bazel/platforms/os:linux_musl": [":libc_musl"],
-        "//conditions:default": [],
-    })`,
-		}),
-	},
-	)
-}
-
-func TestCcLibrary_SystemSharedLibsMuslEmpty(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library system_shared_lib empty for musl variant",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-		name: "libc_musl",
-		bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "target_musl_empty",
-    target: {
-        musl: {
-            system_shared_libs: [],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("target_musl_empty", AttrNameToString{
-			"system_dynamic_deps": `[]`,
-		}),
-	})
-}
-
-func TestCcLibrary_SystemSharedLibsLinuxMuslEmpty(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library system_shared_lib empty for linux_musl variant",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-		name: "libc_musl",
-		bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "target_linux_musl_empty",
-    target: {
-        linux_musl: {
-            system_shared_libs: [],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("target_linux_musl_empty", AttrNameToString{
-			"system_dynamic_deps": `[]`,
-		}),
-	})
-}
-func TestCcLibrary_SystemSharedLibsSharedAndRoot(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library system_shared_libs set for shared and root",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "libc",
-    bazel_module: { bp2build_available: false },
-}
-cc_library {
-    name: "libm",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library {
-    name: "foo",
-    system_shared_libs: ["libc"],
-    shared: {
-        system_shared_libs: ["libm"],
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"system_dynamic_deps": `[":libc"]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"system_dynamic_deps": `[
-        ":libc",
-        ":libm",
-    ]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryOsSelects(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library - selects for all os targets",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "foo-lib",
-    srcs: ["base.cpp"],
-    target: {
-        android: {
-            srcs: ["android.cpp"],
-        },
-        linux: {
-            srcs: ["linux.cpp"],
-        },
-        linux_glibc: {
-            srcs: ["linux_glibc.cpp"],
-        },
-        darwin: {
-            srcs: ["darwin.cpp"],
-        },
-        bionic: {
-            srcs: ["bionic.cpp"],
-        },
-        linux_musl: {
-            srcs: ["linux_musl.cpp"],
-        },
-        windows: {
-            srcs: ["windows.cpp"],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
-			"srcs": `["base.cpp"] + select({
-        "//build/bazel/platforms/os:android": [
-            "linux.cpp",
-            "bionic.cpp",
-            "android.cpp",
-        ],
-        "//build/bazel/platforms/os:darwin": ["darwin.cpp"],
-        "//build/bazel/platforms/os:linux_bionic": [
-            "linux.cpp",
-            "bionic.cpp",
-        ],
-        "//build/bazel/platforms/os:linux_glibc": [
-            "linux.cpp",
-            "linux_glibc.cpp",
-        ],
-        "//build/bazel/platforms/os:linux_musl": [
-            "linux.cpp",
-            "linux_musl.cpp",
-        ],
-        "//build/bazel/platforms/os:windows": ["windows.cpp"],
-        "//conditions:default": [],
-    })`,
-		}),
-	},
-	)
-}
-
-func TestLibcryptoHashInjection(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library - libcrypto hash injection",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "libcrypto",
-    target: {
-        android: {
-            inject_bssl_hash: true,
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("libcrypto", AttrNameToString{
-			"inject_bssl_hash": `select({
-        "//build/bazel/platforms/os:android": True,
-        "//conditions:default": None,
-    })`,
-		}),
-	},
-	)
-}
-
-func TestCcLibraryCppStdWithGnuExtensions_ConvertsToFeatureAttr(t *testing.T) {
-	type testCase struct {
-		cpp_std        string
-		c_std          string
-		gnu_extensions string
-		bazel_cpp_std  string
-		bazel_c_std    string
-	}
-
-	testCases := []testCase{
-		// Existing usages of cpp_std in AOSP are:
-		// experimental, c++11, c++17, c++2a, c++98, gnu++11, gnu++17
-		//
-		// not set, only emit if gnu_extensions is disabled. the default (gnu+17
-		// is set in the toolchain.)
-		{cpp_std: "", gnu_extensions: "", bazel_cpp_std: ""},
-		{cpp_std: "", gnu_extensions: "false", bazel_cpp_std: "cpp_std_default_no_gnu", bazel_c_std: "c_std_default_no_gnu"},
-		{cpp_std: "", gnu_extensions: "true", bazel_cpp_std: ""},
-		// experimental defaults to gnu++2a
-		{cpp_std: "experimental", gnu_extensions: "", bazel_cpp_std: "cpp_std_experimental"},
-		{cpp_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "cpp_std_experimental_no_gnu", bazel_c_std: "c_std_default_no_gnu"},
-		{cpp_std: "experimental", gnu_extensions: "true", bazel_cpp_std: "cpp_std_experimental"},
-		// Explicitly setting a c++ std does not use replace gnu++ std even if
-		// gnu_extensions is true.
-		// "c++11",
-		{cpp_std: "c++11", gnu_extensions: "", bazel_cpp_std: "c++11"},
-		{cpp_std: "c++11", gnu_extensions: "false", bazel_cpp_std: "c++11", bazel_c_std: "c_std_default_no_gnu"},
-		{cpp_std: "c++11", gnu_extensions: "true", bazel_cpp_std: "c++11"},
-		// "c++17",
-		{cpp_std: "c++17", gnu_extensions: "", bazel_cpp_std: "c++17"},
-		{cpp_std: "c++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c_std_default_no_gnu"},
-		{cpp_std: "c++17", gnu_extensions: "true", bazel_cpp_std: "c++17"},
-		// "c++2a",
-		{cpp_std: "c++2a", gnu_extensions: "", bazel_cpp_std: "c++2a"},
-		{cpp_std: "c++2a", gnu_extensions: "false", bazel_cpp_std: "c++2a", bazel_c_std: "c_std_default_no_gnu"},
-		{cpp_std: "c++2a", gnu_extensions: "true", bazel_cpp_std: "c++2a"},
-		// "c++98",
-		{cpp_std: "c++98", gnu_extensions: "", bazel_cpp_std: "c++98"},
-		{cpp_std: "c++98", gnu_extensions: "false", bazel_cpp_std: "c++98", bazel_c_std: "c_std_default_no_gnu"},
-		{cpp_std: "c++98", gnu_extensions: "true", bazel_cpp_std: "c++98"},
-		// gnu++ is replaced with c++ if gnu_extensions is explicitly false.
-		// "gnu++11",
-		{cpp_std: "gnu++11", gnu_extensions: "", bazel_cpp_std: "gnu++11"},
-		{cpp_std: "gnu++11", gnu_extensions: "false", bazel_cpp_std: "c++11", bazel_c_std: "c_std_default_no_gnu"},
-		{cpp_std: "gnu++11", gnu_extensions: "true", bazel_cpp_std: "gnu++11"},
-		// "gnu++17",
-		{cpp_std: "gnu++17", gnu_extensions: "", bazel_cpp_std: "gnu++17"},
-		{cpp_std: "gnu++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c_std_default_no_gnu"},
-		{cpp_std: "gnu++17", gnu_extensions: "true", bazel_cpp_std: "gnu++17"},
-
-		// some c_std test cases
-		{c_std: "experimental", gnu_extensions: "", bazel_c_std: "c_std_experimental"},
-		{c_std: "experimental", gnu_extensions: "false", bazel_cpp_std: "cpp_std_default_no_gnu", bazel_c_std: "c_std_experimental_no_gnu"},
-		{c_std: "experimental", gnu_extensions: "true", bazel_c_std: "c_std_experimental"},
-		{c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "", bazel_cpp_std: "gnu++17", bazel_c_std: "gnu11"},
-		{c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "false", bazel_cpp_std: "c++17", bazel_c_std: "c11"},
-		{c_std: "gnu11", cpp_std: "gnu++17", gnu_extensions: "true", bazel_cpp_std: "gnu++17", bazel_c_std: "gnu11"},
-	}
-	for i, tc := range testCases {
-		name := fmt.Sprintf("cpp std: %q, c std: %q, gnu_extensions: %q", tc.cpp_std, tc.c_std, tc.gnu_extensions)
-		t.Run(name, func(t *testing.T) {
-			name_prefix := fmt.Sprintf("a_%v", i)
-			cppStdProp := ""
-			if tc.cpp_std != "" {
-				cppStdProp = fmt.Sprintf("    cpp_std: \"%s\",", tc.cpp_std)
-			}
-			cStdProp := ""
-			if tc.c_std != "" {
-				cStdProp = fmt.Sprintf("    c_std: \"%s\",", tc.c_std)
-			}
-			gnuExtensionsProp := ""
-			if tc.gnu_extensions != "" {
-				gnuExtensionsProp = fmt.Sprintf("    gnu_extensions: %s,", tc.gnu_extensions)
-			}
-			attrs := AttrNameToString{}
-			if tc.bazel_cpp_std != "" {
-				attrs["cpp_std"] = fmt.Sprintf(`"%s"`, tc.bazel_cpp_std)
-			}
-			if tc.bazel_c_std != "" {
-				attrs["c_std"] = fmt.Sprintf(`"%s"`, tc.bazel_c_std)
-			}
-
-			runCcLibraryTestCase(t, Bp2buildTestCase{
-				Description: fmt.Sprintf(
-					"cc_library with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
-				ModuleTypeUnderTest:        "cc_library",
-				ModuleTypeUnderTestFactory: cc.LibraryFactory,
-				Blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
-cc_library {
-	name: "%s_full",
-%s // cpp_std: *string
-%s // c_std: *string
-%s // gnu_extensions: *bool
-	include_build_directory: false,
-}
-`, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp),
-				ExpectedBazelTargets: makeCcLibraryTargets(name_prefix+"_full", attrs),
-			})
-
-			runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-				Description: fmt.Sprintf(
-					"cc_library_static with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
-				ModuleTypeUnderTest:        "cc_library_static",
-				ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
-				Blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
-cc_library_static {
-	name: "%s_static",
-%s // cpp_std: *string
-%s // c_std: *string
-%s // gnu_extensions: *bool
-	include_build_directory: false,
-}
-`, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp),
-				ExpectedBazelTargets: []string{
-					MakeBazelTarget("cc_library_static", name_prefix+"_static", attrs),
-				},
-			})
-
-			runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-				Description: fmt.Sprintf(
-					"cc_library_shared with cpp_std: %s and gnu_extensions: %s", tc.cpp_std, tc.gnu_extensions),
-				ModuleTypeUnderTest:        "cc_library_shared",
-				ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
-				Blueprint: soongCcLibraryPreamble + fmt.Sprintf(`
-cc_library_shared {
-	name: "%s_shared",
-%s // cpp_std: *string
-%s // c_std: *string
-%s // gnu_extensions: *bool
-	include_build_directory: false,
-}
-`, name_prefix, cppStdProp, cStdProp, gnuExtensionsProp),
-				ExpectedBazelTargets: []string{
-					MakeBazelTarget("cc_library_shared", name_prefix+"_shared", attrs),
-				},
-			})
-		})
-	}
-}
-
-func TestCcLibraryProtoSimple(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `cc_library {
-	name: "foo",
-	srcs: ["foo.proto"],
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-				"srcs": `["foo.proto"]`,
-			}), MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
-				"deps": `[":foo_proto"]`,
-			}), MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
-				"deps":                              `[":libprotobuf-cpp-lite"]`,
-			}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"dynamic_deps":                      `[":libprotobuf-cpp-lite"]`,
-				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryProtoNoCanonicalPathFromRoot(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `cc_library {
-	name: "foo",
-	srcs: ["foo.proto"],
-	proto: { canonical_path_from_root: false},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-				"srcs":                `["foo.proto"]`,
-				"strip_import_prefix": `""`,
-			}), MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
-				"deps": `[":foo_proto"]`,
-			}), MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
-				"deps":                              `[":libprotobuf-cpp-lite"]`,
-			}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"dynamic_deps":                      `[":libprotobuf-cpp-lite"]`,
-				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryProtoExplicitCanonicalPathFromRoot(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `cc_library {
-	name: "foo",
-	srcs: ["foo.proto"],
-	proto: { canonical_path_from_root: true},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-				"srcs": `["foo.proto"]`,
-			}), MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
-				"deps": `[":foo_proto"]`,
-			}), MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
-				"deps":                              `[":libprotobuf-cpp-lite"]`,
-			}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"dynamic_deps":                      `[":libprotobuf-cpp-lite"]`,
-				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryProtoFull(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `cc_library {
-	name: "foo",
-	srcs: ["foo.proto"],
-	proto: {
-		type: "full",
-	},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-				"srcs": `["foo.proto"]`,
-			}), MakeBazelTarget("cc_proto_library", "foo_cc_proto", AttrNameToString{
-				"deps": `[":foo_proto"]`,
-			}), MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"implementation_whole_archive_deps": `[":foo_cc_proto"]`,
-				"deps":                              `[":libprotobuf-cpp-full"]`,
-			}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"dynamic_deps":                      `[":libprotobuf-cpp-full"]`,
-				"implementation_whole_archive_deps": `[":foo_cc_proto"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryProtoLite(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `cc_library {
-	name: "foo",
-	srcs: ["foo.proto"],
-	proto: {
-		type: "lite",
-	},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-				"srcs": `["foo.proto"]`,
-			}), MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
-				"deps": `[":foo_proto"]`,
-			}), MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
-				"deps":                              `[":libprotobuf-cpp-lite"]`,
-			}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"dynamic_deps":                      `[":libprotobuf-cpp-lite"]`,
-				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryProtoExportHeaders(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `cc_library {
-	name: "foo",
-	srcs: ["foo.proto"],
-	proto: {
-		export_proto_headers: true,
-	},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-				"srcs": `["foo.proto"]`,
-			}), MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
-				"deps": `[":foo_proto"]`,
-			}), MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"deps":               `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":foo_cc_proto_lite"]`,
-			}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":foo_cc_proto_lite"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryProtoIncludeDirs(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `cc_library {
-	name: "foo",
-	srcs: ["foo.proto"],
-	proto: {
-		include_dirs: ["external/protobuf/src"],
-	},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-				"srcs": `["foo.proto"]`,
-				"deps": `["//external/protobuf:libprotobuf-proto"]`,
-			}), MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
-				"deps": `[":foo_proto"]`,
-			}), MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"deps":                              `[":libprotobuf-cpp-lite"]`,
-				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
-			}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"dynamic_deps":                      `[":libprotobuf-cpp-lite"]`,
-				"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryProtoIncludeDirsUnknown(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `cc_library {
-	name: "foo",
-	srcs: ["foo.proto"],
-	proto: {
-		include_dirs: ["external/protobuf/abc"],
-	},
-	include_build_directory: false,
-}`,
-		ExpectedErr: fmt.Errorf("module \"foo\": Could not find the proto_library target for include dir: external/protobuf/abc"),
-	})
-}
-
-func TestCcLibraryConvertedProtoFilegroups(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `
-filegroup {
-	name: "a_fg_proto",
-	srcs: ["a_fg.proto"],
-}
-
-cc_library {
-	name: "a",
-	srcs: [
-    ":a_fg_proto",
-    "a.proto",
-  ],
-	proto: {
-		export_proto_headers: true,
-	},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("proto_library", "a_proto", AttrNameToString{
-				"deps": `[":a_fg_proto_bp2build_converted"]`,
-				"srcs": `["a.proto"]`,
-			}), MakeBazelTarget("cc_lite_proto_library", "a_cc_proto_lite", AttrNameToString{
-				"deps": `[
-        ":a_fg_proto_bp2build_converted",
-        ":a_proto",
-    ]`,
-			}), MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
-				"deps":               `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":a_cc_proto_lite"]`,
-			}), MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
-				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":a_cc_proto_lite"]`,
-			}), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_proto", AttrNameToString{
-				"srcs": `["a_fg.proto"]`,
-				"tags": `[
-        "apex_available=//apex_available:anyapex",
-        "manual",
-    ]`,
-			}), MakeBazelTargetNoRestrictions("alias", "a_fg_proto_bp2build_converted", AttrNameToString{
-				"actual": `"//.:a_fg_proto_proto"`,
-				"tags": `[
-        "apex_available=//apex_available:anyapex",
-        "manual",
-    ]`,
-			}), MakeBazelTargetNoRestrictions("filegroup", "a_fg_proto", AttrNameToString{
-				"srcs": `["a_fg.proto"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryConvertedProtoFilegroupsNoProtoFiles(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `
-filegroup {
-	name: "a_fg_proto",
-	srcs: ["a_fg.proto"],
-}
-
-cc_library {
-	name: "a",
-	srcs: [
-    ":a_fg_proto",
-  ],
-	proto: {
-		export_proto_headers: true,
-	},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_lite_proto_library", "a_cc_proto_lite", AttrNameToString{
-				"deps": `[":a_fg_proto_bp2build_converted"]`,
-			}), MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
-				"deps":               `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":a_cc_proto_lite"]`,
-			}), MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
-				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":a_cc_proto_lite"]`,
-			}), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_proto", AttrNameToString{
-				"srcs": `["a_fg.proto"]`,
-				"tags": `[
-        "apex_available=//apex_available:anyapex",
-        "manual",
-    ]`,
-			}), MakeBazelTargetNoRestrictions("alias", "a_fg_proto_bp2build_converted", AttrNameToString{
-				"actual": `"//.:a_fg_proto_proto"`,
-				"tags": `[
-        "apex_available=//apex_available:anyapex",
-        "manual",
-    ]`,
-			}), MakeBazelTargetNoRestrictions("filegroup", "a_fg_proto", AttrNameToString{
-				"srcs": `["a_fg.proto"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryExternalConvertedProtoFilegroups(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"path/to/A/Android.bp": `
-filegroup {
-	name: "a_fg_proto",
-	srcs: ["a_fg.proto"],
-}`,
-		},
-		Blueprint: soongCcProtoPreamble + `
-cc_library {
-	name: "a",
-	srcs: [
-    ":a_fg_proto",
-    "a.proto",
-  ],
-	proto: {
-		export_proto_headers: true,
-	},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("proto_library", "a_proto", AttrNameToString{
-				"deps": `["//path/to/A:a_fg_proto_bp2build_converted"]`,
-				"srcs": `["a.proto"]`,
-			}), MakeBazelTarget("cc_lite_proto_library", "a_cc_proto_lite", AttrNameToString{
-				"deps": `[
-        "//path/to/A:a_fg_proto_bp2build_converted",
-        ":a_proto",
-    ]`,
-			}), MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
-				"deps":               `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":a_cc_proto_lite"]`,
-			}), MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
-				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":a_cc_proto_lite"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryProtoFilegroups(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble +
-			simpleModuleDoNotConvertBp2build("filegroup", "a_fg_proto") +
-			simpleModuleDoNotConvertBp2build("filegroup", "b_protos") +
-			simpleModuleDoNotConvertBp2build("filegroup", "c-proto-srcs") +
-			simpleModuleDoNotConvertBp2build("filegroup", "proto-srcs-d") + `
-cc_library {
-	name: "a",
-	srcs: [":a_fg_proto"],
-	proto: {
-		export_proto_headers: true,
-	},
-	include_build_directory: false,
-}
-
-cc_library {
-	name: "b",
-	srcs: [":b_protos"],
-	proto: {
-		export_proto_headers: true,
-	},
-	include_build_directory: false,
-}
-
-cc_library {
-	name: "c",
-	srcs: [":c-proto-srcs"],
-	proto: {
-		export_proto_headers: true,
-	},
-	include_build_directory: false,
-}
-
-cc_library {
-	name: "d",
-	srcs: [":proto-srcs-d"],
-	proto: {
-		export_proto_headers: true,
-	},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("proto_library", "a_proto", AttrNameToString{
-				"srcs": `[":a_fg_proto"]`,
-			}), MakeBazelTarget("cc_lite_proto_library", "a_cc_proto_lite", AttrNameToString{
-				"deps": `[":a_proto"]`,
-			}), MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
-				"deps":               `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":a_cc_proto_lite"]`,
-				"srcs":               `[":a_fg_proto_cpp_srcs"]`,
-				"srcs_as":            `[":a_fg_proto_as_srcs"]`,
-				"srcs_c":             `[":a_fg_proto_c_srcs"]`,
-			}), MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
-				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":a_cc_proto_lite"]`,
-				"srcs":               `[":a_fg_proto_cpp_srcs"]`,
-				"srcs_as":            `[":a_fg_proto_as_srcs"]`,
-				"srcs_c":             `[":a_fg_proto_c_srcs"]`,
-			}), MakeBazelTarget("proto_library", "b_proto", AttrNameToString{
-				"srcs": `[":b_protos"]`,
-			}), MakeBazelTarget("cc_lite_proto_library", "b_cc_proto_lite", AttrNameToString{
-				"deps": `[":b_proto"]`,
-			}), MakeBazelTarget("cc_library_static", "b_bp2build_cc_library_static", AttrNameToString{
-				"deps":               `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":b_cc_proto_lite"]`,
-				"srcs":               `[":b_protos_cpp_srcs"]`,
-				"srcs_as":            `[":b_protos_as_srcs"]`,
-				"srcs_c":             `[":b_protos_c_srcs"]`,
-			}), MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
-				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":b_cc_proto_lite"]`,
-				"srcs":               `[":b_protos_cpp_srcs"]`,
-				"srcs_as":            `[":b_protos_as_srcs"]`,
-				"srcs_c":             `[":b_protos_c_srcs"]`,
-			}), MakeBazelTarget("proto_library", "c_proto", AttrNameToString{
-				"srcs": `[":c-proto-srcs"]`,
-			}), MakeBazelTarget("cc_lite_proto_library", "c_cc_proto_lite", AttrNameToString{
-				"deps": `[":c_proto"]`,
-			}), MakeBazelTarget("cc_library_static", "c_bp2build_cc_library_static", AttrNameToString{
-				"deps":               `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":c_cc_proto_lite"]`,
-				"srcs":               `[":c-proto-srcs_cpp_srcs"]`,
-				"srcs_as":            `[":c-proto-srcs_as_srcs"]`,
-				"srcs_c":             `[":c-proto-srcs_c_srcs"]`,
-			}), MakeBazelTarget("cc_library_shared", "c", AttrNameToString{
-				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":c_cc_proto_lite"]`,
-				"srcs":               `[":c-proto-srcs_cpp_srcs"]`,
-				"srcs_as":            `[":c-proto-srcs_as_srcs"]`,
-				"srcs_c":             `[":c-proto-srcs_c_srcs"]`,
-			}), MakeBazelTarget("proto_library", "d_proto", AttrNameToString{
-				"srcs": `[":proto-srcs-d"]`,
-			}), MakeBazelTarget("cc_lite_proto_library", "d_cc_proto_lite", AttrNameToString{
-				"deps": `[":d_proto"]`,
-			}), MakeBazelTarget("cc_library_static", "d_bp2build_cc_library_static", AttrNameToString{
-				"deps":               `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":d_cc_proto_lite"]`,
-				"srcs":               `[":proto-srcs-d_cpp_srcs"]`,
-				"srcs_as":            `[":proto-srcs-d_as_srcs"]`,
-				"srcs_c":             `[":proto-srcs-d_c_srcs"]`,
-			}), MakeBazelTarget("cc_library_shared", "d", AttrNameToString{
-				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":d_cc_proto_lite"]`,
-				"srcs":               `[":proto-srcs-d_cpp_srcs"]`,
-				"srcs_as":            `[":proto-srcs-d_as_srcs"]`,
-				"srcs_c":             `[":proto-srcs-d_c_srcs"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryDisabledArchAndTarget(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `cc_library {
-	name: "foo",
-	srcs: ["foo.cpp"],
-	host_supported: true,
-	target: {
-		darwin: {
-			enabled: false,
-		},
-		windows: {
-			enabled: false,
-		},
-		linux_glibc_x86: {
-			enabled: false,
-		},
-	},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo", AttrNameToString{
-			"srcs": `["foo.cpp"]`,
-			"target_compatible_with": `select({
-        "//build/bazel/platforms/os_arch:darwin_arm64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:darwin_x86_64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:linux_glibc_x86": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:windows_x86": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:windows_x86_64": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-		}),
-	})
-}
-
-func TestCcLibraryDisabledArchAndTargetWithDefault(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `cc_library {
-	name: "foo",
-	srcs: ["foo.cpp"],
-  enabled: false,
-	host_supported: true,
-	target: {
-		darwin: {
-			enabled: true,
-		},
-		windows: {
-			enabled: false,
-		},
-		linux_glibc_x86: {
-			enabled: false,
-		},
-	},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo", AttrNameToString{
-			"srcs": `["foo.cpp"]`,
-			"target_compatible_with": `select({
-        "//build/bazel/platforms/os_arch:darwin_arm64": [],
-        "//build/bazel/platforms/os_arch:darwin_x86_64": [],
-        "//conditions:default": ["@platforms//:incompatible"],
-    })`,
-		}),
-	})
-}
-
-func TestCcLibrarySharedDisabled(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `cc_library {
-	name: "foo",
-	srcs: ["foo.cpp"],
-	enabled: false,
-	shared: {
-		enabled: true,
-	},
-	target: {
-		android: {
-			shared: {
-				enabled: false,
-			},
-		}
-  },
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-			"srcs":                   `["foo.cpp"]`,
-			"target_compatible_with": `["@platforms//:incompatible"]`,
-		}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-			"srcs": `["foo.cpp"]`,
-			"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-		}),
-		},
-	})
-}
-
-func TestCcLibraryStaticDisabledForSomeArch(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `cc_library {
-	name: "foo",
-	host_supported: true,
-	srcs: ["foo.cpp"],
-	shared: {
-		enabled: false
-	},
-	target: {
-		darwin: {
-			enabled: true,
-		},
-		windows: {
-			enabled: false,
-		},
-		linux_glibc_x86: {
-			shared: {
-				enabled: true,
-			},
-		},
-	},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-			"srcs": `["foo.cpp"]`,
-			"target_compatible_with": `select({
-        "//build/bazel/platforms/os:windows": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-		}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-			"srcs": `["foo.cpp"]`,
-			"target_compatible_with": `select({
-        "//build/bazel/platforms/os_arch:darwin_arm64": [],
-        "//build/bazel/platforms/os_arch:darwin_x86_64": [],
-        "//build/bazel/platforms/os_arch:linux_glibc_x86": [],
-        "//conditions:default": ["@platforms//:incompatible"],
-    })`,
-		}),
-		}})
-}
-
-func TestCcLibraryStubs(t *testing.T) {
-	expectedBazelTargets := makeCcLibraryTargets("a", AttrNameToString{
-		"stubs_symbol_file": `"a.map.txt"`,
-	})
-	expectedBazelTargets = append(expectedBazelTargets, makeCcStubSuiteTargets("a", AttrNameToString{
-		"soname":               `"a.so"`,
-		"source_library_label": `"//foo/bar:a"`,
-		"stubs_symbol_file":    `"a.map.txt"`,
-		"stubs_versions": `[
-        "28",
-        "29",
-        "current",
-    ]`,
-	}))
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library stubs",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Dir:                        "foo/bar",
-		Filesystem: map[string]string{
-			"foo/bar/Android.bp": `
-cc_library {
-    name: "a",
-    stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] },
-    bazel_module: { bp2build_available: true },
-    include_build_directory: false,
-}
-`,
-		},
-		Blueprint:            soongCcLibraryPreamble,
-		ExpectedBazelTargets: expectedBazelTargets,
-	},
-	)
-}
-
-func TestCcApiContributionsWithHdrs(t *testing.T) {
-	bp := `
-	cc_library {
-		name: "libfoo",
-		stubs: { symbol_file: "libfoo.map.txt", versions: ["28", "29", "current"] },
-		llndk: { symbol_file: "libfoo.map.txt", override_export_include_dirs: ["dir2"]},
-		export_include_dirs: ["dir1"],
-	}
-	`
-	expectedBazelTargets := []string{
-		MakeBazelTarget(
-			"cc_api_library_headers",
-			"libfoo.module-libapi.headers",
-			AttrNameToString{
-				"export_includes": `["dir1"]`,
-			}),
-		MakeBazelTarget(
-			"cc_api_library_headers",
-			"libfoo.vendorapi.headers",
-			AttrNameToString{
-				"export_includes": `["dir2"]`,
-			}),
-		MakeBazelTarget(
-			"cc_api_contribution",
-			"libfoo.contribution",
-			AttrNameToString{
-				"api":          `"libfoo.map.txt"`,
-				"library_name": `"libfoo"`,
-				"api_surfaces": `[
-        "module-libapi",
-        "vendorapi",
-    ]`,
-				"hdrs": `[
-        ":libfoo.module-libapi.headers",
-        ":libfoo.vendorapi.headers",
-    ]`,
-			}),
-	}
-	RunApiBp2BuildTestCase(t, cc.RegisterLibraryBuildComponents, Bp2buildTestCase{
-		Blueprint:            bp,
-		Description:          "cc API contributions to module-libapi and vendorapi",
-		ExpectedBazelTargets: expectedBazelTargets,
-	})
-}
-
-func TestCcApiSurfaceCombinations(t *testing.T) {
-	testCases := []struct {
-		bp                  string
-		expectedApi         string
-		expectedApiSurfaces string
-		description         string
-	}{
-		{
-			bp: `
-			cc_library {
-				name: "a",
-				stubs: {symbol_file: "a.map.txt"},
-			}`,
-			expectedApi:         `"a.map.txt"`,
-			expectedApiSurfaces: `["module-libapi"]`,
-			description:         "Library that contributes to module-libapi",
-		},
-		{
-			bp: `
-			cc_library {
-				name: "a",
-				llndk: {symbol_file: "a.map.txt"},
-			}`,
-			expectedApi:         `"a.map.txt"`,
-			expectedApiSurfaces: `["vendorapi"]`,
-			description:         "Library that contributes to vendorapi",
-		},
-		{
-			bp: `
-			cc_library {
-				name: "a",
-				llndk: {symbol_file: "a.map.txt"},
-				stubs: {symbol_file: "a.map.txt"},
-			}`,
-			expectedApi: `"a.map.txt"`,
-			expectedApiSurfaces: `[
-        "module-libapi",
-        "vendorapi",
-    ]`,
-			description: "Library that contributes to module-libapi and vendorapi",
-		},
-	}
-	for _, testCase := range testCases {
-		expectedBazelTargets := []string{
-			MakeBazelTarget(
-				"cc_api_contribution",
-				"a.contribution",
-				AttrNameToString{
-					"library_name": `"a"`,
-					"hdrs":         `[]`,
-					"api":          testCase.expectedApi,
-					"api_surfaces": testCase.expectedApiSurfaces,
-				},
-			),
-		}
-		RunApiBp2BuildTestCase(t, cc.RegisterLibraryBuildComponents, Bp2buildTestCase{
-			Blueprint:            testCase.bp,
-			Description:          testCase.description,
-			ExpectedBazelTargets: expectedBazelTargets,
-		})
-	}
-}
-
-// llndk struct property in Soong provides users with several options to configure the exported include dirs
-// Test the generated bazel targets for the different configurations
-func TestCcVendorApiHeaders(t *testing.T) {
-	testCases := []struct {
-		bp                     string
-		expectedIncludes       string
-		expectedSystemIncludes string
-		description            string
-	}{
-		{
-			bp: `
-			cc_library {
-				name: "a",
-				export_include_dirs: ["include"],
-				export_system_include_dirs: ["base_system_include"],
-				llndk: {
-					symbol_file: "a.map.txt",
-					export_headers_as_system: true,
-				},
-			}
-			`,
-			expectedIncludes: "",
-			expectedSystemIncludes: `[
-        "base_system_include",
-        "include",
-    ]`,
-			description: "Headers are exported as system to API surface",
-		},
-		{
-			bp: `
-			cc_library {
-				name: "a",
-				export_include_dirs: ["include"],
-				export_system_include_dirs: ["base_system_include"],
-				llndk: {
-					symbol_file: "a.map.txt",
-					override_export_include_dirs: ["llndk_include"],
-				},
-			}
-			`,
-			expectedIncludes:       `["llndk_include"]`,
-			expectedSystemIncludes: `["base_system_include"]`,
-			description:            "Non-system Headers are ovverriden before export to API surface",
-		},
-		{
-			bp: `
-			cc_library {
-				name: "a",
-				export_include_dirs: ["include"],
-				export_system_include_dirs: ["base_system_include"],
-				llndk: {
-					symbol_file: "a.map.txt",
-					override_export_include_dirs: ["llndk_include"],
-					export_headers_as_system: true,
-				},
-			}
-			`,
-			expectedIncludes: "", // includes are set to nil
-			expectedSystemIncludes: `[
-        "base_system_include",
-        "llndk_include",
-    ]`,
-			description: "System Headers are extended before export to API surface",
-		},
-	}
-	for _, testCase := range testCases {
-		attrs := AttrNameToString{}
-		if testCase.expectedIncludes != "" {
-			attrs["export_includes"] = testCase.expectedIncludes
-		}
-		if testCase.expectedSystemIncludes != "" {
-			attrs["export_system_includes"] = testCase.expectedSystemIncludes
-		}
-
-		expectedBazelTargets := []string{
-			MakeBazelTarget("cc_api_library_headers", "a.vendorapi.headers", attrs),
-			// Create a target for cc_api_contribution target
-			MakeBazelTarget("cc_api_contribution", "a.contribution", AttrNameToString{
-				"api":          `"a.map.txt"`,
-				"api_surfaces": `["vendorapi"]`,
-				"hdrs":         `[":a.vendorapi.headers"]`,
-				"library_name": `"a"`,
-			}),
-		}
-		RunApiBp2BuildTestCase(t, cc.RegisterLibraryBuildComponents, Bp2buildTestCase{
-			Blueprint:            testCase.bp,
-			ExpectedBazelTargets: expectedBazelTargets,
-		})
-	}
-}
-
-func TestCcLibraryStubsAcrossConfigsDuplicatesRemoved(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "stub target generation of the same lib across configs should not result in duplicates",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"bar.map.txt": "",
-		},
-		Blueprint: `
-cc_library {
-	name: "barlib",
-	stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] },
-	bazel_module: { bp2build_available: false },
-}
-cc_library {
-	name: "foolib",
-	shared_libs: ["barlib"],
-	target: {
-		android: {
-			shared_libs: ["barlib"],
-		},
-	},
-	bazel_module: { bp2build_available: true },
-	apex_available: ["foo"],
-}`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foolib", AttrNameToString{
-			"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:foo": ["@api_surfaces//module-libapi/current:barlib"],
-        "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:barlib"],
-        "//conditions:default": [":barlib"],
-    })`,
-			"local_includes": `["."]`,
-			"tags":           `["apex_available=foo"]`,
-		}),
-	})
-}
-
-func TestCcLibraryExcludesLibsHost(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"bar.map.txt": "",
-		},
-		Blueprint: simpleModuleDoNotConvertBp2build("cc_library", "bazlib") + `
-cc_library {
-	name: "quxlib",
-	stubs: { symbol_file: "bar.map.txt", versions: ["current"] },
-	bazel_module: { bp2build_available: false },
-}
-cc_library {
-	name: "barlib",
-	stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] },
-	bazel_module: { bp2build_available: false },
-}
-cc_library {
-	name: "foolib",
-	shared_libs: ["barlib", "quxlib"],
-	target: {
-		host: {
-			shared_libs: ["bazlib"],
-			exclude_shared_libs: ["barlib"],
-		},
-	},
-	include_build_directory: false,
-	bazel_module: { bp2build_available: true },
-	apex_available: ["foo"],
-}`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foolib", AttrNameToString{
-			"implementation_dynamic_deps": `select({
-        "//build/bazel/platforms/os:darwin": [":bazlib"],
-        "//build/bazel/platforms/os:linux_bionic": [":bazlib"],
-        "//build/bazel/platforms/os:linux_glibc": [":bazlib"],
-        "//build/bazel/platforms/os:linux_musl": [":bazlib"],
-        "//build/bazel/platforms/os:windows": [":bazlib"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/os:darwin": [":quxlib"],
-        "//build/bazel/platforms/os:linux_bionic": [":quxlib"],
-        "//build/bazel/platforms/os:linux_glibc": [":quxlib"],
-        "//build/bazel/platforms/os:linux_musl": [":quxlib"],
-        "//build/bazel/platforms/os:windows": [":quxlib"],
-        "//build/bazel/rules/apex:foo": [
-            "@api_surfaces//module-libapi/current:barlib",
-            "@api_surfaces//module-libapi/current:quxlib",
-        ],
-        "//build/bazel/rules/apex:system": [
-            "@api_surfaces//module-libapi/current:barlib",
-            "@api_surfaces//module-libapi/current:quxlib",
-        ],
-        "//conditions:default": [
-            ":barlib",
-            ":quxlib",
-        ],
-    })`,
-			"tags": `["apex_available=foo"]`,
-		}),
-	})
-}
-
-func TestCcLibraryEscapeLdflags(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcProtoPreamble + `cc_library {
-	name: "foo",
-	ldflags: ["-Wl,--rpath,${ORIGIN}"],
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo", AttrNameToString{
-			"linkopts": `["-Wl,--rpath,$${ORIGIN}"]`,
-		}),
-	})
-}
-
-func TestCcLibraryConvertLex(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"foo.c":   "",
-			"bar.cc":  "",
-			"foo1.l":  "",
-			"bar1.ll": "",
-			"foo2.l":  "",
-			"bar2.ll": "",
-		},
-		Blueprint: `cc_library {
-	name: "foo_lib",
-	srcs: ["foo.c", "bar.cc", "foo1.l", "foo2.l", "bar1.ll", "bar2.ll"],
-	lex: { flags: ["--foo_flags"] },
-	include_build_directory: false,
-	bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: append([]string{
-			MakeBazelTarget("genlex", "foo_lib_genlex_l", AttrNameToString{
-				"srcs": `[
-        "foo1.l",
-        "foo2.l",
-    ]`,
-				"lexopts": `["--foo_flags"]`,
-			}),
-			MakeBazelTarget("genlex", "foo_lib_genlex_ll", AttrNameToString{
-				"srcs": `[
-        "bar1.ll",
-        "bar2.ll",
-    ]`,
-				"lexopts": `["--foo_flags"]`,
-			}),
-		},
-			makeCcLibraryTargets("foo_lib", AttrNameToString{
-				"srcs": `[
-        "bar.cc",
-        ":foo_lib_genlex_ll",
-    ]`,
-				"srcs_c": `[
-        "foo.c",
-        ":foo_lib_genlex_l",
-    ]`,
-			})...),
-	})
-}
-
-func TestCCLibraryRuntimeDeps(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Blueprint: `cc_library_shared {
-	name: "bar",
-}
-
-cc_library {
-  name: "foo",
-  runtime_libs: ["foo"],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "bar", AttrNameToString{
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"runtime_deps":   `[":foo"]`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"runtime_deps":   `[":foo"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithInstructionSet(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `cc_library {
-    name: "foo",
-    arch: {
-      arm: {
-        instruction_set: "arm",
-      }
-    }
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("foo", AttrNameToString{
-			"features": `select({
-        "//build/bazel/platforms/arch:arm": ["arm_isa_arm"],
-        "//conditions:default": [],
-    })`,
-			"local_includes": `["."]`,
-		}),
-	})
-}
-
-func TestCcLibraryEmptySuffix(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library with empty suffix",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"foo.c": "",
-		},
-		Blueprint: `cc_library {
-    name: "foo",
-    suffix: "",
-    srcs: ["foo.c"],
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"srcs_c": `["foo.c"]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"srcs_c": `["foo.c"]`,
-				"suffix": `""`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySuffix(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library with suffix",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"foo.c": "",
-		},
-		Blueprint: `cc_library {
-    name: "foo",
-    suffix: "-suf",
-    srcs: ["foo.c"],
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"srcs_c": `["foo.c"]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"srcs_c": `["foo.c"]`,
-				"suffix": `"-suf"`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryArchVariantSuffix(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library with arch-variant suffix",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"foo.c": "",
-		},
-		Blueprint: `cc_library {
-    name: "foo",
-    arch: {
-        arm64: { suffix: "-64" },
-        arm:   { suffix: "-32" },
-		},
-    srcs: ["foo.c"],
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"srcs_c": `["foo.c"]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"srcs_c": `["foo.c"]`,
-				"suffix": `select({
-        "//build/bazel/platforms/arch:arm": "-32",
-        "//build/bazel/platforms/arch:arm64": "-64",
-        "//conditions:default": None,
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithAidlLibrary(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library with aidl_library",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-aidl_library {
-    name: "A_aidl",
-    srcs: ["aidl/A.aidl"],
-	hdrs: ["aidl/Header.aidl"],
-	strip_import_prefix: "aidl",
-}
-cc_library {
-	name: "foo",
-	aidl: {
-		libs: ["A_aidl"],
-	},
-	export_include_dirs: ["include"],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTargetNoRestrictions("aidl_library", "A_aidl", AttrNameToString{
-				"srcs":                `["aidl/A.aidl"]`,
-				"hdrs":                `["aidl/Header.aidl"]`,
-				"strip_import_prefix": `"aidl"`,
-				"tags":                `["apex_available=//apex_available:anyapex"]`,
-			}),
-			MakeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
-				"deps":            `[":A_aidl"]`,
-				"local_includes":  `["."]`,
-				"export_includes": `["include"]`,
-			}),
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
-				"local_includes":                    `["."]`,
-				"export_includes":                   `["include"]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
-				"local_includes":                    `["."]`,
-				"export_includes":                   `["include"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithAidlSrcs(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library with aidl srcs",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-filegroup {
-    name: "A_aidl",
-    srcs: ["aidl/A.aidl"],
-	path: "aidl",
-}
-cc_library {
-	name: "foo",
-	srcs: [
-		":A_aidl",
-		"B.aidl",
-	],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTargetNoRestrictions("aidl_library", "A_aidl", AttrNameToString{
-				"srcs":                `["aidl/A.aidl"]`,
-				"strip_import_prefix": `"aidl"`,
-				"tags":                `["apex_available=//apex_available:anyapex"]`,
-			}),
-			MakeBazelTarget("aidl_library", "foo_aidl_library", AttrNameToString{
-				"srcs": `["B.aidl"]`,
-			}),
-			MakeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
-				"local_includes": `["."]`,
-				"deps": `[
-        ":A_aidl",
-        ":foo_aidl_library",
-    ]`,
-			}),
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
-				"local_includes":                    `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
-				"local_includes":                    `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithNonAdjacentAidlFilegroup(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library with non aidl filegroup",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"path/to/A/Android.bp": `
-filegroup {
-    name: "A_aidl",
-    srcs: ["aidl/A.aidl"],
-    path: "aidl",
-}`,
-		},
-		Blueprint: `
-cc_library {
-    name: "foo",
-    srcs: [
-        ":A_aidl",
-    ],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
-				"local_includes": `["."]`,
-				"deps":           `["//path/to/A:A_aidl"]`,
-			}),
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
-				"local_includes":                    `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"local_includes":                    `["."]`,
-				"implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithExportAidlHeaders(t *testing.T) {
-	t.Parallel()
-
-	expectedBazelTargets := []string{
-		MakeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
-			"local_includes": `["."]`,
-			"deps":           `[":foo_aidl_library"]`,
-		}),
-		MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-			"whole_archive_deps": `[":foo_cc_aidl_library"]`,
-			"local_includes":     `["."]`,
-		}),
-		MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-			"whole_archive_deps": `[":foo_cc_aidl_library"]`,
-			"local_includes":     `["."]`,
-		}),
-	}
-	testCases := []struct {
-		description          string
-		bp                   string
-		expectedBazelTargets []string
-	}{
-		{
-			description: "cc_library with aidl srcs and aidl.export_aidl_headers set",
-			bp: `
-			cc_library {
-				name: "foo",
-				srcs: [
-					"Foo.aidl",
-				],
-				aidl: {
-					export_aidl_headers: true,
-				}
-			}`,
-			expectedBazelTargets: append(
-				expectedBazelTargets,
-				MakeBazelTarget("aidl_library", "foo_aidl_library", AttrNameToString{
-					"srcs": `["Foo.aidl"]`,
-				})),
-		},
-		{
-			description: "cc_library with aidl.libs and aidl.export_aidl_headers set",
-			bp: `
-			aidl_library {
-				name: "foo_aidl_library",
-				srcs: ["Foo.aidl"],
-			}
-			cc_library {
-				name: "foo",
-				aidl: {
-					libs: ["foo_aidl_library"],
-					export_aidl_headers: true,
-				}
-			}`,
-			expectedBazelTargets: append(
-				expectedBazelTargets,
-				MakeBazelTargetNoRestrictions("aidl_library", "foo_aidl_library", AttrNameToString{
-					"srcs": `["Foo.aidl"]`,
-					"tags": `["apex_available=//apex_available:anyapex"]`,
-				}),
-			),
-		},
-	}
-
-	for _, testCase := range testCases {
-		runCcLibraryTestCase(t, Bp2buildTestCase{
-			Description:                "cc_library with export aidl headers",
-			ModuleTypeUnderTest:        "cc_library",
-			ModuleTypeUnderTestFactory: cc.LibraryFactory,
-			Blueprint:                  testCase.bp,
-			ExpectedBazelTargets:       testCase.expectedBazelTargets,
-		})
-	}
-}
-
-func TestCcLibraryWithTargetApex(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library with target.apex",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-    name: "foo",
-	shared_libs: ["bar", "baz"],
-	static_libs: ["baz", "buh"],
-	target: {
-        apex: {
-            exclude_shared_libs: ["bar"],
-            exclude_static_libs: ["buh"],
-        }
-    }
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"implementation_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
-        "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":buh__BP2BUILD__MISSING__DEP"],
-    })`,
-				"implementation_dynamic_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
-        "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":bar__BP2BUILD__MISSING__DEP"],
-    })`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"implementation_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
-        "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":buh__BP2BUILD__MISSING__DEP"],
-    })`,
-				"implementation_dynamic_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
-        "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":bar__BP2BUILD__MISSING__DEP"],
-    })`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithTargetApexAndExportLibHeaders(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library with target.apex and export_shared|static_lib_headers",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library_static {
-    name: "foo",
-	shared_libs: ["bar", "baz"],
-    static_libs: ["abc"],
-    export_shared_lib_headers: ["baz"],
-    export_static_lib_headers: ["abc"],
-	target: {
-        apex: {
-            exclude_shared_libs: ["baz", "bar"],
-            exclude_static_libs: ["abc"],
-        }
-    }
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":bar__BP2BUILD__MISSING__DEP"],
-    })`,
-				"dynamic_deps": `select({
-        "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":baz__BP2BUILD__MISSING__DEP"],
-    })`,
-				"deps": `select({
-        "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":abc__BP2BUILD__MISSING__DEP"],
-    })`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithSyspropSrcs(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library with sysprop sources",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	srcs: [
-		"bar.sysprop",
-		"baz.sysprop",
-		"blah.cpp",
-	],
-	min_sdk_version: "5",
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("sysprop_library", "foo_sysprop_library", AttrNameToString{
-				"srcs": `[
-        "bar.sysprop",
-        "baz.sysprop",
-    ]`,
-			}),
-			MakeBazelTarget("cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
-				"dep":             `":foo_sysprop_library"`,
-				"min_sdk_version": `"5"`,
-			}),
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"srcs":               `["blah.cpp"]`,
-				"local_includes":     `["."]`,
-				"min_sdk_version":    `"5"`,
-				"whole_archive_deps": `[":foo_cc_sysprop_library_static"]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"srcs":               `["blah.cpp"]`,
-				"local_includes":     `["."]`,
-				"min_sdk_version":    `"5"`,
-				"whole_archive_deps": `[":foo_cc_sysprop_library_static"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithSyspropSrcsSomeConfigs(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library with sysprop sources in some configs but not others",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	host_supported: true,
-	srcs: [
-		"blah.cpp",
-	],
-	target: {
-		android: {
-			srcs: ["bar.sysprop"],
-		},
-	},
-	min_sdk_version: "5",
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTargetNoRestrictions("sysprop_library", "foo_sysprop_library", AttrNameToString{
-				"srcs": `select({
-        "//build/bazel/platforms/os:android": ["bar.sysprop"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTargetNoRestrictions("cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
-				"dep":             `":foo_sysprop_library"`,
-				"min_sdk_version": `"5"`,
-			}),
-			MakeBazelTargetNoRestrictions("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"srcs":            `["blah.cpp"]`,
-				"local_includes":  `["."]`,
-				"min_sdk_version": `"5"`,
-				"whole_archive_deps": `select({
-        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTargetNoRestrictions("cc_library_shared", "foo", AttrNameToString{
-				"srcs":            `["blah.cpp"]`,
-				"local_includes":  `["."]`,
-				"min_sdk_version": `"5"`,
-				"whole_archive_deps": `select({
-        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithAidlAndLibs(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_aidl_library depends on libs from parent cc_library_static",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	srcs: [
-		"Foo.aidl",
-	],
-	static_libs: [
-		"bar-static",
-		"baz-static",
-	],
-	shared_libs: [
-		"bar-shared",
-		"baz-shared",
-	],
-	export_static_lib_headers: [
-		"baz-static",
-	],
-	export_shared_lib_headers: [
-		"baz-shared",
-	],
-}` +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "bar-static") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "baz-static") +
-			simpleModuleDoNotConvertBp2build("cc_library", "bar-shared") +
-			simpleModuleDoNotConvertBp2build("cc_library", "baz-shared"),
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("aidl_library", "foo_aidl_library", AttrNameToString{
-				"srcs": `["Foo.aidl"]`,
-			}),
-			MakeBazelTarget("cc_aidl_library", "foo_cc_aidl_library", AttrNameToString{
-				"local_includes": `["."]`,
-				"deps":           `[":foo_aidl_library"]`,
-				"implementation_deps": `[
-        ":baz-static",
-        ":bar-static",
-    ]`,
-				"implementation_dynamic_deps": `[
-        ":baz-shared",
-        ":bar-shared",
-    ]`,
-			}),
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"implementation_whole_archive_deps": `[":foo_cc_aidl_library"]`,
-				"deps":                              `[":baz-static"]`,
-				"implementation_deps":               `[":bar-static"]`,
-				"dynamic_deps":                      `[":baz-shared"]`,
-				"implementation_dynamic_deps":       `[":bar-shared"]`,
-				"local_includes":                    `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithTidy(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library uses tidy properties",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	srcs: ["foo.cpp"],
-}
-cc_library_static {
-	name: "foo-no-tidy",
-	srcs: ["foo.cpp"],
-	tidy: false,
-}
-cc_library_static {
-	name: "foo-tidy",
-	srcs: ["foo.cpp"],
-	tidy: true,
-	tidy_checks: ["check1", "check2"],
-	tidy_checks_as_errors: ["check1error", "check2error"],
-	tidy_disabled_srcs: ["bar.cpp"],
-	tidy_timeout_srcs: ["baz.cpp"],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"srcs":           `["foo.cpp"]`,
-			}),
-			MakeBazelTarget("cc_library_static", "foo-no-tidy", AttrNameToString{
-				"local_includes": `["."]`,
-				"srcs":           `["foo.cpp"]`,
-				"tidy":           `"never"`,
-			}),
-			MakeBazelTarget("cc_library_static", "foo-tidy", AttrNameToString{
-				"local_includes": `["."]`,
-				"srcs":           `["foo.cpp"]`,
-				"tidy":           `"local"`,
-				"tidy_checks": `[
-        "check1",
-        "check2",
-    ]`,
-				"tidy_checks_as_errors": `[
-        "check1error",
-        "check2error",
-    ]`,
-				"tidy_disabled_srcs": `["bar.cpp"]`,
-				"tidy_timeout_srcs":  `["baz.cpp"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithAfdoEnabled(t *testing.T) {
-	bp := `
-cc_library {
-	name: "foo",
-	afdo: true,
-	include_build_directory: false,
-}`
-
-	// TODO(b/260714900): Add test case for arch-specific afdo profile
-	testCases := []struct {
-		description          string
-		filesystem           map[string]string
-		expectedBazelTargets []string
-	}{
-		{
-			description: "cc_library with afdo enabled and existing profile",
-			filesystem: map[string]string{
-				"vendor/google_data/pgo_profile/sampling/BUILD":    "",
-				"vendor/google_data/pgo_profile/sampling/foo.afdo": "",
-			},
-			expectedBazelTargets: []string{
-				MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{}),
-				MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-					"fdo_profile": `"//vendor/google_data/pgo_profile/sampling:foo"`,
-				}),
-			},
-		},
-		{
-			description: "cc_library with afdo enabled and existing profile in AOSP",
-			filesystem: map[string]string{
-				"toolchain/pgo-profiles/sampling/BUILD":    "",
-				"toolchain/pgo-profiles/sampling/foo.afdo": "",
-			},
-			expectedBazelTargets: []string{
-				MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{}),
-				MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-					"fdo_profile": `"//toolchain/pgo-profiles/sampling:foo"`,
-				}),
-			},
-		},
-		{
-			description: "cc_library with afdo enabled but profile filename doesn't match with module name",
-			filesystem: map[string]string{
-				"toolchain/pgo-profiles/sampling/BUILD":    "",
-				"toolchain/pgo-profiles/sampling/bar.afdo": "",
-			},
-			expectedBazelTargets: []string{
-				MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{}),
-				MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{}),
-			},
-		},
-		{
-			description: "cc_library with afdo enabled but profile doesn't exist",
-			expectedBazelTargets: []string{
-				MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{}),
-				MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{}),
-			},
-		},
-		{
-			description: "cc_library with afdo enabled and existing profile but BUILD file doesn't exist",
-			filesystem: map[string]string{
-				"vendor/google_data/pgo_profile/sampling/foo.afdo": "",
-			},
-			expectedBazelTargets: []string{
-				MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{}),
-				MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{}),
-			},
-		},
-	}
-	for _, testCase := range testCases {
-		t.Run(testCase.description, func(t *testing.T) {
-			runCcLibraryTestCase(t, Bp2buildTestCase{
-				ExpectedBazelTargets:       testCase.expectedBazelTargets,
-				ModuleTypeUnderTest:        "cc_library",
-				ModuleTypeUnderTestFactory: cc.LibraryFactory,
-				Description:                testCase.description,
-				Blueprint:                  binaryReplacer.Replace(bp),
-				Filesystem:                 testCase.filesystem,
-			})
-		})
-	}
-}
-
-func TestCcLibraryHeaderAbiChecker(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library with header abi checker",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `cc_library {
-    name: "foo",
-    header_abi_checker: {
-        enabled: true,
-        symbol_file: "a.map.txt",
-        exclude_symbol_versions: [
-						"29",
-						"30",
-				],
-        exclude_symbol_tags: [
-						"tag1",
-						"tag2",
-				],
-        check_all_apis: true,
-        diff_flags: ["-allow-adding-removing-weak-symbols"],
-    },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"abi_checker_enabled":     `True`,
-				"abi_checker_symbol_file": `"a.map.txt"`,
-				"abi_checker_exclude_symbol_versions": `[
-        "29",
-        "30",
-    ]`,
-				"abi_checker_exclude_symbol_tags": `[
-        "tag1",
-        "tag2",
-    ]`,
-				"abi_checker_check_all_apis": `True`,
-				"abi_checker_diff_flags":     `["-allow-adding-removing-weak-symbols"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryApexAvailable(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library apex_available converted to tags",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "a",
-    srcs: ["a.cpp"],
-    apex_available: ["com.android.foo"],
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
-			"tags":           `["apex_available=com.android.foo"]`,
-			"srcs":           `["a.cpp"]`,
-			"local_includes": `["."]`,
-		}),
-	},
-	)
-}
-
-func TestCcLibraryApexAvailableMultiple(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library apex_available converted to multiple tags",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-    name: "a",
-    srcs: ["a.cpp"],
-    apex_available: ["com.android.foo", "//apex_available:platform", "com.android.bar"],
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
-			"tags": `[
-        "apex_available=com.android.foo",
-        "apex_available=//apex_available:platform",
-        "apex_available=com.android.bar",
-    ]`,
-			"srcs":           `["a.cpp"]`,
-			"local_includes": `["."]`,
-		}),
-	},
-	)
-}
-
-// Export_include_dirs and Export_system_include_dirs have "variant_prepend" tag.
-// In bp2build output, variant info(select) should go before general info.
-// Internal order of the property should be unchanged. (e.g. ["eid1", "eid2"])
-func TestCcLibraryVariantPrependPropOrder(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library variant prepend properties order",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library {
-  name: "a",
-  srcs: ["a.cpp"],
-  export_include_dirs: ["eid1", "eid2"],
-  export_system_include_dirs: ["esid1", "esid2"],
-    target: {
-      android: {
-        export_include_dirs: ["android_eid1", "android_eid2"],
-        export_system_include_dirs: ["android_esid1", "android_esid2"],
-      },
-      android_arm: {
-        export_include_dirs: ["android_arm_eid1", "android_arm_eid2"],
-        export_system_include_dirs: ["android_arm_esid1", "android_arm_esid2"],
-      },
-      linux: {
-        export_include_dirs: ["linux_eid1", "linux_eid2"],
-        export_system_include_dirs: ["linux_esid1", "linux_esid2"],
-      },
-    },
-    multilib: {
-      lib32: {
-        export_include_dirs: ["lib32_eid1", "lib32_eid2"],
-        export_system_include_dirs: ["lib32_esid1", "lib32_esid2"],
-      },
-    },
-    arch: {
-      arm: {
-        export_include_dirs: ["arm_eid1", "arm_eid2"],
-        export_system_include_dirs: ["arm_esid1", "arm_esid2"],
-      },
-    }
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
-			"export_includes": `select({
-        "//build/bazel/platforms/os_arch:android_arm": [
-            "android_arm_eid1",
-            "android_arm_eid2",
-        ],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/os:android": [
-            "android_eid1",
-            "android_eid2",
-            "linux_eid1",
-            "linux_eid2",
-        ],
-        "//build/bazel/platforms/os:linux_bionic": [
-            "linux_eid1",
-            "linux_eid2",
-        ],
-        "//build/bazel/platforms/os:linux_glibc": [
-            "linux_eid1",
-            "linux_eid2",
-        ],
-        "//build/bazel/platforms/os:linux_musl": [
-            "linux_eid1",
-            "linux_eid2",
-        ],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/arch:arm": [
-            "lib32_eid1",
-            "lib32_eid2",
-            "arm_eid1",
-            "arm_eid2",
-        ],
-        "//build/bazel/platforms/arch:x86": [
-            "lib32_eid1",
-            "lib32_eid2",
-        ],
-        "//conditions:default": [],
-    }) + [
-        "eid1",
-        "eid2",
-    ]`,
-			"export_system_includes": `select({
-        "//build/bazel/platforms/os_arch:android_arm": [
-            "android_arm_esid1",
-            "android_arm_esid2",
-        ],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/os:android": [
-            "android_esid1",
-            "android_esid2",
-            "linux_esid1",
-            "linux_esid2",
-        ],
-        "//build/bazel/platforms/os:linux_bionic": [
-            "linux_esid1",
-            "linux_esid2",
-        ],
-        "//build/bazel/platforms/os:linux_glibc": [
-            "linux_esid1",
-            "linux_esid2",
-        ],
-        "//build/bazel/platforms/os:linux_musl": [
-            "linux_esid1",
-            "linux_esid2",
-        ],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/arch:arm": [
-            "lib32_esid1",
-            "lib32_esid2",
-            "arm_esid1",
-            "arm_esid2",
-        ],
-        "//build/bazel/platforms/arch:x86": [
-            "lib32_esid1",
-            "lib32_esid2",
-        ],
-        "//conditions:default": [],
-    }) + [
-        "esid1",
-        "esid2",
-    ]`,
-			"srcs":                   `["a.cpp"]`,
-			"local_includes":         `["."]`,
-			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-		}),
-	},
-	)
-}
-
-func TestCcLibraryWithIntegerOverflowProperty(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library has correct features when integer_overflow property is provided",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-		name: "foo",
-		sanitize: {
-				integer_overflow: true,
-		},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features":       `["ubsan_integer_overflow"]`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["ubsan_integer_overflow"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithMiscUndefinedProperty(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library has correct features when misc_undefined property is provided",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-		name: "foo",
-		sanitize: {
-				misc_undefined: ["undefined", "nullability"],
-		},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features": `[
-        "ubsan_undefined",
-        "ubsan_nullability",
-    ]`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features": `[
-        "ubsan_undefined",
-        "ubsan_nullability",
-    ]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithSanitizerBlocklist(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library has correct feature when sanitize.blocklist is provided",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-		name: "foo",
-		sanitize: {
-			blocklist: "foo_blocklist.txt",
-		},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithUBSanPropertiesArchSpecific(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library has correct feature select when UBSan props are specified in arch specific blocks",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-		name: "foo",
-		sanitize: {
-				misc_undefined: ["undefined", "nullability"],
-		},
-		target: {
-				android: {
-						sanitize: {
-								misc_undefined: ["alignment"],
-						},
-				},
-				linux_glibc: {
-						sanitize: {
-								integer_overflow: true,
-						},
-				},
-		},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features": `[
-        "ubsan_undefined",
-        "ubsan_nullability",
-    ] + select({
-        "//build/bazel/platforms/os:android": ["ubsan_alignment"],
-        "//build/bazel/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features": `[
-        "ubsan_undefined",
-        "ubsan_nullability",
-    ] + select({
-        "//build/bazel/platforms/os:android": ["ubsan_alignment"],
-        "//build/bazel/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryInApexWithStubSharedLibs(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library with in apex with stub shared_libs and export_shared_lib_headers",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "barlib",
-	stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] },
-	bazel_module: { bp2build_available: false },
-	apex_available: ["//apex_available:platform",],
-}
-cc_library {
-	name: "bazlib",
-	stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] },
-	bazel_module: { bp2build_available: false },
-	apex_available: ["//apex_available:platform",],
-}
-cc_library {
-    name: "foo",
-	  shared_libs: ["barlib", "bazlib"],
-    export_shared_lib_headers: ["bazlib"],
-    apex_available: [
-        "//apex_available:platform",
-    ],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"implementation_dynamic_deps": `[":barlib"]`,
-				"dynamic_deps":                `[":bazlib"]`,
-				"local_includes":              `["."]`,
-				"tags":                        `["apex_available=//apex_available:platform"]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"implementation_dynamic_deps": `[":barlib"]`,
-				"dynamic_deps":                `[":bazlib"]`,
-				"local_includes":              `["."]`,
-				"tags":                        `["apex_available=//apex_available:platform"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithThinLto(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library has correct features when thin LTO is enabled",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	lto: {
-		thin: true,
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features":       `["android_thin_lto"]`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["android_thin_lto"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithLtoNever(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library has correct features when LTO is explicitly disabled",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	lto: {
-		never: true,
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features":       `["-android_thin_lto"]`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["-android_thin_lto"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithThinLtoArchSpecific(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library has correct features when LTO differs across arch and os variants",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	target: {
-		android: {
-			lto: {
-				thin: true,
-			},
-		},
-	},
-	arch: {
-		riscv64: {
-			lto: {
-				thin: false,
-			},
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"local_includes": `["."]`,
-				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
-        "//conditions:default": [],
-    })`}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
-        "//conditions:default": [],
-    })`}),
-		},
-	})
-}
-
-func TestCcLibraryWithThinLtoDisabledDefaultEnabledVariant(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library has correct features when LTO disabled by default but enabled on a particular variant",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	lto: {
-		never: true,
-	},
-	target: {
-		android: {
-			lto: {
-				thin: true,
-				never: false,
-			},
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"local_includes": `["."]`,
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_thin_lto"],
-        "//conditions:default": ["-android_thin_lto"],
-    })`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_thin_lto"],
-        "//conditions:default": ["-android_thin_lto"],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithThinLtoWholeProgramVtables(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library has correct features when thin LTO is enabled with whole_program_vtables",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	lto: {
-		thin: true,
-	},
-	whole_program_vtables: true,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features": `[
-        "android_thin_lto",
-        "android_thin_lto_whole_program_vtables",
-    ]`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features": `[
-        "android_thin_lto",
-        "android_thin_lto_whole_program_vtables",
-    ]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryHiddenVisibilityConvertedToFeature(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library changes hidden visibility flag to feature",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	cflags: ["-fvisibility=hidden"],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features":       `["visibility_hidden"]`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["visibility_hidden"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryHiddenVisibilityConvertedToFeatureSharedSpecific(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library changes hidden visibility flag to feature when specific to shared variant",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	shared: {
-		cflags: ["-fvisibility=hidden"],
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["visibility_hidden"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryHiddenVisibilityConvertedToFeatureStaticSpecific(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library changes hidden visibility flag to feature when specific to static variant",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	static: {
-		cflags: ["-fvisibility=hidden"],
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features":       `["visibility_hidden"]`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library changes hidden visibility flag to feature when specific to an os",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	target: {
-		android: {
-			cflags: ["-fvisibility=hidden"],
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["visibility_hidden"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["visibility_hidden"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-// Test that a config_setting specific to an apex is created by cc_library.
-func TestCcLibraryCreatesInApexConfigSetting(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library creates a config_setting for each apex in apex_available",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Dir:                        "build/bazel/rules/apex",
-		Blueprint: `
-cc_library {
-	name: "foo",
-	apex_available: [
-	"//apex_available:platform", // This will be skipped, since it is equivalent to //build/bazel/rules/apex:android-non_apex
-	"myapex"
-	],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTargetNoRestrictions(
-				"config_setting",
-				"myapex",
-				AttrNameToString{
-					"flag_values": `{
-        "//build/bazel/rules/apex:api_domain": "myapex",
-    }`,
-					"constraint_values": `["//build/bazel/platforms/os:android"]`,
-				},
-			),
-		},
-	})
-}
-
-func TestCcLibraryCppFlagsInProductVariables(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library cppflags in product variables",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `cc_library {
-    name: "a",
-    srcs: ["a.cpp"],
-    cppflags: [
-        "-Wextra",
-        "-DDEBUG_ONLY_CODE=0",
-    ],
-    product_variables: {
-        eng: {
-            cppflags: [
-                "-UDEBUG_ONLY_CODE",
-                "-DDEBUG_ONLY_CODE=1",
-            ],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
-			"cppflags": `[
-        "-Wextra",
-        "-DDEBUG_ONLY_CODE=0",
-    ] + select({
-        "//build/bazel/product_config/config_settings:eng": [
-            "-UDEBUG_ONLY_CODE",
-            "-DDEBUG_ONLY_CODE=1",
-        ],
-        "//conditions:default": [],
-    })`,
-			"srcs": `["a.cpp"]`,
-		}),
-	},
-	)
-}
-
-func TestCcLibraryYaccConversion(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library is built from .y/.yy files",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: soongCcLibraryPreamble + `cc_library {
-    name: "a",
-    srcs: [
-	"a.cpp",
-	"a.yy",
-    ],
-    shared_libs: ["sharedlib"],
-    static_libs: ["staticlib"],
-    yacc: {
-	    flags: ["someYaccFlag"],
-	    gen_location_hh: true,
-	    gen_position_hh: true,
-	},
-}
-cc_library_static {
-	name: "staticlib",
-	bazel_module: { bp2build_available: false },
-}
-cc_library {
-	name: "sharedlib",
-	bazel_module: { bp2build_available: false },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_yacc_static_library", "a_yacc", AttrNameToString{
-				"src":                         `"a.yy"`,
-				"implementation_deps":         `[":staticlib"]`,
-				"implementation_dynamic_deps": `[":sharedlib"]`,
-				"flags":                       `["someYaccFlag"]`,
-				"gen_location_hh":             "True",
-				"gen_position_hh":             "True",
-				"local_includes":              `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
-				"srcs":                              `["a.cpp"]`,
-				"implementation_deps":               `[":staticlib"]`,
-				"implementation_dynamic_deps":       `[":sharedlib"]`,
-				"implementation_whole_archive_deps": `[":a_yacc"]`,
-				"local_includes":                    `["."]`,
-			}),
-			MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
-				"srcs":                              `["a.cpp"]`,
-				"implementation_deps":               `[":staticlib"]`,
-				"implementation_dynamic_deps":       `[":sharedlib"]`,
-				"implementation_whole_archive_deps": `[":a_yacc"]`,
-				"local_includes":                    `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryHostLdLibs(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_binary linker flags for host_ldlibs",
-		ModuleTypeUnderTest:        "cc_binary",
-		ModuleTypeUnderTestFactory: cc.BinaryFactory,
-		Blueprint: soongCcLibraryPreamble + `cc_binary {
-    name: "a",
-    host_supported: true,
-    ldflags: ["-lcommon"],
-    target: {
-	linux: {
-		host_ldlibs: [
-			"-llinux",
-		],
-	},
-	darwin: {
-		ldflags: ["-ldarwinadditional"],
-		host_ldlibs: [
-			"-ldarwin",
-		],
-	},
-	windows: {
-		host_ldlibs: [
-			"-lwindows",
-		],
-	},
-    },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTargetNoRestrictions("cc_binary", "a", AttrNameToString{
-				"linkopts": `["-lcommon"] + select({
-        "//build/bazel/platforms/os:darwin": [
-            "-ldarwinadditional",
-            "-ldarwin",
-        ],
-        "//build/bazel/platforms/os:linux_glibc": ["-llinux"],
-        "//build/bazel/platforms/os:windows": ["-lwindows"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithCfi(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library has correct features when cfi is enabled",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	sanitize: {
-		cfi: true,
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features":       `["android_cfi"]`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["android_cfi"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithCfiOsSpecific(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library has correct features when cfi is enabled for specific variants",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	target: {
-		android: {
-			sanitize: {
-				cfi: true,
-			},
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_cfi"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_cfi"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithCfiAndCfiAssemblySupport(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library has correct features when cfi is enabled with cfi_assembly_support",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	sanitize: {
-		cfi: true,
-		config: {
-			cfi_assembly_support: true,
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features": `[
-        "android_cfi",
-        "android_cfi_assembly_support",
-    ]`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features": `[
-        "android_cfi",
-        "android_cfi_assembly_support",
-    ]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryExplicitlyDisablesCfiWhenFalse(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library disables cfi when explciitly set to false in the bp",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library {
-	name: "foo",
-	sanitize: {
-		cfi: false,
-	},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features":       `["-android_cfi"]`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["-android_cfi"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryWithStem(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library with stem property",
-		ModuleTypeUnderTest:        "cc_library_shared",
-		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library_shared {
-	name: "foo_with_stem_simple",
-	stem: "foo",
-}
-cc_library_shared {
-	name: "foo_with_arch_variant_stem",
-	arch: {
-		arm: {
-			stem: "foo-arm",
-		},
-		arm64: {
-			stem: "foo-arm64",
-		},
-	},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo_with_stem_simple", AttrNameToString{
-				"stem":           `"foo"`,
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo_with_arch_variant_stem", AttrNameToString{
-				"stem": `select({
-        "//build/bazel/platforms/arch:arm": "foo-arm",
-        "//build/bazel/platforms/arch:arm64": "foo-arm64",
-        "//conditions:default": None,
-    })`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-// Bazel enforces that proto_library and the .proto file are in the same bazel package
-func TestGenerateProtoLibraryInSamePackage(t *testing.T) {
-	tc := Bp2buildTestCase{
-		Description:                "cc_library depends on .proto files from multiple packages",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	srcs: [
-	   "foo.proto",
-	   "bar/bar.proto", // Different package because there is a bar/Android.bp
-	   "baz/subbaz/baz.proto", // Different package because there is baz/subbaz/Android.bp
-	],
-	proto: {
-		canonical_path_from_root: true,
-	}
-}
-` + simpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"),
-		Filesystem: map[string]string{
-			"bar/Android.bp":        "",
-			"baz/subbaz/Android.bp": "",
-		},
-	}
-
-	// We will run the test 3 times and check in the root, bar and baz/subbaz directories
-	// Root dir
-	tc.ExpectedBazelTargets = []string{
-		MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-			"local_includes":                    `["."]`,
-			"deps":                              `[":libprotobuf-cpp-lite"]`,
-			"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
-		}),
-		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-			"srcs": `["foo.proto"]`,
-		}),
-		MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
-			"deps": `[
-        ":foo_proto",
-        "//bar:foo_proto",
-        "//baz/subbaz:foo_proto",
-    ]`,
-		}),
-	}
-	runCcLibraryTestCase(t, tc)
-
-	// bar dir
-	tc.Dir = "bar"
-	tc.ExpectedBazelTargets = []string{
-		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-			"srcs": `["//bar:bar.proto"]`,
-		}),
-	}
-	runCcLibraryTestCase(t, tc)
-
-	// baz/subbaz dir
-	tc.Dir = "baz/subbaz"
-	tc.ExpectedBazelTargets = []string{
-		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-			"srcs": `["//baz/subbaz:baz.proto"]`,
-		}),
-	}
-	runCcLibraryTestCase(t, tc)
-}
-
-// Bazel enforces that proto_library and the .proto file are in the same bazel package
-func TestGenerateProtoLibraryInSamePackageNotCanonicalFromRoot(t *testing.T) {
-	tc := Bp2buildTestCase{
-		Description:                "cc_library depends on .proto files from multiple packages",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	srcs: [
-	   "foo.proto",
-	   "bar/bar.proto", // Different package because there is a bar/Android.bp
-	   "baz/subbaz/baz.proto", // Different package because there is baz/subbaz/Android.bp
-	],
-	proto: {
-		canonical_path_from_root: false,
-	}
-}
-` + simpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"),
-		Filesystem: map[string]string{
-			"bar/Android.bp":        "",
-			"baz/subbaz/Android.bp": "",
-		},
-	}
-
-	// We will run the test 3 times and check in the root, bar and baz/subbaz directories
-	// Root dir
-	tc.ExpectedBazelTargets = []string{
-		MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-			"local_includes":                    `["."]`,
-			"deps":                              `[":libprotobuf-cpp-lite"]`,
-			"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
-		}),
-		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-			"srcs":                `["foo.proto"]`,
-			"strip_import_prefix": `""`,
-		}),
-		MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
-			"deps": `[
-        ":foo_proto",
-        "//bar:foo_proto",
-        "//baz/subbaz:foo_proto",
-    ]`,
-		}),
-	}
-	runCcLibraryTestCase(t, tc)
-
-	// bar dir
-	tc.Dir = "bar"
-	tc.ExpectedBazelTargets = []string{
-		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-			"srcs":                `["//bar:bar.proto"]`,
-			"strip_import_prefix": `""`,
-			"import_prefix":       `"bar"`,
-		}),
-	}
-	runCcLibraryTestCase(t, tc)
-
-	// baz/subbaz dir
-	tc.Dir = "baz/subbaz"
-	tc.ExpectedBazelTargets = []string{
-		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-			"srcs":                `["//baz/subbaz:baz.proto"]`,
-			"strip_import_prefix": `""`,
-			"import_prefix":       `"baz/subbaz"`,
-		}),
-	}
-	runCcLibraryTestCase(t, tc)
-}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
deleted file mode 100644
index 072f5b3..0000000
--- a/bp2build/cc_library_headers_conversion_test.go
+++ /dev/null
@@ -1,478 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/cc"
-)
-
-const (
-	// See cc/testing.go for more context
-	soongCcLibraryHeadersPreamble = `
-cc_defaults {
-    name: "linux_bionic_supported",
-}`
-)
-
-func TestCcLibraryHeadersLoadStatement(t *testing.T) {
-	testCases := []struct {
-		bazelTargets           BazelTargets
-		expectedLoadStatements string
-	}{
-		{
-			bazelTargets: BazelTargets{
-				BazelTarget{
-					name:      "cc_library_headers_target",
-					ruleClass: "cc_library_headers",
-					// Note: no bzlLoadLocation for native rules
-				},
-			},
-			expectedLoadStatements: ``,
-		},
-	}
-
-	for _, testCase := range testCases {
-		actual := testCase.bazelTargets.LoadStatements()
-		expected := testCase.expectedLoadStatements
-		if actual != expected {
-			t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
-		}
-	}
-}
-
-func registerCcLibraryHeadersModuleTypes(ctx android.RegistrationContext) {
-	cc.RegisterCCBuildComponents(ctx)
-}
-
-func runCcLibraryHeadersTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	RunBp2BuildTestCase(t, registerCcLibraryHeadersModuleTypes, tc)
-}
-
-func TestCcLibraryHeadersSimple(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_headers test",
-		ModuleTypeUnderTest:        "cc_library_headers",
-		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		Filesystem: map[string]string{
-			"lib-1/lib1a.h":                        "",
-			"lib-1/lib1b.h":                        "",
-			"lib-2/lib2a.h":                        "",
-			"lib-2/lib2b.h":                        "",
-			"dir-1/dir1a.h":                        "",
-			"dir-1/dir1b.h":                        "",
-			"dir-2/dir2a.h":                        "",
-			"dir-2/dir2b.h":                        "",
-			"arch_arm64_exported_include_dir/a.h":  "",
-			"arch_x86_exported_include_dir/b.h":    "",
-			"arch_x86_64_exported_include_dir/c.h": "",
-		},
-		Blueprint: soongCcLibraryHeadersPreamble + `
-cc_library_headers {
-    name: "foo_headers",
-    export_include_dirs: ["dir-1", "dir-2"],
-    header_libs: ["lib-1", "lib-2"],
-
-    arch: {
-        arm64: {
-      // We expect dir-1 headers to be dropped, because dir-1 is already in export_include_dirs
-            export_include_dirs: ["arch_arm64_exported_include_dir", "dir-1"],
-        },
-        x86: {
-            export_include_dirs: ["arch_x86_exported_include_dir"],
-        },
-        x86_64: {
-            export_include_dirs: ["arch_x86_64_exported_include_dir"],
-        },
-    },
-    sdk_version: "current",
-    min_sdk_version: "29",
-
-    // TODO: Also support export_header_lib_headers
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
-				"export_includes": `select({
-        "//build/bazel/platforms/arch:arm64": ["arch_arm64_exported_include_dir"],
-        "//build/bazel/platforms/arch:x86": ["arch_x86_exported_include_dir"],
-        "//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir"],
-        "//conditions:default": [],
-    }) + [
-        "dir-1",
-        "dir-2",
-    ]`,
-				"sdk_version":     `"current"`,
-				"min_sdk_version": `"29"`,
-			}),
-		},
-	})
-}
-
-func TestCcApiHeaders(t *testing.T) {
-	fs := map[string]string{
-		"bar/Android.bp": `cc_library_headers { name: "bar_headers", }`,
-	}
-	bp := `
-	cc_library_headers {
-		name: "foo_headers",
-		export_include_dirs: ["dir1", "dir2"],
-		export_header_lib_headers: ["bar_headers"],
-
-		arch: {
-			arm: {
-				export_include_dirs: ["dir_arm"],
-			},
-			x86: {
-				export_include_dirs: ["dir_x86"],
-			},
-		},
-
-		target: {
-			android: {
-				export_include_dirs: ["dir1", "dir_android"],
-			},
-			windows: {
-				export_include_dirs: ["dir_windows"],
-			},
-		}
-	}
-	`
-	expectedBazelTargets := []string{
-		MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.arm", AttrNameToString{
-			"export_includes": `["dir_arm"]`,
-			"arch":            `"arm"`,
-		}),
-		MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.x86", AttrNameToString{
-			"export_includes": `["dir_x86"]`,
-			"arch":            `"x86"`,
-		}),
-		MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.androidos", AttrNameToString{
-			"export_includes": `["dir_android"]`, // common includes are deduped
-		}),
-		// Windows headers are not exported
-		MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution", AttrNameToString{
-			"export_includes": `[
-        "dir1",
-        "dir2",
-    ]`,
-			"deps": `[
-        "//bar:bar_headers.contribution",
-        ":foo_headers.contribution.arm",
-        ":foo_headers.contribution.x86",
-        ":foo_headers.contribution.androidos",
-    ]`,
-		}),
-	}
-	RunApiBp2BuildTestCase(t, cc.RegisterLibraryHeadersBuildComponents, Bp2buildTestCase{
-		Blueprint:            bp,
-		Description:          "Header library contributions to API surfaces",
-		ExpectedBazelTargets: expectedBazelTargets,
-		Filesystem:           fs,
-	})
-}
-
-// header_libs has "variant_prepend" tag. In bp2build output,
-// variant info(select) should go before general info.
-func TestCcLibraryHeadersOsSpecificHeader(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_headers test with os-specific header_libs props",
-		ModuleTypeUnderTest:        "cc_library_headers",
-		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library_headers {
-    name: "android-lib",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_headers {
-    name: "base-lib",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_headers {
-    name: "darwin-lib",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_headers {
-    name: "linux-lib",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_headers {
-    name: "linux_bionic-lib",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_headers {
-    name: "windows-lib",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_headers {
-    name: "foo_headers",
-    header_libs: ["base-lib"],
-		export_header_lib_headers: ["base-lib"],
-    target: {
-        android: {
-						header_libs: ["android-lib"],
-						export_header_lib_headers: ["android-lib"],
-				},
-        darwin: {
-						header_libs: ["darwin-lib"],
-						export_header_lib_headers: ["darwin-lib"],
-				},
-        linux_bionic: {
-						header_libs: ["linux_bionic-lib"],
-						export_header_lib_headers: ["linux_bionic-lib"],
-				},
-        linux_glibc: {
-						header_libs: ["linux-lib"],
-						export_header_lib_headers: ["linux-lib"],
-				},
-        windows: {
-						header_libs: ["windows-lib"],
-						export_header_lib_headers: ["windows-lib"],
-				},
-    },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
-				"deps": `select({
-        "//build/bazel/platforms/os:android": [":android-lib"],
-        "//build/bazel/platforms/os:darwin": [":darwin-lib"],
-        "//build/bazel/platforms/os:linux_bionic": [":linux_bionic-lib"],
-        "//build/bazel/platforms/os:linux_glibc": [":linux-lib"],
-        "//build/bazel/platforms/os:windows": [":windows-lib"],
-        "//conditions:default": [],
-    }) + [":base-lib"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryHeadersOsSpecficHeaderLibsExportHeaderLibHeaders(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_headers test with os-specific header_libs and export_header_lib_headers props",
-		ModuleTypeUnderTest:        "cc_library_headers",
-		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library_headers {
-    name: "android-lib",
-    bazel_module: { bp2build_available: false },
-  }
-cc_library_headers {
-    name: "exported-lib",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_headers {
-    name: "foo_headers",
-    target: {
-        android: {
-            header_libs: ["android-lib", "exported-lib"],
-            export_header_lib_headers: ["exported-lib"]
-        },
-    },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
-				"deps": `select({
-        "//build/bazel/platforms/os:android": [":exported-lib"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryHeadersArchAndTargetExportSystemIncludes(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_headers test with arch-specific and target-specific export_system_include_dirs props",
-		ModuleTypeUnderTest:        "cc_library_headers",
-		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: soongCcLibraryPreamble + `cc_library_headers {
-    name: "foo_headers",
-    export_system_include_dirs: [
-        "shared_include_dir",
-    ],
-    target: {
-        android: {
-            export_system_include_dirs: [
-                "android_include_dir",
-            ],
-        },
-        linux_glibc: {
-            export_system_include_dirs: [
-                "linux_include_dir",
-            ],
-        },
-        darwin: {
-            export_system_include_dirs: [
-                "darwin_include_dir",
-            ],
-        },
-    },
-    arch: {
-        arm: {
-            export_system_include_dirs: [
-                "arm_include_dir",
-            ],
-        },
-        x86_64: {
-            export_system_include_dirs: [
-                "x86_64_include_dir",
-            ],
-        },
-    },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
-				"export_system_includes": `select({
-        "//build/bazel/platforms/os:android": ["android_include_dir"],
-        "//build/bazel/platforms/os:darwin": ["darwin_include_dir"],
-        "//build/bazel/platforms/os:linux_glibc": ["linux_include_dir"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/arch:arm": ["arm_include_dir"],
-        "//build/bazel/platforms/arch:x86_64": ["x86_64_include_dir"],
-        "//conditions:default": [],
-    }) + ["shared_include_dir"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryHeadersNoCrtIgnored(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_headers test",
-		ModuleTypeUnderTest:        "cc_library_headers",
-		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		Filesystem: map[string]string{
-			"lib-1/lib1a.h":                        "",
-			"lib-1/lib1b.h":                        "",
-			"lib-2/lib2a.h":                        "",
-			"lib-2/lib2b.h":                        "",
-			"dir-1/dir1a.h":                        "",
-			"dir-1/dir1b.h":                        "",
-			"dir-2/dir2a.h":                        "",
-			"dir-2/dir2b.h":                        "",
-			"arch_arm64_exported_include_dir/a.h":  "",
-			"arch_x86_exported_include_dir/b.h":    "",
-			"arch_x86_64_exported_include_dir/c.h": "",
-		},
-		Blueprint: soongCcLibraryHeadersPreamble + `
-cc_library_headers {
-    name: "lib-1",
-    export_include_dirs: ["lib-1"],
-    no_libcrt: true,
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_headers", "lib-1", AttrNameToString{
-				"export_includes": `["lib-1"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryHeadersExportedStaticLibHeadersReexported(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_headers exported_static_lib_headers is reexported",
-		ModuleTypeUnderTest:        "cc_library_headers",
-		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: soongCcLibraryHeadersPreamble + `
-cc_library_headers {
-		name: "foo_headers",
-		export_static_lib_headers: ["foo_export"],
-		static_libs: ["foo_export", "foo_no_reexport"],
-    bazel_module: { bp2build_available: true },
-}
-` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
-				"deps": `[":foo_export"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryHeadersExportedSharedLibHeadersReexported(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_headers exported_shared_lib_headers is reexported",
-		ModuleTypeUnderTest:        "cc_library_headers",
-		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: soongCcLibraryHeadersPreamble + `
-cc_library_headers {
-		name: "foo_headers",
-		export_shared_lib_headers: ["foo_export"],
-		shared_libs: ["foo_export", "foo_no_reexport"],
-    bazel_module: { bp2build_available: true },
-}
-` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
-				"deps": `[":foo_export"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryHeadersExportedHeaderLibHeadersReexported(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_headers exported_header_lib_headers is reexported",
-		ModuleTypeUnderTest:        "cc_library_headers",
-		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: soongCcLibraryHeadersPreamble + `
-cc_library_headers {
-		name: "foo_headers",
-		export_header_lib_headers: ["foo_export"],
-		header_libs: ["foo_export", "foo_no_reexport"],
-    bazel_module: { bp2build_available: true },
-}
-` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
-				"deps": `[":foo_export"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryHeadersWholeStaticLibsReexported(t *testing.T) {
-	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_headers whole_static_libs is reexported",
-		ModuleTypeUnderTest:        "cc_library_headers",
-		ModuleTypeUnderTestFactory: cc.LibraryHeaderFactory,
-		Filesystem:                 map[string]string{},
-		Blueprint: soongCcLibraryHeadersPreamble + `
-cc_library_headers {
-		name: "foo_headers",
-		whole_static_libs: ["foo_export"],
-    bazel_module: { bp2build_available: true },
-}
-` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
-				"deps": `[":foo_export"]`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
deleted file mode 100644
index ccb426f..0000000
--- a/bp2build/cc_library_shared_conversion_test.go
+++ /dev/null
@@ -1,1587 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/cc"
-)
-
-const (
-	// See cc/testing.go for more context
-	// TODO(alexmarquez): Split out the preamble into common code?
-	soongCcLibrarySharedPreamble = soongCcLibraryStaticPreamble
-)
-
-func registerCcLibrarySharedModuleTypes(ctx android.RegistrationContext) {
-	cc.RegisterCCBuildComponents(ctx)
-	ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
-	ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
-	ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
-}
-
-func runCcLibrarySharedTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	t.Parallel()
-	(&tc).ModuleTypeUnderTest = "cc_library_shared"
-	(&tc).ModuleTypeUnderTestFactory = cc.LibrarySharedFactory
-	RunBp2BuildTestCase(t, registerCcLibrarySharedModuleTypes, tc)
-}
-
-func TestCcLibrarySharedSimple(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared simple overall test",
-		Filesystem: map[string]string{
-			// NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
-			"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": "",
-			// NOTE: local_include_dir headers *should not* appear in Bazel hdrs later (?)
-			"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": "",
-			// NOTE: export_include_dir headers *should* appear in Bazel hdrs later
-			"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": "",
-			// NOTE: Soong implicitly includes headers in the current directory
-			"implicit_include_1.h": "",
-			"implicit_include_2.h": "",
-		},
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_headers {
-    name: "header_lib_1",
-    export_include_dirs: ["header_lib_1"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_headers {
-    name: "header_lib_2",
-    export_include_dirs: ["header_lib_2"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_shared {
-    name: "shared_lib_1",
-    srcs: ["shared_lib_1.cc"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_shared {
-    name: "shared_lib_2",
-    srcs: ["shared_lib_2.cc"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "whole_static_lib_1",
-    srcs: ["whole_static_lib_1.cc"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "whole_static_lib_2",
-    srcs: ["whole_static_lib_2.cc"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_shared {
-    name: "foo_shared",
-    srcs: [
-        "foo_shared1.cc",
-        "foo_shared2.cc",
-    ],
-    cflags: [
-        "-Dflag1",
-        "-Dflag2"
-    ],
-    shared_libs: [
-        "shared_lib_1",
-        "shared_lib_2"
-    ],
-    whole_static_libs: [
-        "whole_static_lib_1",
-        "whole_static_lib_2"
-    ],
-    include_dirs: [
-        "include_dir_1",
-        "include_dir_2",
-    ],
-    local_include_dirs: [
-        "local_include_dir_1",
-        "local_include_dir_2",
-    ],
-    export_include_dirs: [
-        "export_include_dir_1",
-        "export_include_dir_2"
-    ],
-    header_libs: [
-        "header_lib_1",
-        "header_lib_2"
-    ],
-    sdk_version: "current",
-    min_sdk_version: "29",
-
-    // TODO: Also support export_header_lib_headers
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
-				"absolute_includes": `[
-        "include_dir_1",
-        "include_dir_2",
-    ]`,
-				"copts": `[
-        "-Dflag1",
-        "-Dflag2",
-    ]`,
-				"export_includes": `[
-        "export_include_dir_1",
-        "export_include_dir_2",
-    ]`,
-				"implementation_deps": `[
-        ":header_lib_1",
-        ":header_lib_2",
-    ]`,
-				"implementation_dynamic_deps": `[
-        ":shared_lib_1",
-        ":shared_lib_2",
-    ]`,
-				"local_includes": `[
-        "local_include_dir_1",
-        "local_include_dir_2",
-        ".",
-    ]`,
-				"srcs": `[
-        "foo_shared1.cc",
-        "foo_shared2.cc",
-    ]`,
-				"whole_archive_deps": `[
-        ":whole_static_lib_1",
-        ":whole_static_lib_2",
-    ]`,
-				"sdk_version":     `"current"`,
-				"min_sdk_version": `"29"`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedArchSpecificSharedLib(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared arch-specific shared_libs with whole_static_libs",
-		Filesystem:  map[string]string{},
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_static {
-    name: "static_dep",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_shared {
-    name: "shared_dep",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_shared {
-    name: "foo_shared",
-    arch: { arm64: { shared_libs: ["shared_dep"], whole_static_libs: ["static_dep"] } },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
-				"implementation_dynamic_deps": `select({
-        "//build/bazel/platforms/arch:arm64": [":shared_dep"],
-        "//conditions:default": [],
-    })`,
-				"whole_archive_deps": `select({
-        "//build/bazel/platforms/arch:arm64": [":static_dep"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedOsSpecificSharedLib(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared os-specific shared_libs",
-		Filesystem:  map[string]string{},
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_shared {
-    name: "shared_dep",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_shared {
-    name: "foo_shared",
-    target: { android: { shared_libs: ["shared_dep"], } },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
-				"implementation_dynamic_deps": `select({
-        "//build/bazel/platforms/os:android": [":shared_dep"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedBaseArchOsSpecificSharedLib(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared base, arch, and os-specific shared_libs",
-		Filesystem:  map[string]string{},
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_shared {
-    name: "shared_dep",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_shared {
-    name: "shared_dep2",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_shared {
-    name: "shared_dep3",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_shared {
-    name: "foo_shared",
-    shared_libs: ["shared_dep"],
-    target: { android: { shared_libs: ["shared_dep2"] } },
-    arch: { arm64: { shared_libs: ["shared_dep3"] } },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
-				"implementation_dynamic_deps": `[":shared_dep"] + select({
-        "//build/bazel/platforms/arch:arm64": [":shared_dep3"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/os:android": [":shared_dep2"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedSimpleExcludeSrcs(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared simple exclude_srcs",
-		Filesystem: map[string]string{
-			"common.c":       "",
-			"foo-a.c":        "",
-			"foo-excluded.c": "",
-		},
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_shared {
-    name: "foo_shared",
-    srcs: ["common.c", "foo-*.c"],
-    exclude_srcs: ["foo-excluded.c"],
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
-				"srcs_c": `[
-        "common.c",
-        "foo-a.c",
-    ]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedStrip(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared stripping",
-		Filesystem:  map[string]string{},
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_shared {
-    name: "foo_shared",
-    strip: {
-        keep_symbols: false,
-        keep_symbols_and_debug_frame: true,
-        keep_symbols_list: ["sym", "sym2"],
-        all: true,
-        none: false,
-    },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
-				"strip": `{
-        "all": True,
-        "keep_symbols": False,
-        "keep_symbols_and_debug_frame": True,
-        "keep_symbols_list": [
-            "sym",
-            "sym2",
-        ],
-        "none": False,
-    }`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedVersionScriptAndDynamicList(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared version script and dynamic list",
-		Filesystem: map[string]string{
-			"version_script": "",
-			"dynamic.list":   "",
-		},
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_shared {
-    name: "foo_shared",
-    version_script: "version_script",
-    dynamic_list: "dynamic.list",
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
-				"additional_linker_inputs": `[
-        "version_script",
-        "dynamic.list",
-    ]`,
-				"linkopts": `[
-        "-Wl,--version-script,$(location version_script)",
-        "-Wl,--dynamic-list,$(location dynamic.list)",
-    ]`,
-				"features": `["android_cfi_exports_map"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryLdflagsSplitBySpaceSoongAdded(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "ldflags are split by spaces except for the ones added by soong (version script and dynamic list)",
-		Filesystem: map[string]string{
-			"version_script": "",
-			"dynamic.list":   "",
-		},
-		Blueprint: `
-cc_library_shared {
-    name: "foo",
-    ldflags: [
-        "--nospace_flag",
-        "-z spaceflag",
-    ],
-    version_script: "version_script",
-    dynamic_list: "dynamic.list",
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"additional_linker_inputs": `[
-        "version_script",
-        "dynamic.list",
-    ]`,
-				"linkopts": `[
-        "--nospace_flag",
-        "-z",
-        "spaceflag",
-        "-Wl,--version-script,$(location version_script)",
-        "-Wl,--dynamic-list,$(location dynamic.list)",
-    ]`,
-				"features": `["android_cfi_exports_map"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedNoCrtTrue(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared - nocrt: true disables feature",
-		Filesystem: map[string]string{
-			"impl.cpp": "",
-		},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library_shared {
-    name: "foo_shared",
-    srcs: ["impl.cpp"],
-    nocrt: true,
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
-				"features": `["-link_crt"]`,
-				"srcs":     `["impl.cpp"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedNoCrtFalse(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared - nocrt: false doesn't disable feature",
-		Filesystem: map[string]string{
-			"impl.cpp": "",
-		},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library_shared {
-    name: "foo_shared",
-    srcs: ["impl.cpp"],
-    nocrt: false,
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
-				"srcs": `["impl.cpp"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedNoCrtArchVariant(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared - nocrt in select",
-		Filesystem: map[string]string{
-			"impl.cpp": "",
-		},
-		Blueprint: soongCcLibraryPreamble + `
-cc_library_shared {
-    name: "foo_shared",
-    srcs: ["impl.cpp"],
-    arch: {
-        arm: {
-            nocrt: true,
-        },
-        x86: {
-            nocrt: false,
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
-				"features": `select({
-        "//build/bazel/platforms/arch:arm": ["-link_crt"],
-        "//conditions:default": [],
-    })`,
-				"srcs": `["impl.cpp"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedProto(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Blueprint: soongCcProtoPreamble + `cc_library_shared {
-	name: "foo",
-	srcs: ["foo.proto"],
-	proto: {
-		export_proto_headers: true,
-	},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-				"srcs": `["foo.proto"]`,
-			}), MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
-				"deps": `[":foo_proto"]`,
-			}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":foo_cc_proto_lite"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedUseVersionLib(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Filesystem: map[string]string{
-			soongCcVersionLibBpPath: soongCcVersionLibBp,
-		},
-		Blueprint: soongCcProtoPreamble + `cc_library_shared {
-        name: "foo",
-        use_version_lib: true,
-        include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"use_version_lib":    "True",
-				"whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedStubs(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_shared stubs",
-		ModuleTypeUnderTest:        "cc_library_shared",
-		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		Dir:                        "foo/bar",
-		Filesystem: map[string]string{
-			"foo/bar/Android.bp": `
-cc_library_shared {
-	name: "a",
-	stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] },
-	bazel_module: { bp2build_available: true },
-	include_build_directory: false,
-}
-`,
-		},
-		Blueprint: soongCcLibraryPreamble,
-		ExpectedBazelTargets: []string{makeCcStubSuiteTargets("a", AttrNameToString{
-			"soname":               `"a.so"`,
-			"source_library_label": `"//foo/bar:a"`,
-			"stubs_symbol_file":    `"a.map.txt"`,
-			"stubs_versions": `[
-        "28",
-        "29",
-        "current",
-    ]`,
-		}),
-			MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
-				"stubs_symbol_file": `"a.map.txt"`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedStubs_UseImplementationInSameApex(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_shared stubs",
-		ModuleTypeUnderTest:        "cc_library_shared",
-		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_shared {
-	name: "a",
-	stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] },
-	bazel_module: { bp2build_available: false },
-	include_build_directory: false,
-	apex_available: ["made_up_apex"],
-}
-cc_library_shared {
-	name: "b",
-	shared_libs: [":a"],
-	include_build_directory: false,
-	apex_available: ["made_up_apex"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
-				"implementation_dynamic_deps": `[":a"]`,
-				"tags":                        `["apex_available=made_up_apex"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedStubs_UseStubsInDifferentApex(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_shared stubs",
-		ModuleTypeUnderTest:        "cc_library_shared",
-		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_shared {
-	name: "a",
-	stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] },
-	bazel_module: { bp2build_available: false },
-	include_build_directory: false,
-	apex_available: ["apex_a"],
-}
-cc_library_shared {
-	name: "b",
-	shared_libs: [":a"],
-	include_build_directory: false,
-	apex_available: ["apex_b"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
-				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:apex_b": ["@api_surfaces//module-libapi/current:a"],
-        "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:a"],
-        "//conditions:default": [":a"],
-    })`,
-				"tags": `["apex_available=apex_b"]`,
-			}),
-		},
-	})
-}
-
-// Tests that library in apexfoo links against stubs of platform_lib and otherapex_lib
-func TestCcLibrarySharedStubs_UseStubsFromMultipleApiDomains(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_shared stubs",
-		ModuleTypeUnderTest:        "cc_library_shared",
-		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_shared {
-	name: "libplatform_stable",
-	stubs: { symbol_file: "libplatform_stable.map.txt", versions: ["28", "29", "current"] },
-	apex_available: ["//apex_available:platform"],
-	bazel_module: { bp2build_available: false },
-	include_build_directory: false,
-}
-cc_library_shared {
-	name: "libapexfoo_stable",
-	stubs: { symbol_file: "libapexfoo_stable.map.txt", versions: ["28", "29", "current"] },
-	apex_available: ["apexfoo"],
-	bazel_module: { bp2build_available: false },
-	include_build_directory: false,
-}
-cc_library_shared {
-	name: "libutils",
-	shared_libs: ["libplatform_stable", "libapexfoo_stable",],
-	apex_available: ["//apex_available:platform", "apexfoo", "apexbar"],
-	include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "libutils", AttrNameToString{
-				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:apexbar": [
-            "@api_surfaces//module-libapi/current:libplatform_stable",
-            "@api_surfaces//module-libapi/current:libapexfoo_stable",
-        ],
-        "//build/bazel/rules/apex:apexfoo": [
-            "@api_surfaces//module-libapi/current:libplatform_stable",
-            ":libapexfoo_stable",
-        ],
-        "//build/bazel/rules/apex:system": [
-            "@api_surfaces//module-libapi/current:libplatform_stable",
-            "@api_surfaces//module-libapi/current:libapexfoo_stable",
-        ],
-        "//conditions:default": [
-            ":libplatform_stable",
-            ":libapexfoo_stable",
-        ],
-    })`,
-				"tags": `[
-        "apex_available=//apex_available:platform",
-        "apex_available=apexfoo",
-        "apex_available=apexbar",
-    ]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedStubs_IgnorePlatformAvailable(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_shared stubs",
-		ModuleTypeUnderTest:        "cc_library_shared",
-		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_shared {
-	name: "a",
-	stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] },
-	bazel_module: { bp2build_available: false },
-	include_build_directory: false,
-	apex_available: ["//apex_available:platform", "apex_a"],
-}
-cc_library_shared {
-	name: "b",
-	shared_libs: [":a"],
-	include_build_directory: false,
-	apex_available: ["//apex_available:platform", "apex_b"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
-				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:apex_b": ["@api_surfaces//module-libapi/current:a"],
-        "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:a"],
-        "//conditions:default": [":a"],
-    })`,
-				"tags": `[
-        "apex_available=//apex_available:platform",
-        "apex_available=apex_b",
-    ]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryDoesNotDropStubDepIfNoVariationAcrossAxis(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library depeends on impl for all configurations",
-		ModuleTypeUnderTest:        "cc_library_shared",
-		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_shared {
-	name: "a",
-	stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] },
-	bazel_module: { bp2build_available: false },
-	apex_available: ["//apex_available:platform"],
-}
-cc_library_shared {
-	name: "b",
-	shared_libs: [":a"],
-	include_build_directory: false,
-	apex_available: ["//apex_available:platform"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
-				"implementation_dynamic_deps": `[":a"]`,
-				"tags":                        `["apex_available=//apex_available:platform"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedStubs_MultipleApexAvailable(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		ModuleTypeUnderTest:        "cc_library_shared",
-		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_shared {
-	name: "a",
-	stubs: { symbol_file: "a.map.txt", versions: ["28", "29", "current"] },
-	bazel_module: { bp2build_available: false },
-	include_build_directory: false,
-	apex_available: ["//apex_available:platform", "apex_a", "apex_b"],
-}
-cc_library_shared {
-	name: "b",
-	shared_libs: [":a"],
-	include_build_directory: false,
-	apex_available: ["//apex_available:platform", "apex_b"],
-}
-
-cc_library_shared {
-	name: "c",
-	shared_libs: [":a"],
-	include_build_directory: false,
-	apex_available: ["//apex_available:platform", "apex_a", "apex_b"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
-				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:a"],
-        "//conditions:default": [":a"],
-    })`,
-				"tags": `[
-        "apex_available=//apex_available:platform",
-        "apex_available=apex_b",
-    ]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "c", AttrNameToString{
-				"implementation_dynamic_deps": `[":a"]`,
-				"tags": `[
-        "apex_available=//apex_available:platform",
-        "apex_available=apex_a",
-        "apex_available=apex_b",
-    ]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedSystemSharedLibsSharedEmpty(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_shared system_shared_libs empty shared default",
-		ModuleTypeUnderTest:        "cc_library_shared",
-		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_defaults {
-    name: "empty_defaults",
-    shared: {
-        system_shared_libs: [],
-    },
-    include_build_directory: false,
-}
-cc_library_shared {
-    name: "empty",
-    defaults: ["empty_defaults"],
-}
-`,
-		ExpectedBazelTargets: []string{MakeBazelTarget("cc_library_shared", "empty", AttrNameToString{
-			"system_dynamic_deps": "[]",
-		})},
-	})
-}
-
-func TestCcLibrarySharedConvertLex(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_shared with lex files",
-		ModuleTypeUnderTest:        "cc_library_shared",
-		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		Filesystem: map[string]string{
-			"foo.c":   "",
-			"bar.cc":  "",
-			"foo1.l":  "",
-			"bar1.ll": "",
-			"foo2.l":  "",
-			"bar2.ll": "",
-		},
-		Blueprint: `cc_library_shared {
-	name: "foo_lib",
-	srcs: ["foo.c", "bar.cc", "foo1.l", "foo2.l", "bar1.ll", "bar2.ll"],
-	lex: { flags: ["--foo_flags"] },
-	include_build_directory: false,
-	bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("genlex", "foo_lib_genlex_l", AttrNameToString{
-				"srcs": `[
-        "foo1.l",
-        "foo2.l",
-    ]`,
-				"lexopts": `["--foo_flags"]`,
-			}),
-			MakeBazelTarget("genlex", "foo_lib_genlex_ll", AttrNameToString{
-				"srcs": `[
-        "bar1.ll",
-        "bar2.ll",
-    ]`,
-				"lexopts": `["--foo_flags"]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo_lib", AttrNameToString{
-				"srcs": `[
-        "bar.cc",
-        ":foo_lib_genlex_ll",
-    ]`,
-				"srcs_c": `[
-        "foo.c",
-        ":foo_lib_genlex_l",
-    ]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedClangUnknownFlags(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Blueprint: soongCcProtoPreamble + `cc_library_shared {
-	name: "foo",
-	conlyflags: ["-a", "-finline-functions"],
-	cflags: ["-b","-finline-functions"],
-	cppflags: ["-c", "-finline-functions"],
-	ldflags: ["-d","-finline-functions", "-e"],
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"conlyflags": `["-a"]`,
-				"copts":      `["-b"]`,
-				"cppflags":   `["-c"]`,
-				"linkopts": `[
-        "-d",
-        "-e",
-    ]`,
-			}),
-		},
-	})
-}
-
-func TestCCLibraryFlagSpaceSplitting(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Blueprint: soongCcProtoPreamble + `cc_library_shared {
-	name: "foo",
-	conlyflags: [ "-include header.h"],
-	cflags: ["-include header.h"],
-	cppflags: ["-include header.h"],
-	version_script: "version_script",
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"additional_linker_inputs": `["version_script"]`,
-				"conlyflags": `[
-        "-include",
-        "header.h",
-    ]`,
-				"copts": `[
-        "-include",
-        "header.h",
-    ]`,
-				"cppflags": `[
-        "-include",
-        "header.h",
-    ]`,
-				"linkopts": `["-Wl,--version-script,$(location version_script)"]`,
-				"features": `["android_cfi_exports_map"]`,
-			}),
-		},
-	})
-}
-
-func TestCCLibrarySharedRuntimeDeps(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Blueprint: `cc_library_shared {
-	name: "bar",
-}
-
-cc_library_shared {
-  name: "foo",
-  runtime_libs: ["foo"],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "bar", AttrNameToString{
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"runtime_deps":   `[":foo"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedEmptySuffix(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared with empty suffix",
-		Filesystem: map[string]string{
-			"foo.c": "",
-		},
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_shared {
-    name: "foo_shared",
-    suffix: "",
-    srcs: ["foo.c"],
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
-				"srcs_c": `["foo.c"]`,
-				"suffix": `""`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedSuffix(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared with suffix",
-		Filesystem: map[string]string{
-			"foo.c": "",
-		},
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_shared {
-    name: "foo_shared",
-    suffix: "-suf",
-    srcs: ["foo.c"],
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
-				"srcs_c": `["foo.c"]`,
-				"suffix": `"-suf"`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedArchVariantSuffix(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared with arch-variant suffix",
-		Filesystem: map[string]string{
-			"foo.c": "",
-		},
-		Blueprint: soongCcLibrarySharedPreamble + `
-cc_library_shared {
-    name: "foo_shared",
-    arch: {
-        arm64: { suffix: "-64" },
-        arm:   { suffix: "-32" },
-		},
-    srcs: ["foo.c"],
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
-				"srcs_c": `["foo.c"]`,
-				"suffix": `select({
-        "//build/bazel/platforms/arch:arm": "-32",
-        "//build/bazel/platforms/arch:arm64": "-64",
-        "//conditions:default": None,
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedWithSyspropSrcs(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared with sysprop sources",
-		Blueprint: `
-cc_library_shared {
-	name: "foo",
-	srcs: [
-		"bar.sysprop",
-		"baz.sysprop",
-		"blah.cpp",
-	],
-	min_sdk_version: "5",
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("sysprop_library", "foo_sysprop_library", AttrNameToString{
-				"srcs": `[
-        "bar.sysprop",
-        "baz.sysprop",
-    ]`,
-			}),
-			MakeBazelTarget("cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
-				"dep":             `":foo_sysprop_library"`,
-				"min_sdk_version": `"5"`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"srcs":               `["blah.cpp"]`,
-				"local_includes":     `["."]`,
-				"min_sdk_version":    `"5"`,
-				"whole_archive_deps": `[":foo_cc_sysprop_library_static"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedWithSyspropSrcsSomeConfigs(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared with sysprop sources in some configs but not others",
-		Blueprint: `
-cc_library_shared {
-	name: "foo",
-	srcs: [
-		"blah.cpp",
-	],
-	target: {
-		android: {
-			srcs: ["bar.sysprop"],
-		},
-	},
-	min_sdk_version: "5",
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("sysprop_library", "foo_sysprop_library", AttrNameToString{
-				"srcs": `select({
-        "//build/bazel/platforms/os:android": ["bar.sysprop"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
-				"dep":             `":foo_sysprop_library"`,
-				"min_sdk_version": `"5"`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"srcs":            `["blah.cpp"]`,
-				"local_includes":  `["."]`,
-				"min_sdk_version": `"5"`,
-				"whole_archive_deps": `select({
-        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedHeaderAbiChecker(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared with header abi checker",
-		Blueprint: `cc_library_shared {
-    name: "foo",
-    header_abi_checker: {
-        enabled: true,
-        symbol_file: "a.map.txt",
-        exclude_symbol_versions: [
-						"29",
-						"30",
-				],
-        exclude_symbol_tags: [
-						"tag1",
-						"tag2",
-				],
-        check_all_apis: true,
-        diff_flags: ["-allow-adding-removing-weak-symbols"],
-    },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"abi_checker_enabled":     `True`,
-				"abi_checker_symbol_file": `"a.map.txt"`,
-				"abi_checker_exclude_symbol_versions": `[
-        "29",
-        "30",
-    ]`,
-				"abi_checker_exclude_symbol_tags": `[
-        "tag1",
-        "tag2",
-    ]`,
-				"abi_checker_check_all_apis": `True`,
-				"abi_checker_diff_flags":     `["-allow-adding-removing-weak-symbols"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedWithIntegerOverflowProperty(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared has correct features when integer_overflow property is provided",
-		Blueprint: `
-cc_library_shared {
-		name: "foo",
-		sanitize: {
-				integer_overflow: true,
-		},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["ubsan_integer_overflow"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedWithMiscUndefinedProperty(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared has correct features when misc_undefined property is provided",
-		Blueprint: `
-cc_library_shared {
-		name: "foo",
-		sanitize: {
-				misc_undefined: ["undefined", "nullability"],
-		},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features": `[
-        "ubsan_undefined",
-        "ubsan_nullability",
-    ]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedWithUBSanPropertiesArchSpecific(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared has correct feature select when UBSan props are specified in arch specific blocks",
-		Blueprint: `
-cc_library_shared {
-		name: "foo",
-		sanitize: {
-				misc_undefined: ["undefined", "nullability"],
-		},
-		target: {
-				android: {
-						sanitize: {
-								misc_undefined: ["alignment"],
-						},
-				},
-				linux_glibc: {
-						sanitize: {
-								integer_overflow: true,
-						},
-				},
-		},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features": `[
-        "ubsan_undefined",
-        "ubsan_nullability",
-    ] + select({
-        "//build/bazel/platforms/os:android": ["ubsan_alignment"],
-        "//build/bazel/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedWithSanitizerBlocklist(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared has correct features when sanitize.blocklist is provided",
-		Blueprint: `
-cc_library_shared {
-	name: "foo",
-	sanitize: {
-		blocklist: "foo_blocklist.txt",
-	},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedWithThinLto(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared has correct features when thin lto is enabled",
-		Blueprint: `
-cc_library_shared {
-	name: "foo",
-	lto: {
-		thin: true,
-	},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["android_thin_lto"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedWithLtoNever(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared has correct features when thin lto is enabled",
-		Blueprint: `
-cc_library_shared {
-	name: "foo",
-	lto: {
-		never: true,
-	},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["-android_thin_lto"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedWithThinLtoArchSpecific(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared has correct features when LTO differs across arch and os variants",
-		Blueprint: `
-cc_library_shared {
-	name: "foo",
-	target: {
-		android: {
-			lto: {
-				thin: true,
-			},
-		},
-	},
-	arch: {
-		riscv64: {
-			lto: {
-				thin: false,
-			},
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
-        "//conditions:default": [],
-    })`}),
-		},
-	})
-}
-
-func TestCcLibrarySharedWithThinLtoDisabledDefaultEnabledVariant(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared with thin lto disabled by default but enabled on a particular variant",
-		Blueprint: `
-cc_library_shared {
-	name: "foo",
-	lto: {
-		never: true,
-	},
-	target: {
-		android: {
-			lto: {
-				thin: true,
-				never: false,
-			},
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_thin_lto"],
-        "//conditions:default": ["-android_thin_lto"],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedWithThinLtoAndWholeProgramVtables(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared has correct features when thin LTO is enabled with whole_program_vtables",
-		Blueprint: `
-cc_library_shared {
-	name: "foo",
-	lto: {
-		thin: true,
-	},
-	whole_program_vtables: true,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features": `[
-        "android_thin_lto",
-        "android_thin_lto_whole_program_vtables",
-    ]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedHiddenVisibilityConvertedToFeature(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared changes hidden visibility flag to feature",
-		Blueprint: `
-cc_library_shared{
-	name: "foo",
-	cflags: ["-fvisibility=hidden"],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["visibility_hidden"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared changes hidden visibility flag to feature for specific os",
-		Blueprint: `
-cc_library_shared{
-	name: "foo",
-	target: {
-		android: {
-			cflags: ["-fvisibility=hidden"],
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["visibility_hidden"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedStubsDessertVersionConversion(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared converts dessert codename versions to numerical versions",
-		Blueprint: `
-cc_library_shared {
-	name: "a",
-	include_build_directory: false,
-	stubs: {
-		symbol_file: "a.map.txt",
-		versions: [
-			"Q",
-			"R",
-			"31",
-		],
-	},
-}
-cc_library_shared {
-	name: "b",
-	include_build_directory: false,
-	stubs: {
-		symbol_file: "b.map.txt",
-		versions: [
-			"Q",
-			"R",
-			"31",
-			"current",
-		],
-	},
-}
-`,
-		ExpectedBazelTargets: []string{
-			makeCcStubSuiteTargets("a", AttrNameToString{
-				"soname":               `"a.so"`,
-				"source_library_label": `"//:a"`,
-				"stubs_symbol_file":    `"a.map.txt"`,
-				"stubs_versions": `[
-        "29",
-        "30",
-        "31",
-        "current",
-    ]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
-				"stubs_symbol_file": `"a.map.txt"`,
-			}),
-			makeCcStubSuiteTargets("b", AttrNameToString{
-				"soname":               `"b.so"`,
-				"source_library_label": `"//:b"`,
-				"stubs_symbol_file":    `"b.map.txt"`,
-				"stubs_versions": `[
-        "29",
-        "30",
-        "31",
-        "current",
-    ]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "b", AttrNameToString{
-				"stubs_symbol_file": `"b.map.txt"`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedWithCfi(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared has correct features when cfi is enabled for specific variants",
-		Blueprint: `
-cc_library_shared {
-	name: "foo",
-	sanitize: {
-		cfi: true,
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["android_cfi"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedWithCfiOsSpecific(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared has correct features when cfi is enabled",
-		Blueprint: `
-cc_library_shared {
-	name: "foo",
-	target: {
-		android: {
-			sanitize: {
-				cfi: true,
-			},
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_cfi"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedWithCfiAndCfiAssemblySupport(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared has correct features when cfi is enabled with cfi assembly support",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	sanitize: {
-		cfi: true,
-		config: {
-			cfi_assembly_support: true,
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features": `[
-        "android_cfi",
-        "android_cfi_assembly_support",
-    ]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySharedExplicitlyDisablesCfiWhenFalse(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_shared disables cfi when explciitly set to false in the bp",
-		Blueprint: `
-cc_library_shared {
-	name: "foo",
-	sanitize: {
-		cfi: false,
-	},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["-android_cfi"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCCLibrarySharedRscriptSrc(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: ``,
-		Blueprint: `
-cc_library_shared{
-    name : "foo",
-    srcs : [
-        "ccSrc.cc",
-        "rsSrc.rscript",
-    ],
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("rscript_to_cpp", "foo_renderscript", AttrNameToString{
-				"srcs": `["rsSrc.rscript"]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"absolute_includes": `[
-        "frameworks/rs",
-        "frameworks/rs/cpp",
-    ]`,
-				"local_includes": `["."]`,
-				"srcs": `[
-        "ccSrc.cc",
-        "foo_renderscript",
-    ]`,
-			})}})
-}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
deleted file mode 100644
index 26baf89..0000000
--- a/bp2build/cc_library_static_conversion_test.go
+++ /dev/null
@@ -1,2284 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"fmt"
-	"testing"
-
-	"android/soong/android"
-	"android/soong/cc"
-	"android/soong/genrule"
-)
-
-const (
-	// See cc/testing.go for more context
-	soongCcLibraryStaticPreamble = `
-cc_defaults {
-    name: "linux_bionic_supported",
-}`
-)
-
-func TestCcLibraryStaticLoadStatement(t *testing.T) {
-	testCases := []struct {
-		bazelTargets           BazelTargets
-		expectedLoadStatements string
-	}{
-		{
-			bazelTargets: BazelTargets{
-				BazelTarget{
-					name:      "cc_library_static_target",
-					ruleClass: "cc_library_static",
-					// NOTE: No bzlLoadLocation for native rules
-				},
-			},
-			expectedLoadStatements: ``,
-		},
-	}
-
-	for _, testCase := range testCases {
-		actual := testCase.bazelTargets.LoadStatements()
-		expected := testCase.expectedLoadStatements
-		if actual != expected {
-			t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
-		}
-	}
-}
-
-func registerCcLibraryStaticModuleTypes(ctx android.RegistrationContext) {
-	cc.RegisterCCBuildComponents(ctx)
-	ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
-	ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
-	// Required for system_shared_libs dependencies.
-	ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
-}
-
-func runCcLibraryStaticTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-
-	(&tc).ModuleTypeUnderTest = "cc_library_static"
-	(&tc).ModuleTypeUnderTestFactory = cc.LibraryStaticFactory
-	RunBp2BuildTestCase(t, registerCcLibraryStaticModuleTypes, tc)
-}
-
-func TestCcLibraryStaticSimple(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static test",
-		Filesystem: map[string]string{
-			// NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
-			"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": "",
-			// NOTE: local_include_dir headers *should not* appear in Bazel hdrs later (?)
-			"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": "",
-			// NOTE: export_include_dir headers *should* appear in Bazel hdrs later
-			"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": "",
-			// NOTE: Soong implicitly includes headers in the current directory
-			"implicit_include_1.h": "",
-			"implicit_include_2.h": "",
-		},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_headers {
-    name: "header_lib_1",
-    export_include_dirs: ["header_lib_1"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_headers {
-    name: "header_lib_2",
-    export_include_dirs: ["header_lib_2"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "static_lib_1",
-    srcs: ["static_lib_1.cc"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "static_lib_2",
-    srcs: ["static_lib_2.cc"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "whole_static_lib_1",
-    srcs: ["whole_static_lib_1.cc"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "whole_static_lib_2",
-    srcs: ["whole_static_lib_2.cc"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "foo_static",
-    srcs: [
-        "foo_static1.cc",
-        "foo_static2.cc",
-    ],
-    cflags: [
-        "-Dflag1",
-        "-Dflag2"
-    ],
-    static_libs: [
-        "static_lib_1",
-        "static_lib_2"
-    ],
-    whole_static_libs: [
-        "whole_static_lib_1",
-        "whole_static_lib_2"
-    ],
-    include_dirs: [
-        "include_dir_1",
-        "include_dir_2",
-    ],
-    local_include_dirs: [
-        "local_include_dir_1",
-        "local_include_dir_2",
-    ],
-    export_include_dirs: [
-        "export_include_dir_1",
-        "export_include_dir_2"
-    ],
-    header_libs: [
-        "header_lib_1",
-        "header_lib_2"
-    ],
-    sdk_version: "current",
-    min_sdk_version: "29",
-
-    // TODO: Also support export_header_lib_headers
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"absolute_includes": `[
-        "include_dir_1",
-        "include_dir_2",
-    ]`,
-				"copts": `[
-        "-Dflag1",
-        "-Dflag2",
-    ]`,
-				"export_includes": `[
-        "export_include_dir_1",
-        "export_include_dir_2",
-    ]`,
-				"implementation_deps": `[
-        ":header_lib_1",
-        ":header_lib_2",
-        ":static_lib_1",
-        ":static_lib_2",
-    ]`,
-				"local_includes": `[
-        "local_include_dir_1",
-        "local_include_dir_2",
-        ".",
-    ]`,
-				"srcs": `[
-        "foo_static1.cc",
-        "foo_static2.cc",
-    ]`,
-				"whole_archive_deps": `[
-        ":whole_static_lib_1",
-        ":whole_static_lib_2",
-    ]`,
-				"sdk_version":     `"current"`,
-				"min_sdk_version": `"29"`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticSubpackage(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static subpackage test",
-		Filesystem: map[string]string{
-			// subpackage with subdirectory
-			"subpackage/Android.bp":                         "",
-			"subpackage/subpackage_header.h":                "",
-			"subpackage/subdirectory/subdirectory_header.h": "",
-			// subsubpackage with subdirectory
-			"subpackage/subsubpackage/Android.bp":                         "",
-			"subpackage/subsubpackage/subsubpackage_header.h":             "",
-			"subpackage/subsubpackage/subdirectory/subdirectory_header.h": "",
-			// subsubsubpackage with subdirectory
-			"subpackage/subsubpackage/subsubsubpackage/Android.bp":                         "",
-			"subpackage/subsubpackage/subsubsubpackage/subsubsubpackage_header.h":          "",
-			"subpackage/subsubpackage/subsubsubpackage/subdirectory/subdirectory_header.h": "",
-		},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    srcs: [],
-    include_dirs: [
-        "subpackage",
-    ],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"absolute_includes": `["subpackage"]`,
-				"local_includes":    `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticExportIncludeDir(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static export include dir",
-		Filesystem: map[string]string{
-			// subpackage with subdirectory
-			"subpackage/Android.bp":                         "",
-			"subpackage/subpackage_header.h":                "",
-			"subpackage/subdirectory/subdirectory_header.h": "",
-		},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    export_include_dirs: ["subpackage"],
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"export_includes": `["subpackage"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticExportSystemIncludeDir(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static export system include dir",
-		Filesystem: map[string]string{
-			// subpackage with subdirectory
-			"subpackage/Android.bp":                         "",
-			"subpackage/subpackage_header.h":                "",
-			"subpackage/subdirectory/subdirectory_header.h": "",
-		},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    export_system_include_dirs: ["subpackage"],
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"export_system_includes": `["subpackage"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticManyIncludeDirs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static include_dirs, local_include_dirs, export_include_dirs (b/183742505)",
-		Dir:         "subpackage",
-		Filesystem: map[string]string{
-			// subpackage with subdirectory
-			"subpackage/Android.bp": `
-cc_library_static {
-    name: "foo_static",
-    // include_dirs are workspace/root relative
-    include_dirs: [
-        "subpackage/subsubpackage",
-        "subpackage2",
-        "subpackage3/subsubpackage"
-    ],
-    local_include_dirs: ["subsubpackage2"], // module dir relative
-    export_include_dirs: ["./exported_subsubpackage"], // module dir relative
-    include_build_directory: true,
-    bazel_module: { bp2build_available: true },
-}`,
-			"subpackage/subsubpackage/header.h":          "",
-			"subpackage/subsubpackage2/header.h":         "",
-			"subpackage/exported_subsubpackage/header.h": "",
-			"subpackage2/header.h":                       "",
-			"subpackage3/subsubpackage/header.h":         "",
-		},
-		Blueprint: soongCcLibraryStaticPreamble,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"absolute_includes": `[
-        "subpackage/subsubpackage",
-        "subpackage2",
-        "subpackage3/subsubpackage",
-    ]`,
-				"export_includes": `["./exported_subsubpackage"]`,
-				"local_includes": `[
-        "subsubpackage2",
-        ".",
-    ]`,
-			})},
-	})
-}
-
-func TestCcLibraryStaticIncludeBuildDirectoryDisabled(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static include_build_directory disabled",
-		Filesystem: map[string]string{
-			// subpackage with subdirectory
-			"subpackage/Android.bp":                         "",
-			"subpackage/subpackage_header.h":                "",
-			"subpackage/subdirectory/subdirectory_header.h": "",
-		},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    include_dirs: ["subpackage"], // still used, but local_include_dirs is recommended
-    local_include_dirs: ["subpackage2"],
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"absolute_includes": `["subpackage"]`,
-				"local_includes":    `["subpackage2"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticIncludeBuildDirectoryEnabled(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static include_build_directory enabled",
-		Filesystem: map[string]string{
-			// subpackage with subdirectory
-			"subpackage/Android.bp":                         "",
-			"subpackage/subpackage_header.h":                "",
-			"subpackage2/Android.bp":                        "",
-			"subpackage2/subpackage2_header.h":              "",
-			"subpackage/subdirectory/subdirectory_header.h": "",
-		},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    include_dirs: ["subpackage"], // still used, but local_include_dirs is recommended
-    local_include_dirs: ["subpackage2"],
-    include_build_directory: true,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"absolute_includes": `["subpackage"]`,
-				"local_includes": `[
-        "subpackage2",
-        ".",
-    ]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticArchSpecificStaticLib(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static arch-specific static_libs",
-		Filesystem:  map[string]string{},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "static_dep",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_static {
-    name: "static_dep2",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_static {
-    name: "foo_static",
-    arch: { arm64: { static_libs: ["static_dep"], whole_static_libs: ["static_dep2"] } },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"implementation_deps": `select({
-        "//build/bazel/platforms/arch:arm64": [":static_dep"],
-        "//conditions:default": [],
-    })`,
-				"whole_archive_deps": `select({
-        "//build/bazel/platforms/arch:arm64": [":static_dep2"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticOsSpecificStaticLib(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static os-specific static_libs",
-		Filesystem:  map[string]string{},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "static_dep",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_static {
-    name: "static_dep2",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_static {
-    name: "foo_static",
-    target: { android: { static_libs: ["static_dep"], whole_static_libs: ["static_dep2"] } },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"implementation_deps": `select({
-        "//build/bazel/platforms/os:android": [":static_dep"],
-        "//conditions:default": [],
-    })`,
-				"whole_archive_deps": `select({
-        "//build/bazel/platforms/os:android": [":static_dep2"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticBaseArchOsSpecificStaticLib(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static base, arch and os-specific static_libs",
-		Filesystem:  map[string]string{},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "static_dep",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_static {
-    name: "static_dep2",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_static {
-    name: "static_dep3",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_static {
-    name: "static_dep4",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_static {
-    name: "foo_static",
-    static_libs: ["static_dep"],
-    whole_static_libs: ["static_dep2"],
-    target: { android: { static_libs: ["static_dep3"] } },
-    arch: { arm64: { static_libs: ["static_dep4"] } },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"implementation_deps": `[":static_dep"] + select({
-        "//build/bazel/platforms/arch:arm64": [":static_dep4"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/os:android": [":static_dep3"],
-        "//conditions:default": [],
-    })`,
-				"whole_archive_deps": `[":static_dep2"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticSimpleExcludeSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static simple exclude_srcs",
-		Filesystem: map[string]string{
-			"common.c":       "",
-			"foo-a.c":        "",
-			"foo-excluded.c": "",
-		},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    srcs: ["common.c", "foo-*.c"],
-    exclude_srcs: ["foo-excluded.c"],
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"srcs_c": `[
-        "common.c",
-        "foo-a.c",
-    ]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticOneArchSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static one arch specific srcs",
-		Filesystem: map[string]string{
-			"common.c":  "",
-			"foo-arm.c": "",
-		},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    srcs: ["common.c"],
-    arch: { arm: { srcs: ["foo-arm.c"] } },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"srcs_c": `["common.c"] + select({
-        "//build/bazel/platforms/arch:arm": ["foo-arm.c"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticOneArchSrcsExcludeSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static one arch specific srcs and exclude_srcs",
-		Filesystem: map[string]string{
-			"common.c":           "",
-			"for-arm.c":          "",
-			"not-for-arm.c":      "",
-			"not-for-anything.c": "",
-		},
-		Blueprint: 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"] },
-    },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"srcs_c": `["common.c"] + select({
-        "//build/bazel/platforms/arch:arm": ["for-arm.c"],
-        "//conditions:default": ["not-for-arm.c"],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticTwoArchExcludeSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static arch specific exclude_srcs for 2 architectures",
-		Filesystem: map[string]string{
-			"common.c":      "",
-			"for-arm.c":     "",
-			"for-x86.c":     "",
-			"not-for-arm.c": "",
-			"not-for-x86.c": "",
-		},
-		Blueprint: 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"] },
-    },
-    include_build_directory: false,
-} `,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"srcs_c": `["common.c"] + select({
-        "//build/bazel/platforms/arch:arm": [
-            "not-for-x86.c",
-            "for-arm.c",
-        ],
-        "//build/bazel/platforms/arch:x86": [
-            "not-for-arm.c",
-            "for-x86.c",
-        ],
-        "//conditions:default": [
-            "not-for-arm.c",
-            "not-for-x86.c",
-        ],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticFourArchExcludeSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static arch specific exclude_srcs for 4 architectures",
-		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": "",
-		},
-		Blueprint: 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"] },
-  },
-    include_build_directory: false,
-} `,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"srcs_c": `["common.c"] + select({
-        "//build/bazel/platforms/arch:arm": [
-            "not-for-arm64.c",
-            "not-for-x86.c",
-            "not-for-x86_64.c",
-            "for-arm.c",
-        ],
-        "//build/bazel/platforms/arch:arm64": [
-            "not-for-arm.c",
-            "not-for-x86.c",
-            "not-for-x86_64.c",
-            "for-arm64.c",
-        ],
-        "//build/bazel/platforms/arch:x86": [
-            "not-for-arm.c",
-            "not-for-arm64.c",
-            "not-for-x86_64.c",
-            "for-x86.c",
-        ],
-        "//build/bazel/platforms/arch:x86_64": [
-            "not-for-arm.c",
-            "not-for-arm64.c",
-            "not-for-x86.c",
-            "for-x86_64.c",
-        ],
-        "//conditions:default": [
-            "not-for-arm.c",
-            "not-for-arm64.c",
-            "not-for-x86.c",
-            "not-for-x86_64.c",
-        ],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticOneArchEmpty(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static one arch empty",
-		Filesystem: map[string]string{
-			"common.cc":       "",
-			"foo-no-arm.cc":   "",
-			"foo-excluded.cc": "",
-		},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    srcs: ["common.cc", "foo-*.cc"],
-    exclude_srcs: ["foo-excluded.cc"],
-    arch: {
-        arm: { exclude_srcs: ["foo-no-arm.cc"] },
-    },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"srcs": `["common.cc"] + select({
-        "//build/bazel/platforms/arch:arm": [],
-        "//conditions:default": ["foo-no-arm.cc"],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticOneArchEmptyOtherSet(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static one arch empty other set",
-		Filesystem: map[string]string{
-			"common.cc":       "",
-			"foo-no-arm.cc":   "",
-			"x86-only.cc":     "",
-			"foo-excluded.cc": "",
-		},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    srcs: ["common.cc", "foo-*.cc"],
-    exclude_srcs: ["foo-excluded.cc"],
-    arch: {
-        arm: { exclude_srcs: ["foo-no-arm.cc"] },
-        x86: { srcs: ["x86-only.cc"] },
-    },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"srcs": `["common.cc"] + select({
-        "//build/bazel/platforms/arch:arm": [],
-        "//build/bazel/platforms/arch:x86": [
-            "foo-no-arm.cc",
-            "x86-only.cc",
-        ],
-        "//conditions:default": ["foo-no-arm.cc"],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticMultipleDepSameName(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static multiple dep same name panic",
-		Filesystem:  map[string]string{},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "static_dep",
-    bazel_module: { bp2build_available: false },
-}
-cc_library_static {
-    name: "foo_static",
-    static_libs: ["static_dep", "static_dep"],
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"implementation_deps": `[":static_dep"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticOneMultilibSrcsExcludeSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static 1 multilib srcs and exclude_srcs",
-		Filesystem: map[string]string{
-			"common.c":        "",
-			"for-lib32.c":     "",
-			"not-for-lib32.c": "",
-		},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    srcs: ["common.c", "not-for-*.c"],
-    multilib: {
-        lib32: { srcs: ["for-lib32.c"], exclude_srcs: ["not-for-lib32.c"] },
-    },
-    include_build_directory: false,
-} `,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"srcs_c": `["common.c"] + select({
-        "//build/bazel/platforms/arch:arm": ["for-lib32.c"],
-        "//build/bazel/platforms/arch:x86": ["for-lib32.c"],
-        "//conditions:default": ["not-for-lib32.c"],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticTwoMultilibSrcsExcludeSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static 2 multilib srcs and exclude_srcs",
-		Filesystem: map[string]string{
-			"common.c":        "",
-			"for-lib32.c":     "",
-			"for-lib64.c":     "",
-			"not-for-lib32.c": "",
-			"not-for-lib64.c": "",
-		},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    srcs: ["common.c", "not-for-*.c"],
-    multilib: {
-        lib32: { srcs: ["for-lib32.c"], exclude_srcs: ["not-for-lib32.c"] },
-        lib64: { srcs: ["for-lib64.c"], exclude_srcs: ["not-for-lib64.c"] },
-    },
-    include_build_directory: false,
-} `,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"srcs_c": `["common.c"] + select({
-        "//build/bazel/platforms/arch:arm": [
-            "not-for-lib64.c",
-            "for-lib32.c",
-        ],
-        "//build/bazel/platforms/arch:arm64": [
-            "not-for-lib32.c",
-            "for-lib64.c",
-        ],
-        "//build/bazel/platforms/arch:riscv64": [
-            "not-for-lib32.c",
-            "for-lib64.c",
-        ],
-        "//build/bazel/platforms/arch:x86": [
-            "not-for-lib64.c",
-            "for-lib32.c",
-        ],
-        "//build/bazel/platforms/arch:x86_64": [
-            "not-for-lib32.c",
-            "for-lib64.c",
-        ],
-        "//conditions:default": [
-            "not-for-lib32.c",
-            "not-for-lib64.c",
-        ],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarySTaticArchMultilibSrcsExcludeSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static arch and multilib srcs and exclude_srcs",
-		Filesystem: map[string]string{
-			"common.c":             "",
-			"for-arm.c":            "",
-			"for-arm64.c":          "",
-			"for-x86.c":            "",
-			"for-x86_64.c":         "",
-			"for-lib32.c":          "",
-			"for-lib64.c":          "",
-			"not-for-arm.c":        "",
-			"not-for-arm64.c":      "",
-			"not-for-riscv64.c":    "",
-			"not-for-x86.c":        "",
-			"not-for-x86_64.c":     "",
-			"not-for-lib32.c":      "",
-			"not-for-lib64.c":      "",
-			"not-for-everything.c": "",
-		},
-		Blueprint: 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"] },
-       riscv64: { srcs: ["for-riscv64.c"], exclude_srcs: ["not-for-riscv64.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"] },
-   },
-   multilib: {
-       lib32: { srcs: ["for-lib32.c"], exclude_srcs: ["not-for-lib32.c"] },
-       lib64: { srcs: ["for-lib64.c"], exclude_srcs: ["not-for-lib64.c"] },
-   },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"srcs_c": `["common.c"] + select({
-        "//build/bazel/platforms/arch:arm": [
-            "not-for-arm64.c",
-            "not-for-lib64.c",
-            "not-for-riscv64.c",
-            "not-for-x86.c",
-            "not-for-x86_64.c",
-            "for-arm.c",
-            "for-lib32.c",
-        ],
-        "//build/bazel/platforms/arch:arm64": [
-            "not-for-arm.c",
-            "not-for-lib32.c",
-            "not-for-riscv64.c",
-            "not-for-x86.c",
-            "not-for-x86_64.c",
-            "for-arm64.c",
-            "for-lib64.c",
-        ],
-        "//build/bazel/platforms/arch:riscv64": [
-            "not-for-arm.c",
-            "not-for-arm64.c",
-            "not-for-lib32.c",
-            "not-for-x86.c",
-            "not-for-x86_64.c",
-            "for-riscv64.c",
-            "for-lib64.c",
-        ],
-        "//build/bazel/platforms/arch:x86": [
-            "not-for-arm.c",
-            "not-for-arm64.c",
-            "not-for-lib64.c",
-            "not-for-riscv64.c",
-            "not-for-x86_64.c",
-            "for-x86.c",
-            "for-lib32.c",
-        ],
-        "//build/bazel/platforms/arch:x86_64": [
-            "not-for-arm.c",
-            "not-for-arm64.c",
-            "not-for-lib32.c",
-            "not-for-riscv64.c",
-            "not-for-x86.c",
-            "for-x86_64.c",
-            "for-lib64.c",
-        ],
-        "//conditions:default": [
-            "not-for-arm.c",
-            "not-for-arm64.c",
-            "not-for-lib32.c",
-            "not-for-lib64.c",
-            "not-for-riscv64.c",
-            "not-for-x86.c",
-            "not-for-x86_64.c",
-        ],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticGeneratedHeadersAllPartitions(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Blueprint: soongCcLibraryStaticPreamble + `
-genrule {
-    name: "generated_hdr",
-    cmd: "nothing to see here",
-    bazel_module: { bp2build_available: false },
-}
-
-genrule {
-    name: "export_generated_hdr",
-    cmd: "nothing to see here",
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "foo_static",
-    srcs: ["cpp_src.cpp", "as_src.S", "c_src.c"],
-    generated_headers: ["generated_hdr", "export_generated_hdr"],
-    export_generated_headers: ["export_generated_hdr"],
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"export_includes": `["."]`,
-				"local_includes":  `["."]`,
-				"hdrs":            `[":export_generated_hdr"]`,
-				"srcs": `[
-        "cpp_src.cpp",
-        ":generated_hdr",
-    ]`,
-				"srcs_as": `[
-        "as_src.S",
-        ":generated_hdr",
-    ]`,
-				"srcs_c": `[
-        "c_src.c",
-        ":generated_hdr",
-    ]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticGeneratedHeadersMultipleExports(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Blueprint: soongCcLibraryStaticPreamble + `
-genrule {
-    name: "generated_hdr",
-    cmd: "nothing to see here",
-    export_include_dirs: ["foo", "bar"],
-    bazel_module: { bp2build_available: false },
-}
-
-genrule {
-    name: "export_generated_hdr",
-    cmd: "nothing to see here",
-    export_include_dirs: ["a", "b"],
-    bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "foo_static",
-    generated_headers: ["generated_hdr", "export_generated_hdr"],
-    export_generated_headers: ["export_generated_hdr"],
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"deps":                `[":export_generated_hdr__header_library"]`,
-				"implementation_deps": `[":generated_hdr__header_library"]`,
-			}),
-		},
-	})
-}
-
-// generated_headers has "variant_prepend" tag. In bp2build output,
-// variant info(select) should go before general info.
-func TestCcLibraryStaticArchSrcsExcludeSrcsGeneratedFiles(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static arch srcs/exclude_srcs with generated files",
-		Filesystem: map[string]string{
-			"common.cpp":             "",
-			"for-x86.cpp":            "",
-			"not-for-x86.cpp":        "",
-			"not-for-everything.cpp": "",
-			"dep/Android.bp": simpleModuleDoNotConvertBp2build("genrule", "generated_src_other_pkg") +
-				simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg") +
-				simpleModuleDoNotConvertBp2build("genrule", "generated_src_other_pkg_x86") +
-				simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_x86") +
-				simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_android"),
-		},
-		Blueprint: soongCcLibraryStaticPreamble +
-			simpleModuleDoNotConvertBp2build("genrule", "generated_src") +
-			simpleModuleDoNotConvertBp2build("genrule", "generated_src_not_x86") +
-			simpleModuleDoNotConvertBp2build("genrule", "generated_src_android") +
-			simpleModuleDoNotConvertBp2build("genrule", "generated_hdr") + `
-cc_library_static {
-    name: "foo_static",
-    srcs: ["common.cpp", "not-for-*.cpp"],
-    exclude_srcs: ["not-for-everything.cpp"],
-    generated_sources: ["generated_src", "generated_src_other_pkg", "generated_src_not_x86"],
-    generated_headers: ["generated_hdr", "generated_hdr_other_pkg"],
-    export_generated_headers: ["generated_hdr_other_pkg"],
-    arch: {
-        x86: {
-          srcs: ["for-x86.cpp"],
-          exclude_srcs: ["not-for-x86.cpp"],
-          generated_headers: ["generated_hdr_other_pkg_x86"],
-          exclude_generated_sources: ["generated_src_not_x86"],
-    export_generated_headers: ["generated_hdr_other_pkg_x86"],
-        },
-    },
-    target: {
-        android: {
-            generated_sources: ["generated_src_android"],
-            generated_headers: ["generated_hdr_other_pkg_android"],
-    export_generated_headers: ["generated_hdr_other_pkg_android"],
-        },
-    },
-
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"srcs": `[
-        "common.cpp",
-        ":generated_src",
-        "//dep:generated_src_other_pkg",
-        ":generated_hdr",
-    ] + select({
-        "//build/bazel/platforms/arch:x86": ["for-x86.cpp"],
-        "//conditions:default": [
-            "not-for-x86.cpp",
-            ":generated_src_not_x86",
-        ],
-    }) + select({
-        "//build/bazel/platforms/os:android": [":generated_src_android"],
-        "//conditions:default": [],
-    })`,
-				"hdrs": `select({
-        "//build/bazel/platforms/os:android": ["//dep:generated_hdr_other_pkg_android"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/arch:x86": ["//dep:generated_hdr_other_pkg_x86"],
-        "//conditions:default": [],
-    }) + ["//dep:generated_hdr_other_pkg"]`,
-				"local_includes":           `["."]`,
-				"export_absolute_includes": `["dep"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticGetTargetProperties(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-
-		Description: "cc_library_static complex GetTargetProperties",
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    target: {
-        android: {
-            srcs: ["android_src.c"],
-        },
-        android_arm: {
-            srcs: ["android_arm_src.c"],
-        },
-        android_arm64: {
-            srcs: ["android_arm64_src.c"],
-        },
-        android_x86: {
-            srcs: ["android_x86_src.c"],
-        },
-        android_x86_64: {
-            srcs: ["android_x86_64_src.c"],
-        },
-        linux_bionic_arm64: {
-            srcs: ["linux_bionic_arm64_src.c"],
-        },
-        linux_bionic_x86_64: {
-            srcs: ["linux_bionic_x86_64_src.c"],
-        },
-    },
-    include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"srcs_c": `select({
-        "//build/bazel/platforms/os:android": ["android_src.c"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/platforms/os_arch:android_arm": ["android_arm_src.c"],
-        "//build/bazel/platforms/os_arch:android_arm64": ["android_arm64_src.c"],
-        "//build/bazel/platforms/os_arch:android_x86": ["android_x86_src.c"],
-        "//build/bazel/platforms/os_arch:android_x86_64": ["android_x86_64_src.c"],
-        "//build/bazel/platforms/os_arch:linux_bionic_arm64": ["linux_bionic_arm64_src.c"],
-        "//build/bazel/platforms/os_arch:linux_bionic_x86_64": ["linux_bionic_x86_64_src.c"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticProductVariableSelects(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static product variable selects",
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    srcs: ["common.c"],
-    product_variables: {
-      malloc_not_svelte: {
-        cflags: ["-Wmalloc_not_svelte"],
-      },
-      malloc_zero_contents: {
-        cflags: ["-Wmalloc_zero_contents"],
-      },
-      binder32bit: {
-        cflags: ["-Wbinder32bit"],
-      },
-    },
-    include_build_directory: false,
-} `,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"copts": `select({
-        "//build/bazel/product_config/config_settings:binder32bit": ["-Wbinder32bit"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_config/config_settings:malloc_not_svelte": ["-Wmalloc_not_svelte"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_config/config_settings:malloc_zero_contents": ["-Wmalloc_zero_contents"],
-        "//conditions:default": [],
-    })`,
-				"srcs_c": `["common.c"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticProductVariableArchSpecificSelects(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static arch-specific product variable selects",
-		Filesystem:  map[string]string{},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    srcs: ["common.c"],
-    product_variables: {
-      malloc_not_svelte: {
-        cflags: ["-Wmalloc_not_svelte"],
-      },
-    },
-    arch: {
-        arm64: {
-            product_variables: {
-                malloc_not_svelte: {
-                    cflags: ["-Warm64_malloc_not_svelte"],
-                },
-            },
-        },
-    },
-    multilib: {
-        lib32: {
-            product_variables: {
-                malloc_not_svelte: {
-                    cflags: ["-Wlib32_malloc_not_svelte"],
-                },
-            },
-        },
-    },
-    target: {
-        android: {
-            product_variables: {
-                malloc_not_svelte: {
-                    cflags: ["-Wandroid_malloc_not_svelte"],
-                },
-            },
-        }
-    },
-    include_build_directory: false,
-} `,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"copts": `select({
-        "//build/bazel/product_config/config_settings:malloc_not_svelte": ["-Wmalloc_not_svelte"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_config/config_settings:malloc_not_svelte-android": ["-Wandroid_malloc_not_svelte"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_config/config_settings:malloc_not_svelte-arm": ["-Wlib32_malloc_not_svelte"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_config/config_settings:malloc_not_svelte-arm64": ["-Warm64_malloc_not_svelte"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_config/config_settings:malloc_not_svelte-x86": ["-Wlib32_malloc_not_svelte"],
-        "//conditions:default": [],
-    })`,
-				"srcs_c": `["common.c"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticProductVariableStringReplacement(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static product variable string replacement",
-		Filesystem:  map[string]string{},
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "foo_static",
-    srcs: ["common.S"],
-    product_variables: {
-      platform_sdk_version: {
-          asflags: ["-DPLATFORM_SDK_VERSION=%d"],
-      },
-    },
-    include_build_directory: false,
-} `,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
-				"asflags": `select({
-        "//build/bazel/product_config/config_settings:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
-        "//conditions:default": [],
-    })`,
-				"srcs_as": `["common.S"]`,
-			}),
-		},
-	})
-}
-
-func TestStaticLibrary_SystemSharedLibsRootEmpty(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static system_shared_lib empty root",
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library_static {
-    name: "root_empty",
-    system_shared_libs: [],
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "root_empty", AttrNameToString{
-				"system_dynamic_deps": `[]`,
-			}),
-		},
-	})
-}
-
-func TestStaticLibrary_SystemSharedLibsStaticEmpty(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static system_shared_lib empty static default",
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_defaults {
-    name: "static_empty_defaults",
-    static: {
-        system_shared_libs: [],
-    },
-    include_build_directory: false,
-}
-cc_library_static {
-    name: "static_empty",
-    defaults: ["static_empty_defaults"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "static_empty", AttrNameToString{
-				"system_dynamic_deps": `[]`,
-			}),
-		},
-	})
-}
-
-func TestStaticLibrary_SystemSharedLibsBionicEmpty(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static system_shared_lib empty for bionic variant",
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library {
-		name: "libc_musl",
-		bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "target_bionic_empty",
-    target: {
-        bionic: {
-            system_shared_libs: [],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "target_bionic_empty", AttrNameToString{
-				"system_dynamic_deps": `select({
-        "//build/bazel/platforms/os:linux_musl": [":libc_musl"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestStaticLibrary_SystemSharedLibsLinuxBionicEmpty(t *testing.T) {
-	// Note that this behavior is technically incorrect (it's a simplification).
-	// The correct behavior would be if bp2build wrote `system_dynamic_deps = []`
-	// only for linux_bionic, but `android` had `["libc", "libdl", "libm"].
-	// b/195791252 tracks the fix.
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static system_shared_lib empty for linux_bionic variant",
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library {
-		name: "libc_musl",
-		bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "target_linux_bionic_empty",
-    target: {
-        linux_bionic: {
-            system_shared_libs: [],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "target_linux_bionic_empty", AttrNameToString{
-				"system_dynamic_deps": `select({
-        "//build/bazel/platforms/os:linux_musl": [":libc_musl"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestStaticLibrary_SystemSharedLibsMuslEmpty(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static system_shared_lib empty for musl variant",
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library {
-		name: "libc_musl",
-		bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "target_musl_empty",
-    target: {
-        musl: {
-            system_shared_libs: [],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "target_musl_empty", AttrNameToString{
-				"system_dynamic_deps": `[]`,
-			}),
-		},
-	})
-}
-
-func TestStaticLibrary_SystemSharedLibsLinuxMuslEmpty(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static system_shared_lib empty for linux_musl variant",
-		Blueprint: soongCcLibraryStaticPreamble + `
-cc_library {
-		name: "libc_musl",
-		bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "target_linux_musl_empty",
-    target: {
-        linux_musl: {
-            system_shared_libs: [],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "target_linux_musl_empty", AttrNameToString{
-				"system_dynamic_deps": `[]`,
-			}),
-		},
-	})
-}
-
-func TestStaticLibrary_SystemSharedLibsBionic(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static system_shared_libs set for bionic variant",
-		Blueprint: soongCcLibraryStaticPreamble +
-			simpleModuleDoNotConvertBp2build("cc_library", "libc") + `
-cc_library {
-	name: "libc_musl",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "target_bionic",
-    target: {
-        bionic: {
-            system_shared_libs: ["libc"],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "target_bionic", AttrNameToString{
-				"system_dynamic_deps": `select({
-        "//build/bazel/platforms/os:android": [":libc"],
-        "//build/bazel/platforms/os:linux_bionic": [":libc"],
-        "//build/bazel/platforms/os:linux_musl": [":libc_musl"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestStaticLibrary_SystemSharedLibsLinuxRootAndLinuxBionic(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static system_shared_libs set for root and linux_bionic variant",
-		Blueprint: soongCcLibraryStaticPreamble +
-			simpleModuleDoNotConvertBp2build("cc_library", "libc") +
-			simpleModuleDoNotConvertBp2build("cc_library", "libm") + `
-cc_library {
-	name: "libc_musl",
-	bazel_module: { bp2build_available: false },
-}
-
-cc_library_static {
-    name: "target_linux_bionic",
-    system_shared_libs: ["libc"],
-    target: {
-        linux_bionic: {
-            system_shared_libs: ["libm"],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "target_linux_bionic", AttrNameToString{
-				"system_dynamic_deps": `[":libc"] + select({
-        "//build/bazel/platforms/os:linux_bionic": [":libm"],
-        "//build/bazel/platforms/os:linux_musl": [":libc_musl"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibrarystatic_SystemSharedLibUsedAsDep(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static system_shared_lib empty for linux_bionic variant",
-		Blueprint: soongCcLibraryStaticPreamble +
-			simpleModuleDoNotConvertBp2build("cc_library", "libc") + `
-
-cc_library {
-    name: "libm",
-    stubs: {
-        symbol_file: "libm.map.txt",
-        versions: ["current"],
-    },
-    bazel_module: { bp2build_available: false },
-    apex_available: ["com.android.runtime"],
-}
-
-cc_library_static {
-    name: "used_in_bionic_oses",
-    target: {
-        android: {
-            shared_libs: ["libc"],
-        },
-        linux_bionic: {
-            shared_libs: ["libc"],
-        },
-    },
-    include_build_directory: false,
-    apex_available: ["foo"],
-}
-
-cc_library_static {
-    name: "all",
-    shared_libs: ["libc"],
-    include_build_directory: false,
-    apex_available: ["foo"],
-}
-
-cc_library_static {
-    name: "keep_for_empty_system_shared_libs",
-    shared_libs: ["libc"],
-    system_shared_libs: [],
-    include_build_directory: false,
-    apex_available: ["foo"],
-}
-
-cc_library_static {
-    name: "used_with_stubs",
-    shared_libs: ["libm"],
-    include_build_directory: false,
-    apex_available: ["foo"],
-}
-
-cc_library_static {
-    name: "keep_with_stubs",
-    shared_libs: ["libm"],
-    system_shared_libs: [],
-    include_build_directory: false,
-    apex_available: ["foo"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "all", AttrNameToString{
-				"tags": `["apex_available=foo"]`,
-			}),
-			MakeBazelTarget("cc_library_static", "keep_for_empty_system_shared_libs", AttrNameToString{
-				"implementation_dynamic_deps": `[":libc"]`,
-				"system_dynamic_deps":         `[]`,
-				"tags":                        `["apex_available=foo"]`,
-			}),
-			MakeBazelTarget("cc_library_static", "keep_with_stubs", AttrNameToString{
-				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:foo": ["@api_surfaces//module-libapi/current:libm"],
-        "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:libm"],
-        "//conditions:default": [":libm"],
-    })`,
-				"system_dynamic_deps": `[]`,
-				"tags":                `["apex_available=foo"]`,
-			}),
-			MakeBazelTarget("cc_library_static", "used_in_bionic_oses", AttrNameToString{
-				"tags": `["apex_available=foo"]`,
-			}),
-			MakeBazelTarget("cc_library_static", "used_with_stubs", AttrNameToString{
-				"tags": `["apex_available=foo"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticProto(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Blueprint: soongCcProtoPreamble + `cc_library_static {
-	name: "foo",
-	srcs: ["foo.proto"],
-	proto: {
-		export_proto_headers: true,
-	},
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
-				"srcs": `["foo.proto"]`,
-			}), MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
-				"deps": `[":foo_proto"]`,
-			}), MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"deps":               `[":libprotobuf-cpp-lite"]`,
-				"whole_archive_deps": `[":foo_cc_proto_lite"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticUseVersionLib(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Filesystem: map[string]string{
-			soongCcVersionLibBpPath: soongCcVersionLibBp,
-		},
-		Blueprint: soongCcProtoPreamble + `cc_library_static {
-	name: "foo",
-	use_version_lib: true,
-	static_libs: ["libbuildversion"],
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticUseVersionLibHasDep(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Filesystem: map[string]string{
-			soongCcVersionLibBpPath: soongCcVersionLibBp,
-		},
-		Blueprint: soongCcProtoPreamble + `cc_library_static {
-	name: "foo",
-	use_version_lib: true,
-	whole_static_libs: ["libbuildversion"],
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticStdInFlags(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Blueprint: soongCcProtoPreamble + `cc_library_static {
-	name: "foo",
-	cflags: ["-std=candcpp"],
-	conlyflags: ["-std=conly"],
-	cppflags: ["-std=cpp"],
-	include_build_directory: false,
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"conlyflags": `["-std=conly"]`,
-				"cppflags":   `["-std=cpp"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticStl(t *testing.T) {
-	testCases := []struct {
-		desc string
-		prop string
-		attr AttrNameToString
-	}{
-		{
-			desc: "c++_shared deduped to libc++",
-			prop: `stl: "c++_shared",`,
-			attr: AttrNameToString{
-				"stl": `"libc++"`,
-			},
-		},
-		{
-			desc: "libc++ to libc++",
-			prop: `stl: "libc++",`,
-			attr: AttrNameToString{
-				"stl": `"libc++"`,
-			},
-		},
-		{
-			desc: "c++_static to libc++_static",
-			prop: `stl: "c++_static",`,
-			attr: AttrNameToString{
-				"stl": `"libc++_static"`,
-			},
-		},
-		{
-			desc: "libc++_static to libc++_static",
-			prop: `stl: "libc++_static",`,
-			attr: AttrNameToString{
-				"stl": `"libc++_static"`,
-			},
-		},
-		{
-			desc: "system to system",
-			prop: `stl: "system",`,
-			attr: AttrNameToString{
-				"stl": `"system"`,
-			},
-		},
-		{
-			desc: "none to none",
-			prop: `stl: "none",`,
-			attr: AttrNameToString{
-				"stl": `"none"`,
-			},
-		},
-		{
-			desc: "empty to empty",
-			attr: AttrNameToString{},
-		},
-	}
-	for _, tc := range testCases {
-		t.Run(tc.desc, func(*testing.T) {
-			runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-				Blueprint: fmt.Sprintf(`cc_library_static {
-	name: "foo",
-	include_build_directory: false,
-	%s
-}`, tc.prop),
-				ExpectedBazelTargets: []string{
-					MakeBazelTarget("cc_library_static", "foo", tc.attr),
-				},
-			})
-		})
-	}
-}
-
-func TestCCLibraryStaticRuntimeDeps(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Blueprint: `cc_library_shared {
-	name: "bar",
-}
-
-cc_library_static {
-  name: "foo",
-  runtime_libs: ["foo"],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_shared", "bar", AttrNameToString{
-				"local_includes": `["."]`,
-			}),
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"runtime_deps":   `[":foo"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticWithSyspropSrcs(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static with sysprop sources",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	srcs: [
-		"bar.sysprop",
-		"baz.sysprop",
-		"blah.cpp",
-	],
-	min_sdk_version: "5",
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("sysprop_library", "foo_sysprop_library", AttrNameToString{
-				"srcs": `[
-        "bar.sysprop",
-        "baz.sysprop",
-    ]`,
-			}),
-			MakeBazelTarget("cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
-				"dep":             `":foo_sysprop_library"`,
-				"min_sdk_version": `"5"`,
-			}),
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"srcs":               `["blah.cpp"]`,
-				"local_includes":     `["."]`,
-				"min_sdk_version":    `"5"`,
-				"whole_archive_deps": `[":foo_cc_sysprop_library_static"]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticWithSyspropSrcsSomeConfigs(t *testing.T) {
-	runCcLibraryTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static with sysprop sources in some configs but not others",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	srcs: [
-		"blah.cpp",
-	],
-	target: {
-		android: {
-			srcs: ["bar.sysprop"],
-		},
-	},
-	min_sdk_version: "5",
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("sysprop_library", "foo_sysprop_library", AttrNameToString{
-				"srcs": `select({
-        "//build/bazel/platforms/os:android": ["bar.sysprop"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("cc_sysprop_library_static", "foo_cc_sysprop_library_static", AttrNameToString{
-				"dep":             `":foo_sysprop_library"`,
-				"min_sdk_version": `"5"`,
-			}),
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"srcs":            `["blah.cpp"]`,
-				"local_includes":  `["."]`,
-				"min_sdk_version": `"5"`,
-				"whole_archive_deps": `select({
-        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticWithIntegerOverflowProperty(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static has correct features when integer_overflow property is provided",
-		Blueprint: `
-cc_library_static {
-		name: "foo",
-		sanitize: {
-				integer_overflow: true,
-		},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features":       `["ubsan_integer_overflow"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticWithMiscUndefinedProperty(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static has correct features when misc_undefined property is provided",
-		Blueprint: `
-cc_library_static {
-		name: "foo",
-		sanitize: {
-				misc_undefined: ["undefined", "nullability"],
-		},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features": `[
-        "ubsan_undefined",
-        "ubsan_nullability",
-    ]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticWithUBSanPropertiesArchSpecific(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static has correct feature select when UBSan props are specified in arch specific blocks",
-		Blueprint: `
-cc_library_static {
-		name: "foo",
-		sanitize: {
-				misc_undefined: ["undefined", "nullability"],
-		},
-		target: {
-				android: {
-						sanitize: {
-								misc_undefined: ["alignment"],
-						},
-				},
-				linux_glibc: {
-						sanitize: {
-								integer_overflow: true,
-						},
-				},
-		},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features": `[
-        "ubsan_undefined",
-        "ubsan_nullability",
-    ] + select({
-        "//build/bazel/platforms/os:android": ["ubsan_alignment"],
-        "//build/bazel/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticWithSanitizerBlocklist(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static has correct features when sanitize.blocklist is provided",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	sanitize: {
-		blocklist: "foo_blocklist.txt",
-	},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticWithThinLto(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static has correct features when thin lto is enabled",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	lto: {
-		thin: true,
-	},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features":       `["android_thin_lto"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticWithLtoNever(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static has correct features when thin lto is enabled",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	lto: {
-		never: true,
-	},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features":       `["-android_thin_lto"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticWithThinLtoArchSpecific(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static has correct features when LTO differs across arch and os variants",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	target: {
-		android: {
-			lto: {
-				thin: true,
-			},
-		},
-	},
-	arch: {
-		riscv64: {
-			lto: {
-				thin: false,
-			},
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_arm64": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_x86": ["android_thin_lto"],
-        "//build/bazel/platforms/os_arch:android_x86_64": ["android_thin_lto"],
-        "//conditions:default": [],
-    })`}),
-		},
-	})
-}
-
-func TestCcLibraryStaticWithThinLtoDisabledDefaultEnabledVariant(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static has correct features when LTO disabled by default but enabled on a particular variant",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	lto: {
-		never: true,
-	},
-	target: {
-		android: {
-			lto: {
-				thin: true,
-				never: false,
-			},
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"local_includes": `["."]`,
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_thin_lto"],
-        "//conditions:default": ["-android_thin_lto"],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticWithThinLtoAndWholeProgramVtables(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static has correct features when thin lto is enabled with whole_program_vtables",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	lto: {
-		thin: true,
-	},
-	whole_program_vtables: true,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features": `[
-        "android_thin_lto",
-        "android_thin_lto_whole_program_vtables",
-    ]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticHiddenVisibilityConvertedToFeature(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static changes hidden visibility flag to feature",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	cflags: ["-fvisibility=hidden"],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features":       `["visibility_hidden"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticHiddenVisibilityConvertedToFeatureOsSpecific(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static changes hidden visibility flag to feature for specific os",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	target: {
-		android: {
-			cflags: ["-fvisibility=hidden"],
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["visibility_hidden"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticWithCfi(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static has correct features when cfi is enabled",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	sanitize: {
-		cfi: true,
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features":       `["android_cfi"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticWithCfiOsSpecific(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static has correct features when cfi is enabled for specific variants",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	target: {
-		android: {
-			sanitize: {
-				cfi: true,
-			},
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_cfi"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticWithCfiAndCfiAssemblySupport(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static has correct features when cfi is enabled with cfi_assembly_support",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	sanitize: {
-		cfi: true,
-		config: {
-			cfi_assembly_support: true,
-		},
-	},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features": `[
-        "android_cfi",
-        "android_cfi_assembly_support",
-    ]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCcLibraryStaticExplicitlyDisablesCfiWhenFalse(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_library_static disables cfi when explciitly set to false in the bp",
-		Blueprint: `
-cc_library_static {
-	name: "foo",
-	sanitize: {
-		cfi: false,
-	},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features":       `["-android_cfi"]`,
-				"local_includes": `["."]`,
-			}),
-		},
-	})
-}
-
-func TestCCLibraryStaticRscriptSrc(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: `cc_library_static with rscript files in sources`,
-		Blueprint: `
-cc_library_static{
-    name : "foo",
-    srcs : [
-        "ccSrc.cc",
-        "rsSrc.rscript",
-    ],
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("rscript_to_cpp", "foo_renderscript", AttrNameToString{
-				"srcs": `["rsSrc.rscript"]`,
-			}),
-			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"absolute_includes": `[
-        "frameworks/rs",
-        "frameworks/rs/cpp",
-    ]`,
-				"local_includes": `["."]`,
-				"srcs": `[
-        "ccSrc.cc",
-        "foo_renderscript",
-    ]`,
-			})}})
-}
-
-func TestCcLibraryWithProtoInGeneratedSrcs(t *testing.T) {
-	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library with a .proto file generated from a genrule",
-		ModuleTypeUnderTest:        "cc_library_static",
-		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		Blueprint: soongCcLibraryPreamble + `
-cc_library_static {
-	name: "mylib",
-	generated_sources: ["myprotogen"],
-}
-genrule {
-	name: "myprotogen",
-	out: ["myproto.proto"],
-}
-` + simpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"),
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_library_static", "mylib", AttrNameToString{
-				"local_includes":                    `["."]`,
-				"deps":                              `[":libprotobuf-cpp-lite"]`,
-				"implementation_whole_archive_deps": `[":mylib_cc_proto_lite"]`,
-			}),
-			MakeBazelTarget("cc_lite_proto_library", "mylib_cc_proto_lite", AttrNameToString{
-				"deps": `[":mylib_proto"]`,
-			}),
-			MakeBazelTarget("proto_library", "mylib_proto", AttrNameToString{
-				"srcs": `[":myprotogen"]`,
-			}),
-			MakeBazelTargetNoRestrictions("genrule", "myprotogen", AttrNameToString{
-				"cmd":  `""`,
-				"outs": `["myproto.proto"]`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
deleted file mode 100644
index ecfcb5a..0000000
--- a/bp2build/cc_object_conversion_test.go
+++ /dev/null
@@ -1,480 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/cc"
-)
-
-func registerCcObjectModuleTypes(ctx android.RegistrationContext) {
-	// Always register cc_defaults module factory
-	ctx.RegisterModuleType("cc_defaults", func() android.Module { return cc.DefaultsFactory() })
-	ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
-}
-
-func runCcObjectTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "cc_object"
-	(&tc).ModuleTypeUnderTestFactory = cc.ObjectFactory
-	RunBp2BuildTestCase(t, registerCcObjectModuleTypes, tc)
-}
-
-func TestCcObjectSimple(t *testing.T) {
-	runCcObjectTestCase(t, Bp2buildTestCase{
-		Description: "simple cc_object generates cc_object with include header dep",
-		Filesystem: map[string]string{
-			"a/b/foo.h":     "",
-			"a/b/bar.h":     "",
-			"a/b/exclude.c": "",
-			"a/b/c.c":       "",
-		},
-		Blueprint: `cc_object {
-    name: "foo",
-    local_include_dirs: ["include"],
-    system_shared_libs: [],
-    cflags: [
-        "-Wno-gcc-compat",
-        "-Wall",
-        "-Werror",
-    ],
-    srcs: [
-        "a/b/*.c"
-    ],
-    exclude_srcs: ["a/b/exclude.c"],
-    sdk_version: "current",
-    min_sdk_version: "29",
-	crt: true,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_object", "foo", AttrNameToString{
-				"copts": `[
-        "-fno-addrsig",
-        "-Wno-gcc-compat",
-        "-Wall",
-        "-Werror",
-    ]`,
-				"local_includes": `[
-        "include",
-        ".",
-    ]`,
-				"srcs":                `["a/b/c.c"]`,
-				"system_dynamic_deps": `[]`,
-				"sdk_version":         `"current"`,
-				"min_sdk_version":     `"29"`,
-				"crt":                 "True",
-			}),
-		},
-	})
-}
-
-func TestCcObjectDefaults(t *testing.T) {
-	runCcObjectTestCase(t, Bp2buildTestCase{
-		Blueprint: `cc_object {
-    name: "foo",
-    system_shared_libs: [],
-    srcs: [
-        "a/b/*.h",
-        "a/b/c.c"
-    ],
-
-    defaults: ["foo_defaults"],
-}
-
-cc_defaults {
-    name: "foo_defaults",
-    defaults: ["foo_bar_defaults"],
-}
-
-cc_defaults {
-    name: "foo_bar_defaults",
-    cflags: [
-        "-Werror",
-    ],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_object", "foo", AttrNameToString{
-				"copts": `[
-        "-Werror",
-        "-fno-addrsig",
-    ]`,
-				"local_includes":      `["."]`,
-				"srcs":                `["a/b/c.c"]`,
-				"system_dynamic_deps": `[]`,
-			}),
-		}})
-}
-
-func TestCcObjectCcObjetDepsInObjs(t *testing.T) {
-	runCcObjectTestCase(t, Bp2buildTestCase{
-		Description: "cc_object with cc_object deps in objs props",
-		Filesystem: map[string]string{
-			"a/b/c.c": "",
-			"x/y/z.c": "",
-		},
-		Blueprint: `cc_object {
-    name: "foo",
-    system_shared_libs: [],
-    srcs: ["a/b/c.c"],
-    objs: ["bar"],
-    include_build_directory: false,
-}
-
-cc_object {
-    name: "bar",
-    system_shared_libs: [],
-    srcs: ["x/y/z.c"],
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_object", "bar", AttrNameToString{
-				"copts":               `["-fno-addrsig"]`,
-				"srcs":                `["x/y/z.c"]`,
-				"system_dynamic_deps": `[]`,
-			}), MakeBazelTarget("cc_object", "foo", AttrNameToString{
-				"copts":               `["-fno-addrsig"]`,
-				"objs":                `[":bar"]`,
-				"srcs":                `["a/b/c.c"]`,
-				"system_dynamic_deps": `[]`,
-			}),
-		},
-	})
-}
-
-func TestCcObjectIncludeBuildDirFalse(t *testing.T) {
-	runCcObjectTestCase(t, Bp2buildTestCase{
-		Description: "cc_object with include_build_dir: false",
-		Filesystem: map[string]string{
-			"a/b/c.c": "",
-			"x/y/z.c": "",
-		},
-		Blueprint: `cc_object {
-    name: "foo",
-    system_shared_libs: [],
-    srcs: ["a/b/c.c"],
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_object", "foo", AttrNameToString{
-				"copts":               `["-fno-addrsig"]`,
-				"srcs":                `["a/b/c.c"]`,
-				"system_dynamic_deps": `[]`,
-			}),
-		},
-	})
-}
-
-func TestCcObjectProductVariable(t *testing.T) {
-	runCcObjectTestCase(t, Bp2buildTestCase{
-		Description: "cc_object with product variable",
-		Blueprint: `cc_object {
-    name: "foo",
-    system_shared_libs: [],
-    include_build_directory: false,
-    product_variables: {
-        platform_sdk_version: {
-            asflags: ["-DPLATFORM_SDK_VERSION=%d"],
-        },
-    },
-    srcs: ["src.S"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_object", "foo", AttrNameToString{
-				"asflags": `select({
-        "//build/bazel/product_config/config_settings:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
-        "//conditions:default": [],
-    })`,
-				"copts":               `["-fno-addrsig"]`,
-				"srcs_as":             `["src.S"]`,
-				"system_dynamic_deps": `[]`,
-			}),
-		},
-	})
-}
-
-func TestCcObjectCflagsOneArch(t *testing.T) {
-	runCcObjectTestCase(t, Bp2buildTestCase{
-		Description: "cc_object setting cflags for one arch",
-		Blueprint: `cc_object {
-    name: "foo",
-    system_shared_libs: [],
-    srcs: ["a.cpp"],
-    arch: {
-        x86: {
-            cflags: ["-fPIC"], // string list
-        },
-        arm: {
-            srcs: ["arch/arm/file.cpp"], // label list
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_object", "foo", AttrNameToString{
-				"copts": `["-fno-addrsig"] + select({
-        "//build/bazel/platforms/arch:x86": ["-fPIC"],
-        "//conditions:default": [],
-    })`,
-				"srcs": `["a.cpp"] + select({
-        "//build/bazel/platforms/arch:arm": ["arch/arm/file.cpp"],
-        "//conditions:default": [],
-    })`,
-				"system_dynamic_deps": `[]`,
-			}),
-		},
-	})
-}
-
-func TestCcObjectCflagsFourArch(t *testing.T) {
-	runCcObjectTestCase(t, Bp2buildTestCase{
-		Description: "cc_object setting cflags for 4 architectures",
-		Blueprint: `cc_object {
-    name: "foo",
-    system_shared_libs: [],
-    srcs: ["base.cpp"],
-    arch: {
-        x86: {
-            srcs: ["x86.cpp"],
-            cflags: ["-fPIC"],
-        },
-        x86_64: {
-            srcs: ["x86_64.cpp"],
-            cflags: ["-fPIC"],
-        },
-        arm: {
-            srcs: ["arm.cpp"],
-            cflags: ["-Wall"],
-        },
-        arm64: {
-            srcs: ["arm64.cpp"],
-            cflags: ["-Wall"],
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_object", "foo", AttrNameToString{
-				"copts": `["-fno-addrsig"] + select({
-        "//build/bazel/platforms/arch:arm": ["-Wall"],
-        "//build/bazel/platforms/arch:arm64": ["-Wall"],
-        "//build/bazel/platforms/arch:x86": ["-fPIC"],
-        "//build/bazel/platforms/arch:x86_64": ["-fPIC"],
-        "//conditions:default": [],
-    })`,
-				"srcs": `["base.cpp"] + select({
-        "//build/bazel/platforms/arch:arm": ["arm.cpp"],
-        "//build/bazel/platforms/arch:arm64": ["arm64.cpp"],
-        "//build/bazel/platforms/arch:x86": ["x86.cpp"],
-        "//build/bazel/platforms/arch:x86_64": ["x86_64.cpp"],
-        "//conditions:default": [],
-    })`,
-				"system_dynamic_deps": `[]`,
-			}),
-		},
-	})
-}
-
-func TestCcObjectLinkerScript(t *testing.T) {
-	runCcObjectTestCase(t, Bp2buildTestCase{
-		Description: "cc_object setting linker_script",
-		Blueprint: `cc_object {
-    name: "foo",
-    srcs: ["base.cpp"],
-    linker_script: "bunny.lds",
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_object", "foo", AttrNameToString{
-				"copts":         `["-fno-addrsig"]`,
-				"linker_script": `"bunny.lds"`,
-				"srcs":          `["base.cpp"]`,
-			}),
-		},
-	})
-}
-
-func TestCcObjectDepsAndLinkerScriptSelects(t *testing.T) {
-	runCcObjectTestCase(t, Bp2buildTestCase{
-		Description: "cc_object setting deps and linker_script across archs",
-		Blueprint: `cc_object {
-    name: "foo",
-    srcs: ["base.cpp"],
-    arch: {
-        x86: {
-            objs: ["x86_obj"],
-            linker_script: "x86.lds",
-        },
-        x86_64: {
-            objs: ["x86_64_obj"],
-            linker_script: "x86_64.lds",
-        },
-        arm: {
-            objs: ["arm_obj"],
-            linker_script: "arm.lds",
-        },
-    },
-    include_build_directory: false,
-}
-
-cc_object {
-    name: "x86_obj",
-    system_shared_libs: [],
-    srcs: ["x86.cpp"],
-    include_build_directory: false,
-    bazel_module: { bp2build_available: false },
-}
-
-cc_object {
-    name: "x86_64_obj",
-    system_shared_libs: [],
-    srcs: ["x86_64.cpp"],
-    include_build_directory: false,
-    bazel_module: { bp2build_available: false },
-}
-
-cc_object {
-    name: "arm_obj",
-    system_shared_libs: [],
-    srcs: ["arm.cpp"],
-    include_build_directory: false,
-    bazel_module: { bp2build_available: false },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_object", "foo", AttrNameToString{
-				"copts": `["-fno-addrsig"]`,
-				"objs": `select({
-        "//build/bazel/platforms/arch:arm": [":arm_obj"],
-        "//build/bazel/platforms/arch:x86": [":x86_obj"],
-        "//build/bazel/platforms/arch:x86_64": [":x86_64_obj"],
-        "//conditions:default": [],
-    })`,
-				"linker_script": `select({
-        "//build/bazel/platforms/arch:arm": "arm.lds",
-        "//build/bazel/platforms/arch:x86": "x86.lds",
-        "//build/bazel/platforms/arch:x86_64": "x86_64.lds",
-        "//conditions:default": None,
-    })`,
-				"srcs": `["base.cpp"]`,
-			}),
-		},
-	})
-}
-
-func TestCcObjectSelectOnLinuxAndBionicArchs(t *testing.T) {
-	runCcObjectTestCase(t, Bp2buildTestCase{
-		Description: "cc_object setting srcs based on linux and bionic archs",
-		Blueprint: `cc_object {
-    name: "foo",
-    srcs: ["base.cpp"],
-    target: {
-        linux_arm64: {
-            srcs: ["linux_arm64.cpp",]
-        },
-        linux_x86: {
-            srcs: ["linux_x86.cpp",]
-        },
-        bionic_arm64: {
-            srcs: ["bionic_arm64.cpp",]
-        },
-    },
-    include_build_directory: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_object", "foo", AttrNameToString{
-				"copts": `["-fno-addrsig"]`,
-				"srcs": `["base.cpp"] + select({
-        "//build/bazel/platforms/os_arch:android_arm64": [
-            "linux_arm64.cpp",
-            "bionic_arm64.cpp",
-        ],
-        "//build/bazel/platforms/os_arch:android_x86": ["linux_x86.cpp"],
-        "//build/bazel/platforms/os_arch:linux_bionic_arm64": [
-            "linux_arm64.cpp",
-            "bionic_arm64.cpp",
-        ],
-        "//build/bazel/platforms/os_arch:linux_glibc_x86": ["linux_x86.cpp"],
-        "//build/bazel/platforms/os_arch:linux_musl_arm64": ["linux_arm64.cpp"],
-        "//build/bazel/platforms/os_arch:linux_musl_x86": ["linux_x86.cpp"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestCcObjectHeaderLib(t *testing.T) {
-	runCcObjectTestCase(t, Bp2buildTestCase{
-		Description: "simple cc_object generates cc_object with include header dep",
-		Filesystem: map[string]string{
-			"a/b/foo.h":     "",
-			"a/b/bar.h":     "",
-			"a/b/exclude.c": "",
-			"a/b/c.c":       "",
-		},
-		Blueprint: `cc_object {
-    name: "foo",
-	header_libs: ["libheaders"],
-    system_shared_libs: [],
-    cflags: [
-        "-Wno-gcc-compat",
-        "-Wall",
-        "-Werror",
-    ],
-    srcs: [
-        "a/b/*.c"
-    ],
-    exclude_srcs: ["a/b/exclude.c"],
-    sdk_version: "current",
-    min_sdk_version: "29",
-}
-
-cc_library_headers {
-    name: "libheaders",
-	export_include_dirs: ["include"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_object", "foo", AttrNameToString{
-				"copts": `[
-        "-fno-addrsig",
-        "-Wno-gcc-compat",
-        "-Wall",
-        "-Werror",
-    ]`,
-				"deps":                `[":libheaders"]`,
-				"local_includes":      `["."]`,
-				"srcs":                `["a/b/c.c"]`,
-				"system_dynamic_deps": `[]`,
-				"sdk_version":         `"current"`,
-				"min_sdk_version":     `"29"`,
-			}),
-			MakeBazelTarget("cc_library_headers", "libheaders", AttrNameToString{
-				"export_includes": `["include"]`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/cc_prebuilt_binary_conversion_test.go b/bp2build/cc_prebuilt_binary_conversion_test.go
deleted file mode 100644
index 0e8048c..0000000
--- a/bp2build/cc_prebuilt_binary_conversion_test.go
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package bp2build
-
-import (
-	"fmt"
-	"testing"
-
-	"android/soong/cc"
-)
-
-func runCcPrebuiltBinaryTestCase(t *testing.T, testCase Bp2buildTestCase) {
-	t.Helper()
-	description := fmt.Sprintf("cc_prebuilt_binary: %s", testCase.Description)
-	testCase.ModuleTypeUnderTest = "cc_prebuilt_binary"
-	testCase.ModuleTypeUnderTestFactory = cc.PrebuiltBinaryFactory
-	testCase.Description = description
-	t.Run(description, func(t *testing.T) {
-		t.Helper()
-		RunBp2BuildTestCaseSimple(t, testCase)
-	})
-}
-
-func TestPrebuiltBinary(t *testing.T) {
-	runCcPrebuiltBinaryTestCase(t,
-		Bp2buildTestCase{
-			Description: "simple",
-			Filesystem: map[string]string{
-				"bin": "",
-			},
-			Blueprint: `
-cc_prebuilt_binary {
-	name: "bintest",
-	srcs: ["bin"],
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_binary", "bintest", AttrNameToString{
-					"src": `"bin"`,
-				})},
-		})
-}
-
-func TestPrebuiltBinaryWithStrip(t *testing.T) {
-	runCcPrebuiltBinaryTestCase(t,
-		Bp2buildTestCase{
-			Description: "with strip",
-			Filesystem: map[string]string{
-				"bin": "",
-			},
-			Blueprint: `
-cc_prebuilt_binary {
-	name: "bintest",
-	srcs: ["bin"],
-	strip: { all: true },
-	bazel_module: { bp2build_available: true },
-}`, ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_binary", "bintest", AttrNameToString{
-					"src": `"bin"`,
-					"strip": `{
-        "all": True,
-    }`,
-				}),
-			},
-		})
-}
-
-func TestPrebuiltBinaryWithArchVariance(t *testing.T) {
-	runCcPrebuiltBinaryTestCase(t,
-		Bp2buildTestCase{
-			Description: "with arch variance",
-			Filesystem: map[string]string{
-				"bina": "",
-				"binb": "",
-			},
-			Blueprint: `
-cc_prebuilt_binary {
-	name: "bintest",
-	arch: {
-		arm64: { srcs: ["bina"], },
-		arm: { srcs: ["binb"], },
-	},
-	bazel_module: { bp2build_available: true },
-}`, ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_binary", "bintest", AttrNameToString{
-					"src": `select({
-        "//build/bazel/platforms/arch:arm": "binb",
-        "//build/bazel/platforms/arch:arm64": "bina",
-        "//conditions:default": None,
-    })`,
-				}),
-			},
-		})
-}
-
-func TestPrebuiltBinaryMultipleSrcsFails(t *testing.T) {
-	runCcPrebuiltBinaryTestCase(t,
-		Bp2buildTestCase{
-			Description: "fails because multiple sources",
-			Filesystem: map[string]string{
-				"bina": "",
-				"binb": "",
-			},
-			Blueprint: `
-cc_prebuilt_binary {
-	name: "bintest",
-	srcs: ["bina", "binb"],
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedErr: fmt.Errorf("Expected at most one source file"),
-		})
-}
-
-// TODO: nosrcs test
diff --git a/bp2build/cc_prebuilt_library_conversion_test.go b/bp2build/cc_prebuilt_library_conversion_test.go
deleted file mode 100644
index b88960e..0000000
--- a/bp2build/cc_prebuilt_library_conversion_test.go
+++ /dev/null
@@ -1,362 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package bp2build
-
-import (
-	"fmt"
-	"testing"
-
-	"android/soong/cc"
-)
-
-func runCcPrebuiltLibraryTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "cc_prebuilt_library"
-	(&tc).ModuleTypeUnderTestFactory = cc.PrebuiltLibraryFactory
-	RunBp2BuildTestCaseSimple(t, tc)
-}
-
-func TestPrebuiltLibraryStaticAndSharedSimple(t *testing.T) {
-	runCcPrebuiltLibraryTestCase(t,
-		Bp2buildTestCase{
-			Description: "prebuilt library static and shared simple",
-			Filesystem: map[string]string{
-				"libf.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library {
-	name: "libtest",
-	srcs: ["libf.so"],
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
-					"static_library": `"libf.so"`,
-				}),
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static_alwayslink", AttrNameToString{
-					"static_library": `"libf.so"`,
-					"alwayslink":     "True",
-				}),
-				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
-					"shared_library": `"libf.so"`,
-				}),
-			},
-		})
-}
-
-func TestPrebuiltLibraryWithArchVariance(t *testing.T) {
-	runCcPrebuiltLibraryTestCase(t,
-		Bp2buildTestCase{
-			Description: "prebuilt library with arch variance",
-			Filesystem: map[string]string{
-				"libf.so": "",
-				"libg.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library {
-	name: "libtest",
-	arch: {
-		arm64: { srcs: ["libf.so"], },
-		arm: { srcs: ["libg.so"], },
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
-					"static_library": `select({
-        "//build/bazel/platforms/arch:arm": "libg.so",
-        "//build/bazel/platforms/arch:arm64": "libf.so",
-        "//conditions:default": None,
-    })`}),
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static_alwayslink", AttrNameToString{
-					"alwayslink": "True",
-					"static_library": `select({
-        "//build/bazel/platforms/arch:arm": "libg.so",
-        "//build/bazel/platforms/arch:arm64": "libf.so",
-        "//conditions:default": None,
-    })`}),
-				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
-					"shared_library": `select({
-        "//build/bazel/platforms/arch:arm": "libg.so",
-        "//build/bazel/platforms/arch:arm64": "libf.so",
-        "//conditions:default": None,
-    })`,
-				}),
-			},
-		})
-}
-
-func TestPrebuiltLibraryAdditionalAttrs(t *testing.T) {
-	runCcPrebuiltLibraryTestCase(t,
-		Bp2buildTestCase{
-			Description: "prebuilt library additional attributes",
-			Filesystem: map[string]string{
-				"libf.so":             "",
-				"testdir/1/include.h": "",
-				"testdir/2/other.h":   "",
-			},
-			Blueprint: `
-cc_prebuilt_library {
-	name: "libtest",
-	srcs: ["libf.so"],
-	export_include_dirs: ["testdir/1/"],
-	export_system_include_dirs: ["testdir/2/"],
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
-					"static_library":         `"libf.so"`,
-					"export_includes":        `["testdir/1/"]`,
-					"export_system_includes": `["testdir/2/"]`,
-				}),
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static_alwayslink", AttrNameToString{
-					"static_library":         `"libf.so"`,
-					"export_includes":        `["testdir/1/"]`,
-					"export_system_includes": `["testdir/2/"]`,
-					"alwayslink":             "True",
-				}),
-				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
-					"shared_library":         `"libf.so"`,
-					"export_includes":        `["testdir/1/"]`,
-					"export_system_includes": `["testdir/2/"]`,
-				}),
-			},
-		})
-}
-
-func TestPrebuiltLibrarySharedStanzaFails(t *testing.T) {
-	runCcPrebuiltLibraryTestCase(t,
-		Bp2buildTestCase{
-			Description: "prebuilt library with shared stanza fails because multiple sources",
-			Filesystem: map[string]string{
-				"libf.so": "",
-				"libg.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library {
-	name: "libtest",
-	srcs: ["libf.so"],
-	shared: {
-		srcs: ["libg.so"],
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedErr: fmt.Errorf("Expected at most one source file"),
-		})
-}
-
-func TestPrebuiltLibraryStaticStanzaFails(t *testing.T) {
-	RunBp2BuildTestCaseSimple(t,
-		Bp2buildTestCase{
-			Description:                "prebuilt library with static stanza fails because multiple sources",
-			ModuleTypeUnderTest:        "cc_prebuilt_library",
-			ModuleTypeUnderTestFactory: cc.PrebuiltLibraryFactory,
-			Filesystem: map[string]string{
-				"libf.so": "",
-				"libg.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library {
-	name: "libtest",
-	srcs: ["libf.so"],
-	static: {
-		srcs: ["libg.so"],
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedErr: fmt.Errorf("Expected at most one source file"),
-		})
-}
-
-func TestPrebuiltLibrarySharedAndStaticStanzas(t *testing.T) {
-	runCcPrebuiltLibraryTestCase(t,
-		Bp2buildTestCase{
-			Description: "prebuilt library with both shared and static stanzas",
-			Filesystem: map[string]string{
-				"libf.so": "",
-				"libg.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library {
-	name: "libtest",
-	static: {
-		srcs: ["libf.so"],
-	},
-	shared: {
-		srcs: ["libg.so"],
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
-					"static_library": `"libf.so"`,
-				}),
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static_alwayslink", AttrNameToString{
-					"static_library": `"libf.so"`,
-					"alwayslink":     "True",
-				}),
-				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
-					"shared_library": `"libg.so"`,
-				}),
-			},
-		})
-}
-
-// TODO(b/228623543): When this bug is fixed, enable this test
-//func TestPrebuiltLibraryOnlyShared(t *testing.T) {
-//	runCcPrebuiltLibraryTestCase(t,
-//		bp2buildTestCase{
-//			description:                "prebuilt library shared only",
-//			filesystem: map[string]string{
-//				"libf.so": "",
-//			},
-//			blueprint: `
-//cc_prebuilt_library {
-//	name: "libtest",
-//	srcs: ["libf.so"],
-//	static: {
-//		enabled: false,
-//	},
-//	bazel_module: { bp2build_available: true },
-//}`,
-//			expectedBazelTargets: []string{
-//				makeBazelTarget("cc_prebuilt_library_shared", "libtest", attrNameToString{
-//					"shared_library": `"libf.so"`,
-//				}),
-//			},
-//		})
-//}
-
-// TODO(b/228623543): When this bug is fixed, enable this test
-//func TestPrebuiltLibraryOnlyStatic(t *testing.T) {
-//	runCcPrebuiltLibraryTestCase(t,
-//		bp2buildTestCase{
-//			description:                "prebuilt library static only",
-//			filesystem: map[string]string{
-//				"libf.so": "",
-//			},
-//			blueprint: `
-//cc_prebuilt_library {
-//	name: "libtest",
-//	srcs: ["libf.so"],
-//	shared: {
-//		enabled: false,
-//	},
-//	bazel_module: { bp2build_available: true },
-//}`,
-//			expectedBazelTargets: []string{
-//				makeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", attrNameToString{
-//					"static_library": `"libf.so"`,
-//				}),
-//				makeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static_always", attrNameToString{
-//					"static_library": `"libf.so"`,
-//					"alwayslink": "True",
-//				}),
-//			},
-//		})
-//}
-
-func TestPrebuiltLibraryWithExportIncludesArchVariant(t *testing.T) {
-	runCcPrebuiltLibraryTestCase(t, Bp2buildTestCase{
-		Description: "cc_prebuilt_library correctly translates export_includes with arch variance",
-		Filesystem: map[string]string{
-			"libf.so": "",
-			"libg.so": "",
-		},
-		Blueprint: `
-cc_prebuilt_library {
-	name: "libtest",
-	srcs: ["libf.so"],
-	arch: {
-		arm: { export_include_dirs: ["testdir/1/"], },
-		arm64: { export_include_dirs: ["testdir/2/"], },
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
-				"shared_library": `"libf.so"`,
-				"export_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
-				"static_library": `"libf.so"`,
-				"export_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static_alwayslink", AttrNameToString{
-				"alwayslink":     "True",
-				"static_library": `"libf.so"`,
-				"export_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestPrebuiltLibraryWithExportSystemIncludesArchVariant(t *testing.T) {
-	runCcPrebuiltLibraryTestCase(t, Bp2buildTestCase{
-		Description: "cc_prebuilt_ibrary correctly translates export_system_includes with arch variance",
-		Filesystem: map[string]string{
-			"libf.so": "",
-			"libg.so": "",
-		},
-		Blueprint: `
-cc_prebuilt_library {
-	name: "libtest",
-	srcs: ["libf.so"],
-	arch: {
-		arm: { export_system_include_dirs: ["testdir/1/"], },
-		arm64: { export_system_include_dirs: ["testdir/2/"], },
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
-				"shared_library": `"libf.so"`,
-				"export_system_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static", AttrNameToString{
-				"static_library": `"libf.so"`,
-				"export_system_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("cc_prebuilt_library_static", "libtest_bp2build_cc_library_static_alwayslink", AttrNameToString{
-				"alwayslink":     "True",
-				"static_library": `"libf.so"`,
-				"export_system_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/cc_prebuilt_library_shared_conversion_test.go b/bp2build/cc_prebuilt_library_shared_conversion_test.go
deleted file mode 100644
index 9e975ae..0000000
--- a/bp2build/cc_prebuilt_library_shared_conversion_test.go
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/cc"
-)
-
-func runCcPrebuiltLibrarySharedTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Parallel()
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "cc_prebuilt_library_shared"
-	(&tc).ModuleTypeUnderTestFactory = cc.PrebuiltSharedLibraryFactory
-	RunBp2BuildTestCaseSimple(t, tc)
-}
-
-func TestPrebuiltLibrarySharedSimple(t *testing.T) {
-	runCcPrebuiltLibrarySharedTestCase(t,
-		Bp2buildTestCase{
-			Description: "prebuilt library shared simple",
-			Filesystem: map[string]string{
-				"libf.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library_shared {
-	name: "libtest",
-	srcs: ["libf.so"],
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
-					"shared_library": `"libf.so"`,
-				}),
-			},
-		})
-}
-
-func TestPrebuiltLibrarySharedWithArchVariance(t *testing.T) {
-	runCcPrebuiltLibrarySharedTestCase(t,
-		Bp2buildTestCase{
-			Description: "prebuilt library shared with arch variance",
-			Filesystem: map[string]string{
-				"libf.so": "",
-				"libg.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library_shared {
-	name: "libtest",
-	arch: {
-		arm64: { srcs: ["libf.so"], },
-		arm: { srcs: ["libg.so"], },
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
-					"shared_library": `select({
-        "//build/bazel/platforms/arch:arm": "libg.so",
-        "//build/bazel/platforms/arch:arm64": "libf.so",
-        "//conditions:default": None,
-    })`,
-				}),
-			},
-		})
-}
-
-func TestPrebuiltLibrarySharedAdditionalAttrs(t *testing.T) {
-	runCcPrebuiltLibrarySharedTestCase(t,
-		Bp2buildTestCase{
-			Description: "prebuilt library shared additional attributes",
-			Filesystem: map[string]string{
-				"libf.so":             "",
-				"testdir/1/include.h": "",
-				"testdir/2/other.h":   "",
-			},
-			Blueprint: `
-cc_prebuilt_library_shared {
-	name: "libtest",
-	srcs: ["libf.so"],
-	export_include_dirs: ["testdir/1/"],
-	export_system_include_dirs: ["testdir/2/"],
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
-					"shared_library":         `"libf.so"`,
-					"export_includes":        `["testdir/1/"]`,
-					"export_system_includes": `["testdir/2/"]`,
-				}),
-			},
-		})
-}
-
-func TestPrebuiltLibrarySharedWithExportIncludesArchVariant(t *testing.T) {
-	runCcPrebuiltLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_prebuilt_library_shared correctly translates export_includes with arch variance",
-		Filesystem: map[string]string{
-			"libf.so": "",
-			"libg.so": "",
-		},
-		Blueprint: `
-cc_prebuilt_library_shared {
-	name: "libtest",
-	srcs: ["libf.so"],
-	arch: {
-		arm: { export_include_dirs: ["testdir/1/"], },
-		arm64: { export_include_dirs: ["testdir/2/"], },
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
-				"shared_library": `"libf.so"`,
-				"export_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestPrebuiltLibrarySharedWithExportSystemIncludesArchVariant(t *testing.T) {
-	runCcPrebuiltLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description: "cc_prebuilt_library_shared correctly translates export_system_includes with arch variance",
-		Filesystem: map[string]string{
-			"libf.so": "",
-			"libg.so": "",
-		},
-		Blueprint: `
-cc_prebuilt_library_shared {
-	name: "libtest",
-	srcs: ["libf.so"],
-	arch: {
-		arm: { export_system_include_dirs: ["testdir/1/"], },
-		arm64: { export_system_include_dirs: ["testdir/2/"], },
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
-				"shared_library": `"libf.so"`,
-				"export_system_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/cc_prebuilt_library_shared_test.go b/bp2build/cc_prebuilt_library_shared_test.go
deleted file mode 100644
index 58c0a70..0000000
--- a/bp2build/cc_prebuilt_library_shared_test.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package bp2build
-
-import (
-	"fmt"
-	"testing"
-
-	"android/soong/cc"
-)
-
-func TestSharedPrebuiltLibrary(t *testing.T) {
-	RunBp2BuildTestCaseSimple(t,
-		Bp2buildTestCase{
-			Description:                "prebuilt library shared simple",
-			ModuleTypeUnderTest:        "cc_prebuilt_library_shared",
-			ModuleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
-			Filesystem: map[string]string{
-				"libf.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library_shared {
-	name: "libtest",
-	srcs: ["libf.so"],
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
-					"shared_library": `"libf.so"`,
-				}),
-			},
-		})
-}
-
-func TestSharedPrebuiltLibraryWithArchVariance(t *testing.T) {
-	RunBp2BuildTestCaseSimple(t,
-		Bp2buildTestCase{
-			Description:                "prebuilt library shared with arch variance",
-			ModuleTypeUnderTest:        "cc_prebuilt_library_shared",
-			ModuleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
-			Filesystem: map[string]string{
-				"libf.so": "",
-				"libg.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library_shared {
-	name: "libtest",
-	arch: {
-		arm64: { srcs: ["libf.so"], },
-		arm: { srcs: ["libg.so"], },
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_library_shared", "libtest", AttrNameToString{
-					"shared_library": `select({
-        "//build/bazel/platforms/arch:arm": "libg.so",
-        "//build/bazel/platforms/arch:arm64": "libf.so",
-        "//conditions:default": None,
-    })`,
-				}),
-			},
-		})
-}
-
-func TestSharedPrebuiltLibrarySharedStanzaFails(t *testing.T) {
-	RunBp2BuildTestCaseSimple(t,
-		Bp2buildTestCase{
-			Description:                "prebuilt library shared with shared stanza fails because multiple sources",
-			ModuleTypeUnderTest:        "cc_prebuilt_library_shared",
-			ModuleTypeUnderTestFactory: cc.PrebuiltSharedLibraryFactory,
-			Filesystem: map[string]string{
-				"libf.so": "",
-				"libg.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library_shared {
-	name: "libtest",
-	srcs: ["libf.so"],
-	shared: {
-		srcs: ["libg.so"],
-	},
-	bazel_module: { bp2build_available: true},
-}`,
-			ExpectedErr: fmt.Errorf("Expected at most one source file"),
-		})
-}
diff --git a/bp2build/cc_prebuilt_library_static_conversion_test.go b/bp2build/cc_prebuilt_library_static_conversion_test.go
deleted file mode 100644
index 77562e7..0000000
--- a/bp2build/cc_prebuilt_library_static_conversion_test.go
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/cc"
-)
-
-func runCcPrebuiltLibraryStaticTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Parallel()
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "cc_prebuilt_library_static"
-	(&tc).ModuleTypeUnderTestFactory = cc.PrebuiltStaticLibraryFactory
-	RunBp2BuildTestCaseSimple(t, tc)
-}
-
-func TestPrebuiltLibraryStaticSimple(t *testing.T) {
-	runCcPrebuiltLibraryStaticTestCase(t,
-		Bp2buildTestCase{
-			Description: "prebuilt library static simple",
-			Filesystem: map[string]string{
-				"libf.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library_static {
-	name: "libtest",
-	srcs: ["libf.so"],
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
-					"static_library": `"libf.so"`,
-				}),
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest_alwayslink", AttrNameToString{
-					"static_library": `"libf.so"`,
-					"alwayslink":     "True",
-				}),
-			},
-		})
-}
-
-func TestPrebuiltLibraryStaticWithArchVariance(t *testing.T) {
-	runCcPrebuiltLibraryStaticTestCase(t,
-		Bp2buildTestCase{
-			Description: "prebuilt library with arch variance",
-			Filesystem: map[string]string{
-				"libf.so": "",
-				"libg.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library_static {
-	name: "libtest",
-	arch: {
-		arm64: { srcs: ["libf.so"], },
-		arm: { srcs: ["libg.so"], },
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
-					"static_library": `select({
-        "//build/bazel/platforms/arch:arm": "libg.so",
-        "//build/bazel/platforms/arch:arm64": "libf.so",
-        "//conditions:default": None,
-    })`}),
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest_alwayslink", AttrNameToString{
-					"alwayslink": "True",
-					"static_library": `select({
-        "//build/bazel/platforms/arch:arm": "libg.so",
-        "//build/bazel/platforms/arch:arm64": "libf.so",
-        "//conditions:default": None,
-    })`}),
-			},
-		})
-}
-
-func TestPrebuiltLibraryStaticAdditionalAttrs(t *testing.T) {
-	runCcPrebuiltLibraryStaticTestCase(t,
-		Bp2buildTestCase{
-			Description: "prebuilt library additional attributes",
-			Filesystem: map[string]string{
-				"libf.so":             "",
-				"testdir/1/include.h": "",
-				"testdir/2/other.h":   "",
-			},
-			Blueprint: `
-cc_prebuilt_library_static {
-	name: "libtest",
-	srcs: ["libf.so"],
-	export_include_dirs: ["testdir/1/"],
-	export_system_include_dirs: ["testdir/2/"],
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
-					"static_library":         `"libf.so"`,
-					"export_includes":        `["testdir/1/"]`,
-					"export_system_includes": `["testdir/2/"]`,
-				}),
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest_alwayslink", AttrNameToString{
-					"static_library":         `"libf.so"`,
-					"export_includes":        `["testdir/1/"]`,
-					"export_system_includes": `["testdir/2/"]`,
-					"alwayslink":             "True",
-				}),
-			},
-		})
-}
-
-func TestPrebuiltLibraryStaticWithExportIncludesArchVariant(t *testing.T) {
-	runCcPrebuiltLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_prebuilt_library_static correctly translates export_includes with arch variance",
-		Filesystem: map[string]string{
-			"libf.so": "",
-			"libg.so": "",
-		},
-		Blueprint: `
-cc_prebuilt_library_static {
-	name: "libtest",
-	srcs: ["libf.so"],
-	arch: {
-		arm: { export_include_dirs: ["testdir/1/"], },
-		arm64: { export_include_dirs: ["testdir/2/"], },
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
-				"static_library": `"libf.so"`,
-				"export_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("cc_prebuilt_library_static", "libtest_alwayslink", AttrNameToString{
-				"alwayslink":     "True",
-				"static_library": `"libf.so"`,
-				"export_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestPrebuiltLibraryStaticWithExportSystemIncludesArchVariant(t *testing.T) {
-	runCcPrebuiltLibraryStaticTestCase(t, Bp2buildTestCase{
-		Description: "cc_prebuilt_library_static correctly translates export_system_includes with arch variance",
-		Filesystem: map[string]string{
-			"libf.so": "",
-			"libg.so": "",
-		},
-		Blueprint: `
-cc_prebuilt_library_static {
-	name: "libtest",
-	srcs: ["libf.so"],
-	arch: {
-		arm: { export_system_include_dirs: ["testdir/1/"], },
-		arm64: { export_system_include_dirs: ["testdir/2/"], },
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
-				"static_library": `"libf.so"`,
-				"export_system_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("cc_prebuilt_library_static", "libtest_alwayslink", AttrNameToString{
-				"alwayslink":     "True",
-				"static_library": `"libf.so"`,
-				"export_system_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/cc_prebuilt_library_static_test.go b/bp2build/cc_prebuilt_library_static_test.go
deleted file mode 100644
index 17da813..0000000
--- a/bp2build/cc_prebuilt_library_static_test.go
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package bp2build
-
-import (
-	"fmt"
-	"testing"
-
-	"android/soong/cc"
-)
-
-func TestStaticPrebuiltLibrary(t *testing.T) {
-	RunBp2BuildTestCaseSimple(t,
-		Bp2buildTestCase{
-			Description:                "prebuilt library static simple",
-			ModuleTypeUnderTest:        "cc_prebuilt_library_static",
-			ModuleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
-			Filesystem: map[string]string{
-				"libf.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library_static {
-	name: "libtest",
-	srcs: ["libf.so"],
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
-					"static_library": `"libf.so"`,
-				}),
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest_alwayslink", AttrNameToString{
-					"static_library": `"libf.so"`,
-					"alwayslink":     "True",
-				}),
-			},
-		})
-}
-
-func TestStaticPrebuiltLibraryWithArchVariance(t *testing.T) {
-	RunBp2BuildTestCaseSimple(t,
-		Bp2buildTestCase{
-			Description:                "prebuilt library static with arch variance",
-			ModuleTypeUnderTest:        "cc_prebuilt_library_static",
-			ModuleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
-			Filesystem: map[string]string{
-				"libf.so": "",
-				"libg.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library_static {
-	name: "libtest",
-	arch: {
-		arm64: { srcs: ["libf.so"], },
-		arm: { srcs: ["libg.so"], },
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest", AttrNameToString{
-					"static_library": `select({
-        "//build/bazel/platforms/arch:arm": "libg.so",
-        "//build/bazel/platforms/arch:arm64": "libf.so",
-        "//conditions:default": None,
-    })`}),
-				MakeBazelTarget("cc_prebuilt_library_static", "libtest_alwayslink", AttrNameToString{
-					"alwayslink": "True",
-					"static_library": `select({
-        "//build/bazel/platforms/arch:arm": "libg.so",
-        "//build/bazel/platforms/arch:arm64": "libf.so",
-        "//conditions:default": None,
-    })`}),
-			},
-		})
-}
-
-func TestStaticPrebuiltLibraryStaticStanzaFails(t *testing.T) {
-	RunBp2BuildTestCaseSimple(t,
-		Bp2buildTestCase{
-			Description:                "prebuilt library with static stanza fails because multiple sources",
-			ModuleTypeUnderTest:        "cc_prebuilt_library_static",
-			ModuleTypeUnderTestFactory: cc.PrebuiltStaticLibraryFactory,
-			Filesystem: map[string]string{
-				"libf.so": "",
-				"libg.so": "",
-			},
-			Blueprint: `
-cc_prebuilt_library_static {
-	name: "libtest",
-	srcs: ["libf.so"],
-	static: {
-		srcs: ["libg.so"],
-	},
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedErr: fmt.Errorf("Expected at most one source file"),
-		})
-}
-
-func TestCcLibraryStaticConvertLex(t *testing.T) {
-	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
-		Description:                "cc_library_static with lex files",
-		ModuleTypeUnderTest:        "cc_library_static",
-		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		Filesystem: map[string]string{
-			"foo.c":   "",
-			"bar.cc":  "",
-			"foo1.l":  "",
-			"bar1.ll": "",
-			"foo2.l":  "",
-			"bar2.ll": "",
-		},
-		Blueprint: `cc_library_static {
-	name: "foo_lib",
-	srcs: ["foo.c", "bar.cc", "foo1.l", "foo2.l", "bar1.ll", "bar2.ll"],
-	lex: { flags: ["--foo_flags"] },
-	include_build_directory: false,
-	bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("genlex", "foo_lib_genlex_l", AttrNameToString{
-				"srcs": `[
-        "foo1.l",
-        "foo2.l",
-    ]`,
-				"lexopts": `["--foo_flags"]`,
-			}),
-			MakeBazelTarget("genlex", "foo_lib_genlex_ll", AttrNameToString{
-				"srcs": `[
-        "bar1.ll",
-        "bar2.ll",
-    ]`,
-				"lexopts": `["--foo_flags"]`,
-			}),
-			MakeBazelTarget("cc_library_static", "foo_lib", AttrNameToString{
-				"srcs": `[
-        "bar.cc",
-        ":foo_lib_genlex_ll",
-    ]`,
-				"srcs_c": `[
-        "foo.c",
-        ":foo_lib_genlex_l",
-    ]`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/cc_prebuilt_object_conversion_test.go b/bp2build/cc_prebuilt_object_conversion_test.go
deleted file mode 100644
index 903c816..0000000
--- a/bp2build/cc_prebuilt_object_conversion_test.go
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package bp2build
-
-import (
-	"fmt"
-	"testing"
-
-	"android/soong/cc"
-)
-
-func runCcPrebuiltObjectTestCase(t *testing.T, testCase Bp2buildTestCase) {
-	t.Helper()
-	description := fmt.Sprintf("cc_prebuilt_object: %s", testCase.Description)
-	testCase.ModuleTypeUnderTest = "cc_prebuilt_object"
-	testCase.ModuleTypeUnderTestFactory = cc.PrebuiltObjectFactory
-	testCase.Description = description
-	t.Run(description, func(t *testing.T) {
-		t.Helper()
-		RunBp2BuildTestCaseSimple(t, testCase)
-	})
-}
-
-func TestPrebuiltObject(t *testing.T) {
-	runCcPrebuiltObjectTestCase(t,
-		Bp2buildTestCase{
-			Description: "simple",
-			Filesystem: map[string]string{
-				"obj.o": "",
-			},
-			Blueprint: `
-cc_prebuilt_object {
-	name: "objtest",
-	srcs: ["obj.o"],
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_object", "objtest", AttrNameToString{
-					"src": `"obj.o"`,
-				})},
-		})
-}
-
-func TestPrebuiltObjectWithArchVariance(t *testing.T) {
-	runCcPrebuiltObjectTestCase(t,
-		Bp2buildTestCase{
-			Description: "with arch variance",
-			Filesystem: map[string]string{
-				"obja.o": "",
-				"objb.o": "",
-			},
-			Blueprint: `
-cc_prebuilt_object {
-	name: "objtest",
-	arch: {
-		arm64: { srcs: ["obja.o"], },
-		arm: { srcs: ["objb.o"], },
-	},
-	bazel_module: { bp2build_available: true },
-}`, ExpectedBazelTargets: []string{
-				MakeBazelTarget("cc_prebuilt_object", "objtest", AttrNameToString{
-					"src": `select({
-        "//build/bazel/platforms/arch:arm": "objb.o",
-        "//build/bazel/platforms/arch:arm64": "obja.o",
-        "//conditions:default": None,
-    })`,
-				}),
-			},
-		})
-}
-
-func TestPrebuiltObjectMultipleSrcsFails(t *testing.T) {
-	runCcPrebuiltObjectTestCase(t,
-		Bp2buildTestCase{
-			Description: "fails because multiple sources",
-			Filesystem: map[string]string{
-				"obja": "",
-				"objb": "",
-			},
-			Blueprint: `
-cc_prebuilt_object {
-	name: "objtest",
-	srcs: ["obja.o", "objb.o"],
-	bazel_module: { bp2build_available: true },
-}`,
-			ExpectedErr: fmt.Errorf("Expected at most one source file"),
-		})
-}
-
-// TODO: nosrcs test
diff --git a/bp2build/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go
deleted file mode 100644
index 3c037b4..0000000
--- a/bp2build/cc_test_conversion_test.go
+++ /dev/null
@@ -1,374 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"fmt"
-	"testing"
-
-	"android/soong/android"
-	"android/soong/cc"
-	"android/soong/genrule"
-)
-
-type ccTestBp2buildTestCase struct {
-	description string
-	blueprint   string
-	filesystem  map[string]string
-	targets     []testBazelTarget
-}
-
-func registerCcTestModuleTypes(ctx android.RegistrationContext) {
-	cc.RegisterCCBuildComponents(ctx)
-	ctx.RegisterModuleType("cc_binary", cc.BinaryFactory)
-	ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
-	ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
-	ctx.RegisterModuleType("cc_test_library", cc.TestLibraryFactory)
-	ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
-}
-
-func runCcTestTestCase(t *testing.T, testCase ccTestBp2buildTestCase) {
-	t.Helper()
-	moduleTypeUnderTest := "cc_test"
-	description := fmt.Sprintf("%s %s", moduleTypeUnderTest, testCase.description)
-	t.Run(description, func(t *testing.T) {
-		t.Helper()
-		RunBp2BuildTestCase(t, registerCcTestModuleTypes, Bp2buildTestCase{
-			ExpectedBazelTargets:       generateBazelTargetsForTest(testCase.targets, android.HostAndDeviceSupported),
-			Filesystem:                 testCase.filesystem,
-			ModuleTypeUnderTest:        moduleTypeUnderTest,
-			ModuleTypeUnderTestFactory: cc.TestFactory,
-			Description:                description,
-			Blueprint:                  testCase.blueprint,
-		})
-	})
-}
-
-func TestBasicCcTest(t *testing.T) {
-	runCcTestTestCase(t, ccTestBp2buildTestCase{
-		description: "basic cc_test with commonly used attributes",
-		blueprint: `
-cc_test {
-    name: "mytest",
-    host_supported: true,
-    srcs: ["test.cpp"],
-    target: {
-        android: {
-            srcs: ["android.cpp"],
-            shared_libs: ["foolib"],
-        },
-        linux: {
-            srcs: ["linux.cpp"],
-        },
-        host: {
-            static_libs: ["hostlib"],
-        },
-    },
-    static_libs: ["cc_test_lib1"],
-    shared_libs: ["cc_test_lib2"],
-    data: [":data_mod", "file.txt"],
-    data_bins: [":cc_bin"],
-    data_libs: [":cc_lib"],
-    cflags: ["-Wall"],
-}
-
-cc_test_library {
-    name: "cc_test_lib1",
-    host_supported: true,
-    include_build_directory: false,
-}
-` + simpleModuleDoNotConvertBp2build("cc_library", "foolib") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "hostlib") +
-			simpleModuleDoNotConvertBp2build("genrule", "data_mod") +
-			simpleModuleDoNotConvertBp2build("cc_binary", "cc_bin") +
-			simpleModuleDoNotConvertBp2build("cc_library", "cc_lib") +
-			simpleModuleDoNotConvertBp2build("cc_test_library", "cc_test_lib2") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
-		targets: []testBazelTarget{
-			{"cc_library_shared", "cc_test_lib1", AttrNameToString{}},
-			{"cc_library_static", "cc_test_lib1_bp2build_cc_library_static", AttrNameToString{}},
-			{"cc_test", "mytest", AttrNameToString{
-				"copts": `["-Wall"]`,
-				"data": `[
-        ":data_mod",
-        "file.txt",
-        ":cc_bin",
-        ":cc_lib",
-    ]`,
-				"deps": `[
-        ":cc_test_lib1_bp2build_cc_library_static",
-        ":libgtest_main",
-        ":libgtest",
-    ] + select({
-        "//build/bazel/platforms/os:darwin": [":hostlib"],
-        "//build/bazel/platforms/os:linux_bionic": [":hostlib"],
-        "//build/bazel/platforms/os:linux_glibc": [":hostlib"],
-        "//build/bazel/platforms/os:linux_musl": [":hostlib"],
-        "//build/bazel/platforms/os:windows": [":hostlib"],
-        "//conditions:default": [],
-    })`,
-				"local_includes": `["."]`,
-				"dynamic_deps": `[":cc_test_lib2"] + select({
-        "//build/bazel/platforms/os:android": [":foolib"],
-        "//conditions:default": [],
-    })`,
-				"srcs": `["test.cpp"] + select({
-        "//build/bazel/platforms/os:android": [
-            "linux.cpp",
-            "android.cpp",
-        ],
-        "//build/bazel/platforms/os:linux_bionic": ["linux.cpp"],
-        "//build/bazel/platforms/os:linux_glibc": ["linux.cpp"],
-        "//build/bazel/platforms/os:linux_musl": ["linux.cpp"],
-        "//conditions:default": [],
-    })`,
-			},
-			},
-		},
-	})
-}
-
-func TestBasicCcTestGtestIsolatedDisabled(t *testing.T) {
-	runCcTestTestCase(t, ccTestBp2buildTestCase{
-		description: "cc test with disabled gtest and isolated props",
-		blueprint: `
-cc_test {
-    name: "mytest",
-    host_supported: true,
-    srcs: ["test.cpp"],
-    gtest: false,
-    isolated: false,
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_test", "mytest", AttrNameToString{
-				"gtest":          "False",
-				"local_includes": `["."]`,
-				"srcs":           `["test.cpp"]`,
-			},
-			},
-		},
-	})
-}
-
-func TestCcTest_TestOptions_Tags(t *testing.T) {
-	runCcTestTestCase(t, ccTestBp2buildTestCase{
-		description: "cc test with test_options.tags converted to tags",
-		blueprint: `
-cc_test {
-    name: "mytest",
-    host_supported: true,
-    srcs: ["test.cpp"],
-    test_options: { tags: ["no-remote"] },
-}
-` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
-		targets: []testBazelTarget{
-			{"cc_test", "mytest", AttrNameToString{
-				"tags":           `["no-remote"]`,
-				"local_includes": `["."]`,
-				"srcs":           `["test.cpp"]`,
-				"deps": `[
-        ":libgtest_main",
-        ":libgtest",
-    ]`,
-			},
-			},
-		},
-	})
-}
-
-func TestCcTest_TestConfig(t *testing.T) {
-	runCcTestTestCase(t, ccTestBp2buildTestCase{
-		description: "cc test that sets a test_config",
-		filesystem: map[string]string{
-			"test_config.xml": "",
-		},
-		blueprint: `
-cc_test {
-	name: "mytest",
-	srcs: ["test.cpp"],
-	test_config: "test_config.xml",
-}
-` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
-		targets: []testBazelTarget{
-			{"cc_test", "mytest", AttrNameToString{
-				"local_includes":         `["."]`,
-				"srcs":                   `["test.cpp"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-				"test_config":            `"test_config.xml"`,
-				"deps": `[
-        ":libgtest_main",
-        ":libgtest",
-    ]`,
-			},
-			},
-		},
-	})
-}
-
-func TestCcTest_TestConfigAndroidTestXML(t *testing.T) {
-	runCcTestTestCase(t, ccTestBp2buildTestCase{
-		description: "cc test that defaults to test config AndroidTest.xml",
-		filesystem: map[string]string{
-			"AndroidTest.xml": "",
-		},
-		blueprint: `
-cc_test {
-	name: "mytest",
-	srcs: ["test.cpp"],
-}
-` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
-		targets: []testBazelTarget{
-			{"cc_test", "mytest", AttrNameToString{
-				"local_includes":         `["."]`,
-				"srcs":                   `["test.cpp"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-				"test_config":            `"AndroidTest.xml"`,
-				"deps": `[
-        ":libgtest_main",
-        ":libgtest",
-    ]`,
-			},
-			},
-		},
-	})
-}
-
-func TestCcTest_TestConfigTemplateOptions(t *testing.T) {
-	runCcTestTestCase(t, ccTestBp2buildTestCase{
-		description: "cc test that sets test config template attributes",
-		filesystem: map[string]string{
-			"test_config_template.xml": "",
-		},
-		blueprint: `
-cc_test {
-	name: "mytest",
-	srcs: ["test.cpp"],
-	test_config_template: "test_config_template.xml",
-	auto_gen_config: true,
-	isolated: true,
-}
-` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_isolated_main") +
-			simpleModuleDoNotConvertBp2build("cc_library", "liblog"),
-		targets: []testBazelTarget{
-			{"cc_test", "mytest", AttrNameToString{
-				"auto_generate_test_config": "True",
-				"local_includes":            `["."]`,
-				"srcs":                      `["test.cpp"]`,
-				"target_compatible_with":    `["//build/bazel/platforms/os:android"]`,
-				"template_configs": `[
-        "'<target_preparer class=\"com.android.tradefed.targetprep.RootTargetPreparer\">\\n        <option name=\"force-root\" value=\"false\" />\\n    </target_preparer>'",
-        "'<option name=\"not-shardable\" value=\"true\" />'",
-    ]`,
-				"template_install_base": `"/data/local/tmp"`,
-				"template_test_config":  `"test_config_template.xml"`,
-				"deps":                  `[":libgtest_isolated_main"]`,
-				"dynamic_deps":          `[":liblog"]`,
-			},
-			},
-		},
-	})
-}
-
-func TestCcTest_WithExplicitGTestDepInAndroidBp(t *testing.T) {
-	runCcTestTestCase(t, ccTestBp2buildTestCase{
-		description: "cc test that lists libgtest in Android.bp should not have dups of libgtest in BUILD file",
-		blueprint: `
-cc_test {
-	name: "mytest",
-	srcs: ["test.cpp"],
-	static_libs: ["libgtest"],
-}
-` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
-		targets: []testBazelTarget{
-			{"cc_test", "mytest", AttrNameToString{
-				"local_includes":         `["."]`,
-				"srcs":                   `["test.cpp"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-				"deps": `[
-        ":libgtest",
-        ":libgtest_main",
-    ]`,
-			},
-			},
-		},
-	})
-
-}
-
-func TestCcTest_WithIsolatedTurnedOn(t *testing.T) {
-	runCcTestTestCase(t, ccTestBp2buildTestCase{
-		description: "cc test that sets `isolated: true` should run with ligtest_isolated_main instead of libgtest_main",
-		blueprint: `
-cc_test {
-	name: "mytest",
-	srcs: ["test.cpp"],
-	isolated: true,
-}
-` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_isolated_main") +
-			simpleModuleDoNotConvertBp2build("cc_library", "liblog"),
-		targets: []testBazelTarget{
-			{"cc_test", "mytest", AttrNameToString{
-				"local_includes":         `["."]`,
-				"srcs":                   `["test.cpp"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-				"deps":                   `[":libgtest_isolated_main"]`,
-				"dynamic_deps":           `[":liblog"]`,
-			},
-			},
-		},
-	})
-
-}
-
-func TestCcTest_GtestExplicitlySpecifiedInAndroidBp(t *testing.T) {
-	runCcTestTestCase(t, ccTestBp2buildTestCase{
-		description: "If `gtest` is explicit in Android.bp, it should be explicit in BUILD files as well",
-		blueprint: `
-cc_test {
-	name: "mytest_with_gtest",
-	gtest: true,
-}
-cc_test {
-	name: "mytest_with_no_gtest",
-	gtest: false,
-}
-` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
-		targets: []testBazelTarget{
-			{"cc_test", "mytest_with_gtest", AttrNameToString{
-				"local_includes": `["."]`,
-				"deps": `[
-        ":libgtest_main",
-        ":libgtest",
-    ]`,
-				"gtest":                  "True",
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-			},
-			},
-			{"cc_test", "mytest_with_no_gtest", AttrNameToString{
-				"local_includes":         `["."]`,
-				"gtest":                  "False",
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-			},
-			},
-		},
-	})
-}
diff --git a/bp2build/cc_yasm_conversion_test.go b/bp2build/cc_yasm_conversion_test.go
deleted file mode 100644
index 55d4feb..0000000
--- a/bp2build/cc_yasm_conversion_test.go
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/cc"
-)
-
-func runYasmTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	RunBp2BuildTestCase(t, registerYasmModuleTypes, tc)
-}
-
-func registerYasmModuleTypes(ctx android.RegistrationContext) {
-	cc.RegisterCCBuildComponents(ctx)
-	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
-	ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
-	ctx.RegisterModuleType("cc_prebuilt_library_static", cc.PrebuiltStaticLibraryFactory)
-	ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
-}
-
-func TestYasmSimple(t *testing.T) {
-	runYasmTestCase(t, Bp2buildTestCase{
-		Description:                "Simple yasm test",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"main.cpp":   "",
-			"myfile.asm": "",
-		},
-		Blueprint: `
-cc_library {
-  name: "foo",
-  srcs: ["main.cpp", "myfile.asm"],
-}`,
-		ExpectedBazelTargets: append([]string{
-			MakeBazelTarget("yasm", "foo_yasm", map[string]string{
-				"include_dirs": `["."]`,
-				"srcs":         `["myfile.asm"]`,
-			}),
-		}, makeCcLibraryTargets("foo", map[string]string{
-			"local_includes": `["."]`,
-			"srcs": `[
-        "main.cpp",
-        ":foo_yasm",
-    ]`,
-		})...),
-	})
-}
-
-func TestYasmWithIncludeDirs(t *testing.T) {
-	runYasmTestCase(t, Bp2buildTestCase{
-		Description:                "Simple yasm test",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"main.cpp":                    "",
-			"myfile.asm":                  "",
-			"include1/foo/myinclude.inc":  "",
-			"include2/foo/myinclude2.inc": "",
-		},
-		Blueprint: `
-cc_library {
-  name: "foo",
-  local_include_dirs: ["include1/foo"],
-  export_include_dirs: ["include2/foo"],
-  srcs: ["main.cpp", "myfile.asm"],
-}`,
-		ExpectedBazelTargets: append([]string{
-			MakeBazelTarget("yasm", "foo_yasm", map[string]string{
-				"include_dirs": `[
-        "include1/foo",
-        ".",
-        "include2/foo",
-    ]`,
-				"srcs": `["myfile.asm"]`,
-			}),
-		}, makeCcLibraryTargets("foo", map[string]string{
-			"local_includes": `[
-        "include1/foo",
-        ".",
-    ]`,
-			"export_includes": `["include2/foo"]`,
-			"srcs": `[
-        "main.cpp",
-        ":foo_yasm",
-    ]`,
-		})...),
-	})
-}
-
-func TestYasmConditionalBasedOnArch(t *testing.T) {
-	runYasmTestCase(t, Bp2buildTestCase{
-		Description:                "Simple yasm test",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"main.cpp":   "",
-			"myfile.asm": "",
-		},
-		Blueprint: `
-cc_library {
-  name: "foo",
-  srcs: ["main.cpp"],
-  arch: {
-    x86: {
-      srcs: ["myfile.asm"],
-    },
-  },
-}`,
-		ExpectedBazelTargets: append([]string{
-			MakeBazelTarget("yasm", "foo_yasm", map[string]string{
-				"include_dirs": `["."]`,
-				"srcs": `select({
-        "//build/bazel/platforms/arch:x86": ["myfile.asm"],
-        "//conditions:default": [],
-    })`,
-			}),
-		}, makeCcLibraryTargets("foo", map[string]string{
-			"local_includes": `["."]`,
-			"srcs": `["main.cpp"] + select({
-        "//build/bazel/platforms/arch:x86": [":foo_yasm"],
-        "//conditions:default": [],
-    })`,
-		})...),
-	})
-}
-
-func TestYasmPartiallyConditional(t *testing.T) {
-	runYasmTestCase(t, Bp2buildTestCase{
-		Description:                "Simple yasm test",
-		ModuleTypeUnderTest:        "cc_library",
-		ModuleTypeUnderTestFactory: cc.LibraryFactory,
-		Filesystem: map[string]string{
-			"main.cpp":         "",
-			"myfile.asm":       "",
-			"mysecondfile.asm": "",
-		},
-		Blueprint: `
-cc_library {
-  name: "foo",
-  srcs: ["main.cpp", "myfile.asm"],
-  arch: {
-    x86: {
-      srcs: ["mysecondfile.asm"],
-    },
-  },
-}`,
-		ExpectedBazelTargets: append([]string{
-			MakeBazelTarget("yasm", "foo_yasm", map[string]string{
-				"include_dirs": `["."]`,
-				"srcs": `["myfile.asm"] + select({
-        "//build/bazel/platforms/arch:x86": ["mysecondfile.asm"],
-        "//conditions:default": [],
-    })`,
-			}),
-		}, makeCcLibraryTargets("foo", map[string]string{
-			"local_includes": `["."]`,
-			"srcs": `[
-        "main.cpp",
-        ":foo_yasm",
-    ]`,
-		})...),
-	})
-}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index f280924..9f1aa09 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -1,19 +1,10 @@
 package bp2build
 
 import (
-	"encoding/json"
-	"fmt"
 	"reflect"
-	"strconv"
 	"strings"
 
 	"android/soong/android"
-	"android/soong/apex"
-	"android/soong/cc"
-	cc_config "android/soong/cc/config"
-	java_config "android/soong/java/config"
-	"android/soong/starlark_fmt"
-
 	"github.com/google/blueprint/proptools"
 )
 
@@ -23,87 +14,6 @@
 	Contents string
 }
 
-// PRIVATE: Use CreateSoongInjectionDirFiles instead
-func soongInjectionFiles(cfg android.Config, metrics CodegenMetrics) ([]BazelFile, error) {
-	var files []BazelFile
-
-	files = append(files, newFile("android", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
-	files = append(files, newFile("android", "constants.bzl", android.BazelCcToolchainVars(cfg)))
-
-	files = append(files, newFile("cc_toolchain", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
-	files = append(files, newFile("cc_toolchain", "config_constants.bzl", cc_config.BazelCcToolchainVars(cfg)))
-	files = append(files, newFile("cc_toolchain", "sanitizer_constants.bzl", cc.BazelCcSanitizerToolchainVars(cfg)))
-
-	files = append(files, newFile("java_toolchain", GeneratedBuildFileName, "")) // Creates a //java_toolchain package.
-	files = append(files, newFile("java_toolchain", "constants.bzl", java_config.BazelJavaToolchainVars(cfg)))
-
-	files = append(files, newFile("apex_toolchain", GeneratedBuildFileName, "")) // Creates a //apex_toolchain package.
-	apexToolchainVars, err := apex.BazelApexToolchainVars()
-	if err != nil {
-		return nil, err
-	}
-	files = append(files, newFile("apex_toolchain", "constants.bzl", apexToolchainVars))
-
-	files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.Serialize().ConvertedModules, "\n")))
-
-	convertedModulePathMap, err := json.MarshalIndent(metrics.convertedModulePathMap, "", "\t")
-	if err != nil {
-		panic(err)
-	}
-	files = append(files, newFile("metrics", GeneratedBuildFileName, "")) // Creates a //metrics package.
-	files = append(files, newFile("metrics", "converted_modules_path_map.json", string(convertedModulePathMap)))
-	files = append(files, newFile("metrics", "converted_modules_path_map.bzl", "modules = "+strings.ReplaceAll(string(convertedModulePathMap), "\\", "\\\\")))
-
-	files = append(files, newFile("product_config", "soong_config_variables.bzl", cfg.Bp2buildSoongConfigDefinitions.String()))
-
-	files = append(files, newFile("product_config", "arch_configuration.bzl", android.StarlarkArchConfigurations()))
-
-	apiLevelsMap, err := android.GetApiLevelsMap(cfg)
-	if err != nil {
-		return nil, err
-	}
-	apiLevelsContent, err := json.Marshal(apiLevelsMap)
-	if err != nil {
-		return nil, err
-	}
-	files = append(files, newFile("api_levels", GeneratedBuildFileName, `exports_files(["api_levels.json"])`))
-	// TODO(b/269691302)  value of apiLevelsContent is product variable dependent and should be avoided for soong injection
-	files = append(files, newFile("api_levels", "api_levels.json", string(apiLevelsContent)))
-	files = append(files, newFile("api_levels", "platform_versions.bzl", platformVersionContents(cfg)))
-
-	files = append(files, newFile("allowlists", GeneratedBuildFileName, ""))
-	// TODO(b/262781701): Create an alternate soong_build entrypoint for writing out these files only when requested
-	files = append(files, newFile("allowlists", "mixed_build_prod_allowlist.txt", strings.Join(android.GetBazelEnabledModules(android.BazelProdMode), "\n")+"\n"))
-	files = append(files, newFile("allowlists", "mixed_build_staging_allowlist.txt", strings.Join(android.GetBazelEnabledModules(android.BazelStagingMode), "\n")+"\n"))
-
-	return files, nil
-}
-
-func platformVersionContents(cfg android.Config) string {
-	// Despite these coming from cfg.productVariables, they are actually hardcoded in global
-	// makefiles, not set in individual product config makesfiles, so they're safe to just export
-	// and load() directly.
-
-	platformVersionActiveCodenames := make([]string, 0, len(cfg.PlatformVersionActiveCodenames()))
-	for _, codename := range cfg.PlatformVersionActiveCodenames() {
-		platformVersionActiveCodenames = append(platformVersionActiveCodenames, fmt.Sprintf("%q", codename))
-	}
-
-	platformSdkVersion := "None"
-	if cfg.RawPlatformSdkVersion() != nil {
-		platformSdkVersion = strconv.Itoa(*cfg.RawPlatformSdkVersion())
-	}
-
-	return fmt.Sprintf(`
-platform_versions = struct(
-    platform_sdk_final = %s,
-    platform_sdk_version = %s,
-    platform_sdk_codename = %q,
-    platform_version_active_codenames = [%s],
-)
-`, starlark_fmt.PrintBool(cfg.PlatformSdkFinal()), platformSdkVersion, cfg.PlatformSdkCodename(), strings.Join(platformVersionActiveCodenames, ", "))
-}
-
 func CreateBazelFiles(ruleShims map[string]RuleShim, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
 	var files []BazelFile
 
@@ -137,20 +47,7 @@
 		targets.sort()
 
 		var content string
-		if mode == Bp2Build || mode == ApiBp2build {
-			content = `# READ THIS FIRST:
-# This file was automatically generated by bp2build for the Bazel migration project.
-# Feel free to edit or test it, but do *not* check it into your version control system.
-`
-			content += targets.LoadStatements()
-			content += "\n\n"
-			// Get package rule from the handcrafted BUILD file, otherwise emit the default one.
-			prText := "package(default_visibility = [\"//visibility:public\"])\n"
-			if pr := targets.packageRule(); pr != nil {
-				prText = pr.content
-			}
-			content += prText
-		} else if mode == QueryView {
+		if mode == QueryView {
 			content = soongModuleLoad
 		}
 		if content != "" {
@@ -173,14 +70,6 @@
 
 const (
 	bazelRulesSubDir = "build/bazel/queryview_rules"
-
-	// additional files:
-	//  * workspace file
-	//  * base BUILD file
-	//  * rules BUILD file
-	//  * rules providers.bzl file
-	//  * rules soong_module.bzl file
-	numAdditionalFiles = 5
 )
 
 var (
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index 15284ce..2f806fa 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -17,8 +17,6 @@
 import (
 	"sort"
 	"testing"
-
-	"android/soong/android"
 )
 
 type bazelFilepath struct {
@@ -80,109 +78,3 @@
 		}
 	}
 }
-
-func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
-	testConfig := android.TestConfig("", make(map[string]string), "", make(map[string][]byte))
-	files, err := soongInjectionFiles(testConfig, CreateCodegenMetrics())
-	if err != nil {
-		t.Error(err)
-	}
-	expectedFilePaths := []bazelFilepath{
-		{
-			dir:      "android",
-			basename: GeneratedBuildFileName,
-		},
-		{
-			dir:      "android",
-			basename: "constants.bzl",
-		},
-		{
-			dir:      "cc_toolchain",
-			basename: GeneratedBuildFileName,
-		},
-		{
-			dir:      "cc_toolchain",
-			basename: "config_constants.bzl",
-		},
-		{
-			dir:      "cc_toolchain",
-			basename: "sanitizer_constants.bzl",
-		},
-		{
-			dir:      "java_toolchain",
-			basename: GeneratedBuildFileName,
-		},
-		{
-			dir:      "java_toolchain",
-			basename: "constants.bzl",
-		},
-		{
-			dir:      "apex_toolchain",
-			basename: GeneratedBuildFileName,
-		},
-		{
-			dir:      "apex_toolchain",
-			basename: "constants.bzl",
-		},
-		{
-			dir:      "metrics",
-			basename: "converted_modules.txt",
-		},
-		{
-			dir:      "metrics",
-			basename: "BUILD.bazel",
-		},
-		{
-			dir:      "metrics",
-			basename: "converted_modules_path_map.json",
-		},
-		{
-			dir:      "metrics",
-			basename: "converted_modules_path_map.bzl",
-		},
-		{
-			dir:      "product_config",
-			basename: "soong_config_variables.bzl",
-		},
-		{
-			dir:      "product_config",
-			basename: "arch_configuration.bzl",
-		},
-		{
-			dir:      "api_levels",
-			basename: GeneratedBuildFileName,
-		},
-		{
-			dir:      "api_levels",
-			basename: "api_levels.json",
-		},
-		{
-			dir:      "api_levels",
-			basename: "platform_versions.bzl",
-		},
-		{
-			dir:      "allowlists",
-			basename: GeneratedBuildFileName,
-		},
-		{
-			dir:      "allowlists",
-			basename: "mixed_build_prod_allowlist.txt",
-		},
-		{
-			dir:      "allowlists",
-			basename: "mixed_build_staging_allowlist.txt",
-		},
-	}
-
-	if len(files) != len(expectedFilePaths) {
-		t.Errorf("Expected %d file, got %d", len(expectedFilePaths), len(files))
-	}
-
-	for i := range files {
-		actualFile, expectedFile := files[i], expectedFilePaths[i]
-
-		if actualFile.Dir != expectedFile.dir || actualFile.Basename != expectedFile.basename {
-			t.Errorf("Did not find expected file %s/%s", actualFile.Dir, actualFile.Basename)
-		}
-	}
-}
diff --git a/bp2build/droidstubs_conversion_test.go b/bp2build/droidstubs_conversion_test.go
deleted file mode 100644
index 12c1cfe..0000000
--- a/bp2build/droidstubs_conversion_test.go
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/java"
-)
-
-func registerJavaApiModules(ctx android.RegistrationContext) {
-	java.RegisterSdkLibraryBuildComponents(ctx)
-	java.RegisterStubsBuildComponents(ctx)
-}
-
-func TestDroidstubsApiContributions(t *testing.T) {
-	bp := `
-	droidstubs {
-		name: "framework-stubs",
-		check_api: {
-			current: {
-				api_file: "framework.current.txt",
-			},
-		},
-	}
-
-	// Modules without check_api should not generate a Bazel API target
-	droidstubs {
-		name: "framework-docs",
-	}
-
-	// java_sdk_library is a macro that creates droidstubs
-	java_sdk_library {
-		name: "module-stubs",
-		srcs: ["A.java"],
-
-		// These api surfaces are added by default, but add them explicitly to make
-		// this test hermetic
-		public: {
-			enabled: true,
-		},
-		system: {
-			enabled: true,
-		},
-
-		// Disable other api surfaces to keep unit test scope limited
-		module_lib: {
-			enabled: false,
-		},
-		test: {
-			enabled: false,
-		},
-	}
-	`
-	expectedBazelTargets := []string{
-		MakeBazelTargetNoRestrictions(
-			"java_api_contribution",
-			"framework-stubs.contribution",
-			AttrNameToString{
-				"api":                    `"framework.current.txt"`,
-				"api_surface":            `"publicapi"`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-			}),
-		MakeBazelTargetNoRestrictions(
-			"java_api_contribution",
-			"module-stubs.stubs.source.contribution",
-			AttrNameToString{
-				"api":                    `"api/current.txt"`,
-				"api_surface":            `"publicapi"`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-			}),
-		MakeBazelTargetNoRestrictions(
-			"java_api_contribution",
-			"module-stubs.stubs.source.system.contribution",
-			AttrNameToString{
-				"api":                    `"api/system-current.txt"`,
-				"api_surface":            `"systemapi"`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-			}),
-	}
-	RunApiBp2BuildTestCase(t, registerJavaApiModules, Bp2buildTestCase{
-		Blueprint:            bp,
-		ExpectedBazelTargets: expectedBazelTargets,
-		Filesystem: map[string]string{
-			"api/current.txt":        "",
-			"api/removed.txt":        "",
-			"api/system-current.txt": "",
-			"api/system-removed.txt": "",
-		},
-	})
-}
diff --git a/bp2build/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go
deleted file mode 100644
index cb2e207..0000000
--- a/bp2build/filegroup_conversion_test.go
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"fmt"
-	"testing"
-
-	"android/soong/android"
-)
-
-func runFilegroupTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "filegroup"
-	(&tc).ModuleTypeUnderTestFactory = android.FileGroupFactory
-	RunBp2BuildTestCase(t, registerFilegroupModuleTypes, tc)
-}
-
-func registerFilegroupModuleTypes(ctx android.RegistrationContext) {}
-
-func TestFilegroupSameNameAsFile_OneFile(t *testing.T) {
-	runFilegroupTestCase(t, Bp2buildTestCase{
-		Description: "filegroup - same name as file, with one file",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-filegroup {
-    name: "foo",
-    srcs: ["foo"],
-}
-`,
-		ExpectedBazelTargets: []string{}})
-}
-
-func TestFilegroupSameNameAsFile_MultipleFiles(t *testing.T) {
-	runFilegroupTestCase(t, Bp2buildTestCase{
-		Description: "filegroup - same name as file, with multiple files",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-filegroup {
-	name: "foo",
-	srcs: ["foo", "bar"],
-}
-`,
-		ExpectedErr: fmt.Errorf("filegroup 'foo' cannot contain a file with the same name"),
-	})
-}
-
-func TestFilegroupWithAidlSrcs(t *testing.T) {
-	testcases := []struct {
-		name               string
-		bp                 string
-		expectedBazelAttrs AttrNameToString
-	}{
-		{
-			name: "filegroup with only aidl srcs",
-			bp: `
-	filegroup {
-		name: "foo",
-		srcs: ["aidl/foo.aidl"],
-		path: "aidl",
-	}`,
-			expectedBazelAttrs: AttrNameToString{
-				"srcs":                `["aidl/foo.aidl"]`,
-				"strip_import_prefix": `"aidl"`,
-				"tags":                `["apex_available=//apex_available:anyapex"]`,
-			},
-		},
-		{
-			name: "filegroup without path",
-			bp: `
-	filegroup {
-		name: "foo",
-		srcs: ["aidl/foo.aidl"],
-	}`,
-			expectedBazelAttrs: AttrNameToString{
-				"srcs": `["aidl/foo.aidl"]`,
-				"tags": `["apex_available=//apex_available:anyapex"]`,
-			},
-		},
-	}
-
-	for _, test := range testcases {
-		t.Run(test.name, func(t *testing.T) {
-			expectedBazelTargets := []string{
-				MakeBazelTargetNoRestrictions("aidl_library", "foo", test.expectedBazelAttrs),
-			}
-			runFilegroupTestCase(t, Bp2buildTestCase{
-				Description:          test.name,
-				Blueprint:            test.bp,
-				ExpectedBazelTargets: expectedBazelTargets,
-			})
-		})
-	}
-}
-
-func TestFilegroupWithAidlAndNonAidlSrcs(t *testing.T) {
-	runFilegroupTestCase(t, Bp2buildTestCase{
-		Description: "filegroup with aidl and non-aidl srcs",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-filegroup {
-    name: "foo",
-    srcs: [
-		"aidl/foo.aidl",
-		"buf.proto",
-	],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTargetNoRestrictions("filegroup", "foo", AttrNameToString{
-				"srcs": `[
-        "aidl/foo.aidl",
-        "buf.proto",
-    ]`}),
-		}})
-}
-
-func TestFilegroupWithProtoSrcs(t *testing.T) {
-	runFilegroupTestCase(t, Bp2buildTestCase{
-		Description: "filegroup with proto and non-proto srcs",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-filegroup {
-		name: "foo",
-		srcs: ["proto/foo.proto"],
-		path: "proto",
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTargetNoRestrictions("proto_library", "foo_proto", AttrNameToString{
-				"srcs":                `["proto/foo.proto"]`,
-				"strip_import_prefix": `"proto"`,
-				"tags": `[
-        "apex_available=//apex_available:anyapex",
-        "manual",
-    ]`,
-			}),
-			MakeBazelTargetNoRestrictions("alias", "foo_bp2build_converted", AttrNameToString{
-				"actual": `"//.:foo_proto"`,
-				"tags": `[
-        "apex_available=//apex_available:anyapex",
-        "manual",
-    ]`,
-			}),
-			MakeBazelTargetNoRestrictions("filegroup", "foo", AttrNameToString{
-				"srcs": `["proto/foo.proto"]`}),
-		}})
-}
-
-func TestFilegroupWithProtoAndNonProtoSrcs(t *testing.T) {
-	runFilegroupTestCase(t, Bp2buildTestCase{
-		Description: "filegroup with proto and non-proto srcs",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-filegroup {
-    name: "foo",
-    srcs: [
-		"foo.proto",
-		"buf.cpp",
-	],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTargetNoRestrictions("filegroup", "foo", AttrNameToString{
-				"srcs": `[
-        "foo.proto",
-        "buf.cpp",
-    ]`}),
-		}})
-}
-
-func TestFilegroupWithProtoInDifferentPackage(t *testing.T) {
-	runFilegroupTestCase(t, Bp2buildTestCase{
-		Description: "filegroup with .proto in different package",
-		Filesystem: map[string]string{
-			"subdir/Android.bp": "",
-		},
-		Blueprint: `
-filegroup {
-    name: "foo",
-    srcs: ["subdir/foo.proto"],
-}`,
-		Dir: "subdir", // check in subdir
-		ExpectedBazelTargets: []string{
-			MakeBazelTargetNoRestrictions("proto_library", "foo_proto", AttrNameToString{
-				"srcs":                `["//subdir:foo.proto"]`,
-				"import_prefix":       `"subdir"`,
-				"strip_import_prefix": `""`,
-				"tags": `[
-        "apex_available=//apex_available:anyapex",
-        "manual",
-    ]`}),
-		}})
-}
diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go
deleted file mode 100644
index 5a73969..0000000
--- a/bp2build/genrule_conversion_test.go
+++ /dev/null
@@ -1,774 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"fmt"
-	"path/filepath"
-	"testing"
-
-	"android/soong/android"
-	"android/soong/cc"
-	"android/soong/genrule"
-	"android/soong/java"
-)
-
-func registerGenruleModuleTypes(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("genrule_defaults", func() android.Module { return genrule.DefaultsFactory() })
-}
-
-func runGenruleTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "genrule"
-	(&tc).ModuleTypeUnderTestFactory = genrule.GenRuleFactory
-	RunBp2BuildTestCase(t, registerGenruleModuleTypes, tc)
-}
-
-func otherGenruleBp(genruleTarget string) map[string]string {
-	return map[string]string{
-		"other/Android.bp": fmt.Sprintf(`%s {
-    name: "foo.tool",
-    out: ["foo_tool.out"],
-    srcs: ["foo_tool.in"],
-    cmd: "cp $(in) $(out)",
-}
-%s {
-    name: "other.tool",
-    out: ["other_tool.out"],
-    srcs: ["other_tool.in"],
-    cmd: "cp $(in) $(out)",
-}`, genruleTarget, genruleTarget),
-		"other/file.txt": "",
-	}
-}
-
-func TestGenruleCliVariableReplacement(t *testing.T) {
-	testCases := []struct {
-		moduleType string
-		factory    android.ModuleFactory
-		genDir     string
-		hod        android.HostOrDeviceSupported
-	}{
-		{
-			moduleType: "genrule",
-			factory:    genrule.GenRuleFactory,
-			genDir:     "$(RULEDIR)",
-		},
-		{
-			moduleType: "cc_genrule",
-			factory:    cc.GenRuleFactory,
-			genDir:     "$(RULEDIR)",
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule",
-			factory:    java.GenRuleFactory,
-			genDir:     "$(RULEDIR)",
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule_host",
-			factory:    java.GenRuleFactoryHost,
-			genDir:     "$(RULEDIR)",
-			hod:        android.HostSupported,
-		},
-	}
-
-	bp := `%s {
-    name: "foo.tool",
-    out: ["foo_tool.out"],
-    srcs: ["foo_tool.in"],
-    cmd: "cp $(in) $(out)",
-    bazel_module: { bp2build_available: false },
-}
-
-%s {
-    name: "foo",
-    out: ["foo.out"],
-    srcs: ["foo.in"],
-    tools: [":foo.tool"],
-    cmd: "$(location :foo.tool) --genDir=$(genDir) arg $(in) $(out)",
-    bazel_module: { bp2build_available: true },
-}`
-
-	for _, tc := range testCases {
-		moduleAttrs := AttrNameToString{
-			"cmd":   fmt.Sprintf(`"$(location :foo.tool) --genDir=%s arg $(SRCS) $(OUTS)"`, tc.genDir),
-			"outs":  `["foo.out"]`,
-			"srcs":  `["foo.in"]`,
-			"tools": `[":foo.tool"]`,
-		}
-
-		expectedBazelTargets := []string{
-			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
-		}
-
-		t.Run(tc.moduleType, func(t *testing.T) {
-			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				Bp2buildTestCase{
-					ModuleTypeUnderTest:        tc.moduleType,
-					ModuleTypeUnderTestFactory: tc.factory,
-					Blueprint:                  fmt.Sprintf(bp, tc.moduleType, tc.moduleType),
-					ExpectedBazelTargets:       expectedBazelTargets,
-				})
-		})
-	}
-}
-
-func TestGenruleLocationsLabel(t *testing.T) {
-	testCases := []struct {
-		moduleType string
-		factory    android.ModuleFactory
-		hod        android.HostOrDeviceSupported
-	}{
-		{
-			moduleType: "genrule",
-			factory:    genrule.GenRuleFactory,
-		},
-		{
-			moduleType: "cc_genrule",
-			factory:    cc.GenRuleFactory,
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule",
-			factory:    java.GenRuleFactory,
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule_host",
-			factory:    java.GenRuleFactoryHost,
-			hod:        android.HostSupported,
-		},
-	}
-
-	bp := `%s {
-    name: "foo.tools",
-    out: ["foo_tool.out", "foo_tool2.out"],
-    srcs: ["foo_tool.in"],
-    cmd: "cp $(in) $(out)",
-    bazel_module: { bp2build_available: true },
-}
-
-%s {
-    name: "foo",
-    out: ["foo.out"],
-    srcs: ["foo.in"],
-    tools: [":foo.tools"],
-    cmd: "$(locations :foo.tools) -s $(out) $(in)",
-    bazel_module: { bp2build_available: true },
-}`
-
-	for _, tc := range testCases {
-		fooAttrs := AttrNameToString{
-			"cmd":   `"$(locations :foo.tools) -s $(OUTS) $(SRCS)"`,
-			"outs":  `["foo.out"]`,
-			"srcs":  `["foo.in"]`,
-			"tools": `[":foo.tools"]`,
-		}
-		fooToolsAttrs := AttrNameToString{
-			"cmd": `"cp $(SRCS) $(OUTS)"`,
-			"outs": `[
-        "foo_tool.out",
-        "foo_tool2.out",
-    ]`,
-			"srcs": `["foo_tool.in"]`,
-		}
-
-		expectedBazelTargets := []string{
-			makeBazelTargetHostOrDevice("genrule", "foo", fooAttrs, tc.hod),
-			makeBazelTargetHostOrDevice("genrule", "foo.tools", fooToolsAttrs, tc.hod),
-		}
-
-		t.Run(tc.moduleType, func(t *testing.T) {
-			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				Bp2buildTestCase{
-					ModuleTypeUnderTest:        tc.moduleType,
-					ModuleTypeUnderTestFactory: tc.factory,
-					Blueprint:                  fmt.Sprintf(bp, tc.moduleType, tc.moduleType),
-					ExpectedBazelTargets:       expectedBazelTargets,
-				})
-		})
-	}
-}
-
-func TestGenruleLocationsAbsoluteLabel(t *testing.T) {
-	testCases := []struct {
-		moduleType string
-		factory    android.ModuleFactory
-		hod        android.HostOrDeviceSupported
-	}{
-		{
-			moduleType: "genrule",
-			factory:    genrule.GenRuleFactory,
-		},
-		{
-			moduleType: "cc_genrule",
-			factory:    cc.GenRuleFactory,
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule",
-			factory:    java.GenRuleFactory,
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule_host",
-			factory:    java.GenRuleFactoryHost,
-			hod:        android.HostSupported,
-		},
-	}
-
-	bp := `%s {
-    name: "foo",
-    out: ["foo.out"],
-    srcs: ["foo.in"],
-    tool_files: [":foo.tool"],
-    cmd: "$(locations :foo.tool) -s $(out) $(in)",
-    bazel_module: { bp2build_available: true },
-}`
-
-	for _, tc := range testCases {
-		moduleAttrs := AttrNameToString{
-			"cmd":   `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`,
-			"outs":  `["foo.out"]`,
-			"srcs":  `["foo.in"]`,
-			"tools": `["//other:foo.tool"]`,
-		}
-
-		expectedBazelTargets := []string{
-			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
-		}
-
-		t.Run(tc.moduleType, func(t *testing.T) {
-			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				Bp2buildTestCase{
-					ModuleTypeUnderTest:        tc.moduleType,
-					ModuleTypeUnderTestFactory: tc.factory,
-					Blueprint:                  fmt.Sprintf(bp, tc.moduleType),
-					ExpectedBazelTargets:       expectedBazelTargets,
-					Filesystem:                 otherGenruleBp(tc.moduleType),
-				})
-		})
-	}
-}
-
-func TestGenruleSrcsLocationsAbsoluteLabel(t *testing.T) {
-	testCases := []struct {
-		moduleType string
-		factory    android.ModuleFactory
-		hod        android.HostOrDeviceSupported
-	}{
-		{
-			moduleType: "genrule",
-			factory:    genrule.GenRuleFactory,
-		},
-		{
-			moduleType: "cc_genrule",
-			factory:    cc.GenRuleFactory,
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule",
-			factory:    java.GenRuleFactory,
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule_host",
-			factory:    java.GenRuleFactoryHost,
-			hod:        android.HostSupported,
-		},
-	}
-
-	bp := `%s {
-    name: "foo",
-    out: ["foo.out"],
-    srcs: [":other.tool", "other/file.txt",],
-    tool_files: [":foo.tool"],
-    cmd: "$(locations :foo.tool) $(location other/file.txt) -s $(out) $(location :other.tool)",
-    bazel_module: { bp2build_available: true },
-}`
-
-	for _, tc := range testCases {
-		moduleAttrs := AttrNameToString{
-			"cmd":  `"$(locations //other:foo.tool) $(location //other:file.txt) -s $(OUTS) $(location //other:other.tool)"`,
-			"outs": `["foo.out"]`,
-			"srcs": `[
-        "//other:other.tool",
-        "//other:file.txt",
-    ]`,
-			"tools": `["//other:foo.tool"]`,
-		}
-
-		expectedBazelTargets := []string{
-			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
-		}
-
-		t.Run(tc.moduleType, func(t *testing.T) {
-			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				Bp2buildTestCase{
-					ModuleTypeUnderTest:        tc.moduleType,
-					ModuleTypeUnderTestFactory: tc.factory,
-					Blueprint:                  fmt.Sprintf(bp, tc.moduleType),
-					ExpectedBazelTargets:       expectedBazelTargets,
-					Filesystem:                 otherGenruleBp(tc.moduleType),
-				})
-		})
-	}
-}
-
-func TestGenruleLocationLabelShouldSubstituteFirstToolLabel(t *testing.T) {
-	testCases := []struct {
-		moduleType string
-		factory    android.ModuleFactory
-		hod        android.HostOrDeviceSupported
-	}{
-		{
-			moduleType: "genrule",
-			factory:    genrule.GenRuleFactory,
-		},
-		{
-			moduleType: "cc_genrule",
-			factory:    cc.GenRuleFactory,
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule",
-			factory:    java.GenRuleFactory,
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule_host",
-			factory:    java.GenRuleFactoryHost,
-			hod:        android.HostSupported,
-		},
-	}
-
-	bp := `%s {
-    name: "foo",
-    out: ["foo.out"],
-    srcs: ["foo.in"],
-    tool_files: [":foo.tool", ":other.tool"],
-    cmd: "$(location) -s $(out) $(in)",
-    bazel_module: { bp2build_available: true },
-}`
-
-	for _, tc := range testCases {
-		moduleAttrs := AttrNameToString{
-			"cmd":  `"$(location //other:foo.tool) -s $(OUTS) $(SRCS)"`,
-			"outs": `["foo.out"]`,
-			"srcs": `["foo.in"]`,
-			"tools": `[
-        "//other:foo.tool",
-        "//other:other.tool",
-    ]`,
-		}
-
-		expectedBazelTargets := []string{
-			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
-		}
-
-		t.Run(tc.moduleType, func(t *testing.T) {
-			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				Bp2buildTestCase{
-					ModuleTypeUnderTest:        tc.moduleType,
-					ModuleTypeUnderTestFactory: tc.factory,
-					Blueprint:                  fmt.Sprintf(bp, tc.moduleType),
-					ExpectedBazelTargets:       expectedBazelTargets,
-					Filesystem:                 otherGenruleBp(tc.moduleType),
-				})
-		})
-	}
-}
-
-func TestGenruleLocationsLabelShouldSubstituteFirstToolLabel(t *testing.T) {
-	testCases := []struct {
-		moduleType string
-		factory    android.ModuleFactory
-		hod        android.HostOrDeviceSupported
-	}{
-		{
-			moduleType: "genrule",
-			factory:    genrule.GenRuleFactory,
-		},
-		{
-			moduleType: "cc_genrule",
-			factory:    cc.GenRuleFactory,
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule",
-			factory:    java.GenRuleFactory,
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule_host",
-			factory:    java.GenRuleFactoryHost,
-			hod:        android.HostSupported,
-		},
-	}
-
-	bp := `%s {
-    name: "foo",
-    out: ["foo.out"],
-    srcs: ["foo.in"],
-    tool_files: [":foo.tool", ":other.tool"],
-    cmd: "$(locations) -s $(out) $(in)",
-    bazel_module: { bp2build_available: true },
-}`
-
-	for _, tc := range testCases {
-		moduleAttrs := AttrNameToString{
-			"cmd":  `"$(locations //other:foo.tool) -s $(OUTS) $(SRCS)"`,
-			"outs": `["foo.out"]`,
-			"srcs": `["foo.in"]`,
-			"tools": `[
-        "//other:foo.tool",
-        "//other:other.tool",
-    ]`,
-		}
-
-		expectedBazelTargets := []string{
-			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
-		}
-
-		t.Run(tc.moduleType, func(t *testing.T) {
-			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				Bp2buildTestCase{
-					ModuleTypeUnderTest:        tc.moduleType,
-					ModuleTypeUnderTestFactory: tc.factory,
-					Blueprint:                  fmt.Sprintf(bp, tc.moduleType),
-					ExpectedBazelTargets:       expectedBazelTargets,
-					Filesystem:                 otherGenruleBp(tc.moduleType),
-				})
-		})
-	}
-}
-
-func TestGenruleWithoutToolsOrToolFiles(t *testing.T) {
-	testCases := []struct {
-		moduleType string
-		factory    android.ModuleFactory
-		hod        android.HostOrDeviceSupported
-	}{
-		{
-			moduleType: "genrule",
-			factory:    genrule.GenRuleFactory,
-		},
-		{
-			moduleType: "cc_genrule",
-			factory:    cc.GenRuleFactory,
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule",
-			factory:    java.GenRuleFactory,
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule_host",
-			factory:    java.GenRuleFactoryHost,
-			hod:        android.HostSupported,
-		},
-	}
-
-	bp := `%s {
-    name: "foo",
-    out: ["foo.out"],
-    srcs: ["foo.in"],
-    cmd: "cp $(in) $(out)",
-    bazel_module: { bp2build_available: true },
-}`
-
-	for _, tc := range testCases {
-		moduleAttrs := AttrNameToString{
-			"cmd":  `"cp $(SRCS) $(OUTS)"`,
-			"outs": `["foo.out"]`,
-			"srcs": `["foo.in"]`,
-		}
-
-		expectedBazelTargets := []string{
-			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
-		}
-
-		t.Run(tc.moduleType, func(t *testing.T) {
-			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				Bp2buildTestCase{
-					ModuleTypeUnderTest:        tc.moduleType,
-					ModuleTypeUnderTestFactory: tc.factory,
-					Blueprint:                  fmt.Sprintf(bp, tc.moduleType),
-					ExpectedBazelTargets:       expectedBazelTargets,
-				})
-		})
-	}
-}
-
-func TestGenruleBp2BuildInlinesDefaults(t *testing.T) {
-	testCases := []Bp2buildTestCase{
-		{
-			Description: "genrule applies properties from a genrule_defaults dependency if not specified",
-			Blueprint: `genrule_defaults {
-    name: "gen_defaults",
-    cmd: "do-something $(in) $(out)",
-}
-genrule {
-    name: "gen",
-    out: ["out"],
-    srcs: ["in1"],
-    defaults: ["gen_defaults"],
-    bazel_module: { bp2build_available: true },
-}
-`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{
-					"cmd":  `"do-something $(SRCS) $(OUTS)"`,
-					"outs": `["out"]`,
-					"srcs": `["in1"]`,
-				}),
-			},
-		},
-		{
-			Description: "genrule does merges properties from a genrule_defaults dependency, latest-first",
-			Blueprint: `genrule_defaults {
-    name: "gen_defaults",
-    out: ["out-from-defaults"],
-    srcs: ["in-from-defaults"],
-    cmd: "cmd-from-defaults",
-}
-genrule {
-    name: "gen",
-    out: ["out"],
-    srcs: ["in1"],
-    defaults: ["gen_defaults"],
-    cmd: "do-something $(in) $(out)",
-    bazel_module: { bp2build_available: true },
-}
-`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{
-					"cmd": `"do-something $(SRCS) $(OUTS)"`,
-					"outs": `[
-        "out-from-defaults",
-        "out",
-    ]`,
-					"srcs": `[
-        "in-from-defaults",
-        "in1",
-    ]`,
-				}),
-			},
-		},
-		{
-			Description: "genrule applies properties from list of genrule_defaults",
-			Blueprint: `genrule_defaults {
-    name: "gen_defaults1",
-    cmd: "cp $(in) $(out)",
-}
-
-genrule_defaults {
-    name: "gen_defaults2",
-    srcs: ["in1"],
-}
-
-genrule {
-    name: "gen",
-    out: ["out"],
-    defaults: ["gen_defaults1", "gen_defaults2"],
-    bazel_module: { bp2build_available: true },
-}
-`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{
-					"cmd":  `"cp $(SRCS) $(OUTS)"`,
-					"outs": `["out"]`,
-					"srcs": `["in1"]`,
-				}),
-			},
-		},
-		{
-			Description: "genrule applies properties from genrule_defaults transitively",
-			Blueprint: `genrule_defaults {
-    name: "gen_defaults1",
-    defaults: ["gen_defaults2"],
-    cmd: "cmd1 $(in) $(out)", // overrides gen_defaults2's cmd property value.
-}
-
-genrule_defaults {
-    name: "gen_defaults2",
-    defaults: ["gen_defaults3"],
-    cmd: "cmd2 $(in) $(out)",
-    out: ["out-from-2"],
-    srcs: ["in1"],
-}
-
-genrule_defaults {
-    name: "gen_defaults3",
-    out: ["out-from-3"],
-    srcs: ["srcs-from-3"],
-}
-
-genrule {
-    name: "gen",
-    out: ["out"],
-    defaults: ["gen_defaults1"],
-    bazel_module: { bp2build_available: true },
-}
-`,
-			ExpectedBazelTargets: []string{
-				MakeBazelTargetNoRestrictions("genrule", "gen", AttrNameToString{
-					"cmd": `"cmd1 $(SRCS) $(OUTS)"`,
-					"outs": `[
-        "out-from-3",
-        "out-from-2",
-        "out",
-    ]`,
-					"srcs": `[
-        "srcs-from-3",
-        "in1",
-    ]`,
-				}),
-			},
-		},
-	}
-
-	for _, testCase := range testCases {
-		t.Run(testCase.Description, func(t *testing.T) {
-			runGenruleTestCase(t, testCase)
-		})
-	}
-}
-
-func TestCcGenruleArchAndExcludeSrcs(t *testing.T) {
-	name := "cc_genrule with arch"
-	bp := `
-	cc_genrule {
-		name: "foo",
-		srcs: [
-			"foo1.in",
-			"foo2.in",
-		],
-		exclude_srcs: ["foo2.in"],
-		arch: {
-			arm: {
-				srcs: [
-					"foo1_arch.in",
-					"foo2_arch.in",
-				],
-				exclude_srcs: ["foo2_arch.in"],
-			},
-		},
-		cmd: "cat $(in) > $(out)",
-		bazel_module: { bp2build_available: true },
-	}`
-
-	expectedBazelAttrs := AttrNameToString{
-		"srcs": `["foo1.in"] + select({
-        "//build/bazel/platforms/arch:arm": ["foo1_arch.in"],
-        "//conditions:default": [],
-    })`,
-		"cmd":                    `"cat $(SRCS) > $(OUTS)"`,
-		"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-	}
-
-	expectedBazelTargets := []string{
-		MakeBazelTargetNoRestrictions("genrule", "foo", expectedBazelAttrs),
-	}
-
-	t.Run(name, func(t *testing.T) {
-		RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-			Bp2buildTestCase{
-				ModuleTypeUnderTest:        "cc_genrule",
-				ModuleTypeUnderTestFactory: cc.GenRuleFactory,
-				Blueprint:                  bp,
-				ExpectedBazelTargets:       expectedBazelTargets,
-			})
-	})
-}
-
-func TestGenruleWithExportIncludeDirs(t *testing.T) {
-	testCases := []struct {
-		moduleType string
-		factory    android.ModuleFactory
-		hod        android.HostOrDeviceSupported
-	}{
-		{
-			moduleType: "genrule",
-			factory:    genrule.GenRuleFactory,
-		},
-		{
-			moduleType: "cc_genrule",
-			factory:    cc.GenRuleFactory,
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule",
-			factory:    java.GenRuleFactory,
-			hod:        android.DeviceSupported,
-		},
-		{
-			moduleType: "java_genrule_host",
-			factory:    java.GenRuleFactoryHost,
-			hod:        android.HostSupported,
-		},
-	}
-
-	dir := "baz"
-
-	bp := `%s {
-    name: "foo",
-    out: ["foo.out.h"],
-    srcs: ["foo.in"],
-    cmd: "cp $(in) $(out)",
-    export_include_dirs: ["foo", "bar", "."],
-    bazel_module: { bp2build_available: true },
-}`
-
-	for _, tc := range testCases {
-		moduleAttrs := AttrNameToString{
-			"cmd":  `"cp $(SRCS) $(OUTS)"`,
-			"outs": `["foo.out.h"]`,
-			"srcs": `["foo.in"]`,
-		}
-
-		expectedBazelTargets := []string{
-			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
-			makeBazelTargetHostOrDevice("cc_library_headers", "foo__header_library", AttrNameToString{
-				"hdrs": `[":foo"]`,
-				"export_includes": `[
-        "foo",
-        "baz/foo",
-        "bar",
-        "baz/bar",
-        ".",
-        "baz",
-    ]`,
-			},
-				tc.hod),
-		}
-
-		t.Run(tc.moduleType, func(t *testing.T) {
-			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				Bp2buildTestCase{
-					ModuleTypeUnderTest:        tc.moduleType,
-					ModuleTypeUnderTestFactory: tc.factory,
-					Filesystem: map[string]string{
-						filepath.Join(dir, "Android.bp"): fmt.Sprintf(bp, tc.moduleType),
-					},
-					Dir:                  dir,
-					ExpectedBazelTargets: expectedBazelTargets,
-				})
-		})
-	}
-}
diff --git a/bp2build/gensrcs_conversion_test.go b/bp2build/gensrcs_conversion_test.go
deleted file mode 100644
index e808340..0000000
--- a/bp2build/gensrcs_conversion_test.go
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2020 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"android/soong/android"
-	"android/soong/genrule"
-	"testing"
-)
-
-func TestGensrcs(t *testing.T) {
-	testcases := []struct {
-		name               string
-		bp                 string
-		expectedBazelAttrs AttrNameToString
-	}{
-		{
-			name: "gensrcs with common usage of properties",
-			bp: `
-			gensrcs {
-                name: "foo",
-                srcs: ["test/input.txt", ":external_files"],
-                tool_files: ["program.py"],
-                cmd: "$(location program.py) $(in) $(out) $(location foo/file.txt) $(location :external_files)",
-                data: ["foo/file.txt", ":external_files"],
-                output_extension: "out",
-                bazel_module: { bp2build_available: true },
-			}`,
-			expectedBazelAttrs: AttrNameToString{
-				"srcs": `[
-        "test/input.txt",
-        ":external_files__BP2BUILD__MISSING__DEP",
-    ]`,
-				"tools":            `["program.py"]`,
-				"output_extension": `"out"`,
-				"cmd":              `"$(location program.py) $(SRC) $(OUT) $(location foo/file.txt) $(location :external_files__BP2BUILD__MISSING__DEP)"`,
-				"data": `[
-        "foo/file.txt",
-        ":external_files__BP2BUILD__MISSING__DEP",
-    ]`,
-			},
-		},
-		{
-			name: "gensrcs with out_extension unset",
-			bp: `
-			gensrcs {
-                name: "foo",
-                srcs: ["input.txt"],
-                cmd: "cat $(in) > $(out)",
-                bazel_module: { bp2build_available: true },
-			}`,
-			expectedBazelAttrs: AttrNameToString{
-				"srcs": `["input.txt"]`,
-				"cmd":  `"cat $(SRC) > $(OUT)"`,
-			},
-		},
-	}
-
-	for _, test := range testcases {
-		expectedBazelTargets := []string{
-			MakeBazelTargetNoRestrictions("gensrcs", "foo", test.expectedBazelAttrs),
-		}
-		t.Run(test.name, func(t *testing.T) {
-			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
-				Bp2buildTestCase{
-					ModuleTypeUnderTest:        "gensrcs",
-					ModuleTypeUnderTestFactory: genrule.GenSrcsFactory,
-					Blueprint:                  test.bp,
-					ExpectedBazelTargets:       expectedBazelTargets,
-				})
-		})
-	}
-}
diff --git a/bp2build/go_conversion_test.go b/bp2build/go_conversion_test.go
deleted file mode 100644
index 2387641..0000000
--- a/bp2build/go_conversion_test.go
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"github.com/google/blueprint/bootstrap"
-
-	"android/soong/android"
-)
-
-func runGoTests(t *testing.T, tc Bp2buildTestCase) {
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
-		tCtx := ctx.(*android.TestContext)
-		bootstrap.RegisterGoModuleTypes(tCtx.Context.Context) // android.TestContext --> android.Context --> blueprint.Context
-	}, tc)
-}
-
-func TestConvertGoPackage(t *testing.T) {
-	bp := `
-bootstrap_go_package {
-	name: "foo",
-	pkgPath: "android/foo",
-	deps: [
-		"bar",
-	],
-	srcs: [
-		"foo1.go",
-		"foo2.go",
-	],
-	linux: {
-		srcs: [
-			"foo_linux.go",
-		],
-		testSrcs: [
-			"foo_linux_test.go",
-		],
-	},
-	darwin: {
-		srcs: [
-			"foo_darwin.go",
-		],
-		testSrcs: [
-			"foo_darwin_test.go",
-		],
-	},
-	testSrcs: [
-		"foo1_test.go",
-		"foo2_test.go",
-	],
-}
-`
-	depBp := `
-bootstrap_go_package {
-	name: "bar",
-}
-`
-	t.Parallel()
-	runGoTests(t, Bp2buildTestCase{
-		Description:         "Convert bootstrap_go_package to go_library",
-		ModuleTypeUnderTest: "bootrstap_go_package",
-		Blueprint:           bp,
-		Filesystem: map[string]string{
-			"bar/Android.bp": depBp, // Put dep in Android.bp to reduce boilerplate in ExpectedBazelTargets
-		},
-		ExpectedBazelTargets: []string{makeBazelTargetHostOrDevice("go_library", "foo",
-			AttrNameToString{
-				"deps":       `["//bar:bar"]`,
-				"importpath": `"android/foo"`,
-				"srcs": `[
-        "foo1.go",
-        "foo2.go",
-    ] + select({
-        "//build/bazel/platforms/os:darwin": ["foo_darwin.go"],
-        "//build/bazel/platforms/os:linux_glibc": ["foo_linux.go"],
-        "//conditions:default": [],
-    })`,
-			},
-			android.HostSupported,
-		),
-			makeBazelTargetHostOrDevice("go_test", "foo-test",
-				AttrNameToString{
-					"embed": `[":foo"]`,
-					"srcs": `[
-        "foo1_test.go",
-        "foo2_test.go",
-    ] + select({
-        "//build/bazel/platforms/os:darwin": ["foo_darwin_test.go"],
-        "//build/bazel/platforms/os:linux_glibc": ["foo_linux_test.go"],
-        "//conditions:default": [],
-    })`,
-				},
-				android.HostSupported,
-			)},
-	})
-}
-
-func TestConvertGoBinaryWithTransitiveDeps(t *testing.T) {
-	bp := `
-blueprint_go_binary {
-	name: "foo",
-	srcs: ["main.go"],
-	deps: ["bar"],
-}
-`
-	depBp := `
-bootstrap_go_package {
-	name: "bar",
-	deps: ["baz"],
-}
-bootstrap_go_package {
-	name: "baz",
-}
-`
-	t.Parallel()
-	runGoTests(t, Bp2buildTestCase{
-		Description: "Convert blueprint_go_binary to go_binary",
-		Blueprint:   bp,
-		Filesystem: map[string]string{
-			"bar/Android.bp": depBp, // Put dep in Android.bp to reduce boilerplate in ExpectedBazelTargets
-		},
-		ExpectedBazelTargets: []string{makeBazelTargetHostOrDevice("go_binary", "foo",
-			AttrNameToString{
-				"deps": `[
-        "//bar:bar",
-        "//bar:baz",
-    ]`,
-				"srcs": `["main.go"]`,
-			},
-			android.HostSupported,
-		)},
-	})
-}
-
-func TestConvertGoBinaryWithTestSrcs(t *testing.T) {
-	bp := `
-blueprint_go_binary {
-	name: "foo",
-	srcs: ["main.go"],
-	testSrcs: ["main_test.go"],
-}
-`
-	t.Parallel()
-	runGoTests(t, Bp2buildTestCase{
-		Description: "Convert blueprint_go_binary with testSrcs",
-		Blueprint:   bp,
-		ExpectedBazelTargets: []string{
-			makeBazelTargetHostOrDevice("go_binary", "foo",
-				AttrNameToString{
-					"deps":  `[]`,
-					"embed": `[":foo-source"]`,
-				},
-				android.HostSupported,
-			),
-			makeBazelTargetHostOrDevice("go_source", "foo-source",
-				AttrNameToString{
-					"deps": `[]`,
-					"srcs": `["main.go"]`,
-				},
-				android.HostSupported,
-			),
-			makeBazelTargetHostOrDevice("go_test", "foo-test",
-				AttrNameToString{
-					"embed": `[":foo-source"]`,
-					"srcs":  `["main_test.go"]`,
-				},
-				android.HostSupported,
-			),
-		},
-	})
-}
-
-func TestConvertGoBinaryWithSrcInDifferentPackage(t *testing.T) {
-	bp := `
-blueprint_go_binary {
-	name: "foo",
-	srcs: ["subdir/main.go"],
-}
-`
-	t.Parallel()
-	runGoTests(t, Bp2buildTestCase{
-		Description: "Convert blueprint_go_binary with src in different package",
-		Blueprint:   bp,
-		Filesystem: map[string]string{
-			"subdir/Android.bp": "",
-		},
-		ExpectedBazelTargets: []string{makeBazelTargetHostOrDevice("go_binary", "foo",
-			AttrNameToString{
-				"deps": `[]`,
-				"srcs": `["//subdir:main.go"]`,
-			},
-			android.HostSupported,
-		)},
-	})
-}
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
deleted file mode 100644
index 39e55c4..0000000
--- a/bp2build/java_binary_host_conversion_test.go
+++ /dev/null
@@ -1,337 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/cc"
-	"android/soong/java"
-)
-
-func runJavaBinaryHostTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "java_binary_host"
-	(&tc).ModuleTypeUnderTestFactory = java.BinaryHostFactory
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("cc_library_host_shared", cc.LibraryHostSharedFactory)
-		ctx.RegisterModuleType("java_library", java.LibraryFactory)
-		ctx.RegisterModuleType("java_import_host", java.ImportFactory)
-	}, tc)
-}
-
-var testFs = map[string]string{
-	"test.mf": "Main-Class: com.android.test.MainClass",
-	"other/Android.bp": `cc_library_host_shared {
-    name: "jni-lib-1",
-    stl: "none",
-}`,
-}
-
-func TestJavaBinaryHost(t *testing.T) {
-	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
-		Description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.",
-		Filesystem:  testFs,
-		Blueprint: `java_binary_host {
-    name: "java-binary-host-1",
-    srcs: ["a.java", "b.java"],
-    exclude_srcs: ["b.java"],
-    manifest: "test.mf",
-    jni_libs: ["jni-lib-1"],
-    javacflags: ["-Xdoclint:all/protected"],
-    bazel_module: { bp2build_available: true },
-    java_version: "8",
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-binary-host-1_lib", AttrNameToString{
-				"srcs":         `["a.java"]`,
-				"deps":         `["//other:jni-lib-1"]`,
-				"java_version": `"8"`,
-				"javacopts":    `["-Xdoclint:all/protected"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("java_binary", "java-binary-host-1", AttrNameToString{
-				"main_class": `"com.android.test.MainClass"`,
-				"jvm_flags":  `["-Djava.library.path=$${RUNPATH}other/jni-lib-1"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-				"runtime_deps": `[":java-binary-host-1_lib"]`,
-			}),
-		},
-	})
-}
-
-func TestJavaBinaryHostRuntimeDeps(t *testing.T) {
-	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
-		Description: "java_binary_host with srcs, exclude_srcs, jni_libs, javacflags, and manifest.",
-		Filesystem:  testFs,
-		Blueprint: `java_binary_host {
-    name: "java-binary-host-1",
-    static_libs: ["java-dep-1"],
-    manifest: "test.mf",
-    bazel_module: { bp2build_available: true },
-}
-
-java_library {
-    name: "java-dep-1",
-    srcs: ["a.java"],
-    bazel_module: { bp2build_available: false },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_binary", "java-binary-host-1", AttrNameToString{
-				"main_class":   `"com.android.test.MainClass"`,
-				"runtime_deps": `[":java-dep-1"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestJavaBinaryHostLibs(t *testing.T) {
-	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
-		Description: "java_binary_host with srcs, libs.",
-		Filesystem:  testFs,
-		Blueprint: `java_binary_host {
-    name: "java-binary-host-libs",
-    libs: ["java-lib-dep-1"],
-    manifest: "test.mf",
-    srcs: ["a.java"],
-}
-
-java_import_host{
-    name: "java-lib-dep-1",
-    jars: ["foo.jar"],
-    bazel_module: { bp2build_available: false },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-binary-host-libs_lib", AttrNameToString{
-				"srcs": `["a.java"]`,
-				"deps": `[":java-lib-dep-1-neverlink"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("java_binary", "java-binary-host-libs", AttrNameToString{
-				"main_class": `"com.android.test.MainClass"`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-				"runtime_deps": `[":java-binary-host-libs_lib"]`,
-			}),
-		},
-	})
-}
-
-func TestJavaBinaryHostKotlinSrcs(t *testing.T) {
-	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
-		Description: "java_binary_host with srcs, libs.",
-		Filesystem:  testFs,
-		Blueprint: `java_binary_host {
-    name: "java-binary-host",
-    manifest: "test.mf",
-    srcs: ["a.java", "b.kt"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
-				"srcs": `[
-        "a.java",
-        "b.kt",
-    ]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
-				"main_class":   `"com.android.test.MainClass"`,
-				"runtime_deps": `[":java-binary-host_lib"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestJavaBinaryHostKotlinCommonSrcs(t *testing.T) {
-	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
-		Description: "java_binary_host with common_srcs",
-		Filesystem:  testFs,
-		Blueprint: `java_binary_host {
-    name: "java-binary-host",
-    manifest: "test.mf",
-    srcs: ["a.java"],
-    common_srcs: ["b.kt"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
-				"srcs":        `["a.java"]`,
-				"common_srcs": `["b.kt"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
-				"main_class":   `"com.android.test.MainClass"`,
-				"runtime_deps": `[":java-binary-host_lib"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestJavaBinaryHostKotlinWithResourceDir(t *testing.T) {
-	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
-		Description: "java_binary_host with srcs, libs, resource dir  .",
-		Filesystem: map[string]string{
-			"test.mf":        "Main-Class: com.android.test.MainClass",
-			"res/a.res":      "",
-			"res/dir1/b.res": "",
-		},
-		Blueprint: `java_binary_host {
-    name: "java-binary-host",
-    manifest: "test.mf",
-    srcs: ["a.java", "b.kt"],
-    java_resource_dirs: ["res"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
-				"srcs": `[
-        "a.java",
-        "b.kt",
-    ]`,
-				"resources": `[
-        "res/a.res",
-        "res/dir1/b.res",
-    ]`,
-				"resource_strip_prefix": `"res"`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
-				"main_class":   `"com.android.test.MainClass"`,
-				"runtime_deps": `[":java-binary-host_lib"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestJavaBinaryHostKotlinWithResources(t *testing.T) {
-	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
-		Description: "java_binary_host with srcs, libs, resources.",
-		Filesystem: map[string]string{
-			"adir/test.mf":   "Main-Class: com.android.test.MainClass",
-			"adir/res/a.res": "",
-			"adir/res/b.res": "",
-			"adir/Android.bp": `java_binary_host {
-    name: "java-binary-host",
-    manifest: "test.mf",
-    srcs: ["a.java", "b.kt"],
-    java_resources: ["res/a.res", "res/b.res"],
-    bazel_module: { bp2build_available: true },
-}
-`,
-		},
-		Dir:       "adir",
-		Blueprint: "",
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
-				"srcs": `[
-        "a.java",
-        "b.kt",
-    ]`,
-				"resources": `[
-        "res/a.res",
-        "res/b.res",
-    ]`,
-				"resource_strip_prefix": `"adir"`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
-				"main_class":   `"com.android.test.MainClass"`,
-				"runtime_deps": `[":java-binary-host_lib"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestJavaBinaryHostKotlinCflags(t *testing.T) {
-	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
-		Description: "java_binary_host with kotlincflags",
-		Filesystem:  testFs,
-		Blueprint: `java_binary_host {
-    name: "java-binary-host",
-    manifest: "test.mf",
-    srcs: ["a.kt"],
-    kotlincflags: ["-flag1", "-flag2"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
-				"srcs": `["a.kt"]`,
-				"kotlincflags": `[
-        "-flag1",
-        "-flag2",
-    ]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("java_binary", "java-binary-host", AttrNameToString{
-				"main_class":   `"com.android.test.MainClass"`,
-				"runtime_deps": `[":java-binary-host_lib"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/java_host_for_device_conversion_test.go b/bp2build/java_host_for_device_conversion_test.go
deleted file mode 100644
index 448cba4..0000000
--- a/bp2build/java_host_for_device_conversion_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/java"
-)
-
-func runJavaHostForDeviceTestCaseWithRegistrationCtxFunc(t *testing.T, tc Bp2buildTestCase, registrationCtxFunc func(ctx android.RegistrationContext)) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "java_host_for_device"
-	(&tc).ModuleTypeUnderTestFactory = java.HostForDeviceFactory
-	RunBp2BuildTestCase(t, registrationCtxFunc, tc)
-}
-
-func runJavaHostForDeviceTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	runJavaHostForDeviceTestCaseWithRegistrationCtxFunc(t, tc, func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("java_library", java.LibraryFactory)
-	})
-}
-
-func TestJavaHostForDevice(t *testing.T) {
-	runJavaHostForDeviceTestCase(t, Bp2buildTestCase{
-		Description: "java_host_for_device test",
-		Blueprint: `java_host_for_device {
-    name: "java-lib-1",
-    libs: ["java-lib-2"],
-    bazel_module: { bp2build_available: true },
-}
-
-java_library {
-    name: "java-lib-2",
-    srcs: ["b.java"],
-    bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_host_for_device", "java-lib-1", AttrNameToString{
-				"exports": `[":java-lib-2"]`,
-			}),
-			MakeNeverlinkDuplicateTargetWithAttrs("java_library", "java-lib-1", AttrNameToString{
-				"sdk_version": `"none"`,
-			}),
-			MakeBazelTarget("java_library", "java-lib-2", AttrNameToString{
-				"srcs": `["b.java"]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-2"),
-		},
-	})
-}
diff --git a/bp2build/java_import_conversion_test.go b/bp2build/java_import_conversion_test.go
deleted file mode 100644
index 5661620..0000000
--- a/bp2build/java_import_conversion_test.go
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"android/soong/android"
-	"android/soong/java"
-
-	"testing"
-)
-
-func runJavaImportTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	RunBp2BuildTestCase(t, registerJavaImportModuleTypes, tc)
-}
-
-func registerJavaImportModuleTypes(ctx android.RegistrationContext) {
-}
-
-func TestJavaImportMinimal(t *testing.T) {
-	runJavaImportTestCase(t, Bp2buildTestCase{
-		Description:                "Java import - simple example",
-		ModuleTypeUnderTest:        "java_import",
-		ModuleTypeUnderTestFactory: java.ImportFactory,
-		Filesystem: map[string]string{
-			"import.jar": "",
-		},
-		Blueprint: `
-java_import {
-        name: "example_import",
-        jars: ["import.jar"],
-        bazel_module: { bp2build_available: true },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_import", "example_import", AttrNameToString{
-				"jars": `["import.jar"]`,
-			}),
-			MakeBazelTarget("java_library", "example_import-neverlink", AttrNameToString{
-				"exports":     `[":example_import"]`,
-				"neverlink":   `True`,
-				"sdk_version": `"none"`,
-			}),
-		}})
-}
-
-func TestJavaImportArchVariant(t *testing.T) {
-	runJavaImportTestCase(t, Bp2buildTestCase{
-		Description:                "Java import - simple example",
-		ModuleTypeUnderTest:        "java_import",
-		ModuleTypeUnderTestFactory: java.ImportFactory,
-		Filesystem: map[string]string{
-			"import.jar": "",
-		},
-		Blueprint: `
-java_import {
-        name: "example_import",
-		target: {
-			android: {
-				jars: ["android.jar"],
-			},
-			linux_glibc: {
-				jars: ["linux.jar"],
-			},
-		},
-        bazel_module: { bp2build_available: true },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_import", "example_import", AttrNameToString{
-				"jars": `select({
-        "//build/bazel/platforms/os:android": ["android.jar"],
-        "//build/bazel/platforms/os:linux_glibc": ["linux.jar"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("java_library", "example_import-neverlink", AttrNameToString{
-				"exports":     `[":example_import"]`,
-				"neverlink":   `True`,
-				"sdk_version": `"none"`,
-			}),
-		}})
-}
-
-func TestJavaImportHost(t *testing.T) {
-	runJavaImportTestCase(t, Bp2buildTestCase{
-		Description:                "Java import host- simple example",
-		ModuleTypeUnderTest:        "java_import_host",
-		ModuleTypeUnderTestFactory: java.ImportFactory,
-		Filesystem: map[string]string{
-			"import.jar": "",
-		},
-		Blueprint: `
-java_import_host {
-        name: "example_import",
-        jars: ["import.jar"],
-        bazel_module: { bp2build_available: true },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_import", "example_import", AttrNameToString{
-				"jars": `["import.jar"]`,
-			}),
-			MakeBazelTarget("java_library", "example_import-neverlink", AttrNameToString{
-				"exports":     `[":example_import"]`,
-				"neverlink":   `True`,
-				"sdk_version": `"none"`,
-			}),
-		}})
-}
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
deleted file mode 100644
index c501a7b..0000000
--- a/bp2build/java_library_conversion_test.go
+++ /dev/null
@@ -1,880 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"fmt"
-	"testing"
-
-	"android/soong/android"
-	"android/soong/java"
-)
-
-func runJavaLibraryTestCaseWithRegistrationCtxFunc(t *testing.T, tc Bp2buildTestCase, registrationCtxFunc func(ctx android.RegistrationContext)) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "java_library"
-	(&tc).ModuleTypeUnderTestFactory = java.LibraryFactory
-	RunBp2BuildTestCase(t, registrationCtxFunc, tc)
-}
-
-func runJavaLibraryTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, tc, func(ctx android.RegistrationContext) {})
-}
-
-func TestJavaLibrary(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Description: "java_library with srcs, exclude_srcs and libs",
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    srcs: ["a.java", "b.java"],
-    exclude_srcs: ["b.java"],
-    libs: ["java-lib-2"],
-    bazel_module: { bp2build_available: true },
-}
-
-java_library {
-    name: "java-lib-2",
-    srcs: ["b.java"],
-    bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"srcs": `["a.java"]`,
-				"deps": `[":java-lib-2-neverlink"]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-			MakeBazelTarget("java_library", "java-lib-2", AttrNameToString{
-				"srcs": `["b.java"]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-2"),
-		},
-	})
-}
-
-func TestJavaLibraryConvertsStaticLibsToDepsAndExports(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    srcs: ["a.java"],
-    libs: ["java-lib-2"],
-    static_libs: ["java-lib-3"],
-    bazel_module: { bp2build_available: true },
-}
-
-java_library {
-    name: "java-lib-2",
-    srcs: ["b.java"],
-    bazel_module: { bp2build_available: false },
-}
-
-java_library {
-    name: "java-lib-3",
-    srcs: ["c.java"],
-    bazel_module: { bp2build_available: false },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"srcs": `["a.java"]`,
-				"deps": `[
-        ":java-lib-2-neverlink",
-        ":java-lib-3",
-    ]`,
-				"exports": `[":java-lib-3"]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-		},
-	})
-}
-
-func TestJavaLibraryConvertsStaticLibsToExportsIfNoSrcs(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    static_libs: ["java-lib-2"],
-    bazel_module: { bp2build_available: true },
-}
-
-java_library {
-    name: "java-lib-2",
-    srcs: ["a.java"],
-    bazel_module: { bp2build_available: false },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"exports": `[":java-lib-2"]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-		},
-	})
-}
-
-func TestJavaLibraryFailsToConvertLibsWithNoSrcs(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		ExpectedErr: fmt.Errorf("Module has direct dependencies but no sources. Bazel will not allow this."),
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    libs: ["java-lib-2"],
-    bazel_module: { bp2build_available: true },
-}
-
-java_library {
-    name: "java-lib-2",
-    srcs: ["a.java"],
-    bazel_module: { bp2build_available: false },
-}`,
-		ExpectedBazelTargets: []string{},
-	})
-}
-
-func TestJavaLibraryPlugins(t *testing.T) {
-	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    plugins: ["java-plugin-1"],
-    bazel_module: { bp2build_available: true },
-}
-
-java_plugin {
-    name: "java-plugin-1",
-    srcs: ["a.java"],
-    bazel_module: { bp2build_available: false },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"plugins": `[":java-plugin-1"]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-		},
-	}, func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("java_plugin", java.PluginFactory)
-	})
-}
-
-func TestJavaLibraryJavaVersion(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    srcs: ["a.java"],
-    java_version: "11",
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"srcs":         `["a.java"]`,
-				"java_version": `"11"`,
-			}),
-			MakeNeverlinkDuplicateTargetWithAttrs(
-				"java_library",
-				"java-lib-1",
-				AttrNameToString{"java_version": `"11"`}),
-		},
-	})
-}
-
-func TestJavaLibraryErrorproneEnabledManually(t *testing.T) {
-	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    srcs: ["a.java"],
-    javacflags: ["-Xsuper-fast"],
-    errorprone: {
-        enabled: true,
-        javacflags: ["-Xep:SpeedLimit:OFF"],
-        extra_check_modules: ["plugin2"],
-    },
-}
-java_plugin {
-    name: "plugin2",
-    srcs: ["a.java"],
-    bazel_module: { bp2build_available: false },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"javacopts": `[
-        "-Xsuper-fast",
-        "-Xep:SpeedLimit:OFF",
-    ]`,
-				"plugins":                 `[":plugin2"]`,
-				"srcs":                    `["a.java"]`,
-				"errorprone_force_enable": `True`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-		},
-	}, func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("java_plugin", java.PluginFactory)
-	})
-}
-
-func TestJavaLibraryErrorproneJavacflagsErrorproneDisabledByDefault(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    srcs: ["a.java"],
-    javacflags: ["-Xsuper-fast"],
-    errorprone: {
-        javacflags: ["-Xep:SpeedLimit:OFF"],
-    },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"javacopts": `["-Xsuper-fast"]`,
-				"srcs":      `["a.java"]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-		},
-	})
-}
-
-func TestJavaLibraryErrorproneDisabledManually(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    srcs: ["a.java"],
-    javacflags: ["-Xsuper-fast"],
-    errorprone: {
-    enabled: false,
-    },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"javacopts": `[
-        "-Xsuper-fast",
-        "-XepDisableAllChecks",
-    ]`,
-				"srcs": `["a.java"]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-		},
-	})
-}
-
-func TestJavaLibraryLogTags(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "Java library - logtags creates separate dependency",
-		ModuleTypeUnderTest:        "java_library",
-		ModuleTypeUnderTestFactory: java.LibraryFactory,
-		Blueprint: `java_library {
-        name: "example_lib",
-        srcs: [
-			"a.java",
-			"b.java",
-			"a.logtag",
-			"b.logtag",
-		],
-        bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("event_log_tags", "example_lib_logtags", AttrNameToString{
-				"srcs": `[
-        "a.logtag",
-        "b.logtag",
-    ]`,
-			}),
-			MakeBazelTarget("java_library", "example_lib", AttrNameToString{
-				"srcs": `[
-        "a.java",
-        "b.java",
-        ":example_lib_logtags",
-    ]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "example_lib"),
-		}})
-}
-
-func TestJavaLibraryResources(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Dir: "adir",
-		Filesystem: map[string]string{
-			"adir/res/a.res":      "",
-			"adir/res/b.res":      "",
-			"adir/res/dir1/b.res": "",
-			"adir/Android.bp": `java_library {
-    name: "java-lib-1",
-    java_resources: ["res/a.res", "res/b.res"],
-    bazel_module: { bp2build_available: true },
-}`,
-		},
-		Blueprint: "",
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"resources": `[
-        "res/a.res",
-        "res/b.res",
-    ]`,
-				"resource_strip_prefix": `"adir"`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-		},
-	})
-}
-
-func TestJavaLibraryResourceDirs(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Filesystem: map[string]string{
-			"res/a.res":      "",
-			"res/b.res":      "",
-			"res/dir1/b.res": "",
-		},
-		Blueprint: `java_library {
-    name: "java-lib-1",
-	java_resource_dirs: ["res"],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"resource_strip_prefix": `"res"`,
-				"resources": `[
-        "res/a.res",
-        "res/b.res",
-        "res/dir1/b.res",
-    ]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-		},
-	})
-}
-
-func TestJavaLibraryResourcesExcludeDir(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Filesystem: map[string]string{
-			"res/a.res":         "",
-			"res/exclude/b.res": "",
-		},
-		Blueprint: `java_library {
-    name: "java-lib-1",
-	java_resource_dirs: ["res"],
-	exclude_java_resource_dirs: ["res/exclude"],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"resource_strip_prefix": `"res"`,
-				"resources":             `["res/a.res"]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-		},
-	})
-}
-
-func TestJavaLibraryResourcesExcludeFile(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Filesystem: map[string]string{
-			"res/a.res":            "",
-			"res/dir1/b.res":       "",
-			"res/dir1/exclude.res": "",
-		},
-		Blueprint: `java_library {
-    name: "java-lib-1",
-	java_resource_dirs: ["res"],
-	exclude_java_resources: ["res/dir1/exclude.res"],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"resource_strip_prefix": `"res"`,
-				"resources": `[
-        "res/a.res",
-        "res/dir1/b.res",
-    ]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-		},
-	})
-}
-
-func TestJavaLibraryResourcesFailsWithMultipleDirs(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Filesystem: map[string]string{
-			"res/a.res":  "",
-			"res1/a.res": "",
-		},
-		Blueprint: `java_library {
-    name: "java-lib-1",
-	java_resource_dirs: ["res", "res1"],
-}`,
-		ExpectedErr:          fmt.Errorf("bp2build does not support more than one directory in java_resource_dirs (b/226423379)"),
-		ExpectedBazelTargets: []string{},
-	})
-}
-
-func TestJavaLibraryAidl(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Description:                "Java library - aidl creates separate dependency",
-		ModuleTypeUnderTest:        "java_library",
-		ModuleTypeUnderTestFactory: java.LibraryFactory,
-		Blueprint: `java_library {
-        name: "example_lib",
-        srcs: [
-			"a.java",
-			"b.java",
-			"a.aidl",
-			"b.aidl",
-		],
-        bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("aidl_library", "example_lib_aidl_library", AttrNameToString{
-				"srcs": `[
-        "a.aidl",
-        "b.aidl",
-    ]`,
-			}),
-			MakeBazelTarget("java_aidl_library", "example_lib_java_aidl_library", AttrNameToString{
-				"deps": `[":example_lib_aidl_library"]`,
-			}),
-			MakeBazelTarget("java_library", "example_lib", AttrNameToString{
-				"deps":    `[":example_lib_java_aidl_library"]`,
-				"exports": `[":example_lib_java_aidl_library"]`,
-				"srcs": `[
-        "a.java",
-        "b.java",
-    ]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "example_lib"),
-		}})
-}
-
-func TestJavaLibraryAidlSrcsNoFileGroup(t *testing.T) {
-	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
-		Description:                "Java library - aidl filegroup is parsed",
-		ModuleTypeUnderTest:        "java_library",
-		ModuleTypeUnderTestFactory: java.LibraryFactory,
-		Blueprint: `
-java_library {
-        name: "example_lib",
-        srcs: [
-			"a.java",
-			"b.aidl",
-		],
-        bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("aidl_library", "example_lib_aidl_library", AttrNameToString{
-				"srcs": `["b.aidl"]`,
-			}),
-			MakeBazelTarget("java_aidl_library", "example_lib_java_aidl_library", AttrNameToString{
-				"deps": `[":example_lib_aidl_library"]`,
-			}),
-			MakeBazelTarget("java_library", "example_lib", AttrNameToString{
-				"deps":    `[":example_lib_java_aidl_library"]`,
-				"exports": `[":example_lib_java_aidl_library"]`,
-				"srcs":    `["a.java"]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "example_lib"),
-		},
-	}, func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
-	})
-}
-
-func TestJavaLibraryAidlFilegroup(t *testing.T) {
-	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
-		Description:                "Java library - aidl filegroup is parsed",
-		ModuleTypeUnderTest:        "java_library",
-		ModuleTypeUnderTestFactory: java.LibraryFactory,
-		Blueprint: `
-filegroup {
-	name: "random_other_files",
-	srcs: [
-		"a.java",
-		"b.java",
-	],
-}
-filegroup {
-	name: "aidl_files",
-	srcs: [
-		"a.aidl",
-		"b.aidl",
-	],
-}
-java_library {
-        name: "example_lib",
-        srcs: [
-			"a.java",
-			"b.java",
-			":aidl_files",
-			":random_other_files",
-		],
-        bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTargetNoRestrictions("aidl_library", "aidl_files", AttrNameToString{
-				"srcs": `[
-        "a.aidl",
-        "b.aidl",
-    ]`,
-				"tags": `["apex_available=//apex_available:anyapex"]`,
-			}),
-			MakeBazelTarget("java_aidl_library", "example_lib_java_aidl_library", AttrNameToString{
-				"deps": `[":aidl_files"]`,
-			}),
-			MakeBazelTarget("java_library", "example_lib", AttrNameToString{
-				"deps":    `[":example_lib_java_aidl_library"]`,
-				"exports": `[":example_lib_java_aidl_library"]`,
-				"srcs": `[
-        "a.java",
-        "b.java",
-        ":random_other_files",
-    ]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "example_lib"),
-			MakeBazelTargetNoRestrictions("filegroup", "random_other_files", AttrNameToString{
-				"srcs": `[
-        "a.java",
-        "b.java",
-    ]`,
-			}),
-		},
-	}, func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
-	})
-}
-
-func TestJavaLibraryAidlNonAdjacentAidlFilegroup(t *testing.T) {
-	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
-		Description:                "java_library with non adjacent aidl filegroup",
-		ModuleTypeUnderTest:        "java_library",
-		ModuleTypeUnderTestFactory: java.LibraryFactory,
-		Filesystem: map[string]string{
-			"path/to/A/Android.bp": `
-filegroup {
-	name: "A_aidl",
-	srcs: ["aidl/A.aidl"],
-	path: "aidl",
-}`,
-		},
-		Blueprint: `
-java_library {
-	name: "foo",
-	srcs: [
-		":A_aidl",
-	],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_aidl_library", "foo_java_aidl_library", AttrNameToString{
-				"deps": `["//path/to/A:A_aidl"]`,
-			}),
-			MakeBazelTarget("java_library", "foo", AttrNameToString{
-				"exports": `[":foo_java_aidl_library"]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "foo"),
-		},
-	}, func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
-	})
-}
-
-func TestConvertArmNeonVariant(t *testing.T) {
-	t.Helper()
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
-		Description:                "Android Library - simple arch feature",
-		ModuleTypeUnderTest:        "android_library",
-		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
-		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
-android_library {
-	name: "TestLib",
-	manifest: "manifest/AndroidManifest.xml",
-	srcs: ["lib.java"],
-	arch: {
-		arm: {
-			neon: {
-				srcs: ["arm_neon.java"],
-			},
-		},
-	},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget(
-				"android_library",
-				"TestLib",
-				AttrNameToString{
-					"srcs": `["lib.java"] + select({
-        "//build/bazel/platforms/arch/variants:arm-neon": ["arm_neon.java"],
-        "//conditions:default": [],
-    })`,
-					"manifest":       `"manifest/AndroidManifest.xml"`,
-					"resource_files": `[]`,
-				}),
-			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
-		}})
-}
-
-func TestConvertMultipleArchFeatures(t *testing.T) {
-	t.Helper()
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
-		Description:                "Android Library - multiple arch features",
-		ModuleTypeUnderTest:        "android_library",
-		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
-		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
-android_library {
-	name: "TestLib",
-	manifest: "manifest/AndroidManifest.xml",
-	srcs: ["lib.java"],
-	arch: {
-		x86: {
-			ssse3: {
-				srcs: ["ssse3.java"],
-			},
-			sse4_1: {
-				srcs: ["sse4_1.java"],
-			},
-		},
-	},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget(
-				"android_library",
-				"TestLib",
-				AttrNameToString{
-					"srcs": `["lib.java"] + select({
-        "//build/bazel/platforms/arch/variants:x86-sse4_1": ["sse4_1.java"],
-        "//build/bazel/platforms/arch/variants:x86-sse4_1-ssse3": [
-            "sse4_1.java",
-            "ssse3.java",
-        ],
-        "//build/bazel/platforms/arch/variants:x86-ssse3": ["ssse3.java"],
-        "//conditions:default": [],
-    })`,
-					"manifest":       `"manifest/AndroidManifest.xml"`,
-					"resource_files": `[]`,
-				}),
-			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
-		}})
-}
-
-func TestConvertExcludeSrcsArchFeature(t *testing.T) {
-	t.Helper()
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
-		Description:                "Android Library - exclude_srcs with arch feature",
-		ModuleTypeUnderTest:        "android_library",
-		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
-		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
-android_library {
-	name: "TestLib",
-	manifest: "manifest/AndroidManifest.xml",
-	srcs: ["lib.java"],
-	arch: {
-		arm: {
-			srcs: ["arm_non_neon.java"],
-			neon: {
-				exclude_srcs: ["arm_non_neon.java"],
-			},
-		},
-	},
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget(
-				"android_library",
-				"TestLib",
-				AttrNameToString{
-					"srcs": `["lib.java"] + select({
-        "//build/bazel/platforms/arch/variants:arm-neon": [],
-        "//build/bazel/platforms/arch:arm": ["arm_non_neon.java"],
-        "//conditions:default": [],
-    })`,
-					"manifest":       `"manifest/AndroidManifest.xml"`,
-					"resource_files": `[]`,
-				}),
-			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
-		}})
-}
-
-func TestJavaLibraryKotlinSrcs(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Description: "java_library with kotlin srcs",
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    srcs: ["a.java", "b.java", "c.kt"],
-    bazel_module: { bp2build_available: true },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("kt_jvm_library", "java-lib-1", AttrNameToString{
-				"srcs": `[
-        "a.java",
-        "b.java",
-        "c.kt",
-    ]`,
-			}),
-			MakeNeverlinkDuplicateTarget("kt_jvm_library", "java-lib-1"),
-		},
-	})
-}
-
-func TestJavaLibraryKotlincflags(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Description: "java_library with kotlincfalgs",
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    srcs: [ "a.kt"],
-    kotlincflags: ["-flag1", "-flag2"],
-    bazel_module: { bp2build_available: true },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("kt_jvm_library", "java-lib-1", AttrNameToString{
-				"srcs": `["a.kt"]`,
-				"kotlincflags": `[
-        "-flag1",
-        "-flag2",
-    ]`,
-			}),
-			MakeNeverlinkDuplicateTarget("kt_jvm_library", "java-lib-1"),
-		},
-	})
-}
-
-func TestJavaLibraryKotlinCommonSrcs(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Description: "java_library with kotlin common_srcs",
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    srcs: ["a.java", "b.java"],
-    common_srcs: ["c.kt"],
-    bazel_module: { bp2build_available: true },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("kt_jvm_library", "java-lib-1", AttrNameToString{
-				"srcs": `[
-        "a.java",
-        "b.java",
-    ]`,
-				"common_srcs": `["c.kt"]`,
-			}),
-			MakeNeverlinkDuplicateTarget("kt_jvm_library", "java-lib-1"),
-		},
-	})
-}
-
-func TestJavaLibraryArchVariantDeps(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Description: "java_library with arch variant libs",
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    srcs: ["a.java"],
-    libs: ["java-lib-2"],
-    target: {
-        android: {
-            libs: ["java-lib-3"],
-            static_libs: ["java-lib-4"],
-        },
-    },
-    bazel_module: { bp2build_available: true },
-}
-
-	java_library{
-		name: "java-lib-2",
-}
-
-	java_library{
-		name: "java-lib-3",
-}
-
-	java_library{
-		name: "java-lib-4",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"srcs": `["a.java"]`,
-				"exports": `select({
-        "//build/bazel/platforms/os:android": [":java-lib-4"],
-        "//conditions:default": [],
-    })`,
-				"deps": `[":java-lib-2-neverlink"] + select({
-        "//build/bazel/platforms/os:android": [
-            ":java-lib-3-neverlink",
-            ":java-lib-4",
-        ],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-			MakeBazelTarget("java_library", "java-lib-2", AttrNameToString{}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-2"),
-			MakeBazelTarget("java_library", "java-lib-3", AttrNameToString{}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-3"),
-			MakeBazelTarget("java_library", "java-lib-4", AttrNameToString{}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-4"),
-		},
-	})
-}
-
-func TestJavaLibraryArchVariantSrcsWithExcludes(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Description: "java_library with arch variant libs",
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    srcs: ["a.java", "b.java"],
-    target: {
-        android: {
-            exclude_srcs: ["a.java"],
-        },
-    },
-    bazel_module: { bp2build_available: true },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"srcs": `["b.java"] + select({
-        "//build/bazel/platforms/os:android": [],
-        "//conditions:default": ["a.java"],
-    })`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-		},
-	})
-}
-
-func TestJavaLibraryJavaResourcesSingleFilegroup(t *testing.T) {
-	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
-		Filesystem: map[string]string{
-			"res/a.res":      "",
-			"res/b.res":      "",
-			"res/dir1/b.res": "",
-		},
-		Description: "java_library",
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    srcs: ["a.java"],
-    java_resources: [":filegroup1"],
-    bazel_module: { bp2build_available: true },
-}
-
-filegroup {
-    name: "filegroup1",
-    path: "foo",
-    srcs: ["foo/a", "foo/b"],
-}
-
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"srcs":                  `["a.java"]`,
-				"resources":             `[":filegroup1"]`,
-				"resource_strip_prefix": `"foo"`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-			MakeBazelTargetNoRestrictions("filegroup", "filegroup1", AttrNameToString{
-				"srcs": `[
-        "foo/a",
-        "foo/b",
-    ]`}),
-		},
-	}, func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
-	})
-}
diff --git a/bp2build/java_library_host_conversion_test.go b/bp2build/java_library_host_conversion_test.go
deleted file mode 100644
index 9e47b09..0000000
--- a/bp2build/java_library_host_conversion_test.go
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/java"
-)
-
-func runJavaLibraryHostTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "java_library_host"
-	(&tc).ModuleTypeUnderTestFactory = java.LibraryHostFactory
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
-}
-
-func TestJavaLibraryHost(t *testing.T) {
-	runJavaLibraryHostTestCase(t, Bp2buildTestCase{
-		Description: "java_library_host with srcs, exclude_srcs and libs",
-		Blueprint: `java_library_host {
-    name: "java-lib-host-1",
-    srcs: ["a.java", "b.java"],
-    exclude_srcs: ["b.java"],
-    libs: ["java-lib-host-2"],
-    bazel_module: { bp2build_available: true },
-}
-
-java_library_host {
-    name: "java-lib-host-2",
-    srcs: ["c.java"],
-    bazel_module: { bp2build_available: true },
-    java_version: "9",
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-host-1", AttrNameToString{
-				"srcs": `["a.java"]`,
-				"deps": `[":java-lib-host-2-neverlink"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("java_library", "java-lib-host-1-neverlink", AttrNameToString{
-				"exports":   `[":java-lib-host-1"]`,
-				"neverlink": `True`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("java_library", "java-lib-host-2", AttrNameToString{
-				"java_version": `"9"`,
-				"srcs":         `["c.java"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("java_library", "java-lib-host-2-neverlink", AttrNameToString{
-				"exports":   `[":java-lib-host-2"]`,
-				"neverlink": `True`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-				"java_version": `"9"`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/java_plugin_conversion_test.go b/bp2build/java_plugin_conversion_test.go
deleted file mode 100644
index f2b6f20..0000000
--- a/bp2build/java_plugin_conversion_test.go
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/java"
-)
-
-func runJavaPluginTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "java_plugin"
-	(&tc).ModuleTypeUnderTestFactory = java.PluginFactory
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("java_library", java.LibraryFactory)
-	}, tc)
-}
-
-func TestJavaPlugin(t *testing.T) {
-	runJavaPluginTestCase(t, Bp2buildTestCase{
-		Description: "java_plugin with srcs, libs, static_libs",
-		Blueprint: `java_plugin {
-    name: "java-plug-1",
-    srcs: ["a.java", "b.java"],
-    libs: ["java-lib-1"],
-    static_libs: ["java-lib-2"],
-    bazel_module: { bp2build_available: true },
-    java_version: "7",
-}
-
-java_library {
-    name: "java-lib-1",
-    srcs: ["b.java"],
-    bazel_module: { bp2build_available: false },
-}
-
-java_library {
-    name: "java-lib-2",
-    srcs: ["c.java"],
-    bazel_module: { bp2build_available: false },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_plugin", "java-plug-1", AttrNameToString{
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-				"deps": `[
-        ":java-lib-1-neverlink",
-        ":java-lib-2",
-    ]`,
-				"srcs": `[
-        "a.java",
-        "b.java",
-    ]`,
-				"java_version": `"7"`,
-			}),
-		},
-	})
-}
-
-func TestJavaPluginNoSrcs(t *testing.T) {
-	runJavaPluginTestCase(t, Bp2buildTestCase{
-		Description: "java_plugin without srcs converts (static) libs to deps",
-		Blueprint: `java_plugin {
-    name: "java-plug-1",
-    libs: ["java-lib-1"],
-    static_libs: ["java-lib-2"],
-    bazel_module: { bp2build_available: true },
-}
-
-java_library {
-    name: "java-lib-1",
-    srcs: ["b.java"],
-    bazel_module: { bp2build_available: false },
-}
-
-java_library {
-    name: "java-lib-2",
-    srcs: ["c.java"],
-    bazel_module: { bp2build_available: false },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_plugin", "java-plug-1", AttrNameToString{
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-				"deps": `[
-        ":java-lib-1-neverlink",
-        ":java-lib-2",
-    ]`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/java_proto_conversion_test.go b/bp2build/java_proto_conversion_test.go
deleted file mode 100644
index f546cf4..0000000
--- a/bp2build/java_proto_conversion_test.go
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"fmt"
-	"testing"
-
-	"android/soong/android"
-	"android/soong/java"
-)
-
-func runJavaProtoTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "java_library_static"
-	(&tc).ModuleTypeUnderTestFactory = java.LibraryFactory
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
-}
-
-func TestJavaProto(t *testing.T) {
-	testCases := []struct {
-		protoType                string
-		javaLibraryType          string
-		javaLibraryNameExtension string
-	}{
-		{
-			protoType:                "nano",
-			javaLibraryType:          "java_nano_proto_library",
-			javaLibraryNameExtension: "java_proto_nano",
-		},
-		{
-			protoType:                "micro",
-			javaLibraryType:          "java_micro_proto_library",
-			javaLibraryNameExtension: "java_proto_micro",
-		},
-		{
-			protoType:                "lite",
-			javaLibraryType:          "java_lite_proto_library",
-			javaLibraryNameExtension: "java_proto_lite",
-		},
-		{
-			protoType:                "stream",
-			javaLibraryType:          "java_stream_proto_library",
-			javaLibraryNameExtension: "java_proto_stream",
-		},
-		{
-			protoType:                "full",
-			javaLibraryType:          "java_proto_library",
-			javaLibraryNameExtension: "java_proto",
-		},
-	}
-
-	bp := `java_library_static {
-    name: "java-protos",
-    proto: {
-        type: "%s",
-    },
-    srcs: ["a.proto"],
-}`
-
-	protoLibrary := MakeBazelTarget("proto_library", "java-protos_proto", AttrNameToString{
-		"srcs": `["a.proto"]`,
-	})
-
-	for _, tc := range testCases {
-		javaLibraryName := fmt.Sprintf("java-protos_%s", tc.javaLibraryNameExtension)
-
-		runJavaProtoTestCase(t, Bp2buildTestCase{
-			Description: fmt.Sprintf("java_proto %s", tc.protoType),
-			Blueprint:   fmt.Sprintf(bp, tc.protoType),
-			ExpectedBazelTargets: []string{
-				protoLibrary,
-				MakeBazelTarget(
-					tc.javaLibraryType,
-					javaLibraryName,
-					AttrNameToString{
-						"deps": `[":java-protos_proto"]`,
-					}),
-				MakeBazelTarget("java_library", "java-protos", AttrNameToString{
-					"exports": fmt.Sprintf(`[":%s"]`, javaLibraryName),
-				}),
-				MakeNeverlinkDuplicateTarget("java_library", "java-protos"),
-			},
-		})
-	}
-}
-
-func TestJavaProtoDefault(t *testing.T) {
-	runJavaProtoTestCase(t, Bp2buildTestCase{
-		Description: "java_library proto default",
-		Blueprint: `java_library_static {
-    name: "java-protos",
-    srcs: ["a.proto"],
-    java_version: "7",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("proto_library", "java-protos_proto", AttrNameToString{
-				"srcs": `["a.proto"]`,
-			}),
-			MakeBazelTarget(
-				"java_lite_proto_library",
-				"java-protos_java_proto_lite",
-				AttrNameToString{
-					"deps":         `[":java-protos_proto"]`,
-					"java_version": `"7"`,
-				}),
-			MakeBazelTarget("java_library", "java-protos", AttrNameToString{
-				"exports":      `[":java-protos_java_proto_lite"]`,
-				"java_version": `"7"`,
-			}),
-			MakeNeverlinkDuplicateTargetWithAttrs(
-				"java_library",
-				"java-protos",
-				AttrNameToString{"java_version": `"7"`}),
-		},
-	})
-}
diff --git a/bp2build/java_sdk_library_conversion_test.go b/bp2build/java_sdk_library_conversion_test.go
deleted file mode 100644
index 9ce7446..0000000
--- a/bp2build/java_sdk_library_conversion_test.go
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/java"
-)
-
-func runJavaSdkLibraryTestCaseWithRegistrationCtxFunc(t *testing.T, tc Bp2buildTestCase, registrationCtxFunc func(ctx android.RegistrationContext)) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "java_sdk_library"
-	(&tc).ModuleTypeUnderTestFactory = java.SdkLibraryFactory
-	RunBp2BuildTestCase(t, registrationCtxFunc, tc)
-}
-
-func runJavaSdkLibraryTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	runJavaSdkLibraryTestCaseWithRegistrationCtxFunc(t, tc, func(ctx android.RegistrationContext) {})
-}
-
-func TestJavaSdkLibraryApiSurfaceGeneral(t *testing.T) {
-	runJavaSdkLibraryTestCase(t, Bp2buildTestCase{
-		Description: "limited java_sdk_library for api surfaces, general conversion",
-		Filesystem: map[string]string{
-			"build/soong/scripts/gen-java-current-api-files.sh": "",
-			"api/current.txt":               "",
-			"api/system-current.txt":        "",
-			"api/test-current.txt":          "",
-			"api/module-lib-current.txt":    "",
-			"api/system-server-current.txt": "",
-			"api/removed.txt":               "",
-			"api/system-removed.txt":        "",
-			"api/test-removed.txt":          "",
-			"api/module-lib-removed.txt":    "",
-			"api/system-server-removed.txt": "",
-		},
-		Blueprint: `java_sdk_library {
-    name: "java-sdk-lib",
-    srcs: ["a.java"],
-    public: {enabled: true},
-    system: {enabled: true},
-    test: {enabled: true},
-    module_lib: {enabled: true},
-    system_server: {enabled: true},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_sdk_library", "java-sdk-lib", AttrNameToString{
-				"public":        `"api/current.txt"`,
-				"system":        `"api/system-current.txt"`,
-				"test":          `"api/test-current.txt"`,
-				"module_lib":    `"api/module-lib-current.txt"`,
-				"system_server": `"api/system-server-current.txt"`,
-			}),
-		},
-	})
-}
-
-func TestJavaSdkLibraryApiSurfacePublicDefault(t *testing.T) {
-	runJavaSdkLibraryTestCase(t, Bp2buildTestCase{
-		Description: "limited java_sdk_library for api surfaces, public prop uses default value",
-		Filesystem: map[string]string{
-			"build/soong/scripts/gen-java-current-api-files.sh": "",
-			"api/current.txt":               "",
-			"api/system-current.txt":        "",
-			"api/test-current.txt":          "",
-			"api/module-lib-current.txt":    "",
-			"api/system-server-current.txt": "",
-			"api/removed.txt":               "",
-			"api/system-removed.txt":        "",
-			"api/test-removed.txt":          "",
-			"api/module-lib-removed.txt":    "",
-			"api/system-server-removed.txt": "",
-		},
-		Blueprint: `java_sdk_library {
-    name: "java-sdk-lib",
-    srcs: ["a.java"],
-    system: {enabled: false},
-    test: {enabled: false},
-    module_lib: {enabled: false},
-    system_server: {enabled: false},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_sdk_library", "java-sdk-lib", AttrNameToString{
-				"public": `"api/current.txt"`,
-			}),
-		},
-	})
-}
-
-func TestJavaSdkLibraryApiSurfacePublicNotEnabled(t *testing.T) {
-	runJavaSdkLibraryTestCase(t, Bp2buildTestCase{
-		Description: "limited java_sdk_library for api surfaces, public enable is false",
-		Filesystem: map[string]string{
-			"build/soong/scripts/gen-java-current-api-files.sh": "",
-			"api/current.txt": "",
-			"api/removed.txt": "",
-		},
-		Blueprint: `java_sdk_library {
-   name: "java-sdk-lib",
-   srcs: ["a.java"],
-   public: {enabled: false},
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_sdk_library", "java-sdk-lib", AttrNameToString{}),
-		},
-	})
-}
-
-func TestJavaSdkLibraryApiSurfaceNoScopeIsSet(t *testing.T) {
-	runJavaSdkLibraryTestCase(t, Bp2buildTestCase{
-		Description: "limited java_sdk_library for api surfaces, none of the api scopes is set",
-		Filesystem: map[string]string{
-			"build/soong/scripts/gen-java-current-api-files.sh": "",
-			"api/current.txt":        "",
-			"api/system-current.txt": "",
-			"api/test-current.txt":   "",
-			"api/removed.txt":        "",
-			"api/system-removed.txt": "",
-			"api/test-removed.txt":   "",
-		},
-		Blueprint: `java_sdk_library {
-   name: "java-sdk-lib",
-   srcs: ["a.java"],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_sdk_library", "java-sdk-lib", AttrNameToString{
-				"public": `"api/current.txt"`,
-				"system": `"api/system-current.txt"`,
-				"test":   `"api/test-current.txt"`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/java_test_host_conversion_test.go b/bp2build/java_test_host_conversion_test.go
deleted file mode 100644
index f41345e..0000000
--- a/bp2build/java_test_host_conversion_test.go
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/java"
-)
-
-func runJavaTestHostTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "java_test_host"
-	(&tc).ModuleTypeUnderTestFactory = java.TestHostFactory
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("java_library", java.LibraryFactory)
-	}, tc)
-}
-
-func TestJavaTestHostGeneral(t *testing.T) {
-	runJavaTestHostTestCase(t, Bp2buildTestCase{
-		Description: "java_test_host general",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-java_test_host {
-    name: "java_test_host-1",
-    srcs: ["a.java", "b.java"],
-    libs: ["lib_a"],
-    static_libs: ["static_libs_a"],
-    exclude_srcs: ["b.java"],
-    javacflags: ["-Xdoclint:all/protected"],
-    java_version: "8",
-}
-
-java_library {
-    name: "lib_a",
-    bazel_module: { bp2build_available: false },
-}
-
-java_library {
-    name: "static_libs_a",
-    bazel_module: { bp2build_available: false },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java_test_host-1_lib", AttrNameToString{
-				"deps": `[
-        ":lib_a-neverlink",
-        ":static_libs_a",
-    ]`,
-				"java_version": `"8"`,
-				"javacopts":    `["-Xdoclint:all/protected"]`,
-				"srcs":         `["a.java"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("java_test", "java_test_host-1", AttrNameToString{
-				"runtime_deps": `[":java_test_host-1_lib"]`,
-				"deps": `[
-        ":lib_a-neverlink",
-        ":static_libs_a",
-    ]`,
-				"srcs": `["a.java"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestJavaTestHostNoSrcs(t *testing.T) {
-	runJavaTestHostTestCase(t, Bp2buildTestCase{
-		Description: "java_test_host without srcs",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-java_test_host {
-    name: "java_test_host-1",
-    libs: ["lib_a"],
-    static_libs: ["static_libs_a"],
-}
-
-java_library {
-    name: "lib_a",
-    bazel_module: { bp2build_available: false },
-}
-
-java_library {
-    name: "static_libs_a",
-    bazel_module: { bp2build_available: false },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_test", "java_test_host-1", AttrNameToString{
-				"runtime_deps": `[
-        ":lib_a-neverlink",
-        ":static_libs_a",
-    ]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestJavaTestHostKotlinSrcs(t *testing.T) {
-	runJavaTestHostTestCase(t, Bp2buildTestCase{
-		Description: "java_test_host with .kt in srcs",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-java_test_host {
-    name: "java_test_host-1",
-    srcs: ["a.java", "b.kt"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_test", "java_test_host-1", AttrNameToString{
-				"srcs": `[
-        "a.java",
-        "b.kt",
-    ]`,
-				"runtime_deps": `[":java_test_host-1_lib"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-			MakeBazelTarget("kt_jvm_library", "java_test_host-1_lib", AttrNameToString{
-				"srcs": `[
-        "a.java",
-        "b.kt",
-    ]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/license_conversion_test.go b/bp2build/license_conversion_test.go
deleted file mode 100644
index ea6b27a..0000000
--- a/bp2build/license_conversion_test.go
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"android/soong/android"
-	"testing"
-)
-
-func registerLicenseModuleTypes(_ android.RegistrationContext) {}
-
-func TestLicenseBp2Build(t *testing.T) {
-	tests := []struct {
-		description string
-		module      string
-		expected    ExpectedRuleTarget
-	}{
-		{
-			description: "license kind and text notice",
-			module: `
-license {
-    name: "my_license",
-    license_kinds: [ "SPDX-license-identifier-Apache-2.0"],
-    license_text: [ "NOTICE"],
-}`,
-			expected: ExpectedRuleTarget{
-				"android_license",
-				"my_license",
-				AttrNameToString{
-					"license_kinds": `["SPDX-license-identifier-Apache-2.0"]`,
-					"license_text":  `"NOTICE"`,
-				},
-				android.HostAndDeviceDefault,
-			},
-		},
-		{
-			description: "visibility, package_name, copyright_notice",
-			module: `
-license {
-	name: "my_license",
-    package_name: "my_package",
-    visibility: [":__subpackages__"],
-    copyright_notice: "Copyright © 2022",
-}`,
-			expected: ExpectedRuleTarget{
-				"android_license",
-				"my_license",
-				AttrNameToString{
-					"copyright_notice": `"Copyright © 2022"`,
-					"package_name":     `"my_package"`,
-					"visibility":       `[":__subpackages__"]`,
-				},
-				android.HostAndDeviceDefault,
-			},
-		},
-	}
-
-	for _, test := range tests {
-		RunBp2BuildTestCase(t,
-			registerLicenseModuleTypes,
-			Bp2buildTestCase{
-				Description:                test.description,
-				ModuleTypeUnderTest:        "license",
-				ModuleTypeUnderTestFactory: android.LicenseFactory,
-				Blueprint:                  test.module,
-				ExpectedBazelTargets:       []string{test.expected.String()},
-			})
-	}
-}
diff --git a/bp2build/license_kind_conversion_test.go b/bp2build/license_kind_conversion_test.go
deleted file mode 100644
index eda116c..0000000
--- a/bp2build/license_kind_conversion_test.go
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"android/soong/android"
-	"testing"
-)
-
-func registerLicenseKindModuleTypes(_ android.RegistrationContext) {}
-
-func TestLicenseKindBp2Build(t *testing.T) {
-	tests := []struct {
-		description string
-		module      string
-		expected    ExpectedRuleTarget
-	}{
-		{
-			description: "license_kind",
-			module: `
-license_kind {
-    name: "my_license",
-    conditions: [
-        "by_exception_only",
-        "not_allowed",
-    ],
-    url: "https://spdx.org/licenses/0BSD",
-    visibility: ["//visibility:public"],
-}`,
-			expected: ExpectedRuleTarget{
-				"license_kind",
-				"my_license",
-				AttrNameToString{
-					"conditions": `[
-        "by_exception_only",
-        "not_allowed",
-    ]`,
-					"url":        `"https://spdx.org/licenses/0BSD"`,
-					"visibility": `["//visibility:public"]`,
-				},
-				android.HostAndDeviceDefault,
-			},
-		},
-	}
-
-	for _, test := range tests {
-		RunBp2BuildTestCase(t,
-			registerLicenseKindModuleTypes,
-			Bp2buildTestCase{
-				Description:                test.description,
-				ModuleTypeUnderTest:        "license_kind",
-				ModuleTypeUnderTestFactory: android.LicenseKindFactory,
-				Blueprint:                  test.module,
-				ExpectedBazelTargets:       []string{test.expected.String()},
-			})
-	}
-}
diff --git a/bp2build/linker_config_conversion_test.go b/bp2build/linker_config_conversion_test.go
deleted file mode 100644
index 5e7bcd4..0000000
--- a/bp2build/linker_config_conversion_test.go
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"fmt"
-	"testing"
-
-	"android/soong/linkerconfig"
-)
-
-func runLinkerConfigTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "linker_config"
-	(&tc).ModuleTypeUnderTestFactory = linkerconfig.LinkerConfigFactory
-	RunBp2BuildTestCaseSimple(t, tc)
-}
-
-func TestLinkerConfigConvertsSrc(t *testing.T) {
-	runLinkerConfigTestCase(t,
-		Bp2buildTestCase{
-			Blueprint: `
-linker_config {
-	name: "foo",
-	src: "a.json",
-}
-`,
-			ExpectedBazelTargets: []string{MakeBazelTarget("linker_config", "foo", AttrNameToString{
-				"src": `"a.json"`,
-			})},
-		})
-
-}
-
-func TestLinkerConfigNoSrc(t *testing.T) {
-	runLinkerConfigTestCase(t,
-		Bp2buildTestCase{
-			Blueprint: `
-linker_config {
-	name: "foo",
-}
-`,
-			ExpectedBazelTargets: []string{},
-			ExpectedErr:          fmt.Errorf("Android.bp:2:1: module \"foo\": src: empty src is not supported"),
-		})
-
-}
diff --git a/bp2build/metrics.go b/bp2build/metrics.go
deleted file mode 100644
index 00f21c8..0000000
--- a/bp2build/metrics.go
+++ /dev/null
@@ -1,218 +0,0 @@
-package bp2build
-
-import (
-	"fmt"
-	"os"
-	"path/filepath"
-	"strings"
-
-	"android/soong/android"
-	"android/soong/shared"
-	"android/soong/ui/metrics/bp2build_metrics_proto"
-	"google.golang.org/protobuf/proto"
-
-	"github.com/google/blueprint"
-)
-
-// CodegenMetrics represents information about the Blueprint-to-BUILD
-// conversion process.
-// Use CreateCodegenMetrics() to get a properly initialized instance
-type CodegenMetrics struct {
-	serialized *bp2build_metrics_proto.Bp2BuildMetrics
-	// List of modules with unconverted deps
-	// NOTE: NOT in the .proto
-	moduleWithUnconvertedDepsMsgs []string
-
-	// List of modules with missing deps
-	// NOTE: NOT in the .proto
-	moduleWithMissingDepsMsgs []string
-
-	// Map of converted modules and paths to call
-	// NOTE: NOT in the .proto
-	convertedModulePathMap map[string]string
-}
-
-func CreateCodegenMetrics() CodegenMetrics {
-	return CodegenMetrics{
-		serialized: &bp2build_metrics_proto.Bp2BuildMetrics{
-			RuleClassCount:           make(map[string]uint64),
-			ConvertedModuleTypeCount: make(map[string]uint64),
-			TotalModuleTypeCount:     make(map[string]uint64),
-			UnconvertedModules:       make(map[string]*bp2build_metrics_proto.UnconvertedReason),
-		},
-		convertedModulePathMap: make(map[string]string),
-	}
-}
-
-// Serialize returns the protoized version of CodegenMetrics: bp2build_metrics_proto.Bp2BuildMetrics
-func (metrics *CodegenMetrics) Serialize() *bp2build_metrics_proto.Bp2BuildMetrics {
-	return metrics.serialized
-}
-
-// Print the codegen metrics to stdout.
-func (metrics *CodegenMetrics) Print() {
-	generatedTargetCount := uint64(0)
-	for _, ruleClass := range android.SortedKeys(metrics.serialized.RuleClassCount) {
-		count := metrics.serialized.RuleClassCount[ruleClass]
-		fmt.Printf("[bp2build] %s: %d targets\n", ruleClass, count)
-		generatedTargetCount += count
-	}
-	fmt.Printf(
-		`[bp2build] Converted %d Android.bp modules to %d total generated BUILD targets. Included %d handcrafted BUILD targets. There are %d total Android.bp modules.
-%d converted modules have unconverted deps:
-	%s
-%d converted modules have missing deps:
-	%s
-`,
-		metrics.serialized.GeneratedModuleCount,
-		generatedTargetCount,
-		metrics.serialized.HandCraftedModuleCount,
-		metrics.TotalModuleCount(),
-		len(metrics.moduleWithUnconvertedDepsMsgs),
-		strings.Join(metrics.moduleWithUnconvertedDepsMsgs, "\n\t"),
-		len(metrics.moduleWithMissingDepsMsgs),
-		strings.Join(metrics.moduleWithMissingDepsMsgs, "\n\t"),
-	)
-}
-
-const bp2buildMetricsFilename = "bp2build_metrics.pb"
-
-// fail prints $PWD to stderr, followed by the given printf string and args (vals),
-// then the given alert, and then exits with 1 for failure
-func fail(err error, alertFmt string, vals ...interface{}) {
-	cwd, wderr := os.Getwd()
-	if wderr != nil {
-		cwd = "FAILED TO GET $PWD: " + wderr.Error()
-	}
-	fmt.Fprintf(os.Stderr, "\nIn "+cwd+":\n"+alertFmt+"\n"+err.Error()+"\n", vals...)
-	os.Exit(1)
-}
-
-// Write the bp2build-protoized codegen metrics into the given directory
-func (metrics *CodegenMetrics) Write(dir string) {
-	if _, err := os.Stat(dir); os.IsNotExist(err) {
-		// The metrics dir doesn't already exist, so create it (and parents)
-		if err := os.MkdirAll(dir, 0755); err != nil { // rx for all; w for user
-			fail(err, "Failed to `mkdir -p` %s", dir)
-		}
-	} else if err != nil {
-		fail(err, "Failed to `stat` %s", dir)
-	}
-	metricsFile := filepath.Join(dir, bp2buildMetricsFilename)
-	if err := metrics.dump(metricsFile); err != nil {
-		fail(err, "Error outputting %s", metricsFile)
-	}
-	if _, err := os.Stat(metricsFile); err != nil {
-		if os.IsNotExist(err) {
-			fail(err, "MISSING BP2BUILD METRICS OUTPUT: %s", metricsFile)
-		} else {
-			fail(err, "FAILED TO `stat` BP2BUILD METRICS OUTPUT: %s", metricsFile)
-		}
-	}
-}
-
-// ReadCodegenMetrics loads CodegenMetrics from `dir`
-// returns a nil pointer if the file doesn't exist
-func ReadCodegenMetrics(dir string) *CodegenMetrics {
-	metricsFile := filepath.Join(dir, bp2buildMetricsFilename)
-	if _, err := os.Stat(metricsFile); err != nil {
-		if os.IsNotExist(err) {
-			return nil
-		} else {
-			fail(err, "FAILED TO `stat` BP2BUILD METRICS OUTPUT: %s", metricsFile)
-			panic("unreachable after fail")
-		}
-	}
-	if buf, err := os.ReadFile(metricsFile); err != nil {
-		fail(err, "FAILED TO READ BP2BUILD METRICS OUTPUT: %s", metricsFile)
-		panic("unreachable after fail")
-	} else {
-		bp2BuildMetrics := bp2build_metrics_proto.Bp2BuildMetrics{
-			RuleClassCount:           make(map[string]uint64),
-			ConvertedModuleTypeCount: make(map[string]uint64),
-			TotalModuleTypeCount:     make(map[string]uint64),
-		}
-		if err := proto.Unmarshal(buf, &bp2BuildMetrics); err != nil {
-			fail(err, "FAILED TO PARSE BP2BUILD METRICS OUTPUT: %s", metricsFile)
-		}
-		return &CodegenMetrics{
-			serialized:             &bp2BuildMetrics,
-			convertedModulePathMap: make(map[string]string),
-		}
-	}
-}
-
-func (metrics *CodegenMetrics) IncrementRuleClassCount(ruleClass string) {
-	metrics.serialized.RuleClassCount[ruleClass] += 1
-}
-
-func (metrics *CodegenMetrics) AddEvent(event *bp2build_metrics_proto.Event) {
-	metrics.serialized.Events = append(metrics.serialized.Events, event)
-}
-
-func (metrics *CodegenMetrics) SetSymlinkCount(n uint64) {
-	if m := metrics.serialized.WorkspaceSymlinkCount; m != 0 {
-		fmt.Fprintf(os.Stderr, "unexpected non-zero workspaceSymlinkCount of %d", m)
-	}
-	metrics.serialized.WorkspaceSymlinkCount = n
-}
-
-func (metrics *CodegenMetrics) SetMkDirCount(n uint64) {
-	if m := metrics.serialized.WorkspaceMkDirCount; m != 0 {
-		fmt.Fprintf(os.Stderr, "unexpected non-zero workspaceDirCount of %d", m)
-	}
-	metrics.serialized.WorkspaceMkDirCount = n
-}
-
-func (metrics *CodegenMetrics) TotalModuleCount() uint64 {
-	return metrics.serialized.HandCraftedModuleCount +
-		metrics.serialized.GeneratedModuleCount +
-		metrics.serialized.UnconvertedModuleCount
-}
-
-// Dump serializes the metrics to the given filename
-func (metrics *CodegenMetrics) dump(filename string) (err error) {
-	ser := metrics.Serialize()
-	return shared.Save(ser, filename)
-}
-
-type ConversionType int
-
-const (
-	Generated ConversionType = iota
-	Handcrafted
-)
-
-func (metrics *CodegenMetrics) AddConvertedModule(m blueprint.Module, moduleType string, dir string) {
-	//a package module has empty name
-	if moduleType == "package" {
-		return
-	}
-	// Undo prebuilt_ module name prefix modifications
-	moduleName := android.RemoveOptionalPrebuiltPrefix(m.Name())
-	metrics.serialized.ConvertedModules = append(metrics.serialized.ConvertedModules, moduleName)
-	metrics.convertedModulePathMap[moduleName] = "//" + dir
-	metrics.serialized.ConvertedModuleTypeCount[moduleType] += 1
-	metrics.serialized.TotalModuleTypeCount[moduleType] += 1
-	metrics.serialized.GeneratedModuleCount += 1
-}
-
-func (metrics *CodegenMetrics) AddUnconvertedModule(m blueprint.Module, moduleType string, dir string,
-	reason android.UnconvertedReason) {
-	//a package module has empty name
-	if moduleType == "package" {
-		return
-	}
-	// Undo prebuilt_ module name prefix modifications
-	moduleName := android.RemoveOptionalPrebuiltPrefix(m.Name())
-	metrics.serialized.UnconvertedModules[moduleName] = &bp2build_metrics_proto.UnconvertedReason{
-		Type:   bp2build_metrics_proto.UnconvertedReasonType(reason.ReasonType),
-		Detail: reason.Detail,
-	}
-	metrics.serialized.UnconvertedModuleCount += 1
-	metrics.serialized.TotalModuleTypeCount[moduleType] += 1
-
-	if reason.ReasonType == int(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE) {
-		metrics.serialized.HandCraftedModuleCount += 1
-	}
-}
diff --git a/bp2build/package_conversion_test.go b/bp2build/package_conversion_test.go
deleted file mode 100644
index ce848e4..0000000
--- a/bp2build/package_conversion_test.go
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/genrule"
-)
-
-func registerDependentModules(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("license", android.LicenseFactory)
-	ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
-}
-
-func TestPackage(t *testing.T) {
-	tests := []struct {
-		description string
-		modules     string
-		fs          map[string]string
-		expected    []ExpectedRuleTarget
-	}{
-		{
-			description: "with default applicable licenses",
-			modules: `
-license {
-  name: "my_license",
-  visibility: [":__subpackages__"],
-  license_kinds: ["SPDX-license-identifier-Apache-2.0"],
-  license_text: ["NOTICE"],
-}
-
-package {
-  default_applicable_licenses: ["my_license"],
-}
-`,
-			expected: []ExpectedRuleTarget{
-				{
-					"package",
-					"",
-					AttrNameToString{
-						"default_package_metadata": `[":my_license"]`,
-						"default_visibility":       `["//visibility:public"]`,
-					},
-					android.HostAndDeviceDefault,
-				},
-				{
-					"android_license",
-					"my_license",
-					AttrNameToString{
-						"license_kinds": `["SPDX-license-identifier-Apache-2.0"]`,
-						"license_text":  `"NOTICE"`,
-						"visibility":    `[":__subpackages__"]`,
-					},
-					android.HostAndDeviceDefault,
-				},
-			},
-		},
-		{
-			description: "package has METADATA file",
-			fs: map[string]string{
-				"METADATA": ``,
-			},
-			modules: `
-license {
-  name: "my_license",
-  visibility: [":__subpackages__"],
-  license_kinds: ["SPDX-license-identifier-Apache-2.0"],
-  license_text: ["NOTICE"],
-}
-
-package {
-  default_applicable_licenses: ["my_license"],
-}
-`,
-			expected: []ExpectedRuleTarget{
-				{
-					"package",
-					"",
-					AttrNameToString{
-						"default_package_metadata": `[
-        ":my_license",
-        ":default_metadata_file",
-    ]`,
-						"default_visibility": `["//visibility:public"]`,
-					},
-					android.HostAndDeviceDefault,
-				},
-				{
-					"android_license",
-					"my_license",
-					AttrNameToString{
-						"license_kinds": `["SPDX-license-identifier-Apache-2.0"]`,
-						"license_text":  `"NOTICE"`,
-						"visibility":    `[":__subpackages__"]`,
-					},
-					android.HostAndDeviceDefault,
-				},
-				{
-					"filegroup",
-					"default_metadata_file",
-					AttrNameToString{
-						"applicable_licenses": `[]`,
-						"srcs":                `["METADATA"]`,
-					},
-					android.HostAndDeviceDefault,
-				},
-			},
-		},
-	}
-	for _, test := range tests {
-		expected := make([]string, 0, len(test.expected))
-		for _, e := range test.expected {
-			expected = append(expected, e.String())
-		}
-		RunBp2BuildTestCase(t, registerDependentModules,
-			Bp2buildTestCase{
-				Description:                test.description,
-				ModuleTypeUnderTest:        "package",
-				ModuleTypeUnderTestFactory: android.PackageFactory,
-				Blueprint:                  test.modules,
-				ExpectedBazelTargets:       expected,
-				Filesystem:                 test.fs,
-			})
-	}
-}
diff --git a/bp2build/performance_test.go b/bp2build/performance_test.go
deleted file mode 100644
index 5f80b83..0000000
--- a/bp2build/performance_test.go
+++ /dev/null
@@ -1,219 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-// to run the benchmarks in this file, you must run go test with the -bench.
-// The benchmarked portion will run for the specified time (can be set via -benchtime)
-// This can mean if you are benchmarking a faster portion of a larger operation, it will take
-// longer.
-// If you are seeing a small number of iterations for a specific run, the data is less reliable, to
-// run for longer, set -benchtime to a larger value.
-
-import (
-	"fmt"
-	"math"
-	"strings"
-	"testing"
-
-	"android/soong/android"
-)
-
-const (
-	performance_test_dir = "."
-)
-
-func genCustomModule(i int, convert bool) string {
-	var conversionString string
-	if convert {
-		conversionString = `bazel_module: { bp2build_available: true },`
-	}
-	return fmt.Sprintf(`
-custom {
-    name: "arch_paths_%[1]d",
-    string_list_prop: ["\t", "\n"],
-    string_prop: "a\t\n\r",
-    arch_paths: ["outer", ":outer_dep_%[1]d"],
-    arch: {
-      x86: {
-        arch_paths: ["abc", ":x86_dep_%[1]d"],
-      },
-      x86_64: {
-        arch_paths: ["64bit"],
-        arch_paths_exclude: ["outer"],
-      },
-    },
-		%[2]s
-}
-
-custom {
-    name: "outer_dep_%[1]d",
-		%[2]s
-}
-
-custom {
-    name: "x86_dep_%[1]d",
-		%[2]s
-}
-`, i, conversionString)
-}
-
-func genCustomModuleBp(pctConverted float64) string {
-	modules := 100
-
-	bp := make([]string, 0, modules)
-	toConvert := int(math.Round(float64(modules) * pctConverted))
-
-	for i := 0; i < modules; i++ {
-		bp = append(bp, genCustomModule(i, i < toConvert))
-	}
-	return strings.Join(bp, "\n\n")
-}
-
-type testConfig struct {
-	config     android.Config
-	ctx        *android.TestContext
-	codegenCtx *CodegenContext
-}
-
-func (tc testConfig) parse() []error {
-	_, errs := tc.ctx.ParseFileList(performance_test_dir, []string{"Android.bp"})
-	return errs
-}
-
-func (tc testConfig) resolveDependencies() []error {
-	_, errs := tc.ctx.ResolveDependencies(tc.config)
-	return errs
-}
-
-func (tc testConfig) convert() {
-	generateBazelTargetsForDir(tc.codegenCtx, performance_test_dir)
-}
-
-func setup(builddir string, tcSize float64) testConfig {
-	config := android.TestConfig(buildDir, nil, genCustomModuleBp(tcSize), nil)
-	ctx := android.NewTestContext(config)
-
-	registerCustomModuleForBp2buildConversion(ctx)
-	codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
-	return testConfig{
-		config,
-		ctx,
-		codegenCtx,
-	}
-}
-
-var pctToConvert = []float64{0.0, 0.01, 0.05, 0.10, 0.25, 0.5, 0.75, 1.0}
-
-// This is not intended to test performance, but to verify performance infra continues to work
-func TestConvertManyModulesFull(t *testing.T) {
-	for _, tcSize := range pctToConvert {
-
-		t.Run(fmt.Sprintf("pctConverted %f", tcSize), func(t *testing.T) {
-			testConfig := setup(buildDir, tcSize)
-
-			errs := testConfig.parse()
-			if len(errs) > 0 {
-				t.Fatalf("Unexpected errors: %s", errs)
-			}
-
-			errs = testConfig.resolveDependencies()
-			if len(errs) > 0 {
-				t.Fatalf("Unexpected errors: %s", errs)
-			}
-
-			testConfig.convert()
-		})
-	}
-}
-
-func BenchmarkManyModulesFull(b *testing.B) {
-	for _, tcSize := range pctToConvert {
-
-		b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) {
-			for n := 0; n < b.N; n++ {
-				b.StopTimer()
-				testConfig := setup(buildDir, tcSize)
-
-				b.StartTimer()
-				errs := testConfig.parse()
-				if len(errs) > 0 {
-					b.Fatalf("Unexpected errors: %s", errs)
-				}
-
-				errs = testConfig.resolveDependencies()
-				if len(errs) > 0 {
-					b.Fatalf("Unexpected errors: %s", errs)
-				}
-
-				testConfig.convert()
-				b.StopTimer()
-			}
-		})
-	}
-}
-
-func BenchmarkManyModulesResolveDependencies(b *testing.B) {
-	for _, tcSize := range pctToConvert {
-
-		b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) {
-			for n := 0; n < b.N; n++ {
-				b.StopTimer()
-				// setup we don't want to measure
-				testConfig := setup(buildDir, tcSize)
-
-				errs := testConfig.parse()
-				if len(errs) > 0 {
-					b.Fatalf("Unexpected errors: %s", errs)
-				}
-
-				b.StartTimer()
-				errs = testConfig.resolveDependencies()
-				b.StopTimer()
-				if len(errs) > 0 {
-					b.Fatalf("Unexpected errors: %s", errs)
-				}
-
-				testConfig.convert()
-			}
-		})
-	}
-}
-
-func BenchmarkManyModulesGenerateBazelTargetsForDir(b *testing.B) {
-	for _, tcSize := range pctToConvert {
-
-		b.Run(fmt.Sprintf("pctConverted %f", tcSize), func(b *testing.B) {
-			for n := 0; n < b.N; n++ {
-				b.StopTimer()
-				// setup we don't want to measure
-				testConfig := setup(buildDir, tcSize)
-
-				errs := testConfig.parse()
-				if len(errs) > 0 {
-					b.Fatalf("Unexpected errors: %s", errs)
-				}
-
-				errs = testConfig.resolveDependencies()
-				if len(errs) > 0 {
-					b.Fatalf("Unexpected errors: %s", errs)
-				}
-
-				b.StartTimer()
-				testConfig.convert()
-				b.StopTimer()
-			}
-		})
-	}
-}
diff --git a/bp2build/platform_compat_config_conversion_test.go b/bp2build/platform_compat_config_conversion_test.go
deleted file mode 100644
index 4dfcce3..0000000
--- a/bp2build/platform_compat_config_conversion_test.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/java"
-)
-
-func runPlatformCompatConfigTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("java_library", java.LibraryFactory)
-		ctx.RegisterModuleType("platform_compat_config", java.PlatformCompatConfigFactory)
-	}, tc)
-}
-
-func TestPlatformCompatConfig(t *testing.T) {
-	runPlatformCompatConfigTestCase(t, Bp2buildTestCase{
-		Description: "platform_compat_config - conversion test",
-		Blueprint: `
-		platform_compat_config {
-			name: "foo",
-			src: ":lib",
-		}`,
-		Filesystem: map[string]string{
-			"a/b/Android.bp": `
-			java_library {
-				name: "lib",
-				srcs: ["a.java"],
-			}`,
-		},
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("platform_compat_config", "foo", AttrNameToString{
-				"src": `"//a/b:lib"`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go
deleted file mode 100644
index 5b2d609..0000000
--- a/bp2build/prebuilt_etc_conversion_test.go
+++ /dev/null
@@ -1,348 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"fmt"
-	"testing"
-
-	"android/soong/android"
-	"android/soong/etc"
-)
-
-func runPrebuiltEtcTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "prebuilt_etc"
-	(&tc).ModuleTypeUnderTestFactory = etc.PrebuiltEtcFactory
-	RunBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc)
-}
-
-func registerPrebuiltEtcModuleTypes(ctx android.RegistrationContext) {
-}
-
-func TestPrebuiltEtcSimple(t *testing.T) {
-	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
-		Description: "prebuilt_etc - simple example",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc {
-    name: "apex_tz_version",
-    src: "version/tz_version",
-    filename: "tz_version",
-    sub_dir: "tz",
-    installable: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
-				"filename":    `"tz_version"`,
-				"installable": `False`,
-				"src":         `"version/tz_version"`,
-				"dir":         `"etc/tz"`,
-			})}})
-}
-
-func TestPrebuiltEtcArchVariant(t *testing.T) {
-	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
-		Description: "prebuilt_etc - arch variant",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc {
-    name: "apex_tz_version",
-    src: "version/tz_version",
-    filename: "tz_version",
-    sub_dir: "tz",
-    installable: false,
-    arch: {
-      arm: {
-        src: "arm",
-      },
-      arm64: {
-        src: "arm64",
-      },
-    }
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
-				"filename":    `"tz_version"`,
-				"installable": `False`,
-				"src": `select({
-        "//build/bazel/platforms/arch:arm": "arm",
-        "//build/bazel/platforms/arch:arm64": "arm64",
-        "//conditions:default": "version/tz_version",
-    })`,
-				"dir": `"etc/tz"`,
-			})}})
-}
-
-func TestPrebuiltEtcArchAndTargetVariant(t *testing.T) {
-	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
-		Description: "prebuilt_etc - arch variant",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc {
-    name: "apex_tz_version",
-    src: "version/tz_version",
-    filename: "tz_version",
-    sub_dir: "tz",
-    installable: false,
-    arch: {
-      arm: {
-        src: "arm",
-      },
-      arm64: {
-        src: "darwin_or_arm64",
-      },
-    },
-    target: {
-      darwin: {
-        src: "darwin_or_arm64",
-      }
-    },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
-				"filename":    `"tz_version"`,
-				"installable": `False`,
-				"src": `select({
-        "//build/bazel/platforms/os_arch:android_arm": "arm",
-        "//build/bazel/platforms/os_arch:android_arm64": "darwin_or_arm64",
-        "//build/bazel/platforms/os_arch:darwin_arm64": "darwin_or_arm64",
-        "//build/bazel/platforms/os_arch:darwin_x86_64": "darwin_or_arm64",
-        "//build/bazel/platforms/os_arch:linux_bionic_arm64": "darwin_or_arm64",
-        "//conditions:default": "version/tz_version",
-    })`,
-				"dir": `"etc/tz"`,
-			})}})
-}
-func TestPrebuiltEtcProductVariables(t *testing.T) {
-	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
-		Description: "prebuilt etc - product variables",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc {
-    name: "apex_tz_version",
-    src: "version/tz_version",
-    filename: "tz_version",
-    product_variables: {
-      native_coverage: {
-        src: "src1",
-      },
-    },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
-				"filename": `"tz_version"`,
-				"src": `select({
-        "//build/bazel/product_config/config_settings:native_coverage": "src1",
-        "//conditions:default": "version/tz_version",
-    })`,
-				"dir": `"etc"`,
-			})}})
-}
-
-func runPrebuiltUsrShareTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "prebuilt_usr_share"
-	(&tc).ModuleTypeUnderTestFactory = etc.PrebuiltUserShareFactory
-	RunBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc)
-}
-
-func registerPrebuiltUsrShareModuleTypes(ctx android.RegistrationContext) {
-}
-
-func TestPrebuiltUsrShareSimple(t *testing.T) {
-	runPrebuiltUsrShareTestCase(t, Bp2buildTestCase{
-		Description: "prebuilt_usr_share - simple example",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_usr_share {
-    name: "apex_tz_version",
-    src: "version/tz_version",
-    filename: "tz_version",
-    sub_dir: "tz",
-    installable: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
-				"filename":    `"tz_version"`,
-				"installable": `False`,
-				"src":         `"version/tz_version"`,
-				"dir":         `"usr/share/tz"`,
-			})}})
-}
-
-func TestPrebuiltEtcNoSubdir(t *testing.T) {
-	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
-		Description: "prebuilt_etc - no subdir",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc {
-    name: "apex_tz_version",
-    src: "version/tz_version",
-    filename: "tz_version",
-    installable: false,
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
-				"filename":    `"tz_version"`,
-				"installable": `False`,
-				"src":         `"version/tz_version"`,
-				"dir":         `"etc"`,
-			})}})
-}
-
-func TestFilenameAsProperty(t *testing.T) {
-	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
-		Description: "prebuilt_etc - filename is specified as a property ",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc {
-    name: "foo",
-    src: "fooSrc",
-    filename: "fooFileName",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("prebuilt_file", "foo", AttrNameToString{
-				"filename": `"fooFileName"`,
-				"src":      `"fooSrc"`,
-				"dir":      `"etc"`,
-			})}})
-}
-
-func TestFileNameFromSrc(t *testing.T) {
-	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
-		Description: "prebuilt_etc - filename_from_src is true  ",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc {
-    name: "foo",
-    filename_from_src: true,
-    src: "fooSrc",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("prebuilt_file", "foo", AttrNameToString{
-				"filename": `"fooSrc"`,
-				"src":      `"fooSrc"`,
-				"dir":      `"etc"`,
-			})}})
-}
-
-func TestFileNameFromSrcMultipleSrcs(t *testing.T) {
-	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
-		Description: "prebuilt_etc - filename_from_src is true but there are multiple srcs",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc {
-    name: "foo",
-    filename_from_src: true,
-		arch: {
-        arm: {
-            src: "barSrc",
-        },
-        arm64: {
-            src: "bazSrc",
-        },
-	  }
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("prebuilt_file", "foo", AttrNameToString{
-				"filename_from_src": `True`,
-				"dir":               `"etc"`,
-				"src": `select({
-        "//build/bazel/platforms/arch:arm": "barSrc",
-        "//build/bazel/platforms/arch:arm64": "bazSrc",
-        "//conditions:default": None,
-    })`,
-			})}})
-}
-
-func TestFilenameFromModuleName(t *testing.T) {
-	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
-		Description: "prebuilt_etc - neither filename nor filename_from_src are specified ",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc {
-    name: "foo",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("prebuilt_file", "foo", AttrNameToString{
-				"filename": `"foo"`,
-				"dir":      `"etc"`,
-			})}})
-}
-
-func TestPrebuiltEtcProductVariableArchSrcs(t *testing.T) {
-	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
-		Description: "prebuilt etc- SRcs from arch variant product variables",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc {
-    name: "foo",
-    filename: "fooFilename",
-    arch: {
-      arm: {
-        src: "armSrc",
-        product_variables: {
-          native_coverage: {
-            src: "nativeCoverageArmSrc",
-          },
-        },
-      },
-    },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("prebuilt_file", "foo", AttrNameToString{
-				"filename": `"fooFilename"`,
-				"dir":      `"etc"`,
-				"src": `select({
-        "//build/bazel/platforms/arch:arm": "armSrc",
-        "//build/bazel/product_config/config_settings:native_coverage-arm": "nativeCoverageArmSrc",
-        "//conditions:default": None,
-    })`,
-			})}})
-}
-
-func TestPrebuiltEtcProductVariableError(t *testing.T) {
-	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
-		Description: "",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc {
-    name: "foo",
-    filename: "fooFilename",
-    arch: {
-      arm: {
-        src: "armSrc",
-      },
-    },
-    product_variables: {
-      native_coverage: {
-        src: "nativeCoverageArmSrc",
-      },
-    },
-}`,
-		ExpectedErr: fmt.Errorf("label attribute could not be collapsed"),
-	})
-}
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
deleted file mode 100644
index 1b538d0..0000000
--- a/bp2build/python_binary_conversion_test.go
+++ /dev/null
@@ -1,319 +0,0 @@
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/genrule"
-	"android/soong/python"
-)
-
-func runBp2BuildTestCaseWithPythonLibraries(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
-		ctx.RegisterModuleType("python_library_host", python.PythonLibraryHostFactory)
-		ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
-		ctx.RegisterModuleType("python_defaults", python.DefaultsFactory)
-	}, tc)
-}
-
-func TestPythonBinaryHostSimple(t *testing.T) {
-	runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
-		Description:                "simple python_binary_host converts to a native py_binary",
-		ModuleTypeUnderTest:        "python_binary_host",
-		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
-		Filesystem: map[string]string{
-			"a.py":           "",
-			"b/c.py":         "",
-			"b/d.py":         "",
-			"b/e.py":         "",
-			"files/data.txt": "",
-		},
-		Blueprint: `python_binary_host {
-    name: "foo",
-    main: "a.py",
-    srcs: ["**/*.py"],
-    exclude_srcs: ["b/e.py"],
-    data: ["files/data.txt",],
-    libs: ["bar"],
-    bazel_module: { bp2build_available: true },
-}
-    python_library_host {
-      name: "bar",
-      srcs: ["b/e.py"],
-      bazel_module: { bp2build_available: false },
-    }`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("py_binary", "foo", AttrNameToString{
-				"data":    `["files/data.txt"]`,
-				"deps":    `[":bar"]`,
-				"main":    `"a.py"`,
-				"imports": `["."]`,
-				"srcs": `[
-        "a.py",
-        "b/c.py",
-        "b/d.py",
-    ]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestPythonBinaryHostPy2(t *testing.T) {
-	RunBp2BuildTestCaseSimple(t, Bp2buildTestCase{
-		Description:                "py2 python_binary_host",
-		ModuleTypeUnderTest:        "python_binary_host",
-		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
-		Blueprint: `python_binary_host {
-    name: "foo",
-    srcs: ["a.py"],
-    version: {
-        py2: {
-            enabled: true,
-        },
-        py3: {
-            enabled: false,
-        },
-    },
-
-    bazel_module: { bp2build_available: true },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("py_binary", "foo", AttrNameToString{
-				"python_version": `"PY2"`,
-				"imports":        `["."]`,
-				"srcs":           `["a.py"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestPythonBinaryHostPy3(t *testing.T) {
-	RunBp2BuildTestCaseSimple(t, Bp2buildTestCase{
-		Description:                "py3 python_binary_host",
-		ModuleTypeUnderTest:        "python_binary_host",
-		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
-		Blueprint: `python_binary_host {
-    name: "foo",
-    srcs: ["a.py"],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-        },
-    },
-
-    bazel_module: { bp2build_available: true },
-}
-`,
-		ExpectedBazelTargets: []string{
-			// python_version is PY3 by default.
-			MakeBazelTarget("py_binary", "foo", AttrNameToString{
-				"imports": `["."]`,
-				"srcs":    `["a.py"]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestPythonBinaryHostArchVariance(t *testing.T) {
-	RunBp2BuildTestCaseSimple(t, Bp2buildTestCase{
-		Description:                "test arch variants",
-		ModuleTypeUnderTest:        "python_binary_host",
-		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
-		Filesystem: map[string]string{
-			"dir/arm.py": "",
-			"dir/x86.py": "",
-		},
-		Blueprint: `python_binary_host {
-					 name: "foo-arm",
-					 arch: {
-						 arm: {
-							 srcs: ["arm.py"],
-						 },
-						 x86: {
-							 srcs: ["x86.py"],
-						 },
-					},
-				 }`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("py_binary", "foo-arm", AttrNameToString{
-				"imports": `["."]`,
-				"srcs": `select({
-        "//build/bazel/platforms/arch:arm": ["arm.py"],
-        "//build/bazel/platforms/arch:x86": ["x86.py"],
-        "//conditions:default": [],
-    })`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestPythonBinaryMainIsNotSpecified(t *testing.T) {
-	runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
-		Description:                "python_binary_host main label in same package",
-		ModuleTypeUnderTest:        "python_binary_host",
-		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
-		Blueprint: `python_binary_host {
-    name: "foo",
-    bazel_module: { bp2build_available: true },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("py_binary", "foo", AttrNameToString{
-				"imports": `["."]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestPythonBinaryMainIsLabel(t *testing.T) {
-	runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
-		Description:                "python_binary_host main label in same package",
-		ModuleTypeUnderTest:        "python_binary_host",
-		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
-		Blueprint: `python_binary_host {
-    name: "foo",
-    main: ":a",
-    bazel_module: { bp2build_available: true },
-}
-
-genrule {
-		name: "a",
-		bazel_module: { bp2build_available: false },
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("py_binary", "foo", AttrNameToString{
-				"main":    `":a"`,
-				"imports": `["."]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestPythonBinaryMainIsSubpackageFile(t *testing.T) {
-	runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
-		Description:                "python_binary_host main is subpackage file",
-		ModuleTypeUnderTest:        "python_binary_host",
-		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
-		Filesystem: map[string]string{
-			"a/Android.bp": "",
-			"a/b.py":       "",
-		},
-		Blueprint: `python_binary_host {
-    name: "foo",
-    main: "a/b.py",
-    bazel_module: { bp2build_available: true },
-}
-
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("py_binary", "foo", AttrNameToString{
-				"main":    `"//a:b.py"`,
-				"imports": `["."]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestPythonBinaryMainIsSubDirFile(t *testing.T) {
-	runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
-		Description:                "python_binary_host main is file in sub directory that is not Bazel package",
-		ModuleTypeUnderTest:        "python_binary_host",
-		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
-		Filesystem: map[string]string{
-			"a/b.py": "",
-		},
-		Blueprint: `python_binary_host {
-    name: "foo",
-    main: "a/b.py",
-    bazel_module: { bp2build_available: true },
-}
-
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("py_binary", "foo", AttrNameToString{
-				"main":    `"a/b.py"`,
-				"imports": `["."]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
-
-func TestPythonBinaryDuplicatesInRequired(t *testing.T) {
-	runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
-		Description:                "python_binary_host duplicates in required attribute of the module and its defaults",
-		ModuleTypeUnderTest:        "python_binary_host",
-		ModuleTypeUnderTestFactory: python.PythonBinaryHostFactory,
-		Blueprint: `python_binary_host {
-    name: "foo",
-    main: "a.py",
-		defaults: ["d"],
-    required: [
-        "r1",
-    ],
-    bazel_module: { bp2build_available: true },
-}
-
-python_defaults {
-    name: "d",
-    required: [
-        "r1",
-        "r2",
-    ],
-}` + simpleModuleDoNotConvertBp2build("genrule", "r1") +
-			simpleModuleDoNotConvertBp2build("genrule", "r2"),
-
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("py_binary", "foo", AttrNameToString{
-				"main":    `"a.py"`,
-				"imports": `["."]`,
-				"data": `[
-        ":r1",
-        ":r2",
-    ]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/python_library_conversion_test.go b/bp2build/python_library_conversion_test.go
deleted file mode 100644
index a53371d..0000000
--- a/bp2build/python_library_conversion_test.go
+++ /dev/null
@@ -1,350 +0,0 @@
-package bp2build
-
-import (
-	"fmt"
-	"strings"
-	"testing"
-
-	"android/soong/android"
-	"android/soong/python"
-)
-
-// TODO(alexmarquez): Should be lifted into a generic Bp2Build file
-type PythonLibBp2Build func(ctx android.TopDownMutatorContext)
-
-type pythonLibBp2BuildTestCase struct {
-	description          string
-	filesystem           map[string]string
-	blueprint            string
-	expectedBazelTargets []testBazelTarget
-	dir                  string
-	expectedError        error
-}
-
-func convertPythonLibTestCaseToBp2build_Host(tc pythonLibBp2BuildTestCase) Bp2buildTestCase {
-	for i := range tc.expectedBazelTargets {
-		tc.expectedBazelTargets[i].attrs["target_compatible_with"] = `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`
-	}
-
-	return convertPythonLibTestCaseToBp2build(tc)
-}
-
-func convertPythonLibTestCaseToBp2build(tc pythonLibBp2BuildTestCase) Bp2buildTestCase {
-	var bp2BuildTargets []string
-	for _, t := range tc.expectedBazelTargets {
-		bp2BuildTargets = append(bp2BuildTargets, MakeBazelTarget(t.typ, t.name, t.attrs))
-	}
-	// Copy the filesystem so that we can change stuff in it later without it
-	// affecting the original pythonLibBp2BuildTestCase
-	filesystemCopy := make(map[string]string)
-	for k, v := range tc.filesystem {
-		filesystemCopy[k] = v
-	}
-	return Bp2buildTestCase{
-		Description:          tc.description,
-		Filesystem:           filesystemCopy,
-		Blueprint:            tc.blueprint,
-		ExpectedBazelTargets: bp2BuildTargets,
-		Dir:                  tc.dir,
-		ExpectedErr:          tc.expectedError,
-	}
-}
-
-func runPythonLibraryTestCase(t *testing.T, tc pythonLibBp2BuildTestCase) {
-	t.Helper()
-	testCase := convertPythonLibTestCaseToBp2build(tc)
-	testCase.Description = fmt.Sprintf(testCase.Description, "python_library")
-	testCase.Blueprint = fmt.Sprintf(testCase.Blueprint, "python_library")
-	for name, contents := range testCase.Filesystem {
-		if strings.HasSuffix(name, "Android.bp") {
-			testCase.Filesystem[name] = fmt.Sprintf(contents, "python_library")
-		}
-	}
-	testCase.ModuleTypeUnderTest = "python_library"
-	testCase.ModuleTypeUnderTestFactory = python.PythonLibraryFactory
-
-	RunBp2BuildTestCaseSimple(t, testCase)
-}
-
-func runPythonLibraryHostTestCase(t *testing.T, tc pythonLibBp2BuildTestCase) {
-	t.Helper()
-	testCase := convertPythonLibTestCaseToBp2build_Host(tc)
-	testCase.Description = fmt.Sprintf(testCase.Description, "python_library_host")
-	testCase.Blueprint = fmt.Sprintf(testCase.Blueprint, "python_library_host")
-	for name, contents := range testCase.Filesystem {
-		if strings.HasSuffix(name, "Android.bp") {
-			testCase.Filesystem[name] = fmt.Sprintf(contents, "python_library_host")
-		}
-	}
-	testCase.ModuleTypeUnderTest = "python_library_host"
-	testCase.ModuleTypeUnderTestFactory = python.PythonLibraryHostFactory
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
-	},
-		testCase)
-}
-
-func runPythonLibraryTestCases(t *testing.T, tc pythonLibBp2BuildTestCase) {
-	t.Helper()
-	runPythonLibraryTestCase(t, tc)
-	runPythonLibraryHostTestCase(t, tc)
-}
-
-func TestSimplePythonLib(t *testing.T) {
-	testCases := []pythonLibBp2BuildTestCase{
-		{
-			description: "simple %s converts to a native py_library",
-			filesystem: map[string]string{
-				"a.py":           "",
-				"b/c.py":         "",
-				"b/d.py":         "",
-				"b/e.py":         "",
-				"files/data.txt": "",
-			},
-			blueprint: `%s {
-    name: "foo",
-    srcs: ["**/*.py"],
-    exclude_srcs: ["b/e.py"],
-    data: ["files/data.txt",],
-    libs: ["bar"],
-    bazel_module: { bp2build_available: true },
-}
-    python_library {
-      name: "bar",
-      srcs: ["b/e.py"],
-      bazel_module: { bp2build_available: false },
-    }`,
-			expectedBazelTargets: []testBazelTarget{
-				{
-					typ:  "py_library",
-					name: "foo",
-					attrs: AttrNameToString{
-						"data": `["files/data.txt"]`,
-						"deps": `[":bar"]`,
-						"srcs": `[
-        "a.py",
-        "b/c.py",
-        "b/d.py",
-    ]`,
-						"srcs_version": `"PY3"`,
-						"imports":      `["."]`,
-					},
-				},
-			},
-		},
-		{
-			description: "py2 %s converts to a native py_library",
-			blueprint: `%s {
-    name: "foo",
-    srcs: ["a.py"],
-    version: {
-        py2: {
-            enabled: true,
-        },
-        py3: {
-            enabled: false,
-        },
-    },
-
-    bazel_module: { bp2build_available: true },
-}`,
-			expectedBazelTargets: []testBazelTarget{
-				{
-					typ:  "py_library",
-					name: "foo",
-					attrs: AttrNameToString{
-						"srcs":         `["a.py"]`,
-						"srcs_version": `"PY2"`,
-						"imports":      `["."]`,
-					},
-				},
-			},
-		},
-		{
-			description: "py3 %s converts to a native py_library",
-			blueprint: `%s {
-    name: "foo",
-    srcs: ["a.py"],
-    version: {
-        py2: {
-            enabled: false,
-        },
-        py3: {
-            enabled: true,
-        },
-    },
-
-    bazel_module: { bp2build_available: true },
-}`,
-			expectedBazelTargets: []testBazelTarget{
-				{
-					typ:  "py_library",
-					name: "foo",
-					attrs: AttrNameToString{
-						"srcs":         `["a.py"]`,
-						"srcs_version": `"PY3"`,
-						"imports":      `["."]`,
-					},
-				},
-			},
-		},
-		{
-			description: "py2&3 %s converts to a native py_library",
-			blueprint: `%s {
-    name: "foo",
-    srcs: ["a.py"],
-    version: {
-        py2: {
-            enabled: true,
-        },
-        py3: {
-            enabled: true,
-        },
-    },
-
-    bazel_module: { bp2build_available: true },
-}`,
-			expectedBazelTargets: []testBazelTarget{
-				{
-					// srcs_version is PY2ANDPY3 by default.
-					typ:  "py_library",
-					name: "foo",
-					attrs: AttrNameToString{
-						"srcs":    `["a.py"]`,
-						"imports": `["."]`,
-					},
-				},
-			},
-		},
-		{
-			description: "%s: pkg_path in a subdirectory of the same name converts correctly",
-			dir:         "mylib/subpackage",
-			filesystem: map[string]string{
-				"mylib/subpackage/a.py": "",
-				"mylib/subpackage/Android.bp": `%s {
-				name: "foo",
-				srcs: ["a.py"],
-				pkg_path: "mylib/subpackage",
-
-				bazel_module: { bp2build_available: true },
-			}`,
-			},
-			blueprint: `%s {name: "bar"}`,
-			expectedBazelTargets: []testBazelTarget{
-				{
-					// srcs_version is PY2ANDPY3 by default.
-					typ:  "py_library",
-					name: "foo",
-					attrs: AttrNameToString{
-						"srcs":         `["a.py"]`,
-						"imports":      `["../.."]`,
-						"srcs_version": `"PY3"`,
-					},
-				},
-			},
-		},
-		{
-			description: "%s: pkg_path in a subdirectory of a different name fails",
-			dir:         "mylib/subpackage",
-			filesystem: map[string]string{
-				"mylib/subpackage/a.py": "",
-				"mylib/subpackage/Android.bp": `%s {
-				name: "foo",
-				srcs: ["a.py"],
-				pkg_path: "mylib/subpackage2",
-				bazel_module: { bp2build_available: true },
-			}`,
-			},
-			blueprint:     `%s {name: "bar"}`,
-			expectedError: fmt.Errorf("Currently, bp2build only supports pkg_paths that are the same as the folders the Android.bp file is in."),
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.description, func(t *testing.T) {
-			runPythonLibraryTestCases(t, tc)
-		})
-	}
-}
-
-func TestPythonArchVariance(t *testing.T) {
-	runPythonLibraryTestCases(t, pythonLibBp2BuildTestCase{
-		description: "test %s arch variants",
-		filesystem: map[string]string{
-			"dir/arm.py": "",
-			"dir/x86.py": "",
-		},
-		blueprint: `%s {
-					 name: "foo",
-					 arch: {
-						 arm: {
-							 srcs: ["arm.py"],
-						 },
-						 x86: {
-							 srcs: ["x86.py"],
-						 },
-					},
-				 }`,
-		expectedBazelTargets: []testBazelTarget{
-			{
-				typ:  "py_library",
-				name: "foo",
-				attrs: AttrNameToString{
-					"srcs": `select({
-        "//build/bazel/platforms/arch:arm": ["arm.py"],
-        "//build/bazel/platforms/arch:x86": ["x86.py"],
-        "//conditions:default": [],
-    })`,
-					"srcs_version": `"PY3"`,
-					"imports":      `["."]`,
-				},
-			},
-		},
-	})
-}
-
-func TestPythonLibraryWithProtobufs(t *testing.T) {
-	runPythonLibraryTestCases(t, pythonLibBp2BuildTestCase{
-		description: "test %s protobuf",
-		filesystem: map[string]string{
-			"dir/mylib.py":      "",
-			"dir/myproto.proto": "",
-		},
-		blueprint: `%s {
-					 name: "foo",
-					 srcs: [
-						"dir/mylib.py",
-						"dir/myproto.proto",
-					 ],
-				 }`,
-		expectedBazelTargets: []testBazelTarget{
-			{
-				typ:  "proto_library",
-				name: "foo_proto",
-				attrs: AttrNameToString{
-					"srcs": `["dir/myproto.proto"]`,
-				},
-			},
-			{
-				typ:  "py_proto_library",
-				name: "foo_py_proto",
-				attrs: AttrNameToString{
-					"deps": `[":foo_proto"]`,
-				},
-			},
-			{
-				typ:  "py_library",
-				name: "foo",
-				attrs: AttrNameToString{
-					"srcs":         `["dir/mylib.py"]`,
-					"srcs_version": `"PY3"`,
-					"imports":      `["."]`,
-					"deps":         `[":foo_py_proto"]`,
-				},
-			},
-		},
-	})
-}
diff --git a/bp2build/python_test_conversion_test.go b/bp2build/python_test_conversion_test.go
deleted file mode 100644
index 4ff1fa1..0000000
--- a/bp2build/python_test_conversion_test.go
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"android/soong/python"
-	"testing"
-)
-
-func TestPythonTestHostSimple(t *testing.T) {
-	runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
-		Description:                "simple python_test_host converts to a native py_test",
-		ModuleTypeUnderTest:        "python_test_host",
-		ModuleTypeUnderTestFactory: python.PythonTestHostFactory,
-		Filesystem: map[string]string{
-			"a.py":           "",
-			"b/c.py":         "",
-			"b/d.py":         "",
-			"b/e.py":         "",
-			"files/data.txt": "",
-		},
-		Blueprint: `python_test_host {
-    name: "foo",
-    main: "a.py",
-    srcs: ["**/*.py"],
-    exclude_srcs: ["b/e.py"],
-    data: ["files/data.txt",],
-    libs: ["bar"],
-    bazel_module: { bp2build_available: true },
-}
-    python_library_host {
-      name: "bar",
-      srcs: ["b/e.py"],
-      bazel_module: { bp2build_available: false },
-    }`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("py_test", "foo", AttrNameToString{
-				"data":    `["files/data.txt"]`,
-				"deps":    `[":bar"]`,
-				"main":    `"a.py"`,
-				"imports": `["."]`,
-				"srcs": `[
-        "a.py",
-        "b/c.py",
-        "b/d.py",
-    ]`,
-				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
deleted file mode 100644
index 92b3a65..0000000
--- a/bp2build/sh_conversion_test.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/sh"
-)
-
-func TestShBinaryLoadStatement(t *testing.T) {
-	testCases := []struct {
-		bazelTargets           BazelTargets
-		expectedLoadStatements string
-	}{
-		{
-			bazelTargets: BazelTargets{
-				BazelTarget{
-					name:      "sh_binary_target",
-					ruleClass: "sh_binary",
-					// Note: no bzlLoadLocation for native rules
-					// TODO(ruperts): Could open source the existing, experimental Starlark sh_ rules?
-				},
-			},
-			expectedLoadStatements: ``,
-		},
-	}
-
-	for _, testCase := range testCases {
-		actual := testCase.bazelTargets.LoadStatements()
-		expected := testCase.expectedLoadStatements
-		if actual != expected {
-			t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
-		}
-	}
-}
-
-func runShBinaryTestCase(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
-}
-
-func TestShBinarySimple(t *testing.T) {
-	runShBinaryTestCase(t, Bp2buildTestCase{
-		Description:                "sh_binary test",
-		ModuleTypeUnderTest:        "sh_binary",
-		ModuleTypeUnderTestFactory: sh.ShBinaryFactory,
-		Blueprint: `sh_binary {
-    name: "foo",
-    src: "foo.sh",
-    filename: "foo.exe",
-    sub_dir: "sub",
-    bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("sh_binary", "foo", AttrNameToString{
-				"srcs":     `["foo.sh"]`,
-				"filename": `"foo.exe"`,
-				"sub_dir":  `"sub"`,
-			})},
-	})
-}
-
-func TestShBinaryDefaults(t *testing.T) {
-	runShBinaryTestCase(t, Bp2buildTestCase{
-		Description:                "sh_binary test",
-		ModuleTypeUnderTest:        "sh_binary",
-		ModuleTypeUnderTestFactory: sh.ShBinaryFactory,
-		Blueprint: `sh_binary {
-    name: "foo",
-    src: "foo.sh",
-    bazel_module: { bp2build_available: true },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("sh_binary", "foo", AttrNameToString{
-				"srcs": `["foo.sh"]`,
-			})},
-	})
-}
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
deleted file mode 100644
index 8302ce8..0000000
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ /dev/null
@@ -1,1601 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"android/soong/android"
-	"android/soong/cc"
-	"fmt"
-	"testing"
-)
-
-func runSoongConfigModuleTypeTest(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	RunBp2BuildTestCase(t, registerSoongConfigModuleTypes, tc)
-}
-
-func registerSoongConfigModuleTypes(ctx android.RegistrationContext) {
-	cc.RegisterCCBuildComponents(ctx)
-
-	android.RegisterSoongConfigModuleBuildComponents(ctx)
-
-	ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
-	ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
-}
-
-func TestErrorInBpFileDoesNotPanic(t *testing.T) {
-	bp := `
-soong_config_module_type {
-    name: "library_linking_strategy_cc_defaults",
-    module_type: "cc_defaults",
-    config_namespace: "ANDROID",
-    variables: ["library_linking_strategy"],
-    properties: [
-        "shared_libs",
-        "static_libs",
-    ],
-}
-`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - generates selects for library_linking_strategy",
-		ModuleTypeUnderTest:        "cc_binary",
-		ModuleTypeUnderTestFactory: cc.BinaryFactory,
-		Blueprint:                  bp,
-		ExpectedErr:                fmt.Errorf(`unknown variable "library_linking_strategy" in module type "library_linking_strategy_cc_defaults`),
-	})
-}
-
-func TestSoongConfigModuleType(t *testing.T) {
-	bp := `
-soong_config_module_type {
-	name: "custom_cc_library_static",
-	module_type: "cc_library_static",
-	config_namespace: "acme",
-	bool_variables: ["feature1"],
-	properties: ["cflags"],
-}
-
-custom_cc_library_static {
-	name: "foo",
-	bazel_module: { bp2build_available: true },
-	host_supported: true,
-	soong_config_variables: {
-		feature1: {
-			conditions_default: {
-				cflags: ["-DDEFAULT1"],
-			},
-			cflags: ["-DFEATURE1"],
-		},
-	},
-}
-`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - soong_config_module_type is supported in bp2build",
-		ModuleTypeUnderTest:        "cc_library_static",
-		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		Blueprint:                  bp,
-		ExpectedBazelTargets: []string{`cc_library_static(
-    name = "foo",
-    copts = select({
-        "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"],
-        "//conditions:default": ["-DDEFAULT1"],
-    }),
-    local_includes = ["."],
-)`}})
-}
-
-func TestSoongConfigModuleTypeImport(t *testing.T) {
-	configBp := `
-soong_config_module_type {
-	name: "custom_cc_library_static",
-	module_type: "cc_library_static",
-	config_namespace: "acme",
-	bool_variables: ["feature1"],
-	properties: ["cflags"],
-}
-`
-	bp := `
-soong_config_module_type_import {
-	from: "foo/bar/SoongConfig.bp",
-	module_types: ["custom_cc_library_static"],
-}
-
-custom_cc_library_static {
-	name: "foo",
-	bazel_module: { bp2build_available: true },
-	host_supported: true,
-	soong_config_variables: {
-		feature1: {
-			conditions_default: {
-				cflags: ["-DDEFAULT1"],
-			},
-			cflags: ["-DFEATURE1"],
-		},
-	},
-}
-`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - soong_config_module_type_import is supported in bp2build",
-		ModuleTypeUnderTest:        "cc_library_static",
-		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		Filesystem: map[string]string{
-			"foo/bar/SoongConfig.bp": configBp,
-		},
-		Blueprint: bp,
-		ExpectedBazelTargets: []string{`cc_library_static(
-    name = "foo",
-    copts = select({
-        "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"],
-        "//conditions:default": ["-DDEFAULT1"],
-    }),
-    local_includes = ["."],
-)`}})
-}
-
-func TestSoongConfigModuleType_StringVar(t *testing.T) {
-	bp := `
-soong_config_string_variable {
-	name: "board",
-	values: ["soc_a", "soc_b", "soc_c"],
-}
-
-soong_config_module_type {
-	name: "custom_cc_library_static",
-	module_type: "cc_library_static",
-	config_namespace: "acme",
-	variables: ["board"],
-	properties: ["cflags"],
-}
-
-custom_cc_library_static {
-	name: "foo",
-	bazel_module: { bp2build_available: true },
-	host_supported: true,
-	soong_config_variables: {
-		board: {
-			soc_a: {
-				cflags: ["-DSOC_A"],
-			},
-			soc_b: {
-				cflags: ["-DSOC_B"],
-			},
-			soc_c: {},
-			conditions_default: {
-				cflags: ["-DSOC_DEFAULT"]
-			},
-		},
-	},
-}
-`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - generates selects for string vars",
-		ModuleTypeUnderTest:        "cc_library_static",
-		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		Blueprint:                  bp,
-		ExpectedBazelTargets: []string{`cc_library_static(
-    name = "foo",
-    copts = select({
-        "//build/bazel/product_config/config_settings:acme__board__soc_a": ["-DSOC_A"],
-        "//build/bazel/product_config/config_settings:acme__board__soc_b": ["-DSOC_B"],
-        "//build/bazel/product_config/config_settings:acme__board__soc_c": [],
-        "//conditions:default": ["-DSOC_DEFAULT"],
-    }),
-    local_includes = ["."],
-)`}})
-}
-
-func TestSoongConfigModuleType_MultipleBoolVar_PartialUseNotPanic(t *testing.T) {
-	bp := `
-soong_config_bool_variable {
-	name: "feature1",
-}
-
-soong_config_bool_variable {
-	name: "feature2",
-}
-
-soong_config_module_type {
-	name: "custom_cc_library_static",
-	module_type: "cc_library_static",
-	config_namespace: "acme",
-	variables: ["feature1", "feature2",],
-	properties: ["cflags"],
-}
-
-custom_cc_library_static {
-	name: "foo",
-	bazel_module: { bp2build_available: true },
-	host_supported: true,
-	soong_config_variables: {
-		feature1: {
-			conditions_default: {
-				cflags: ["-DDEFAULT1"],
-			},
-			cflags: ["-DFEATURE1"],
-		},
-	},
-}`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - used part of multiple bool variable do not panic",
-		ModuleTypeUnderTest:        "cc_library_static",
-		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		Blueprint:                  bp,
-		ExpectedBazelTargets: []string{`cc_library_static(
-    name = "foo",
-    copts = select({
-        "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"],
-        "//conditions:default": ["-DDEFAULT1"],
-    }),
-    local_includes = ["."],
-)`}})
-}
-
-func TestSoongConfigModuleType_StringAndBoolVar(t *testing.T) {
-	bp := `
-soong_config_bool_variable {
-	name: "feature1",
-}
-
-soong_config_bool_variable {
-	name: "feature2",
-}
-
-soong_config_string_variable {
-	name: "board",
-	values: ["soc_a", "soc_b", "soc_c", "soc_d"],
-}
-
-soong_config_module_type {
-	name: "custom_cc_library_static",
-	module_type: "cc_library_static",
-	config_namespace: "acme",
-	variables: ["feature1", "feature2", "board"],
-	properties: ["cflags"],
-}
-
-custom_cc_library_static {
-	name: "foo",
-	bazel_module: { bp2build_available: true },
-	host_supported: true,
-	soong_config_variables: {
-		feature1: {
-			conditions_default: {
-				cflags: ["-DDEFAULT1"],
-			},
-			cflags: ["-DFEATURE1"],
-		},
-		feature2: {
-			cflags: ["-DFEATURE2"],
-			conditions_default: {
-				cflags: ["-DDEFAULT2"],
-			},
-		},
-		board: {
-			soc_a: {
-				cflags: ["-DSOC_A"],
-			},
-			soc_b: {
-				cflags: ["-DSOC_B"],
-			},
-			soc_c: {},
-			conditions_default: {
-				cflags: ["-DSOC_DEFAULT"]
-			},
-		},
-	},
-}`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - generates selects for multiple variable types",
-		ModuleTypeUnderTest:        "cc_library_static",
-		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		Blueprint:                  bp,
-		ExpectedBazelTargets: []string{`cc_library_static(
-    name = "foo",
-    copts = select({
-        "//build/bazel/product_config/config_settings:acme__board__soc_a": ["-DSOC_A"],
-        "//build/bazel/product_config/config_settings:acme__board__soc_b": ["-DSOC_B"],
-        "//build/bazel/product_config/config_settings:acme__board__soc_c": [],
-        "//conditions:default": ["-DSOC_DEFAULT"],
-    }) + select({
-        "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"],
-        "//conditions:default": ["-DDEFAULT1"],
-    }) + select({
-        "//build/bazel/product_config/config_settings:acme__feature2": ["-DFEATURE2"],
-        "//conditions:default": ["-DDEFAULT2"],
-    }),
-    local_includes = ["."],
-)`}})
-}
-
-func TestSoongConfigModuleType_StringVar_LabelListDeps(t *testing.T) {
-	bp := `
-soong_config_string_variable {
-	name: "board",
-	values: ["soc_a", "soc_b", "soc_c", "soc_d"],
-}
-
-soong_config_module_type {
-	name: "custom_cc_library_static",
-	module_type: "cc_library_static",
-	config_namespace: "acme",
-	variables: ["board"],
-	properties: ["cflags", "static_libs"],
-}
-
-custom_cc_library_static {
-	name: "foo",
-	bazel_module: { bp2build_available: true },
-	host_supported: true,
-	soong_config_variables: {
-		board: {
-			soc_a: {
-				cflags: ["-DSOC_A"],
-				static_libs: ["soc_a_dep"],
-			},
-			soc_b: {
-				cflags: ["-DSOC_B"],
-				static_libs: ["soc_b_dep"],
-			},
-			soc_c: {},
-			conditions_default: {
-				cflags: ["-DSOC_DEFAULT"],
-				static_libs: ["soc_default_static_dep"],
-			},
-		},
-	},
-}`
-
-	otherDeps := `
-cc_library_static { name: "soc_a_dep", bazel_module: { bp2build_available: false } }
-cc_library_static { name: "soc_b_dep", bazel_module: { bp2build_available: false } }
-cc_library_static { name: "soc_default_static_dep", bazel_module: { bp2build_available: false } }
-`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - generates selects for label list attributes",
-		ModuleTypeUnderTest:        "cc_library_static",
-		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		Blueprint:                  bp,
-		Filesystem: map[string]string{
-			"foo/bar/Android.bp": otherDeps,
-		},
-		ExpectedBazelTargets: []string{`cc_library_static(
-    name = "foo",
-    copts = select({
-        "//build/bazel/product_config/config_settings:acme__board__soc_a": ["-DSOC_A"],
-        "//build/bazel/product_config/config_settings:acme__board__soc_b": ["-DSOC_B"],
-        "//build/bazel/product_config/config_settings:acme__board__soc_c": [],
-        "//conditions:default": ["-DSOC_DEFAULT"],
-    }),
-    implementation_deps = select({
-        "//build/bazel/product_config/config_settings:acme__board__soc_a": ["//foo/bar:soc_a_dep"],
-        "//build/bazel/product_config/config_settings:acme__board__soc_b": ["//foo/bar:soc_b_dep"],
-        "//build/bazel/product_config/config_settings:acme__board__soc_c": [],
-        "//conditions:default": ["//foo/bar:soc_default_static_dep"],
-    }),
-    local_includes = ["."],
-)`}})
-}
-
-func TestSoongConfigModuleType_Defaults_SingleNamespace(t *testing.T) {
-	bp := `
-soong_config_module_type {
-	name: "vendor_foo_cc_defaults",
-	module_type: "cc_defaults",
-	config_namespace: "vendor_foo",
-	bool_variables: ["feature"],
-	properties: ["cflags", "cppflags"],
-}
-
-vendor_foo_cc_defaults {
-	name: "foo_defaults_1",
-	soong_config_variables: {
-		feature: {
-			cflags: ["-cflag_feature_1"],
-			conditions_default: {
-				cflags: ["-cflag_default_1"],
-			},
-		},
-	},
-}
-
-vendor_foo_cc_defaults {
-	name: "foo_defaults_2",
-	defaults: ["foo_defaults_1"],
-	soong_config_variables: {
-		feature: {
-			cflags: ["-cflag_feature_2"],
-			conditions_default: {
-				cflags: ["-cflag_default_2"],
-			},
-		},
-	},
-}
-
-cc_library_static {
-	name: "lib",
-	defaults: ["foo_defaults_2"],
-	bazel_module: { bp2build_available: true },
-	host_supported: true,
-}
-`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - defaults with a single namespace",
-		ModuleTypeUnderTest:        "cc_library_static",
-		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		Blueprint:                  bp,
-		ExpectedBazelTargets: []string{`cc_library_static(
-    name = "lib",
-    copts = select({
-        "//build/bazel/product_config/config_settings:vendor_foo__feature": [
-            "-cflag_feature_2",
-            "-cflag_feature_1",
-        ],
-        "//conditions:default": [
-            "-cflag_default_2",
-            "-cflag_default_1",
-        ],
-    }),
-    local_includes = ["."],
-)`}})
-}
-
-func TestSoongConfigModuleType_MultipleDefaults_SingleNamespace(t *testing.T) {
-	bp := `
-soong_config_module_type {
-	name: "foo_cc_defaults",
-	module_type: "cc_defaults",
-	config_namespace: "acme",
-	bool_variables: ["feature"],
-	properties: ["cflags"],
-}
-
-soong_config_module_type {
-	name: "bar_cc_defaults",
-	module_type: "cc_defaults",
-	config_namespace: "acme",
-	bool_variables: ["feature"],
-	properties: ["cflags", "asflags"],
-}
-
-foo_cc_defaults {
-	name: "foo_defaults",
-	soong_config_variables: {
-		feature: {
-			cflags: ["-cflag_foo"],
-			conditions_default: {
-				cflags: ["-cflag_default_foo"],
-			},
-		},
-	},
-}
-
-bar_cc_defaults {
-	name: "bar_defaults",
-	srcs: ["file.S"],
-	soong_config_variables: {
-		feature: {
-			cflags: ["-cflag_bar"],
-			asflags: ["-asflag_bar"],
-			conditions_default: {
-				asflags: ["-asflag_default_bar"],
-				cflags: ["-cflag_default_bar"],
-			},
-		},
-	},
-}
-
-cc_library_static {
-	name: "lib",
-	defaults: ["foo_defaults", "bar_defaults"],
-	bazel_module: { bp2build_available: true },
-	host_supported: true,
-}
-
-cc_library_static {
-	name: "lib2",
-	defaults: ["bar_defaults", "foo_defaults"],
-	bazel_module: { bp2build_available: true },
-	host_supported: true,
-}
-`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - multiple defaults with a single namespace",
-		ModuleTypeUnderTest:        "cc_library_static",
-		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		Blueprint:                  bp,
-		ExpectedBazelTargets: []string{`cc_library_static(
-    name = "lib",
-    asflags = select({
-        "//build/bazel/product_config/config_settings:acme__feature": ["-asflag_bar"],
-        "//conditions:default": ["-asflag_default_bar"],
-    }),
-    copts = select({
-        "//build/bazel/product_config/config_settings:acme__feature": [
-            "-cflag_foo",
-            "-cflag_bar",
-        ],
-        "//conditions:default": [
-            "-cflag_default_foo",
-            "-cflag_default_bar",
-        ],
-    }),
-    local_includes = ["."],
-    srcs_as = ["file.S"],
-)`,
-			`cc_library_static(
-    name = "lib2",
-    asflags = select({
-        "//build/bazel/product_config/config_settings:acme__feature": ["-asflag_bar"],
-        "//conditions:default": ["-asflag_default_bar"],
-    }),
-    copts = select({
-        "//build/bazel/product_config/config_settings:acme__feature": [
-            "-cflag_bar",
-            "-cflag_foo",
-        ],
-        "//conditions:default": [
-            "-cflag_default_bar",
-            "-cflag_default_foo",
-        ],
-    }),
-    local_includes = ["."],
-    srcs_as = ["file.S"],
-)`}})
-}
-
-func TestSoongConfigModuleType_Defaults_MultipleNamespaces(t *testing.T) {
-	bp := `
-soong_config_module_type {
-	name: "vendor_foo_cc_defaults",
-	module_type: "cc_defaults",
-	config_namespace: "vendor_foo",
-	bool_variables: ["feature"],
-	properties: ["cflags"],
-}
-
-soong_config_module_type {
-	name: "vendor_bar_cc_defaults",
-	module_type: "cc_defaults",
-	config_namespace: "vendor_bar",
-	bool_variables: ["feature"],
-	properties: ["cflags"],
-}
-
-soong_config_module_type {
-	name: "vendor_qux_cc_defaults",
-	module_type: "cc_defaults",
-	config_namespace: "vendor_qux",
-	bool_variables: ["feature"],
-	properties: ["cflags"],
-}
-
-vendor_foo_cc_defaults {
-	name: "foo_defaults",
-	soong_config_variables: {
-		feature: {
-			cflags: ["-DVENDOR_FOO_FEATURE"],
-			conditions_default: {
-				cflags: ["-DVENDOR_FOO_DEFAULT"],
-			},
-		},
-	},
-}
-
-vendor_bar_cc_defaults {
-	name: "bar_defaults",
-	soong_config_variables: {
-		feature: {
-			cflags: ["-DVENDOR_BAR_FEATURE"],
-			conditions_default: {
-				cflags: ["-DVENDOR_BAR_DEFAULT"],
-			},
-		},
-	},
-}
-
-vendor_qux_cc_defaults {
-	name: "qux_defaults",
-	defaults: ["bar_defaults"],
-	soong_config_variables: {
-		feature: {
-			cflags: ["-DVENDOR_QUX_FEATURE"],
-			conditions_default: {
-				cflags: ["-DVENDOR_QUX_DEFAULT"],
-			},
-		},
-	},
-}
-
-cc_library_static {
-	name: "lib",
-	defaults: ["foo_defaults", "qux_defaults"],
-	bazel_module: { bp2build_available: true },
-	host_supported: true,
-}
-`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - defaults with multiple namespaces",
-		ModuleTypeUnderTest:        "cc_library_static",
-		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
-		Blueprint:                  bp,
-		ExpectedBazelTargets: []string{`cc_library_static(
-    name = "lib",
-    copts = select({
-        "//build/bazel/product_config/config_settings:vendor_bar__feature": ["-DVENDOR_BAR_FEATURE"],
-        "//conditions:default": ["-DVENDOR_BAR_DEFAULT"],
-    }) + select({
-        "//build/bazel/product_config/config_settings:vendor_foo__feature": ["-DVENDOR_FOO_FEATURE"],
-        "//conditions:default": ["-DVENDOR_FOO_DEFAULT"],
-    }) + select({
-        "//build/bazel/product_config/config_settings:vendor_qux__feature": ["-DVENDOR_QUX_FEATURE"],
-        "//conditions:default": ["-DVENDOR_QUX_DEFAULT"],
-    }),
-    local_includes = ["."],
-)`}})
-}
-
-func TestSoongConfigModuleType_Defaults_UseBaselineValueForStringProp(t *testing.T) {
-	bp := `
-soong_config_string_variable {
-    name: "library_linking_strategy",
-    values: [
-        "prefer_static",
-    ],
-}
-
-soong_config_module_type {
-    name: "library_linking_strategy_custom",
-    module_type: "custom",
-    config_namespace: "ANDROID",
-    variables: ["library_linking_strategy"],
-    properties: [
-        "string_literal_prop",
-    ],
-}
-
-library_linking_strategy_custom {
-    name: "foo",
-    string_literal_prop: "29",
-    soong_config_variables: {
-        library_linking_strategy: {
-            prefer_static: {},
-            conditions_default: {
-              string_literal_prop: "30",
-            },
-        },
-    },
-}`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - generates selects for library_linking_strategy",
-		ModuleTypeUnderTest:        "cc_binary",
-		ModuleTypeUnderTestFactory: cc.BinaryFactory,
-		Blueprint:                  bp,
-		Filesystem:                 map[string]string{},
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("custom", "foo", AttrNameToString{
-				"string_literal_prop": `select({
-        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": "29",
-        "//conditions:default": "30",
-    })`,
-			}),
-		},
-	})
-}
-
-func TestSoongConfigModuleType_UnsetConditions(t *testing.T) {
-	bp := `
-soong_config_string_variable {
-    name: "library_linking_strategy",
-    values: [
-        "prefer_static",
-    ],
-}
-
-soong_config_module_type {
-    name: "library_linking_strategy_cc_defaults",
-    module_type: "cc_defaults",
-    config_namespace: "ANDROID",
-    variables: ["library_linking_strategy"],
-    properties: [
-        "shared_libs",
-        "static_libs",
-    ],
-}
-
-library_linking_strategy_cc_defaults {
-    name: "library_linking_strategy_lib_a_defaults",
-    soong_config_variables: {
-        library_linking_strategy: {
-            prefer_static: {},
-            conditions_default: {
-                shared_libs: [
-                    "lib_a",
-                ],
-            },
-        },
-    },
-}
-
-library_linking_strategy_cc_defaults {
-    name: "library_linking_strategy_merged_defaults",
-    defaults: ["library_linking_strategy_lib_a_defaults"],
-    host_supported: true,
-    soong_config_variables: {
-        library_linking_strategy: {
-            prefer_static: {},
-            conditions_default: {
-                shared_libs: [
-                    "lib_b",
-                ],
-            },
-        },
-    },
-}
-
-cc_binary {
-    name: "library_linking_strategy_sample_binary",
-    srcs: ["library_linking_strategy.cc"],
-    defaults: ["library_linking_strategy_merged_defaults"],
-    include_build_directory: false,
-}`
-
-	otherDeps := `
-cc_library { name: "lib_a", bazel_module: { bp2build_available: false } }
-cc_library { name: "lib_b", bazel_module: { bp2build_available: false } }
-cc_library { name: "lib_default", bazel_module: { bp2build_available: false } }
-`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - generates selects for library_linking_strategy",
-		ModuleTypeUnderTest:        "cc_binary",
-		ModuleTypeUnderTestFactory: cc.BinaryFactory,
-		Blueprint:                  bp,
-		Filesystem: map[string]string{
-			"foo/bar/Android.bp": otherDeps,
-		},
-		ExpectedBazelTargets: []string{`cc_binary(
-    name = "library_linking_strategy_sample_binary",
-    dynamic_deps = select({
-        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
-        "//conditions:default": [
-            "//foo/bar:lib_b",
-            "//foo/bar:lib_a",
-        ],
-    }),
-    srcs = ["library_linking_strategy.cc"],
-)`}})
-}
-
-func TestSoongConfigModuleType_UnsetConditionsExcludeLibs(t *testing.T) {
-	bp := `
-soong_config_string_variable {
-    name: "library_linking_strategy",
-    values: [
-        "prefer_static",
-    ],
-}
-
-soong_config_module_type {
-    name: "library_linking_strategy_cc_defaults",
-    module_type: "cc_defaults",
-    config_namespace: "ANDROID",
-    variables: ["library_linking_strategy"],
-    properties: ["shared_libs"],
-}
-
-library_linking_strategy_cc_defaults {
-    name: "library_linking_strategy_lib_a_defaults",
-    soong_config_variables: {
-        library_linking_strategy: {
-            prefer_static: {},
-            conditions_default: {
-                shared_libs: [
-                    "lib_a",
-                ],
-            },
-        },
-    },
-}
-
-library_linking_strategy_cc_defaults {
-    name: "library_linking_strategy_merged_defaults",
-    defaults: ["library_linking_strategy_lib_a_defaults"],
-    host_supported: true,
-    soong_config_variables: {
-        library_linking_strategy: {
-            prefer_static: {},
-            conditions_default: {
-                shared_libs: [
-                    "lib_b",
-                    "lib_c",
-                ],
-            },
-        },
-    },
-    exclude_shared_libs: ["lib_a"],
-}
-
-cc_binary {
-    name: "library_linking_strategy_sample_binary",
-    defaults: ["library_linking_strategy_merged_defaults"],
-    include_build_directory: false,
-}
-
-cc_binary {
-    name: "library_linking_strategy_sample_binary_with_excludes",
-    defaults: ["library_linking_strategy_merged_defaults"],
-    exclude_shared_libs: ["lib_c"],
-    include_build_directory: false,
-}`
-
-	otherDeps := `
-cc_library { name: "lib_a", bazel_module: { bp2build_available: false } }
-cc_library { name: "lib_b", bazel_module: { bp2build_available: false } }
-cc_library { name: "lib_c", bazel_module: { bp2build_available: false } }
-`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - generates selects for library_linking_strategy",
-		ModuleTypeUnderTest:        "cc_binary",
-		ModuleTypeUnderTestFactory: cc.BinaryFactory,
-		Blueprint:                  bp,
-		Filesystem: map[string]string{
-			"foo/bar/Android.bp": otherDeps,
-		},
-		ExpectedBazelTargets: []string{
-			MakeBazelTargetNoRestrictions("cc_binary", "library_linking_strategy_sample_binary", AttrNameToString{
-				"dynamic_deps": `select({
-        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
-        "//conditions:default": [
-            "//foo/bar:lib_b",
-            "//foo/bar:lib_c",
-        ],
-    })`,
-			}),
-			MakeBazelTargetNoRestrictions("cc_binary", "library_linking_strategy_sample_binary_with_excludes", AttrNameToString{
-				"dynamic_deps": `select({
-        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
-        "//conditions:default": ["//foo/bar:lib_b"],
-    })`,
-			}),
-		}})
-}
-
-func TestSoongConfigModuleType_Defaults(t *testing.T) {
-	bp := `
-soong_config_string_variable {
-    name: "library_linking_strategy",
-    values: [
-        "prefer_static",
-    ],
-}
-
-soong_config_module_type {
-    name: "library_linking_strategy_cc_defaults",
-    module_type: "cc_defaults",
-    config_namespace: "ANDROID",
-    variables: ["library_linking_strategy"],
-    properties: [
-        "shared_libs",
-        "static_libs",
-    ],
-}
-
-library_linking_strategy_cc_defaults {
-    name: "library_linking_strategy_lib_a_defaults",
-    soong_config_variables: {
-        library_linking_strategy: {
-            prefer_static: {
-                static_libs: [
-                    "lib_a",
-                ],
-            },
-            conditions_default: {
-                shared_libs: [
-                    "lib_a",
-                ],
-            },
-        },
-    },
-}
-
-library_linking_strategy_cc_defaults {
-    name: "library_linking_strategy_merged_defaults",
-    defaults: ["library_linking_strategy_lib_a_defaults"],
-    host_supported: true,
-    soong_config_variables: {
-        library_linking_strategy: {
-            prefer_static: {
-                static_libs: [
-                    "lib_b",
-                ],
-            },
-            conditions_default: {
-                shared_libs: [
-                    "lib_b",
-                ],
-            },
-        },
-    },
-}
-
-cc_binary {
-    name: "library_linking_strategy_sample_binary",
-    srcs: ["library_linking_strategy.cc"],
-    defaults: ["library_linking_strategy_merged_defaults"],
-}`
-
-	otherDeps := `
-cc_library { name: "lib_a", bazel_module: { bp2build_available: false } }
-cc_library { name: "lib_b", bazel_module: { bp2build_available: false } }
-cc_library { name: "lib_default", bazel_module: { bp2build_available: false } }
-`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - generates selects for library_linking_strategy",
-		ModuleTypeUnderTest:        "cc_binary",
-		ModuleTypeUnderTestFactory: cc.BinaryFactory,
-		Blueprint:                  bp,
-		Filesystem: map[string]string{
-			"foo/bar/Android.bp": otherDeps,
-		},
-		ExpectedBazelTargets: []string{`cc_binary(
-    name = "library_linking_strategy_sample_binary",
-    deps = select({
-        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [
-            "//foo/bar:lib_b_bp2build_cc_library_static",
-            "//foo/bar:lib_a_bp2build_cc_library_static",
-        ],
-        "//conditions:default": [],
-    }),
-    dynamic_deps = select({
-        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
-        "//conditions:default": [
-            "//foo/bar:lib_b",
-            "//foo/bar:lib_a",
-        ],
-    }),
-    local_includes = ["."],
-    srcs = ["library_linking_strategy.cc"],
-)`}})
-}
-
-func TestSoongConfigModuleType_Defaults_Another(t *testing.T) {
-	bp := `
-soong_config_string_variable {
-    name: "library_linking_strategy",
-    values: [
-        "prefer_static",
-    ],
-}
-
-soong_config_module_type {
-    name: "library_linking_strategy_cc_defaults",
-    module_type: "cc_defaults",
-    config_namespace: "ANDROID",
-    variables: ["library_linking_strategy"],
-    properties: [
-        "shared_libs",
-        "static_libs",
-    ],
-}
-
-library_linking_strategy_cc_defaults {
-    name: "library_linking_strategy_sample_defaults",
-    soong_config_variables: {
-        library_linking_strategy: {
-            prefer_static: {
-                static_libs: [
-                    "lib_a",
-                    "lib_b",
-                ],
-            },
-            conditions_default: {
-                shared_libs: [
-                    "lib_a",
-                    "lib_b",
-                ],
-            },
-        },
-    },
-}
-
-cc_binary {
-    name: "library_linking_strategy_sample_binary",
-    host_supported: true,
-    srcs: ["library_linking_strategy.cc"],
-    defaults: ["library_linking_strategy_sample_defaults"],
-}`
-
-	otherDeps := `
-cc_library { name: "lib_a", bazel_module: { bp2build_available: false } }
-cc_library { name: "lib_b", bazel_module: { bp2build_available: false } }
-`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - generates selects for library_linking_strategy",
-		ModuleTypeUnderTest:        "cc_binary",
-		ModuleTypeUnderTestFactory: cc.BinaryFactory,
-		Blueprint:                  bp,
-		Filesystem: map[string]string{
-			"foo/bar/Android.bp": otherDeps,
-		},
-		ExpectedBazelTargets: []string{`cc_binary(
-    name = "library_linking_strategy_sample_binary",
-    deps = select({
-        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [
-            "//foo/bar:lib_a_bp2build_cc_library_static",
-            "//foo/bar:lib_b_bp2build_cc_library_static",
-        ],
-        "//conditions:default": [],
-    }),
-    dynamic_deps = select({
-        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
-        "//conditions:default": [
-            "//foo/bar:lib_a",
-            "//foo/bar:lib_b",
-        ],
-    }),
-    local_includes = ["."],
-    srcs = ["library_linking_strategy.cc"],
-)`}})
-}
-
-func TestSoongConfigModuleType_Defaults_UnusedProps(t *testing.T) {
-	bp := `
-soong_config_string_variable {
-    name: "alphabet",
-    values: [
-        "a",
-        "b",
-        "c", // unused
-    ],
-}
-
-soong_config_module_type {
-    name: "alphabet_cc_defaults",
-    module_type: "cc_defaults",
-    config_namespace: "ANDROID",
-    variables: ["alphabet"],
-    properties: [
-        "cflags", // unused
-        "shared_libs",
-        "static_libs",
-    ],
-}
-
-alphabet_cc_defaults {
-    name: "alphabet_sample_cc_defaults",
-    soong_config_variables: {
-        alphabet: {
-            a: {
-                shared_libs: [
-                    "lib_a",
-                ],
-            },
-            b: {
-                shared_libs: [
-                    "lib_b",
-                ],
-            },
-            conditions_default: {
-                static_libs: [
-                    "lib_default",
-                ],
-            },
-        },
-    },
-}
-
-cc_binary {
-    name: "alphabet_binary",
-    host_supported: true,
-    srcs: ["main.cc"],
-    defaults: ["alphabet_sample_cc_defaults"],
-}`
-
-	otherDeps := `
-cc_library { name: "lib_a", bazel_module: { bp2build_available: false } }
-cc_library { name: "lib_b", bazel_module: { bp2build_available: false } }
-cc_library { name: "lib_default", bazel_module: { bp2build_available: false } }
-`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - generates selects for library_linking_strategy",
-		ModuleTypeUnderTest:        "cc_binary",
-		ModuleTypeUnderTestFactory: cc.BinaryFactory,
-		Blueprint:                  bp,
-		Filesystem: map[string]string{
-			"foo/bar/Android.bp": otherDeps,
-		},
-		ExpectedBazelTargets: []string{`cc_binary(
-    name = "alphabet_binary",
-    deps = select({
-        "//build/bazel/product_config/config_settings:android__alphabet__a": [],
-        "//build/bazel/product_config/config_settings:android__alphabet__b": [],
-        "//conditions:default": ["//foo/bar:lib_default_bp2build_cc_library_static"],
-    }),
-    dynamic_deps = select({
-        "//build/bazel/product_config/config_settings:android__alphabet__a": ["//foo/bar:lib_a"],
-        "//build/bazel/product_config/config_settings:android__alphabet__b": ["//foo/bar:lib_b"],
-        "//conditions:default": [],
-    }),
-    local_includes = ["."],
-    srcs = ["main.cc"],
-)`}})
-}
-
-func TestSoongConfigModuleType_ProductVariableConfigWithPlatformConfig(t *testing.T) {
-	bp := `
-soong_config_bool_variable {
-    name: "special_build",
-}
-
-soong_config_module_type {
-    name: "alphabet_cc_defaults",
-    module_type: "cc_defaults",
-    config_namespace: "alphabet_module",
-    bool_variables: ["special_build"],
-    properties: ["enabled"],
-}
-
-alphabet_cc_defaults {
-    name: "alphabet_sample_cc_defaults",
-    soong_config_variables: {
-        special_build: {
-            enabled: true,
-        },
-    },
-}
-
-cc_binary {
-    name: "alphabet_binary",
-    srcs: ["main.cc"],
-    host_supported: true,
-    defaults: ["alphabet_sample_cc_defaults"],
-    enabled: false,
-    arch: {
-        x86_64: {
-            enabled: false,
-        },
-    },
-    target: {
-        darwin: {
-            enabled: false,
-        },
-    },
-}`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - generates selects for library_linking_strategy",
-		ModuleTypeUnderTest:        "cc_binary",
-		ModuleTypeUnderTestFactory: cc.BinaryFactory,
-		Blueprint:                  bp,
-		Filesystem:                 map[string]string{},
-		ExpectedBazelTargets: []string{`cc_binary(
-    name = "alphabet_binary",
-    local_includes = ["."],
-    srcs = ["main.cc"],
-    target_compatible_with = select({
-        "//build/bazel/platforms/os_arch:android_x86_64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:darwin_arm64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:darwin_x86_64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:linux_bionic_x86_64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:linux_glibc_x86_64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:linux_musl_x86_64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:windows_x86_64": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_config/config_settings:alphabet_module__special_build": [],
-        "//conditions:default": ["@platforms//:incompatible"],
-    }),
-)`}})
-}
-
-func TestSoongConfigModuleType_ProductVariableConfigOverridesEnable(t *testing.T) {
-	bp := `
-soong_config_bool_variable {
-    name: "special_build",
-}
-
-soong_config_module_type {
-    name: "alphabet_cc_defaults",
-    module_type: "cc_defaults",
-    config_namespace: "alphabet_module",
-    bool_variables: ["special_build"],
-    properties: ["enabled"],
-}
-
-alphabet_cc_defaults {
-    name: "alphabet_sample_cc_defaults",
-    soong_config_variables: {
-        special_build: {
-            enabled: true,
-        },
-    },
-}
-
-cc_binary {
-    name: "alphabet_binary",
-    srcs: ["main.cc"],
-    defaults: ["alphabet_sample_cc_defaults"],
-    enabled: false,
-}
-
-alphabet_cc_defaults {
-    name: "alphabet_sample_cc_defaults_conditions_default",
-    soong_config_variables: {
-        special_build: {
-		conditions_default: {
-			enabled: false,
-		},
-	},
-    },
-}
-
-cc_binary {
-    name: "alphabet_binary_conditions_default",
-    srcs: ["main.cc"],
-    defaults: ["alphabet_sample_cc_defaults_conditions_default"],
-    enabled: false,
-}`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - generates selects for library_linking_strategy",
-		ModuleTypeUnderTest:        "cc_binary",
-		ModuleTypeUnderTestFactory: cc.BinaryFactory,
-		Blueprint:                  bp,
-		Filesystem:                 map[string]string{},
-		ExpectedBazelTargets: []string{`cc_binary(
-    name = "alphabet_binary",
-    local_includes = ["."],
-    srcs = ["main.cc"],
-    target_compatible_with = select({
-        "//build/bazel/product_config/config_settings:alphabet_module__special_build": [],
-        "//conditions:default": ["@platforms//:incompatible"],
-    }),
-)`,
-			MakeBazelTarget("cc_binary", "alphabet_binary_conditions_default", AttrNameToString{
-				"local_includes":         `["."]`,
-				"srcs":                   `["main.cc"]`,
-				"target_compatible_with": `["@platforms//:incompatible"]`,
-			}),
-		}})
-}
-
-func TestSoongConfigModuleType_ProductVariableIgnoredIfEnabledByDefault(t *testing.T) {
-	bp := `
-soong_config_bool_variable {
-    name: "special_build",
-}
-
-soong_config_module_type {
-    name: "alphabet_cc_defaults",
-    module_type: "cc_defaults",
-    config_namespace: "alphabet_module",
-    bool_variables: ["special_build"],
-    properties: ["enabled"],
-}
-
-alphabet_cc_defaults {
-    name: "alphabet_sample_cc_defaults",
-    host_supported: true,
-    soong_config_variables: {
-        special_build: {
-            enabled: true,
-        },
-    },
-}
-
-cc_binary {
-    name: "alphabet_binary",
-    srcs: ["main.cc"],
-    defaults: ["alphabet_sample_cc_defaults"],
-}`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - generates selects for library_linking_strategy",
-		ModuleTypeUnderTest:        "cc_binary",
-		ModuleTypeUnderTestFactory: cc.BinaryFactory,
-		Blueprint:                  bp,
-		Filesystem:                 map[string]string{},
-		ExpectedBazelTargets: []string{`cc_binary(
-    name = "alphabet_binary",
-    local_includes = ["."],
-    srcs = ["main.cc"],
-)`}})
-}
-
-func TestSoongConfigModuleType_CombinedWithArchVariantProperties(t *testing.T) {
-	bp := `
-soong_config_bool_variable {
-    name: "my_bool_variable",
-}
-
-soong_config_string_variable {
-    name: "my_string_variable",
-    values: [
-        "value1",
-        "value2",
-    ],
-}
-
-soong_config_module_type {
-    name: "special_build_cc_defaults",
-    module_type: "cc_defaults",
-    config_namespace: "my_namespace",
-    bool_variables: ["my_bool_variable"],
-    variables: ["my_string_variable"],
-    properties: ["target.android.cflags", "cflags"],
-}
-
-special_build_cc_defaults {
-    name: "sample_cc_defaults",
-    target: {
-        android: {
-            cflags: ["-DFOO"],
-        },
-    },
-    soong_config_variables: {
-        my_bool_variable: {
-            target: {
-                android: {
-                    cflags: ["-DBAR"],
-                },
-            },
-            conditions_default: {
-                target: {
-                    android: {
-                        cflags: ["-DBAZ"],
-                    },
-                },
-            },
-        },
-        my_string_variable: {
-            value1: {
-                cflags: ["-DVALUE1_NOT_ANDROID"],
-                target: {
-                    android: {
-                        cflags: ["-DVALUE1"],
-                    },
-                },
-            },
-            value2: {
-                target: {
-                    android: {
-                        cflags: ["-DVALUE2"],
-                    },
-                },
-            },
-            conditions_default: {
-                target: {
-                    android: {
-                        cflags: ["-DSTRING_VAR_CONDITIONS_DEFAULT"],
-                    },
-                },
-            },
-        },
-    },
-}
-
-cc_binary {
-    name: "my_binary",
-    srcs: ["main.cc"],
-    defaults: ["sample_cc_defaults"],
-}`
-
-	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
-		Description:                "soong config variables - generates selects for library_linking_strategy",
-		ModuleTypeUnderTest:        "cc_binary",
-		ModuleTypeUnderTestFactory: cc.BinaryFactory,
-		Blueprint:                  bp,
-		Filesystem:                 map[string]string{},
-		ExpectedBazelTargets: []string{`cc_binary(
-    name = "my_binary",
-    copts = select({
-        "//build/bazel/platforms/os:android": ["-DFOO"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_config/config_settings:my_namespace__my_bool_variable__android": ["-DBAR"],
-        "//build/bazel/product_config/config_settings:my_namespace__my_bool_variable__conditions_default__android": ["-DBAZ"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__value1": ["-DVALUE1_NOT_ANDROID"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__conditions_default__android": ["-DSTRING_VAR_CONDITIONS_DEFAULT"],
-        "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__value1__android": ["-DVALUE1"],
-        "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__value2__android": ["-DVALUE2"],
-        "//conditions:default": [],
-    }),
-    local_includes = ["."],
-    srcs = ["main.cc"],
-    target_compatible_with = ["//build/bazel/platforms/os:android"],
-)`}})
-}
-
-// If we have
-// A. a soong_config_module_type with target.android_<arch>.* in properties
-// B. a module that uses this module type but does not set target.android_<arch>.* via soong config vars
-// Then we should not panic
-func TestPanicsIfSoongConfigModuleTypeHasArchSpecificProperties(t *testing.T) {
-	commonBp := `
-soong_config_bool_variable {
-	name: "my_bool_variable",
-}
-soong_config_module_type {
-	name: "special_cc_defaults",
-	module_type: "cc_defaults",
-	config_namespace: "my_namespace",
-	bool_variables: ["my_bool_variable"],
-	properties: [
-		"cflags",
-		"target.android_arm64.shared_libs",
-	],
-}
-cc_binary {
-	name: "my_binary",
-	defaults: ["my_special_cc_defaults"],
-}
-`
-	testCases := []struct {
-		desc            string
-		additionalBp    string
-		isPanicExpected bool
-	}{
-		{
-			desc: "target.android_arm64 is not set, bp2build should not panic",
-			additionalBp: `
-special_cc_defaults {
-	name: "my_special_cc_defaults",
-	soong_config_variables: {
-		my_bool_variable: {
-			cflags: ["-DFOO"],
-			conditions_default: {
-				cflags: ["-DBAR"],
-			}
-		}
-	},
-}
-			`,
-			isPanicExpected: false,
-		},
-		{
-			desc: "target.android_arm64 is set using the bool soong config var, bp2build should panic",
-			additionalBp: `
-special_cc_defaults {
-	name: "my_special_cc_defaults",
-	soong_config_variables: {
-		my_bool_variable: {
-			cflags: ["-DFOO"],
-			target: {
-				android_arm64: {
-					shared_libs: ["liblog"],
-				},
-			},
-			conditions_default: {
-				cflags: ["-DBAR"],
-			}
-		}
-	},
-}
-			`,
-			isPanicExpected: true,
-		},
-		{
-			desc: "target.android_arm64 is set using conditions_default for the bool soong config var, bp2build should panic",
-			additionalBp: `
-special_cc_defaults {
-	name: "my_special_cc_defaults",
-	soong_config_variables: {
-		my_bool_variable: {
-			cflags: ["-DFOO"],
-			conditions_default: {
-				cflags: ["-DBAR"],
-				target: {
-					android_arm64: {
-						shared_libs: ["liblog"],
-					},
-				},
-			}
-		}
-	},
-}
-			`,
-			isPanicExpected: true,
-		},
-	}
-	for _, tc := range testCases {
-		bp2buildTestCase := Bp2buildTestCase{
-			Description:                tc.desc,
-			ModuleTypeUnderTest:        "cc_binary",
-			ModuleTypeUnderTestFactory: cc.BinaryFactory,
-			Blueprint:                  commonBp + tc.additionalBp,
-			// Check in `foo` dir so that we can check whether it panics or not and not trip over an empty `ExpectedBazelTargets`
-			Dir:                  "foo",
-			ExpectedBazelTargets: []string{},
-		}
-		if tc.isPanicExpected {
-			bp2buildTestCase.ExpectedErr = fmt.Errorf("TODO: support other target types in soong config variable structs: Android_arm64")
-		}
-		runSoongConfigModuleTypeTest(t, bp2buildTestCase)
-	}
-}
-
-func TestNoPanicIfEnabledIsNotUsed(t *testing.T) {
-	bp := `
-soong_config_string_variable {
-	name: "my_string_variable",
-	values: ["val1", "val2"],
-}
-soong_config_module_type {
-	name: "special_cc_defaults",
-	module_type: "cc_defaults",
-	config_namespace: "my_namespace",
-	variables: ["my_string_variable"],
-	properties: [
-		"cflags",
-		"enabled",
-	],
-}
-special_cc_defaults {
-	name: "my_special_cc_defaults",
-	soong_config_variables: {
-		my_string_variable: {
-			val1: {
-				cflags: ["-DFOO"],
-			},
-			val2: {
-				cflags: ["-DBAR"],
-			},
-		},
-	},
-}
-cc_binary {
-	name: "my_binary",
-	enabled: false,
-	defaults: ["my_special_cc_defaults"],
-}
-`
-	tc := Bp2buildTestCase{
-		Description:                "Soong config vars is not used to set `enabled` property",
-		ModuleTypeUnderTest:        "cc_binary",
-		ModuleTypeUnderTestFactory: cc.BinaryFactory,
-		Blueprint:                  bp,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("cc_binary", "my_binary", AttrNameToString{
-				"copts": `select({
-        "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__val1": ["-DFOO"],
-        "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__val2": ["-DBAR"],
-        "//conditions:default": [],
-    })`,
-				"local_includes":         `["."]`,
-				"target_compatible_with": `["@platforms//:incompatible"]`,
-			}),
-		},
-	}
-	runSoongConfigModuleTypeTest(t, tc)
-}
diff --git a/bp2build/symlink_forest.go b/bp2build/symlink_forest.go
deleted file mode 100644
index 5c33308..0000000
--- a/bp2build/symlink_forest.go
+++ /dev/null
@@ -1,501 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"fmt"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"regexp"
-	"sort"
-	"strconv"
-	"strings"
-	"sync"
-	"sync/atomic"
-
-	"android/soong/shared"
-
-	"github.com/google/blueprint/pathtools"
-)
-
-// A tree structure that describes what to do at each directory in the created
-// symlink tree. Currently it is used to enumerate which files/directories
-// should be excluded from symlinking. Each instance of "node" represents a file
-// or a directory. If excluded is true, then that file/directory should be
-// excluded from symlinking. Otherwise, the node is not excluded, but one of its
-// descendants is (otherwise the node in question would not exist)
-
-// This is a version int written to a file called symlink_forest_version at the root of the
-// symlink forest. If the version here does not match the version in the file, then we'll
-// clean the whole symlink forest and recreate it. This number can be bumped whenever there's
-// an incompatible change to the forest layout or a bug in incrementality that needs to be fixed
-// on machines that may still have the bug present in their forest.
-const symlinkForestVersion = 1
-
-type instructionsNode struct {
-	name     string
-	excluded bool // If false, this is just an intermediate node
-	children map[string]*instructionsNode
-}
-
-type symlinkForestContext struct {
-	verbose bool
-	topdir  string // $TOPDIR
-
-	// State
-	wg           sync.WaitGroup
-	depCh        chan string
-	mkdirCount   atomic.Uint64
-	symlinkCount atomic.Uint64
-}
-
-// Ensures that the node for the given path exists in the tree and returns it.
-func ensureNodeExists(root *instructionsNode, path string) *instructionsNode {
-	if path == "" {
-		return root
-	}
-
-	if path[len(path)-1] == '/' {
-		path = path[:len(path)-1] // filepath.Split() leaves a trailing slash
-	}
-
-	dir, base := filepath.Split(path)
-
-	// First compute the parent node...
-	dn := ensureNodeExists(root, dir)
-
-	// then create the requested node as its direct child, if needed.
-	if child, ok := dn.children[base]; ok {
-		return child
-	} else {
-		dn.children[base] = &instructionsNode{base, false, make(map[string]*instructionsNode)}
-		return dn.children[base]
-	}
-}
-
-// Turns a list of paths to be excluded into a tree
-func instructionsFromExcludePathList(paths []string) *instructionsNode {
-	result := &instructionsNode{"", false, make(map[string]*instructionsNode)}
-
-	for _, p := range paths {
-		ensureNodeExists(result, p).excluded = true
-	}
-
-	return result
-}
-
-func mergeBuildFiles(output string, srcBuildFile string, generatedBuildFile string, verbose bool) error {
-
-	srcBuildFileContent, err := os.ReadFile(srcBuildFile)
-	if err != nil {
-		return err
-	}
-
-	generatedBuildFileContent, err := os.ReadFile(generatedBuildFile)
-	if err != nil {
-		return err
-	}
-
-	// There can't be a package() call in both the source and generated BUILD files.
-	// bp2build will generate a package() call for licensing information, but if
-	// there's no licensing information, it will still generate a package() call
-	// that just sets default_visibility=public. If the handcrafted build file
-	// also has a package() call, we'll allow it to override the bp2build
-	// generated one if it doesn't have any licensing information. If the bp2build
-	// one has licensing information and the handcrafted one exists, we'll leave
-	// them both in for bazel to throw an error.
-	packageRegex := regexp.MustCompile(`(?m)^package\s*\(`)
-	packageDefaultVisibilityRegex := regexp.MustCompile(`(?m)^package\s*\(\s*default_visibility\s*=\s*\[\s*"//visibility:public",?\s*]\s*\)`)
-	if packageRegex.Find(srcBuildFileContent) != nil {
-		if verbose && packageDefaultVisibilityRegex.Find(generatedBuildFileContent) != nil {
-			fmt.Fprintf(os.Stderr, "Both '%s' and '%s' have a package() target, removing the first one\n",
-				generatedBuildFile, srcBuildFile)
-		}
-		generatedBuildFileContent = packageDefaultVisibilityRegex.ReplaceAll(generatedBuildFileContent, []byte{})
-	}
-
-	newContents := generatedBuildFileContent
-	if newContents[len(newContents)-1] != '\n' {
-		newContents = append(newContents, '\n')
-	}
-	newContents = append(newContents, srcBuildFileContent...)
-
-	// Say you run bp2build 4 times:
-	// - The first time there's only an Android.bp file. bp2build will convert it to a build file
-	//   under out/soong/bp2build, then symlink from the forest to that generated file
-	// - Then you add a handcrafted BUILD file in the same directory. bp2build will merge this with
-	//   the generated one, and write the result to the output file in the forest. But the output
-	//   file was a symlink to out/soong/bp2build from the previous step! So we erroneously update
-	//   the file in out/soong/bp2build instead. So far this doesn't cause any problems...
-	// - You run a 3rd bp2build with no relevant changes. Everything continues to work.
-	// - You then add a comment to the handcrafted BUILD file. This causes a merge with the
-	//   generated file again. But since we wrote to the generated file in step 2, the generated
-	//   file has an old copy of the handcrafted file in it! This probably causes duplicate bazel
-	//   targets.
-	// To solve this, if we see that the output file is a symlink from a previous build, remove it.
-	stat, err := os.Lstat(output)
-	if err != nil && !os.IsNotExist(err) {
-		return err
-	} else if err == nil {
-		if stat.Mode()&os.ModeSymlink == os.ModeSymlink {
-			if verbose {
-				fmt.Fprintf(os.Stderr, "Removing symlink so that we can replace it with a merged file: %s\n", output)
-			}
-			err = os.Remove(output)
-			if err != nil {
-				return err
-			}
-		}
-	}
-
-	return pathtools.WriteFileIfChanged(output, newContents, 0666)
-}
-
-// Calls readdir() and returns it as a map from the basename of the files in dir
-// to os.FileInfo.
-func readdirToMap(dir string) map[string]os.FileInfo {
-	entryList, err := ioutil.ReadDir(dir)
-	result := make(map[string]os.FileInfo)
-
-	if err != nil {
-		if os.IsNotExist(err) {
-			// It's okay if a directory doesn't exist; it just means that one of the
-			// trees to be merged contains parts the other doesn't
-			return result
-		} else {
-			fmt.Fprintf(os.Stderr, "Cannot readdir '%s': %s\n", dir, err)
-			os.Exit(1)
-		}
-	}
-
-	for _, fi := range entryList {
-		result[fi.Name()] = fi
-	}
-
-	return result
-}
-
-// Creates a symbolic link at dst pointing to src
-func symlinkIntoForest(topdir, dst, src string) uint64 {
-	srcPath := shared.JoinPath(topdir, src)
-	dstPath := shared.JoinPath(topdir, dst)
-
-	// Check if a symlink already exists.
-	if dstInfo, err := os.Lstat(dstPath); err != nil {
-		if !os.IsNotExist(err) {
-			fmt.Fprintf(os.Stderr, "Failed to lstat '%s': %s", dst, err)
-			os.Exit(1)
-		}
-	} else {
-		if dstInfo.Mode()&os.ModeSymlink != 0 {
-			// Assume that the link's target is correct, i.e. no manual tampering.
-			// E.g. OUT_DIR could have been previously used with a different source tree check-out!
-			return 0
-		} else {
-			if err := os.RemoveAll(dstPath); err != nil {
-				fmt.Fprintf(os.Stderr, "Failed to remove '%s': %s", dst, err)
-				os.Exit(1)
-			}
-		}
-	}
-
-	// Create symlink.
-	if err := os.Symlink(srcPath, dstPath); err != nil {
-		fmt.Fprintf(os.Stderr, "Cannot create symlink at '%s' pointing to '%s': %s", dst, src, err)
-		os.Exit(1)
-	}
-	return 1
-}
-
-func isDir(path string, fi os.FileInfo) bool {
-	if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink {
-		return fi.IsDir()
-	}
-
-	fi2, statErr := os.Stat(path)
-	if statErr == nil {
-		return fi2.IsDir()
-	}
-
-	// Check if this is a dangling symlink. If so, treat it like a file, not a dir.
-	_, lstatErr := os.Lstat(path)
-	if lstatErr != nil {
-		fmt.Fprintf(os.Stderr, "Cannot stat or lstat '%s': %s\n%s\n", path, statErr, lstatErr)
-		os.Exit(1)
-	}
-
-	return false
-}
-
-// maybeCleanSymlinkForest will remove the whole symlink forest directory if the version recorded
-// in the symlink_forest_version file is not equal to symlinkForestVersion.
-func maybeCleanSymlinkForest(topdir, forest string, verbose bool) error {
-	versionFilePath := shared.JoinPath(topdir, forest, "symlink_forest_version")
-	versionFileContents, err := os.ReadFile(versionFilePath)
-	if err != nil && !os.IsNotExist(err) {
-		return err
-	}
-	versionFileString := strings.TrimSpace(string(versionFileContents))
-	symlinkForestVersionString := strconv.Itoa(symlinkForestVersion)
-	if err != nil || versionFileString != symlinkForestVersionString {
-		if verbose {
-			fmt.Fprintf(os.Stderr, "Old symlink_forest_version was %q, current is %q. Cleaning symlink forest before recreating...\n", versionFileString, symlinkForestVersionString)
-		}
-		err = os.RemoveAll(shared.JoinPath(topdir, forest))
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// maybeWriteVersionFile will write the symlink_forest_version file containing symlinkForestVersion
-// if it doesn't exist already. If it exists we know it must contain symlinkForestVersion because
-// we checked for that already in maybeCleanSymlinkForest
-func maybeWriteVersionFile(topdir, forest string) error {
-	versionFilePath := shared.JoinPath(topdir, forest, "symlink_forest_version")
-	_, err := os.Stat(versionFilePath)
-	if err != nil {
-		if !os.IsNotExist(err) {
-			return err
-		}
-		err = os.WriteFile(versionFilePath, []byte(strconv.Itoa(symlinkForestVersion)+"\n"), 0666)
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// Recursively plants a symlink forest at forestDir. The symlink tree will
-// contain every file in buildFilesDir and srcDir excluding the files in
-// instructions. Collects every directory encountered during the traversal of
-// srcDir .
-func plantSymlinkForestRecursive(context *symlinkForestContext, instructions *instructionsNode, forestDir string, buildFilesDir string, srcDir string) {
-	defer context.wg.Done()
-
-	if instructions != nil && instructions.excluded {
-		// Excluded paths are skipped at the level of the non-excluded parent.
-		fmt.Fprintf(os.Stderr, "may not specify a root-level exclude directory '%s'", srcDir)
-		os.Exit(1)
-	}
-
-	// We don't add buildFilesDir here because the bp2build files marker files is
-	// already a dependency which covers it. If we ever wanted to turn this into
-	// a generic symlink forest creation tool, we'd need to add it, too.
-	context.depCh <- srcDir
-
-	srcDirMap := readdirToMap(shared.JoinPath(context.topdir, srcDir))
-	buildFilesMap := readdirToMap(shared.JoinPath(context.topdir, buildFilesDir))
-
-	renamingBuildFile := false
-	if _, ok := srcDirMap["BUILD"]; ok {
-		if _, ok := srcDirMap["BUILD.bazel"]; !ok {
-			if _, ok := buildFilesMap["BUILD.bazel"]; ok {
-				renamingBuildFile = true
-				srcDirMap["BUILD.bazel"] = srcDirMap["BUILD"]
-				delete(srcDirMap, "BUILD")
-				if instructions != nil {
-					if _, ok := instructions.children["BUILD"]; ok {
-						instructions.children["BUILD.bazel"] = instructions.children["BUILD"]
-						delete(instructions.children, "BUILD")
-					}
-				}
-			}
-		}
-	}
-
-	allEntries := make([]string, 0, len(srcDirMap)+len(buildFilesMap))
-	for n := range srcDirMap {
-		allEntries = append(allEntries, n)
-	}
-	for n := range buildFilesMap {
-		if _, ok := srcDirMap[n]; !ok {
-			allEntries = append(allEntries, n)
-		}
-	}
-	// Tests read the error messages generated, so ensure their order is deterministic
-	sort.Strings(allEntries)
-
-	fullForestPath := shared.JoinPath(context.topdir, forestDir)
-	createForestDir := false
-	if fi, err := os.Lstat(fullForestPath); err != nil {
-		if os.IsNotExist(err) {
-			createForestDir = true
-		} else {
-			fmt.Fprintf(os.Stderr, "Could not read info for '%s': %s\n", forestDir, err)
-		}
-	} else if fi.Mode()&os.ModeDir == 0 {
-		if err := os.RemoveAll(fullForestPath); err != nil {
-			fmt.Fprintf(os.Stderr, "Failed to remove '%s': %s", forestDir, err)
-			os.Exit(1)
-		}
-		createForestDir = true
-	}
-	if createForestDir {
-		if err := os.MkdirAll(fullForestPath, 0777); err != nil {
-			fmt.Fprintf(os.Stderr, "Could not mkdir '%s': %s\n", forestDir, err)
-			os.Exit(1)
-		}
-		context.mkdirCount.Add(1)
-	}
-
-	// Start with a list of items that already exist in the forest, and remove
-	// each element as it is processed in allEntries. Any remaining items in
-	// forestMapForDeletion must be removed. (This handles files which were
-	// removed since the previous forest generation).
-	forestMapForDeletion := readdirToMap(shared.JoinPath(context.topdir, forestDir))
-
-	for _, f := range allEntries {
-		if f[0] == '.' {
-			continue // Ignore dotfiles
-		}
-		delete(forestMapForDeletion, f)
-		// todo add deletionCount metric
-
-		// The full paths of children in the input trees and in the output tree
-		forestChild := shared.JoinPath(forestDir, f)
-		srcChild := shared.JoinPath(srcDir, f)
-		if f == "BUILD.bazel" && renamingBuildFile {
-			srcChild = shared.JoinPath(srcDir, "BUILD")
-		}
-		buildFilesChild := shared.JoinPath(buildFilesDir, f)
-
-		// Descend in the instruction tree if it exists
-		var instructionsChild *instructionsNode
-		if instructions != nil {
-			instructionsChild = instructions.children[f]
-		}
-
-		srcChildEntry, sExists := srcDirMap[f]
-		buildFilesChildEntry, bExists := buildFilesMap[f]
-
-		if instructionsChild != nil && instructionsChild.excluded {
-			if bExists {
-				context.symlinkCount.Add(symlinkIntoForest(context.topdir, forestChild, buildFilesChild))
-			}
-			continue
-		}
-
-		sDir := sExists && isDir(shared.JoinPath(context.topdir, srcChild), srcChildEntry)
-		bDir := bExists && isDir(shared.JoinPath(context.topdir, buildFilesChild), buildFilesChildEntry)
-
-		if !sExists {
-			if bDir && instructionsChild != nil {
-				// Not in the source tree, but we have to exclude something from under
-				// this subtree, so descend
-				context.wg.Add(1)
-				go plantSymlinkForestRecursive(context, instructionsChild, forestChild, buildFilesChild, srcChild)
-			} else {
-				// Not in the source tree, symlink BUILD file
-				context.symlinkCount.Add(symlinkIntoForest(context.topdir, forestChild, buildFilesChild))
-			}
-		} else if !bExists {
-			if sDir && instructionsChild != nil {
-				// Not in the build file tree, but we have to exclude something from
-				// under this subtree, so descend
-				context.wg.Add(1)
-				go plantSymlinkForestRecursive(context, instructionsChild, forestChild, buildFilesChild, srcChild)
-			} else {
-				// Not in the build file tree, symlink source tree, carry on
-				context.symlinkCount.Add(symlinkIntoForest(context.topdir, forestChild, srcChild))
-			}
-		} else if sDir && bDir {
-			// Both are directories. Descend.
-			context.wg.Add(1)
-			go plantSymlinkForestRecursive(context, instructionsChild, forestChild, buildFilesChild, srcChild)
-		} else if !sDir && !bDir {
-			// Neither is a directory. Merge them.
-			srcBuildFile := shared.JoinPath(context.topdir, srcChild)
-			generatedBuildFile := shared.JoinPath(context.topdir, buildFilesChild)
-			// The Android.bp file that codegen used to produce `buildFilesChild` is
-			// already a dependency, we can ignore `buildFilesChild`.
-			context.depCh <- srcChild
-			if err := mergeBuildFiles(shared.JoinPath(context.topdir, forestChild), srcBuildFile, generatedBuildFile, context.verbose); err != nil {
-				fmt.Fprintf(os.Stderr, "Error merging %s and %s: %s",
-					srcBuildFile, generatedBuildFile, err)
-				os.Exit(1)
-			}
-		} else {
-			// Both exist and one is a file. This is an error.
-			fmt.Fprintf(os.Stderr,
-				"Conflict in workspace symlink tree creation: both '%s' and '%s' exist and exactly one is a directory\n",
-				srcChild, buildFilesChild)
-			os.Exit(1)
-		}
-	}
-
-	// Remove all files in the forest that exist in neither the source
-	// tree nor the build files tree. (This handles files which were removed
-	// since the previous forest generation).
-	for f := range forestMapForDeletion {
-		var instructionsChild *instructionsNode
-		if instructions != nil {
-			instructionsChild = instructions.children[f]
-		}
-
-		if instructionsChild != nil && instructionsChild.excluded {
-			// This directory may be excluded because bazel writes to it under the
-			// forest root. Thus this path is intentionally left alone.
-			continue
-		}
-		forestChild := shared.JoinPath(context.topdir, forestDir, f)
-		if err := os.RemoveAll(forestChild); err != nil {
-			fmt.Fprintf(os.Stderr, "Failed to remove '%s/%s': %s", forestDir, f, err)
-			os.Exit(1)
-		}
-	}
-}
-
-// PlantSymlinkForest Creates a symlink forest by merging the directory tree at "buildFiles" and
-// "srcDir" while excluding paths listed in "exclude". Returns the set of paths
-// under srcDir on which readdir() had to be called to produce the symlink
-// forest.
-func PlantSymlinkForest(verbose bool, topdir string, forest string, buildFiles string, exclude []string) (deps []string, mkdirCount, symlinkCount uint64) {
-	context := &symlinkForestContext{
-		verbose:      verbose,
-		topdir:       topdir,
-		depCh:        make(chan string),
-		mkdirCount:   atomic.Uint64{},
-		symlinkCount: atomic.Uint64{},
-	}
-
-	err := maybeCleanSymlinkForest(topdir, forest, verbose)
-	if err != nil {
-		fmt.Fprintln(os.Stderr, err)
-		os.Exit(1)
-	}
-
-	instructions := instructionsFromExcludePathList(exclude)
-	go func() {
-		context.wg.Add(1)
-		plantSymlinkForestRecursive(context, instructions, forest, buildFiles, ".")
-		context.wg.Wait()
-		close(context.depCh)
-	}()
-
-	for dep := range context.depCh {
-		deps = append(deps, dep)
-	}
-
-	err = maybeWriteVersionFile(topdir, forest)
-	if err != nil {
-		fmt.Fprintln(os.Stderr, err)
-		os.Exit(1)
-	}
-
-	return deps, context.mkdirCount.Load(), context.symlinkCount.Load()
-}
diff --git a/bp2build/testing.go b/bp2build/testing.go
deleted file mode 100644
index 18ae82d..0000000
--- a/bp2build/testing.go
+++ /dev/null
@@ -1,709 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-/*
-For shareable/common bp2build testing functionality and dumping ground for
-specific-but-shared functionality among tests in package
-*/
-
-import (
-	"fmt"
-	"sort"
-	"strings"
-	"testing"
-
-	"github.com/google/blueprint/proptools"
-
-	"android/soong/android"
-	"android/soong/android/allowlists"
-	"android/soong/bazel"
-)
-
-var (
-	buildDir string
-)
-
-func checkError(t *testing.T, errs []error, expectedErr error) bool {
-	t.Helper()
-
-	if len(errs) != 1 {
-		return false
-	}
-	if strings.Contains(errs[0].Error(), expectedErr.Error()) {
-		return true
-	}
-
-	return false
-}
-
-func errored(t *testing.T, tc Bp2buildTestCase, errs []error) bool {
-	t.Helper()
-	if tc.ExpectedErr != nil {
-		// Rely on checkErrors, as this test case is expected to have an error.
-		return false
-	}
-
-	if len(errs) > 0 {
-		for _, err := range errs {
-			t.Errorf("%s: %s", tc.Description, err)
-		}
-		return true
-	}
-
-	// All good, continue execution.
-	return false
-}
-
-func RunBp2BuildTestCaseSimple(t *testing.T, tc Bp2buildTestCase) {
-	t.Helper()
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
-}
-
-type Bp2buildTestCase struct {
-	Description                string
-	ModuleTypeUnderTest        string
-	ModuleTypeUnderTestFactory android.ModuleFactory
-	// Text to add to the toplevel, root Android.bp file. If Dir is not set, all
-	// ExpectedBazelTargets are assumed to be generated by this file.
-	Blueprint string
-	// ExpectedBazelTargets compares the BazelTargets generated in `Dir` (if not empty).
-	// Otherwise, it checks the BazelTargets generated by `Blueprint` in the root directory.
-	ExpectedBazelTargets []string
-	Filesystem           map[string]string
-	// Dir sets the directory which will be compared against the targets in ExpectedBazelTargets.
-	// This should used in conjunction with the Filesystem property to check for targets
-	// generated from a directory that is not the root.
-	// If not set, all ExpectedBazelTargets are assumed to be generated by the text in the
-	// Blueprint property.
-	Dir string
-	// An error with a string contained within the string of the expected error
-	ExpectedErr         error
-	UnconvertedDepsMode unconvertedDepsMode
-
-	// For every directory listed here, the BUILD file for that directory will
-	// be merged with the generated BUILD file. This allows custom BUILD targets
-	// to be used in tests, or use BUILD files to draw package boundaries.
-	KeepBuildFileForDirs []string
-}
-
-func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
-	t.Helper()
-	bp2buildSetup := android.GroupFixturePreparers(
-		android.FixtureRegisterWithContext(registerModuleTypes),
-		SetBp2BuildTestRunner,
-	)
-	runBp2BuildTestCaseWithSetup(t, bp2buildSetup, tc)
-}
-
-func RunApiBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
-	t.Helper()
-	apiBp2BuildSetup := android.GroupFixturePreparers(
-		android.FixtureRegisterWithContext(registerModuleTypes),
-		SetApiBp2BuildTestRunner,
-	)
-	runBp2BuildTestCaseWithSetup(t, apiBp2BuildSetup, tc)
-}
-
-func runBp2BuildTestCaseWithSetup(t *testing.T, extraPreparer android.FixturePreparer, tc Bp2buildTestCase) {
-	t.Helper()
-	dir := "."
-	filesystem := make(map[string][]byte)
-	for f, content := range tc.Filesystem {
-		filesystem[f] = []byte(content)
-	}
-
-	preparers := []android.FixturePreparer{
-		extraPreparer,
-		android.FixtureMergeMockFs(filesystem),
-		android.FixtureWithRootAndroidBp(tc.Blueprint),
-		android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
-			ctx.RegisterModuleType(tc.ModuleTypeUnderTest, tc.ModuleTypeUnderTestFactory)
-		}),
-		android.FixtureModifyContext(func(ctx *android.TestContext) {
-			// A default configuration for tests to not have to specify bp2build_available on top level
-			// targets.
-			bp2buildConfig := android.NewBp2BuildAllowlist().SetDefaultConfig(
-				allowlists.Bp2BuildConfig{
-					android.Bp2BuildTopLevel: allowlists.Bp2BuildDefaultTrueRecursively,
-				},
-			)
-			for _, f := range tc.KeepBuildFileForDirs {
-				bp2buildConfig.SetKeepExistingBuildFile(map[string]bool{
-					f: /*recursive=*/ false,
-				})
-			}
-			ctx.RegisterBp2BuildConfig(bp2buildConfig)
-			// This setting is added to bp2build invocations. It prevents bp2build
-			// from cloning modules to their original state after mutators run. This
-			// would lose some data intentionally set by these mutators.
-			ctx.SkipCloneModulesAfterMutators = true
-		}),
-		android.FixtureModifyEnv(func(env map[string]string) {
-			if tc.UnconvertedDepsMode == errorModulesUnconvertedDeps {
-				env["BP2BUILD_ERROR_UNCONVERTED"] = "true"
-			}
-		}),
-	}
-
-	preparer := android.GroupFixturePreparers(preparers...)
-	if tc.ExpectedErr != nil {
-		pattern := "\\Q" + tc.ExpectedErr.Error() + "\\E"
-		preparer = preparer.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(pattern))
-	}
-	result := preparer.RunTestWithCustomResult(t).(*BazelTestResult)
-	if len(result.Errs) > 0 {
-		return
-	}
-
-	checkDir := dir
-	if tc.Dir != "" {
-		checkDir = tc.Dir
-	}
-	expectedTargets := map[string][]string{
-		checkDir: tc.ExpectedBazelTargets,
-	}
-
-	result.CompareAllBazelTargets(t, tc.Description, expectedTargets, true)
-}
-
-// SetBp2BuildTestRunner customizes the test fixture mechanism to run tests in Bp2Build mode.
-var SetBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{Bp2Build})
-
-// SetApiBp2BuildTestRunner customizes the test fixture mechanism to run tests in ApiBp2build mode.
-var SetApiBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{ApiBp2build})
-
-// bazelTestRunner customizes the test fixture mechanism to run tests of the bp2build and
-// apiBp2build build modes.
-type bazelTestRunner struct {
-	mode CodegenMode
-}
-
-func (b *bazelTestRunner) FinalPreparer(result *android.TestResult) android.CustomTestResult {
-	ctx := result.TestContext
-	switch b.mode {
-	case Bp2Build:
-		ctx.RegisterForBazelConversion()
-	case ApiBp2build:
-		ctx.RegisterForApiBazelConversion()
-	default:
-		panic(fmt.Errorf("unknown build mode: %d", b.mode))
-	}
-
-	return &BazelTestResult{TestResult: result}
-}
-
-func (b *bazelTestRunner) PostParseProcessor(result android.CustomTestResult) {
-	bazelResult := result.(*BazelTestResult)
-	ctx := bazelResult.TestContext
-	config := bazelResult.Config
-	_, errs := ctx.ResolveDependencies(config)
-	if bazelResult.CollateErrs(errs) {
-		return
-	}
-
-	codegenMode := Bp2Build
-	if ctx.Config().BuildMode == android.ApiBp2build {
-		codegenMode = ApiBp2build
-	}
-	codegenCtx := NewCodegenContext(config, ctx.Context, codegenMode, "")
-	res, errs := GenerateBazelTargets(codegenCtx, false)
-	if bazelResult.CollateErrs(errs) {
-		return
-	}
-
-	// Store additional data for access by tests.
-	bazelResult.conversionResults = res
-}
-
-// BazelTestResult is a wrapper around android.TestResult to provide type safe access to the bazel
-// specific data stored by the bazelTestRunner.
-type BazelTestResult struct {
-	*android.TestResult
-
-	// The result returned by the GenerateBazelTargets function.
-	conversionResults
-}
-
-// CompareAllBazelTargets compares the BazelTargets produced by the test for all the directories
-// with the supplied set of expected targets.
-//
-// If ignoreUnexpected=false then this enforces an exact match where every BazelTarget produced must
-// have a corresponding expected BazelTarget.
-//
-// If ignoreUnexpected=true then it will ignore directories for which there are no expected targets.
-func (b BazelTestResult) CompareAllBazelTargets(t *testing.T, description string, expectedTargets map[string][]string, ignoreUnexpected bool) {
-	t.Helper()
-	actualTargets := b.buildFileToTargets
-
-	// Generate the sorted set of directories to check.
-	dirsToCheck := android.SortedKeys(expectedTargets)
-	if !ignoreUnexpected {
-		// This needs to perform an exact match so add the directories in which targets were
-		// produced to the list of directories to check.
-		dirsToCheck = append(dirsToCheck, android.SortedKeys(actualTargets)...)
-		dirsToCheck = android.SortedUniqueStrings(dirsToCheck)
-	}
-
-	for _, dir := range dirsToCheck {
-		expected := expectedTargets[dir]
-		actual := actualTargets[dir]
-
-		if expected == nil {
-			if actual != nil {
-				t.Errorf("did not expect any bazel modules in %q but found %d", dir, len(actual))
-			}
-		} else if actual == nil {
-			expectedCount := len(expected)
-			if expectedCount > 0 {
-				t.Errorf("expected %d bazel modules in %q but did not find any", expectedCount, dir)
-			}
-		} else {
-			b.CompareBazelTargets(t, description, expected, actual)
-		}
-	}
-}
-
-func (b BazelTestResult) CompareBazelTargets(t *testing.T, description string, expectedContents []string, actualTargets BazelTargets) {
-	t.Helper()
-	if actualCount, expectedCount := len(actualTargets), len(expectedContents); actualCount != expectedCount {
-		t.Errorf("%s: Expected %d bazel target (%s), got %d (%s)",
-			description, expectedCount, expectedContents, actualCount, actualTargets)
-	} else {
-		sort.SliceStable(actualTargets, func(i, j int) bool {
-			return actualTargets[i].name < actualTargets[j].name
-		})
-		sort.SliceStable(expectedContents, func(i, j int) bool {
-			return getTargetName(expectedContents[i]) < getTargetName(expectedContents[j])
-		})
-		for i, actualTarget := range actualTargets {
-			if w, g := expectedContents[i], actualTarget.content; w != g {
-				t.Errorf(
-					"%s[%d]: Expected generated Bazel target to be `%s`, got `%s`",
-					description, i, w, g)
-			}
-		}
-	}
-}
-
-type nestedProps struct {
-	Nested_prop *string
-}
-
-type EmbeddedProps struct {
-	Embedded_prop *string
-}
-
-type OtherEmbeddedProps struct {
-	Other_embedded_prop *string
-}
-
-type customProps struct {
-	EmbeddedProps
-	*OtherEmbeddedProps
-
-	Bool_prop     bool
-	Bool_ptr_prop *bool
-	// Ensure that properties tagged `blueprint:mutated` are omitted
-	Int_prop            int `blueprint:"mutated"`
-	Int64_ptr_prop      *int64
-	String_prop         string
-	String_literal_prop *string `android:"arch_variant"`
-	String_ptr_prop     *string
-	String_list_prop    []string
-
-	Nested_props     nestedProps
-	Nested_props_ptr *nestedProps
-
-	Arch_paths         []string `android:"path,arch_variant"`
-	Arch_paths_exclude []string `android:"path,arch_variant"`
-
-	// Prop used to indicate this conversion should be 1 module -> multiple targets
-	One_to_many_prop *bool
-
-	Api *string // File describing the APIs of this module
-
-	Test_config_setting *bool // Used to test generation of config_setting targets
-
-	Dir *string // Dir in which the Bazel Target will be created
-}
-
-type customModule struct {
-	android.ModuleBase
-	android.BazelModuleBase
-
-	props customProps
-}
-
-// OutputFiles is needed because some instances of this module use dist with a
-// tag property which requires the module implements OutputFileProducer.
-func (m *customModule) OutputFiles(tag string) (android.Paths, error) {
-	return android.PathsForTesting("path" + tag), nil
-}
-
-func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	// nothing for now.
-}
-
-func customModuleFactoryBase() android.Module {
-	module := &customModule{}
-	module.AddProperties(&module.props)
-	android.InitBazelModule(module)
-	return module
-}
-
-func customModuleFactoryHostAndDevice() android.Module {
-	m := customModuleFactoryBase()
-	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibBoth)
-	return m
-}
-
-func customModuleFactoryDeviceSupported() android.Module {
-	m := customModuleFactoryBase()
-	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibBoth)
-	return m
-}
-
-func customModuleFactoryHostSupported() android.Module {
-	m := customModuleFactoryBase()
-	android.InitAndroidArchModule(m, android.HostSupported, android.MultilibBoth)
-	return m
-}
-
-func customModuleFactoryHostAndDeviceDefault() android.Module {
-	m := customModuleFactoryBase()
-	android.InitAndroidArchModule(m, android.HostAndDeviceDefault, android.MultilibBoth)
-	return m
-}
-
-func customModuleFactoryNeitherHostNorDeviceSupported() android.Module {
-	m := customModuleFactoryBase()
-	android.InitAndroidArchModule(m, android.NeitherHostNorDeviceSupported, android.MultilibBoth)
-	return m
-}
-
-type testProps struct {
-	Test_prop struct {
-		Test_string_prop string
-	}
-}
-
-type customTestModule struct {
-	android.ModuleBase
-
-	props      customProps
-	test_props testProps
-}
-
-func (m *customTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	// nothing for now.
-}
-
-func customTestModuleFactoryBase() android.Module {
-	m := &customTestModule{}
-	m.AddProperties(&m.props)
-	m.AddProperties(&m.test_props)
-	return m
-}
-
-func customTestModuleFactory() android.Module {
-	m := customTestModuleFactoryBase()
-	android.InitAndroidModule(m)
-	return m
-}
-
-type customDefaultsModule struct {
-	android.ModuleBase
-	android.DefaultsModuleBase
-}
-
-func customDefaultsModuleFactoryBase() android.DefaultsModule {
-	module := &customDefaultsModule{}
-	module.AddProperties(&customProps{})
-	return module
-}
-
-func customDefaultsModuleFactoryBasic() android.Module {
-	return customDefaultsModuleFactoryBase()
-}
-
-func customDefaultsModuleFactory() android.Module {
-	m := customDefaultsModuleFactoryBase()
-	android.InitDefaultsModule(m)
-	return m
-}
-
-type EmbeddedAttr struct {
-	Embedded_attr *string
-}
-
-type OtherEmbeddedAttr struct {
-	Other_embedded_attr *string
-}
-
-type customBazelModuleAttributes struct {
-	EmbeddedAttr
-	*OtherEmbeddedAttr
-	String_literal_prop bazel.StringAttribute
-	String_ptr_prop     *string
-	String_list_prop    []string
-	Arch_paths          bazel.LabelListAttribute
-	Api                 bazel.LabelAttribute
-}
-
-func (m *customModule) dir() *string {
-	return m.props.Dir
-}
-
-func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	if p := m.props.One_to_many_prop; p != nil && *p {
-		customBp2buildOneToMany(ctx, m)
-		return
-	}
-
-	paths := bazel.LabelListAttribute{}
-	strAttr := bazel.StringAttribute{}
-	for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) {
-		for config, props := range configToProps {
-			if custProps, ok := props.(*customProps); ok {
-				if custProps.Arch_paths != nil {
-					paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, custProps.Arch_paths, custProps.Arch_paths_exclude))
-				}
-				if custProps.String_literal_prop != nil {
-					strAttr.SetSelectValue(axis, config, custProps.String_literal_prop)
-				}
-			}
-		}
-	}
-	productVariableProps := android.ProductVariableProperties(ctx, ctx.Module())
-	if props, ok := productVariableProps["String_literal_prop"]; ok {
-		for c, p := range props {
-			if val, ok := p.(*string); ok {
-				strAttr.SetSelectValue(c.ConfigurationAxis(), c.SelectKey(), val)
-			}
-		}
-	}
-
-	paths.ResolveExcludes()
-
-	attrs := &customBazelModuleAttributes{
-		String_literal_prop: strAttr,
-		String_ptr_prop:     m.props.String_ptr_prop,
-		String_list_prop:    m.props.String_list_prop,
-		Arch_paths:          paths,
-	}
-
-	attrs.Embedded_attr = m.props.Embedded_prop
-	if m.props.OtherEmbeddedProps != nil {
-		attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop}
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class: "custom",
-	}
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name(), Dir: m.dir()}, attrs)
-
-	if proptools.Bool(m.props.Test_config_setting) {
-		m.createConfigSetting(ctx)
-	}
-
-}
-
-func (m *customModule) createConfigSetting(ctx android.TopDownMutatorContext) {
-	csa := bazel.ConfigSettingAttributes{
-		Flag_values: bazel.StringMapAttribute{
-			"//build/bazel/rules/my_string_setting": m.Name(),
-		},
-	}
-	ca := android.CommonAttributes{
-		Name: m.Name() + "_config_setting",
-	}
-	ctx.CreateBazelConfigSetting(
-		csa,
-		ca,
-		ctx.ModuleDir(),
-	)
-}
-
-var _ android.ApiProvider = (*customModule)(nil)
-
-func (c *customModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class: "custom_api_contribution",
-	}
-	apiAttribute := bazel.MakeLabelAttribute(
-		android.BazelLabelForModuleSrcSingle(ctx, proptools.String(c.props.Api)).Label,
-	)
-	attrs := &customBazelModuleAttributes{
-		Api: *apiAttribute,
-	}
-	ctx.CreateBazelTargetModule(props,
-		android.CommonAttributes{Name: c.Name()},
-		attrs)
-}
-
-// A bp2build mutator that uses load statements and creates a 1:M mapping from
-// module to target.
-func customBp2buildOneToMany(ctx android.TopDownMutatorContext, m *customModule) {
-
-	baseName := m.Name()
-	attrs := &customBazelModuleAttributes{}
-
-	myLibraryProps := bazel.BazelTargetModuleProperties{
-		Rule_class:        "my_library",
-		Bzl_load_location: "//build/bazel/rules:rules.bzl",
-	}
-	ctx.CreateBazelTargetModule(myLibraryProps, android.CommonAttributes{Name: baseName}, attrs)
-
-	protoLibraryProps := bazel.BazelTargetModuleProperties{
-		Rule_class:        "proto_library",
-		Bzl_load_location: "//build/bazel/rules:proto.bzl",
-	}
-	ctx.CreateBazelTargetModule(protoLibraryProps, android.CommonAttributes{Name: baseName + "_proto_library_deps"}, attrs)
-
-	myProtoLibraryProps := bazel.BazelTargetModuleProperties{
-		Rule_class:        "my_proto_library",
-		Bzl_load_location: "//build/bazel/rules:proto.bzl",
-	}
-	ctx.CreateBazelTargetModule(myProtoLibraryProps, android.CommonAttributes{Name: baseName + "_my_proto_library_deps"}, attrs)
-}
-
-// Helper method for tests to easily access the targets in a dir.
-func generateBazelTargetsForDir(codegenCtx *CodegenContext, dir string) (BazelTargets, []error) {
-	// TODO: Set generateFilegroups to true and/or remove the generateFilegroups argument completely
-	res, err := GenerateBazelTargets(codegenCtx, false)
-	if err != nil {
-		return BazelTargets{}, err
-	}
-	return res.buildFileToTargets[dir], err
-}
-
-func registerCustomModuleForBp2buildConversion(ctx *android.TestContext) {
-	ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
-	ctx.RegisterForBazelConversion()
-}
-
-func simpleModuleDoNotConvertBp2build(typ, name string) string {
-	return fmt.Sprintf(`
-%s {
-		name: "%s",
-		bazel_module: { bp2build_available: false },
-}`, typ, name)
-}
-
-type AttrNameToString map[string]string
-
-func (a AttrNameToString) clone() AttrNameToString {
-	newAttrs := make(AttrNameToString, len(a))
-	for k, v := range a {
-		newAttrs[k] = v
-	}
-	return newAttrs
-}
-
-// makeBazelTargetNoRestrictions returns bazel target build file definition that can be host or
-// device specific, or independent of host/device.
-func makeBazelTargetHostOrDevice(typ, name string, attrs AttrNameToString, hod android.HostOrDeviceSupported) string {
-	if _, ok := attrs["target_compatible_with"]; !ok {
-		switch hod {
-		case android.HostSupported:
-			attrs["target_compatible_with"] = `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
-        "//conditions:default": [],
-    })`
-		case android.DeviceSupported:
-			attrs["target_compatible_with"] = `["//build/bazel/platforms/os:android"]`
-		}
-	}
-
-	attrStrings := make([]string, 0, len(attrs)+1)
-	if name != "" {
-		attrStrings = append(attrStrings, fmt.Sprintf(`    name = "%s",`, name))
-	}
-	for _, k := range android.SortedKeys(attrs) {
-		attrStrings = append(attrStrings, fmt.Sprintf("    %s = %s,", k, attrs[k]))
-	}
-	return fmt.Sprintf(`%s(
-%s
-)`, typ, strings.Join(attrStrings, "\n"))
-}
-
-// MakeBazelTargetNoRestrictions returns bazel target build file definition that does not add a
-// target_compatible_with.  This is useful for module types like filegroup and genrule that arch not
-// arch variant
-func MakeBazelTargetNoRestrictions(typ, name string, attrs AttrNameToString) string {
-	return makeBazelTargetHostOrDevice(typ, name, attrs, android.HostAndDeviceDefault)
-}
-
-// makeBazelTargetNoRestrictions returns bazel target build file definition that is device specific
-// as this is the most common default in Soong.
-func MakeBazelTarget(typ, name string, attrs AttrNameToString) string {
-	return makeBazelTargetHostOrDevice(typ, name, attrs, android.DeviceSupported)
-}
-
-type ExpectedRuleTarget struct {
-	Rule  string
-	Name  string
-	Attrs AttrNameToString
-	Hod   android.HostOrDeviceSupported
-}
-
-func (ebr ExpectedRuleTarget) String() string {
-	return makeBazelTargetHostOrDevice(ebr.Rule, ebr.Name, ebr.Attrs, ebr.Hod)
-}
-
-func makeCcStubSuiteTargets(name string, attrs AttrNameToString) string {
-	if _, hasStubs := attrs["stubs_symbol_file"]; !hasStubs {
-		return ""
-	}
-	STUB_SUITE_ATTRS := map[string]string{
-		"stubs_symbol_file":    "symbol_file",
-		"stubs_versions":       "versions",
-		"soname":               "soname",
-		"source_library_label": "source_library_label",
-	}
-
-	stubSuiteAttrs := AttrNameToString{}
-	for key, _ := range attrs {
-		if _, stubSuiteAttr := STUB_SUITE_ATTRS[key]; stubSuiteAttr {
-			stubSuiteAttrs[STUB_SUITE_ATTRS[key]] = attrs[key]
-		} else {
-			panic(fmt.Sprintf("unused cc_stub_suite attr %q\n", key))
-		}
-	}
-	return MakeBazelTarget("cc_stub_suite", name+"_stub_libs", stubSuiteAttrs)
-}
-
-func MakeNeverlinkDuplicateTarget(moduleType string, name string) string {
-	return MakeNeverlinkDuplicateTargetWithAttrs(moduleType, name, AttrNameToString{})
-}
-
-func MakeNeverlinkDuplicateTargetWithAttrs(moduleType string, name string, extraAttrs AttrNameToString) string {
-	attrs := extraAttrs
-	attrs["neverlink"] = `True`
-	attrs["exports"] = `[":` + name + `"]`
-	return MakeBazelTarget(moduleType, name+"-neverlink", attrs)
-}
-
-func getTargetName(targetContent string) string {
-	data := strings.Split(targetContent, "name = \"")
-	if len(data) < 2 {
-		return ""
-	} else {
-		endIndex := strings.Index(data[1], "\"")
-		return data[1][:endIndex]
-	}
-}
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 45009c1..38fbd88 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -22,8 +22,6 @@
 	"strings"
 
 	"android/soong/android"
-	"android/soong/bazel"
-	"android/soong/bazel/cquery"
 	"android/soong/cc"
 
 	"github.com/google/blueprint"
@@ -98,7 +96,6 @@
 
 type bpf struct {
 	android.ModuleBase
-	android.BazelModuleBase
 
 	properties BpfProperties
 
@@ -153,7 +150,7 @@
 		// The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
 		"-isystem bionic/libc/kernel/uapi/asm-arm64",
 		"-isystem bionic/libc/kernel/android/uapi",
-		"-I       frameworks/libs/net/common/native/bpf_headers/include/bpf",
+		"-I       packages/modules/Connectivity/staticlibs/native/bpf_headers/include/bpf",
 		// TODO(b/149785767): only give access to specific file with AID_* constants
 		"-I       system/core/libcutils/include",
 		"-I " + ctx.ModuleDir(),
@@ -206,6 +203,16 @@
 		}
 
 	}
+
+	installDir := android.PathForModuleInstall(ctx, "etc", "bpf")
+	if len(bpf.properties.Sub_dir) > 0 {
+		installDir = installDir.Join(ctx, bpf.properties.Sub_dir)
+	}
+	for _, obj := range bpf.objs {
+		ctx.PackageFile(installDir, obj.Base(), obj)
+	}
+
+	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
 }
 
 func (bpf *bpf) AndroidMk() android.AndroidMkData {
@@ -229,52 +236,25 @@
 				names = append(names, objName)
 				fmt.Fprintln(w, "include $(CLEAR_VARS)", " # bpf.bpf.obj")
 				fmt.Fprintln(w, "LOCAL_MODULE := ", objName)
-				data.Entries.WriteLicenseVariables(w)
 				fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", obj.String())
 				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base())
 				fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
 				fmt.Fprintln(w, localModulePath)
+				// AconfigUpdateAndroidMkData may have added elements to Extra.  Process them here.
+				for _, extra := range data.Extra {
+					extra(w, nil)
+				}
 				fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
 				fmt.Fprintln(w)
 			}
 			fmt.Fprintln(w, "include $(CLEAR_VARS)", " # bpf.bpf")
 			fmt.Fprintln(w, "LOCAL_MODULE := ", name)
-			data.Entries.WriteLicenseVariables(w)
 			android.AndroidMkEmitAssignList(w, "LOCAL_REQUIRED_MODULES", names)
 			fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
 		},
 	}
 }
 
-var _ android.MixedBuildBuildable = (*bpf)(nil)
-
-func (bpf *bpf) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
-	return true
-}
-
-func (bpf *bpf) QueueBazelCall(ctx android.BaseModuleContext) {
-	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(
-		bpf.GetBazelLabel(ctx, bpf),
-		cquery.GetOutputFiles,
-		android.GetConfigKey(ctx))
-}
-
-func (bpf *bpf) ProcessBazelQueryResponse(ctx android.ModuleContext) {
-	bazelCtx := ctx.Config().BazelContext
-	objPaths, err := bazelCtx.GetOutputFiles(bpf.GetBazelLabel(ctx, bpf), android.GetConfigKey(ctx))
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-		return
-	}
-
-	bazelOuts := android.Paths{}
-	for _, p := range objPaths {
-		bazelOuts = append(bazelOuts, android.PathForBazelOut(ctx, p))
-	}
-	bpf.objs = bazelOuts
-}
-
 // Implements OutputFileFileProducer interface so that the obj output can be used in the data property
 // of other modules.
 func (bpf *bpf) OutputFiles(tag string) (android.Paths, error) {
@@ -298,39 +278,5 @@
 	module.AddProperties(&module.properties)
 
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
-	android.InitBazelModule(module)
 	return module
 }
-
-type bazelBpfAttributes struct {
-	Srcs              bazel.LabelListAttribute
-	Copts             bazel.StringListAttribute
-	Absolute_includes bazel.StringListAttribute
-	Btf               *bool
-	// TODO(b/249528391): Add support for sub_dir
-}
-
-// bpf bp2build converter
-func (b *bpf) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	if ctx.ModuleType() != "bpf" {
-		return
-	}
-
-	srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, b.properties.Srcs))
-	copts := bazel.MakeStringListAttribute(b.properties.Cflags)
-	absolute_includes := bazel.MakeStringListAttribute(b.properties.Include_dirs)
-	btf := b.properties.Btf
-
-	attrs := bazelBpfAttributes{
-		Srcs:              srcs,
-		Copts:             copts,
-		Absolute_includes: absolute_includes,
-		Btf:               btf,
-	}
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "bpf",
-		Bzl_load_location: "//build/bazel/rules/bpf:bpf.bzl",
-	}
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: b.Name()}, &attrs)
-}
diff --git a/bpf/bpf_test.go b/bpf/bpf_test.go
index a2010ff..6e39096 100644
--- a/bpf/bpf_test.go
+++ b/bpf/bpf_test.go
@@ -71,26 +71,3 @@
 		`\QAndroid.bp:2:3: module "bpf_invalid_name.o" variant "android_common": invalid character '_' in source name\E`)).
 		RunTestWithBp(t, bp)
 }
-
-func TestBpfWithBazel(t *testing.T) {
-	bp := `
-		bpf {
-			name: "bpf.o",
-			srcs: ["bpf.c"],
-			bazel_module: { label: "//bpf" },
-		}
-	`
-
-	result := android.GroupFixturePreparers(
-		prepareForBpfTest, android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: "outputbase",
-				LabelToOutputFiles: map[string][]string{
-					"//bpf": []string{"bpf.o"}}}
-		})).RunTestWithBp(t, bp)
-
-	output := result.Module("bpf.o", "android_common").(*bpf)
-
-	expectedOutputFiles := []string{"outputbase/execroot/__main__/bpf.o"}
-	android.AssertDeepEquals(t, "output files", expectedOutputFiles, output.objs.Strings())
-}
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 672e852..b5b49b1 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -19,6 +19,7 @@
 import (
 	"bytes"
 	"fmt"
+	"os"
 	"reflect"
 	"strings"
 	"testing"
@@ -2215,3 +2216,9 @@
 		})
 	}
 }
+
+func TestMain(m *testing.M) {
+	// Skip checking Android.mk path with cleaning "ANDROID_BUILD_TOP"
+	os.Setenv("ANDROID_BUILD_TOP", "")
+	os.Exit(m.Run())
+}
diff --git a/cc/Android.bp b/cc/Android.bp
index c32d854..9ce8933 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -9,15 +9,15 @@
         "blueprint",
         "blueprint-pathtools",
         "soong",
+        "soong-aconfig",
         "soong-aidl-library",
         "soong-android",
-        "soong-bazel",
         "soong-cc-config",
         "soong-etc",
         "soong-fuzz",
         "soong-genrule",
         "soong-multitree",
-        "soong-snapshot",
+        "soong-testing",
         "soong-tradefed",
     ],
     srcs: [
@@ -25,7 +25,6 @@
         "fdo_profile.go",
         "androidmk.go",
         "api_level.go",
-        "bp2build.go",
         "builder.go",
         "cc.go",
         "ccdeps.go",
@@ -38,7 +37,6 @@
         "lto.go",
         "makevars.go",
         "orderfile.go",
-        "pgo.go",
         "prebuilt.go",
         "proto.go",
         "rs.go",
@@ -46,13 +44,10 @@
         "sabi.go",
         "sdk.go",
         "snapshot_prebuilt.go",
-        "snapshot_utils.go",
         "stl.go",
         "strip.go",
-        "sysprop.go",
         "tidy.go",
         "util.go",
-        "vendor_snapshot.go",
         "vndk.go",
         "vndk_prebuilt.go",
 
@@ -96,11 +91,11 @@
         "afdo_test.go",
         "binary_test.go",
         "cc_test.go",
+        "cc_test_only_property_test.go",
         "compiler_test.go",
         "gen_test.go",
         "genrule_test.go",
         "library_headers_test.go",
-        "library_stub_test.go",
         "library_test.go",
         "lto_test.go",
         "ndk_test.go",
@@ -113,7 +108,6 @@
         "test_data_test.go",
         "tidy_test.go",
         "vendor_public_library_test.go",
-        "vendor_snapshot_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/cc/afdo.go b/cc/afdo.go
index 23d196d..00b2245 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -21,39 +21,17 @@
 	"android/soong/android"
 
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/proptools"
 )
 
-// TODO(b/267229066): Remove globalAfdoProfileProjects after implementing bp2build converter for fdo_profile
-var (
-	globalAfdoProfileProjects = []string{
-		"vendor/google_data/pgo_profile/sampling/",
-		"toolchain/pgo-profiles/sampling/",
-	}
-)
-
-var afdoProfileProjectsConfigKey = android.NewOnceKey("AfdoProfileProjects")
-
 // This flag needs to be in both CFlags and LdFlags to ensure correct symbol ordering
-const afdoFlagsFormat = "-fprofile-sample-use=%s"
-
-func recordMissingAfdoProfileFile(ctx android.BaseModuleContext, missing string) {
-	getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
-}
-
-type afdoRdep struct {
-	VariationName *string
-	ProfilePath   *string
-}
+const afdoFlagsFormat = "-fprofile-sample-use=%s -fprofile-sample-accurate"
 
 type AfdoProperties struct {
 	// Afdo allows developers self-service enroll for
 	// automatic feedback-directed optimization using profile data.
 	Afdo bool
 
-	FdoProfilePath *string `blueprint:"mutated"`
-
-	AfdoRDeps []afdoRdep `blueprint:"mutated"`
+	AfdoDep bool `blueprint:"mutated"`
 }
 
 type afdo struct {
@@ -64,14 +42,40 @@
 	return []interface{}{&afdo.Properties}
 }
 
+func (afdo *afdo) begin(ctx BaseModuleContext) {
+	// Disable on eng builds for faster build.
+	if ctx.Config().Eng() {
+		afdo.Properties.Afdo = false
+	}
+}
+
 // afdoEnabled returns true for binaries and shared libraries
-// that set afdo prop to True and there is a profile available
+// that set afdo prop to True.
 func (afdo *afdo) afdoEnabled() bool {
 	return afdo != nil && afdo.Properties.Afdo
 }
 
+func (afdo *afdo) isAfdoCompile(ctx ModuleContext) bool {
+	fdoProfilePath := getFdoProfilePathFromDep(ctx)
+	return !ctx.Host() && (afdo.Properties.Afdo || afdo.Properties.AfdoDep) && (fdoProfilePath != "")
+}
+
+func getFdoProfilePathFromDep(ctx ModuleContext) string {
+	fdoProfileDeps := ctx.GetDirectDepsWithTag(FdoProfileTag)
+	if len(fdoProfileDeps) > 0 && fdoProfileDeps[0] != nil {
+		if info, ok := android.OtherModuleProvider(ctx, fdoProfileDeps[0], FdoProfileProvider); ok {
+			return info.Path.String()
+		}
+	}
+	return ""
+}
+
 func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
-	if afdo.Properties.Afdo {
+	if ctx.Host() {
+		return flags
+	}
+
+	if afdo.Properties.Afdo || afdo.Properties.AfdoDep {
 		// We use `-funique-internal-linkage-names` to associate profiles to the right internal
 		// functions. This option should be used before generating a profile. Because a profile
 		// generated for a binary without unique names doesn't work well building a binary with
@@ -84,16 +88,20 @@
 		// 3. Make the profile searchable by the build system. So it's used the next time the binary
 		//	  is built.
 		flags.Local.CFlags = append([]string{"-funique-internal-linkage-names"}, flags.Local.CFlags...)
+		// Flags for Flow Sensitive AutoFDO
+		flags.Local.CFlags = append([]string{"-mllvm", "-enable-fs-discriminator=true"}, flags.Local.CFlags...)
+		// TODO(b/266595187): Remove the following feature once it is enabled in LLVM by default.
+		flags.Local.CFlags = append([]string{"-mllvm", "-improved-fs-discriminator=true"}, flags.Local.CFlags...)
 	}
-	if path := afdo.Properties.FdoProfilePath; path != nil {
+	if fdoProfilePath := getFdoProfilePathFromDep(ctx); fdoProfilePath != "" {
 		// The flags are prepended to allow overriding.
-		profileUseFlag := fmt.Sprintf(afdoFlagsFormat, *path)
+		profileUseFlag := fmt.Sprintf(afdoFlagsFormat, fdoProfilePath)
 		flags.Local.CFlags = append([]string{profileUseFlag}, flags.Local.CFlags...)
 		flags.Local.LdFlags = append([]string{profileUseFlag, "-Wl,-mllvm,-no-warn-sample-unused=true"}, flags.Local.LdFlags...)
 
 		// Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
 		// if profileFile gets updated
-		pathForSrc := android.PathForSource(ctx, *path)
+		pathForSrc := android.PathForSource(ctx, fdoProfilePath)
 		flags.CFlagsDeps = append(flags.CFlagsDeps, pathForSrc)
 		flags.LdFlagsDeps = append(flags.LdFlagsDeps, pathForSrc)
 	}
@@ -101,123 +109,86 @@
 	return flags
 }
 
-func (afdo *afdo) addDep(ctx BaseModuleContext, actx android.BottomUpMutatorContext) {
+func (a *afdo) addDep(ctx android.BottomUpMutatorContext, fdoProfileTarget string) {
+	if fdoProfileName, err := ctx.DeviceConfig().AfdoProfile(fdoProfileTarget); fdoProfileName != "" && err == nil {
+		ctx.AddFarVariationDependencies(
+			[]blueprint.Variation{
+				{Mutator: "arch", Variation: ctx.Target().ArchVariation()},
+				{Mutator: "os", Variation: "android"},
+			},
+			FdoProfileTag,
+			fdoProfileName)
+	}
+}
+
+func afdoPropagateViaDepTag(tag blueprint.DependencyTag) bool {
+	libTag, isLibTag := tag.(libraryDependencyTag)
+	// Do not recurse down non-static dependencies
+	if isLibTag {
+		return libTag.static()
+	} else {
+		return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag
+	}
+}
+
+// afdoTransitionMutator creates afdo variants of cc modules.
+type afdoTransitionMutator struct{}
+
+func (a *afdoTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+	return []string{""}
+}
+
+func (a *afdoTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
 	if ctx.Host() {
-		return
+		return ""
 	}
 
-	if ctx.static() && !ctx.staticBinary() {
-		return
-	}
-
-	if c, ok := ctx.Module().(*Module); ok && c.Enabled() {
-		if fdoProfileName, err := actx.DeviceConfig().AfdoProfile(actx.ModuleName()); fdoProfileName != nil && err == nil {
-			actx.AddFarVariationDependencies(
-				[]blueprint.Variation{
-					{Mutator: "arch", Variation: actx.Target().ArchVariation()},
-					{Mutator: "os", Variation: "android"},
-				},
-				FdoProfileTag,
-				[]string{*fdoProfileName}...,
-			)
+	if m, ok := ctx.Module().(*Module); ok && m.afdo != nil {
+		if !afdoPropagateViaDepTag(ctx.DepTag()) {
+			return ""
 		}
+
+		if sourceVariation != "" {
+			return sourceVariation
+		}
+
+		if !m.afdo.afdoEnabled() {
+			return ""
+		}
+
+		// TODO(b/324141705): this is designed to prevent propagating AFDO from static libraries that have afdo: true set, but
+		//  it should be m.static() && !m.staticBinary() so that static binaries use AFDO variants of dependencies.
+		if m.static() {
+			return ""
+		}
+
+		return encodeTarget(ctx.Module().Name())
 	}
+	return ""
 }
 
-// FdoProfileMutator reads the FdoProfileProvider from a direct dep with FdoProfileTag
-// assigns FdoProfileInfo.Path to the FdoProfilePath mutated property
-func (c *Module) fdoProfileMutator(ctx android.BottomUpMutatorContext) {
-	if !c.Enabled() {
-		return
+func (a *afdoTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+	if m, ok := ctx.Module().(*Module); ok && m.afdo != nil {
+		return incomingVariation
 	}
-
-	if !c.afdo.afdoEnabled() {
-		return
-	}
-
-	ctx.VisitDirectDepsWithTag(FdoProfileTag, func(m android.Module) {
-		if ctx.OtherModuleHasProvider(m, FdoProfileProvider) {
-			info := ctx.OtherModuleProvider(m, FdoProfileProvider).(FdoProfileInfo)
-			c.afdo.Properties.FdoProfilePath = proptools.StringPtr(info.Path.String())
-		}
-	})
+	return ""
 }
 
-var _ FdoProfileMutatorInterface = (*Module)(nil)
-
-// Propagate afdo requirements down from binaries and shared libraries
-func afdoDepsMutator(mctx android.TopDownMutatorContext) {
-	if m, ok := mctx.Module().(*Module); ok && m.afdo.afdoEnabled() {
-		path := m.afdo.Properties.FdoProfilePath
-		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
-			tag := mctx.OtherModuleDependencyTag(dep)
-			libTag, isLibTag := tag.(libraryDependencyTag)
-
-			// Do not recurse down non-static dependencies
-			if isLibTag {
-				if !libTag.static() {
-					return false
-				}
-			} else {
-				if tag != objDepTag && tag != reuseObjTag {
-					return false
-				}
+func (a *afdoTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+	if m, ok := ctx.Module().(*Module); ok && m.afdo != nil {
+		if variation == "" {
+			// The empty variation is either a module that has enabled AFDO for itself, or the non-AFDO
+			// variant of a dependency.
+			if m.afdo.afdoEnabled() && !(m.static() && !m.staticBinary()) && !m.Host() {
+				m.afdo.addDep(ctx, ctx.ModuleName())
 			}
-
-			if dep, ok := dep.(*Module); ok {
-				dep.afdo.Properties.AfdoRDeps = append(
-					dep.afdo.Properties.AfdoRDeps,
-					afdoRdep{
-						VariationName: proptools.StringPtr(encodeTarget(m.Name())),
-						ProfilePath:   path,
-					},
-				)
-			}
-
-			return true
-		})
-	}
-}
-
-// Create afdo variants for modules that need them
-func afdoMutator(mctx android.BottomUpMutatorContext) {
-	if m, ok := mctx.Module().(*Module); ok && m.afdo != nil {
-		if !m.static() && m.afdo.Properties.Afdo {
-			mctx.SetDependencyVariation(encodeTarget(m.Name()))
-			return
-		}
-
-		variationNames := []string{""}
-
-		variantNameToProfilePath := make(map[string]*string)
-
-		for _, afdoRDep := range m.afdo.Properties.AfdoRDeps {
-			variantName := *afdoRDep.VariationName
-			// An rdep can be set twice in AfdoRDeps because there can be
-			// more than one path from an afdo-enabled module to
-			// a static dep such as
-			// afdo_enabled_foo -> static_bar ----> static_baz
-			//                   \                      ^
-			//                    ----------------------|
-			// We only need to create one variant per unique rdep
-			if _, exists := variantNameToProfilePath[variantName]; !exists {
-				variationNames = append(variationNames, variantName)
-				variantNameToProfilePath[variantName] = afdoRDep.ProfilePath
-			}
-		}
-
-		if len(variationNames) > 1 {
-			modules := mctx.CreateVariations(variationNames...)
-			for i, name := range variationNames {
-				if name == "" {
-					continue
-				}
-				variation := modules[i].(*Module)
-				variation.Properties.PreventInstall = true
-				variation.Properties.HideFromMake = true
-				variation.afdo.Properties.Afdo = true
-				variation.afdo.Properties.FdoProfilePath = variantNameToProfilePath[name]
-			}
+		} else {
+			// The non-empty variation is the AFDO variant of a dependency of a module that enabled AFDO
+			// for itself.
+			m.Properties.PreventInstall = true
+			m.Properties.HideFromMake = true
+			m.afdo.Properties.AfdoDep = true
+			m.afdo.addDep(ctx, decodeTarget(variation))
 		}
 	}
 }
diff --git a/cc/afdo_test.go b/cc/afdo_test.go
index b250ad1..0679d13 100644
--- a/cc/afdo_test.go
+++ b/cc/afdo_test.go
@@ -15,6 +15,7 @@
 package cc
 
 import (
+	"runtime"
 	"strings"
 	"testing"
 
@@ -42,19 +43,25 @@
 	bp := `
 	cc_library_shared {
 		name: "libTest",
+		host_supported: true,
 		srcs: ["test.c"],
 		static_libs: ["libFoo"],
 		afdo: true,
+		lto: {
+			thin: true,
+		},
 	}
 
 	cc_library_static {
 		name: "libFoo",
+		host_supported: true,
 		srcs: ["foo.c"],
 		static_libs: ["libBar"],
 	}
 
 	cc_library_static {
 		name: "libBar",
+		host_supported: true,
 		srcs: ["bar.c"],
 	}
 	`
@@ -72,13 +79,20 @@
 			"afdo_profiles_package/Android.bp": []byte(`
 				fdo_profile {
 					name: "libTest_afdo",
-					profile: "libTest.afdo",
+					arch: {
+						arm64: {
+							profile: "libTest.afdo",
+						},
+					},
 				}
 			`),
 		}.AddToFixture(),
 	).RunTestWithBp(t, bp)
 
-	expectedCFlag := "-fprofile-sample-use=afdo_profiles_package/libTest.afdo"
+	profileSampleCFlag := "-fprofile-sample-use=afdo_profiles_package/libTest.afdo"
+	uniqueInternalLinkageNamesCFlag := "-funique-internal-linkage-names"
+	afdoLtoLdFlag := "-Wl,-plugin-opt,-import-instr-limit=40"
+	noAfdoLtoLdFlag := "-Wl,-plugin-opt,-import-instr-limit=5"
 
 	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
 	libFooAfdoVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
@@ -86,18 +100,32 @@
 
 	// Check cFlags of afdo-enabled module and the afdo-variant of its static deps
 	cFlags := libTest.Rule("cc").Args["cFlags"]
-	if !strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	if !strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected 'libTest' to enable afdo profile, but did not find %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+	if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+
+	ldFlags := libTest.Rule("ld").Args["ldFlags"]
+	if !strings.Contains(ldFlags, afdoLtoLdFlag) {
+		t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in ldflags %q", afdoLtoLdFlag, ldFlags)
 	}
 
 	cFlags = libFooAfdoVariant.Rule("cc").Args["cFlags"]
-	if !strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libFooAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	if !strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected 'libFooAfdoVariant' to enable afdo profile, but did not find %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+	if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected 'libFooAfdoVariant' to enable afdo, but did not find %q in cflags %q", profileSampleCFlag, cFlags)
 	}
 
 	cFlags = libBarAfdoVariant.Rule("cc").Args["cFlags"]
-	if !strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	if !strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected 'libBarAfdoVariant' to enable afdo profile, but did not find %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+	if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", profileSampleCFlag, cFlags)
 	}
 
 	// Check dependency edge from afdo-enabled module to static deps
@@ -114,12 +142,18 @@
 	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
 
 	cFlags = libFoo.Rule("cc").Args["cFlags"]
-	if strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libFoo' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected 'libFoo' to not enable afdo profile, but found %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+	if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected 'libFoo' to not enable afdo, but found %q in cflags %q", profileSampleCFlag, cFlags)
 	}
 	cFlags = libBar.Rule("cc").Args["cFlags"]
-	if strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libBar' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected 'libBar' to not enable afdo profile, but found %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+	if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected 'libBar' to not enable afdo, but found %q in cflags %q", profileSampleCFlag, cFlags)
 	}
 
 	// Check dependency edges of static deps
@@ -130,6 +164,104 @@
 	if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
 		t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
 	}
+
+	// Verify that the arm variant does not have FDO since the fdo_profile module only has a profile for arm64
+	libTest32 := result.ModuleForTests("libTest", "android_arm_armv7-a-neon_shared")
+	libFooAfdoVariant32 := result.ModuleForTests("libFoo", "android_arm_armv7-a-neon_static_afdo-libTest_lto-thin")
+	libBarAfdoVariant32 := result.ModuleForTests("libBar", "android_arm_armv7-a-neon_static_afdo-libTest_lto-thin")
+
+	cFlags = libTest32.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected arm32 'libTest' not to enable afdo, but found %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+
+	// TODO(b/324141705): when the fdo_profile module doesn't provide a source file the dependencies don't get
+	//  -funique-internal-linkage-names but the module does.
+	if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected arm32 'libTest' to enable -funique-internal-linkage-names but did not find %q in cflags %q",
+			uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+
+	ldFlags = libTest32.Rule("ld").Args["ldFlags"]
+	if !strings.Contains(ldFlags, noAfdoLtoLdFlag) {
+		t.Errorf("Expected arm32 'libTest' to not enable afdo, but did not find %q in ldflags %q", noAfdoLtoLdFlag, ldFlags)
+	}
+	if strings.Contains(ldFlags, afdoLtoLdFlag) {
+		t.Errorf("Expected arm32 'libTest' to not enable afdo, but found %q in ldflags %q", afdoLtoLdFlag, ldFlags)
+	}
+
+	// Check dependency edge from afdo-enabled module to static deps
+	if !hasDirectDep(result, libTest32.Module(), libFooAfdoVariant32.Module()) {
+		t.Errorf("arm32 libTest missing dependency on afdo variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFooAfdoVariant32.Module(), libBarAfdoVariant32.Module()) {
+		t.Errorf("arm32 libTest missing dependency on afdo variant of libBar")
+	}
+
+	cFlags = libFooAfdoVariant32.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected arm32 'libFoo' to not enable afdo profile, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+	if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected arm32 'libFoo' to enable afdo, but did not find %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+	cFlags = libBarAfdoVariant32.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected arm32 'libBar' to not enable afdo profile, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+	if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected arm32 'libBar' to enable afdo, but did not find %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+
+	// Verify that the host variants don't enable afdo
+	libTestHost := result.ModuleForTests("libTest", result.Config.BuildOSTarget.String()+"_shared")
+	libFooHost := result.ModuleForTests("libFoo", result.Config.BuildOSTarget.String()+"_static_lto-thin")
+	libBarHost := result.ModuleForTests("libBar", result.Config.BuildOSTarget.String()+"_static_lto-thin")
+
+	cFlags = libTestHost.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected host 'libTest' to not enable afdo profile, but found %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+
+	if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected host 'libTest' to not enable afdo but found %q in cflags %q",
+			uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+
+	if runtime.GOOS != "darwin" {
+		ldFlags := libTestHost.Rule("ld").Args["ldFlags"]
+		if !strings.Contains(ldFlags, noAfdoLtoLdFlag) {
+			t.Errorf("Expected host 'libTest' to not enable afdo, but did not find %q in ldflags %q", noAfdoLtoLdFlag, ldFlags)
+		}
+		if strings.Contains(ldFlags, afdoLtoLdFlag) {
+			t.Errorf("Expected host 'libTest' to not enable afdo, but found %q in ldflags %q", afdoLtoLdFlag, ldFlags)
+		}
+	}
+
+	// Check dependency edge from afdo-enabled module to static deps
+	if !hasDirectDep(result, libTestHost.Module(), libFooHost.Module()) {
+		t.Errorf("host libTest missing dependency on non-afdo variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFooHost.Module(), libBarHost.Module()) {
+		t.Errorf("host libTest missing dependency on non-afdo variant of libBar")
+	}
+
+	cFlags = libFooHost.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected host 'libFoo' to not enable afdo profile, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+	if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected host 'libFoo' to not enable afdo, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+	cFlags = libBarHost.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected host 'libBar' to not enable afdo profile, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+	if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected host 'libBar' to not enable afdo, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
 }
 
 func TestAfdoEnabledOnStaticDepNoAfdo(t *testing.T) {
@@ -174,11 +306,11 @@
 	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static").Module()
 
 	if !hasDirectDep(result, libTest, libFoo.Module()) {
-		t.Errorf("libTest missing dependency on afdo variant of libFoo")
+		t.Errorf("libTest missing dependency on non-afdo variant of libFoo")
 	}
 
 	if !hasDirectDep(result, libFoo.Module(), libBar) {
-		t.Errorf("libFoo missing dependency on afdo variant of libBar")
+		t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
 	}
 
 	fooVariants := result.ModuleVariantsForTests("foo")
diff --git a/cc/androidmk.go b/cc/androidmk.go
index ce35b5c..ef26366 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -15,8 +15,6 @@
 package cc
 
 import (
-	"github.com/google/blueprint/proptools"
-
 	"fmt"
 	"io"
 	"path/filepath"
@@ -50,6 +48,7 @@
 	InVendorRamdisk() bool
 	InRecovery() bool
 	NotInPlatform() bool
+	InVendorOrProduct() bool
 }
 
 type subAndroidMkProvider interface {
@@ -82,8 +81,9 @@
 		// causing multiple ART APEXes (com.android.art and com.android.art.debug)
 		// to be installed. And this is breaking some older devices (like marlin)
 		// where system.img is small.
-		Required: c.Properties.AndroidMkRuntimeLibs,
-		Include:  "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
+		Required:     c.Properties.AndroidMkRuntimeLibs,
+		OverrideName: c.BaseModuleName(),
+		Include:      "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk",
 
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
@@ -100,21 +100,11 @@
 				if len(c.Properties.AndroidMkSharedLibs) > 0 {
 					entries.AddStrings("LOCAL_SHARED_LIBRARIES", c.Properties.AndroidMkSharedLibs...)
 				}
-				if len(c.Properties.AndroidMkStaticLibs) > 0 {
-					entries.AddStrings("LOCAL_STATIC_LIBRARIES", c.Properties.AndroidMkStaticLibs...)
-				}
-				if len(c.Properties.AndroidMkWholeStaticLibs) > 0 {
-					entries.AddStrings("LOCAL_WHOLE_STATIC_LIBRARIES", c.Properties.AndroidMkWholeStaticLibs...)
-				}
-				if len(c.Properties.AndroidMkHeaderLibs) > 0 {
-					entries.AddStrings("LOCAL_HEADER_LIBRARIES", c.Properties.AndroidMkHeaderLibs...)
-				}
 				if len(c.Properties.AndroidMkRuntimeLibs) > 0 {
 					entries.AddStrings("LOCAL_RUNTIME_LIBRARIES", c.Properties.AndroidMkRuntimeLibs...)
 				}
 				entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType)
-				if c.UseVndk() {
-					entries.SetBool("LOCAL_USE_VNDK", true)
+				if c.InVendorOrProduct() {
 					if c.IsVndk() && !c.static() {
 						entries.SetString("LOCAL_SOONG_VNDK_VERSION", c.VndkVersion())
 						// VNDK libraries available to vendor are not installed because
@@ -124,6 +114,11 @@
 						}
 					}
 				}
+				if c.InVendor() {
+					entries.SetBool("LOCAL_IN_VENDOR", true)
+				} else if c.InProduct() {
+					entries.SetBool("LOCAL_IN_PRODUCT", true)
+				}
 				if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
 					// Make the SDK variant uninstallable so that there are not two rules to install
 					// to the same location.
@@ -133,6 +128,7 @@
 					entries.SetString("SOONG_SDK_VARIANT_MODULES",
 						"$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
 				}
+				android.SetAconfigFileMkEntries(c.AndroidModuleBase(), entries, c.mergedAconfigFiles)
 			},
 		},
 		ExtraFooters: []android.AndroidMkExtraFootersFunc{
@@ -175,15 +171,6 @@
 	}
 }
 
-func AndroidMkWriteTestData(data []android.DataPath, entries *android.AndroidMkEntries) {
-	testFiles := android.AndroidMkDataPaths(data)
-	if len(testFiles) > 0 {
-		entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
-			entries.AddStrings("LOCAL_TEST_DATA", testFiles...)
-		})
-	}
-}
-
 func makeOverrideModuleNames(ctx AndroidMkContext, overrides []string) []string {
 	if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
 		var result []string
@@ -310,7 +297,7 @@
 	// they can be exceptionally used directly when APEXes are not available (e.g. during the
 	// very early stage in the boot process).
 	if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.NotInPlatform() &&
-		!ctx.InRamdisk() && !ctx.InVendorRamdisk() && !ctx.InRecovery() && !ctx.UseVndk() && !ctx.static() {
+		!ctx.InRamdisk() && !ctx.InVendorRamdisk() && !ctx.InRecovery() && !ctx.InVendorOrProduct() && !ctx.static() {
 		if library.buildStubs() && library.isLatestStubVersion() {
 			entries.SubName = ""
 		}
@@ -379,11 +366,6 @@
 			entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
 		}
 	})
-	dataPaths := []android.DataPath{}
-	for _, srcPath := range benchmark.data {
-		dataPaths = append(dataPaths, android.DataPath{SrcPath: srcPath})
-	}
-	AndroidMkWriteTestData(dataPaths, entries)
 }
 
 func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
@@ -411,40 +393,16 @@
 		test.Properties.Test_options.CommonTestOptions.SetAndroidMkEntries(entries)
 	})
 
-	AndroidMkWriteTestData(test.data, entries)
 	androidMkWriteExtraTestConfigs(test.extraTestConfigs, entries)
 }
 
 func (fuzz *fuzzBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	ctx.subAndroidMk(entries, fuzz.binaryDecorator)
 
-	var fuzzFiles []string
-	for _, d := range fuzz.fuzzPackagedModule.Corpus {
-		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.fuzzPackagedModule.CorpusIntermediateDir.String())+":corpus/"+d.Base())
-	}
-
-	for _, d := range fuzz.fuzzPackagedModule.Data {
-		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.fuzzPackagedModule.DataIntermediateDir.String())+":data/"+d.Rel())
-	}
-
-	if fuzz.fuzzPackagedModule.Dictionary != nil {
-		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.fuzzPackagedModule.Dictionary.String())+":"+fuzz.fuzzPackagedModule.Dictionary.Base())
-	}
-
-	if fuzz.fuzzPackagedModule.Config != nil {
-		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.fuzzPackagedModule.Config.String())+":config.json")
-	}
-
 	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 		entries.SetBool("LOCAL_IS_FUZZ_TARGET", true)
-		if len(fuzzFiles) > 0 {
-			entries.AddStrings("LOCAL_TEST_DATA", fuzzFiles...)
-		}
 		if fuzz.installedSharedDeps != nil {
+			// TOOD: move to install dep
 			entries.AddStrings("LOCAL_FUZZ_INSTALLED_SHARED_DEPS", fuzz.installedSharedDeps...)
 		}
 	})
@@ -488,6 +446,7 @@
 		if c.parsedCoverageXmlPath.String() != "" {
 			entries.SetString("SOONG_NDK_API_XML", "$(SOONG_NDK_API_XML) "+c.parsedCoverageXmlPath.String())
 		}
+		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) // Stubs should not be installed
 	})
 }
 
@@ -517,79 +476,6 @@
 	})
 }
 
-func (c *snapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
-	// Each vendor snapshot is exported to androidMk only when BOARD_VNDK_VERSION != current
-	// and the version of the prebuilt is same as BOARD_VNDK_VERSION.
-	if c.shared() {
-		entries.Class = "SHARED_LIBRARIES"
-	} else if c.static() {
-		entries.Class = "STATIC_LIBRARIES"
-	} else if c.header() {
-		entries.Class = "HEADER_LIBRARIES"
-	}
-
-	entries.SubName = ""
-
-	if c.isSanitizerEnabled(cfi) {
-		entries.SubName += ".cfi"
-	} else if c.isSanitizerEnabled(Hwasan) {
-		entries.SubName += ".hwasan"
-	}
-
-	entries.SubName += c.baseProperties.Androidmk_suffix
-
-	entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
-		c.libraryDecorator.androidMkWriteExportedFlags(entries)
-
-		if c.shared() || c.static() {
-			src := c.path.String()
-			// For static libraries which aren't installed, directly use Src to extract filename.
-			// This is safe: generated snapshot modules have a real path as Src, not a module
-			if c.static() {
-				src = proptools.String(c.properties.Src)
-			}
-			path, file := filepath.Split(src)
-			stem, suffix, ext := android.SplitFileExt(file)
-			entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
-			entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
-			entries.SetString("LOCAL_MODULE_STEM", stem)
-			if c.shared() {
-				entries.SetString("LOCAL_MODULE_PATH", path)
-			}
-			if c.tocFile.Valid() {
-				entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String())
-			}
-
-			if c.shared() && len(c.Properties.Overrides) > 0 {
-				entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, c.Properties.Overrides), " "))
-			}
-		}
-
-		if !c.shared() { // static or header
-			entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
-		}
-	})
-}
-
-func (c *snapshotBinaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
-	entries.Class = "EXECUTABLES"
-	entries.SubName = c.baseProperties.Androidmk_suffix
-}
-
-func (c *snapshotObjectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
-	entries.Class = "STATIC_LIBRARIES"
-	entries.SubName = c.baseProperties.Androidmk_suffix
-
-	entries.ExtraFooters = append(entries.ExtraFooters,
-		func(w io.Writer, name, prefix, moduleDir string) {
-			out := entries.OutputFile.Path()
-			varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName)
-
-			fmt.Fprintf(w, "\n%s := %s\n", varname, out.String())
-			fmt.Fprintln(w, ".KATI_READONLY: "+varname)
-		})
-}
-
 func (c *ndkPrebuiltStlLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	entries.Class = "SHARED_LIBRARIES"
 }
diff --git a/cc/binary.go b/cc/binary.go
index 5ba33a2..7aa8e20 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -17,13 +17,8 @@
 import (
 	"path/filepath"
 
-	"android/soong/bazel/cquery"
-
-	"github.com/google/blueprint"
-	"github.com/google/blueprint/proptools"
-
 	"android/soong/android"
-	"android/soong/bazel"
+	"github.com/google/blueprint"
 )
 
 type BinaryLinkerProperties struct {
@@ -71,14 +66,13 @@
 
 // cc_binary produces a binary that is runnable on a device.
 func BinaryFactory() android.Module {
-	module, _ := newBinary(android.HostAndDeviceSupported, true)
-	module.bazelHandler = &ccBinaryBazelHandler{module: module}
+	module, _ := newBinary(android.HostAndDeviceSupported)
 	return module.Init()
 }
 
 // cc_binary_host produces a binary that is runnable on a host.
 func BinaryHostFactory() android.Module {
-	module, _ := newBinary(android.HostSupported, true)
+	module, _ := newBinary(android.HostSupported)
 	return module.Init()
 }
 
@@ -196,10 +190,10 @@
 // Individual module implementations which comprise a C++ binary should call this function,
 // set some fields on the result, and then call the Init function.
 func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
-	return newBinary(hod, true)
+	return newBinary(hod)
 }
 
-func newBinary(hod android.HostOrDeviceSupported, bazelable bool) (*Module, *binaryDecorator) {
+func newBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
 	module := newModule(hod, android.MultilibFirst)
 	binary := &binaryDecorator{
 		baseLinker:    NewBaseLinker(module.sanitize),
@@ -208,7 +202,6 @@
 	module.compiler = NewBaseCompiler()
 	module.linker = binary
 	module.installer = binary
-	module.bazelable = bazelable
 
 	// Allow module to be added as member of an sdk/module_exports.
 	module.sdkMemberTypes = []android.SdkMemberType{
@@ -452,6 +445,10 @@
 	return binary.unstrippedOutputFile
 }
 
+func (binary *binaryDecorator) strippedAllOutputFilePath() android.Path {
+	panic("Not implemented.")
+}
+
 func (binary *binaryDecorator) setSymlinkList(ctx ModuleContext) {
 	for _, symlink := range binary.Properties.Symlinks {
 		binary.symlinks = append(binary.symlinks,
@@ -544,6 +541,11 @@
 	return binary.Properties.Overrides
 }
 
+func (binary *binaryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+	moduleInfoJSON.Class = []string{"EXECUTABLES"}
+	binary.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON)
+}
+
 var _ overridable = (*binaryDecorator)(nil)
 
 func init() {
@@ -568,147 +570,3 @@
 		},
 	})
 }
-
-type ccBinaryBazelHandler struct {
-	module *Module
-}
-
-var _ BazelHandler = (*ccBinaryBazelHandler)(nil)
-
-func (handler *ccBinaryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(label, cquery.GetCcUnstrippedInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
-}
-
-func (handler *ccBinaryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	info, err := bazelCtx.GetCcUnstrippedInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-		return
-	}
-
-	var outputFilePath android.Path = android.PathForBazelOut(ctx, info.OutputFile)
-	if len(info.TidyFiles) > 0 {
-		handler.module.tidyFiles = android.PathsForBazelOut(ctx, info.TidyFiles)
-		outputFilePath = android.AttachValidationActions(ctx, outputFilePath, handler.module.tidyFiles)
-	}
-	handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
-	handler.module.linker.(*binaryDecorator).unstrippedOutputFile = android.PathForBazelOut(ctx, info.UnstrippedOutput)
-
-	handler.module.setAndroidMkVariablesFromCquery(info.CcAndroidMkInfo)
-}
-
-func binaryBp2buildAttrs(ctx android.TopDownMutatorContext, m *Module) binaryAttributes {
-	baseAttrs := bp2BuildParseBaseProps(ctx, m)
-	binaryLinkerAttrs := bp2buildBinaryLinkerProps(ctx, m)
-
-	if proptools.BoolDefault(binaryLinkerAttrs.Linkshared, true) {
-		baseAttrs.implementationDynamicDeps.Add(baseAttrs.protoDependency)
-	} else {
-		baseAttrs.implementationDeps.Add(baseAttrs.protoDependency)
-	}
-
-	// binaries don't have implementation_whole_archive_deps
-	baseAttrs.wholeArchiveDeps.Append(baseAttrs.implementationWholeArchiveDeps)
-
-	attrs := binaryAttributes{
-		binaryLinkerAttrs: binaryLinkerAttrs,
-
-		Srcs:    baseAttrs.srcs,
-		Srcs_c:  baseAttrs.cSrcs,
-		Srcs_as: baseAttrs.asSrcs,
-
-		Copts:      baseAttrs.copts,
-		Cppflags:   baseAttrs.cppFlags,
-		Conlyflags: baseAttrs.conlyFlags,
-		Asflags:    baseAttrs.asFlags,
-
-		Deps:               baseAttrs.implementationDeps,
-		Dynamic_deps:       baseAttrs.implementationDynamicDeps,
-		Whole_archive_deps: baseAttrs.wholeArchiveDeps,
-		System_deps:        baseAttrs.systemDynamicDeps,
-		Runtime_deps:       baseAttrs.runtimeDeps,
-
-		Local_includes:    baseAttrs.localIncludes,
-		Absolute_includes: baseAttrs.absoluteIncludes,
-		Linkopts:          baseAttrs.linkopts,
-		Use_version_lib:   baseAttrs.useVersionLib,
-		Rtti:              baseAttrs.rtti,
-		Stl:               baseAttrs.stl,
-		Cpp_std:           baseAttrs.cppStd,
-
-		Additional_linker_inputs: baseAttrs.additionalLinkerInputs,
-
-		Strip: stripAttributes{
-			Keep_symbols:                 baseAttrs.stripKeepSymbols,
-			Keep_symbols_and_debug_frame: baseAttrs.stripKeepSymbolsAndDebugFrame,
-			Keep_symbols_list:            baseAttrs.stripKeepSymbolsList,
-			All:                          baseAttrs.stripAll,
-			None:                         baseAttrs.stripNone,
-		},
-
-		Features: baseAttrs.features,
-
-		sdkAttributes: bp2BuildParseSdkAttributes(m),
-
-		Native_coverage: baseAttrs.Native_coverage,
-	}
-
-	m.convertTidyAttributes(ctx, &attrs.tidyAttributes)
-
-	return attrs
-}
-
-func binaryBp2build(ctx android.TopDownMutatorContext, m *Module) {
-	// shared with cc_test
-	binaryAttrs := binaryBp2buildAttrs(ctx, m)
-
-	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
-	ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_binary",
-		Bzl_load_location: "//build/bazel/rules/cc:cc_binary.bzl",
-	},
-		android.CommonAttributes{Name: m.Name(), Tags: tags},
-		&binaryAttrs)
-}
-
-// binaryAttributes contains Bazel attributes corresponding to a cc binary
-type binaryAttributes struct {
-	binaryLinkerAttrs
-	Srcs    bazel.LabelListAttribute
-	Srcs_c  bazel.LabelListAttribute
-	Srcs_as bazel.LabelListAttribute
-
-	Copts      bazel.StringListAttribute
-	Cppflags   bazel.StringListAttribute
-	Conlyflags bazel.StringListAttribute
-	Asflags    bazel.StringListAttribute
-
-	Deps               bazel.LabelListAttribute
-	Dynamic_deps       bazel.LabelListAttribute
-	Whole_archive_deps bazel.LabelListAttribute
-	System_deps        bazel.LabelListAttribute
-	Runtime_deps       bazel.LabelListAttribute
-
-	Local_includes    bazel.StringListAttribute
-	Absolute_includes bazel.StringListAttribute
-
-	Linkopts                 bazel.StringListAttribute
-	Additional_linker_inputs bazel.LabelListAttribute
-	Use_version_lib          bazel.BoolAttribute
-
-	Rtti    bazel.BoolAttribute
-	Stl     *string
-	Cpp_std *string
-
-	Strip stripAttributes
-
-	Features bazel.StringListAttribute
-
-	sdkAttributes
-
-	tidyAttributes
-
-	Native_coverage *bool
-}
diff --git a/cc/binary_test.go b/cc/binary_test.go
index 2fac002..3e18940 100644
--- a/cc/binary_test.go
+++ b/cc/binary_test.go
@@ -17,89 +17,9 @@
 import (
 	"testing"
 
-	"android/soong/bazel/cquery"
-
 	"android/soong/android"
 )
 
-func TestCcBinaryWithBazel(t *testing.T) {
-	t.Parallel()
-	bp := `
-cc_binary {
-	name: "foo",
-	srcs: ["foo.cc"],
-	bazel_module: { label: "//foo/bar:bar" },
-}`
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.BazelContext = android.MockBazelContext{
-		OutputBaseDir: "outputbase",
-		LabelToCcBinary: map[string]cquery.CcUnstrippedInfo{
-			"//foo/bar:bar": cquery.CcUnstrippedInfo{
-				OutputFile:       "foo",
-				UnstrippedOutput: "foo.unstripped",
-			},
-		},
-	}
-	ctx := testCcWithConfig(t, config)
-
-	binMod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module()
-	producer := binMod.(android.OutputFileProducer)
-	outputFiles, err := producer.OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_binary outputfiles %s", err)
-	}
-	expectedOutputFiles := []string{"outputbase/execroot/__main__/foo"}
-	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
-
-	unStrippedFilePath := binMod.(*Module).UnstrippedOutputFile()
-	expectedUnStrippedFile := "outputbase/execroot/__main__/foo.unstripped"
-	android.AssertStringEquals(t, "Unstripped output file", expectedUnStrippedFile, unStrippedFilePath.String())
-
-	entries := android.AndroidMkEntriesForTest(t, ctx, binMod)[0]
-	android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_binary", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
-}
-
-func TestCcBinaryWithBazelValidations(t *testing.T) {
-	t.Parallel()
-	bp := `
-cc_binary {
-	name: "foo",
-	srcs: ["foo.cc"],
-	bazel_module: { label: "//foo/bar:bar" },
-	tidy: true,
-}`
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.BazelContext = android.MockBazelContext{
-		OutputBaseDir: "outputbase",
-		LabelToCcBinary: map[string]cquery.CcUnstrippedInfo{
-			"//foo/bar:bar": cquery.CcUnstrippedInfo{
-				OutputFile:       "foo",
-				UnstrippedOutput: "foo.unstripped",
-				TidyFiles:        []string{"foo.c.tidy"},
-			},
-		},
-	}
-	ctx := android.GroupFixturePreparers(
-		prepareForCcTest,
-		android.FixtureMergeEnv(map[string]string{
-			"ALLOW_LOCAL_TIDY_TRUE": "1",
-		}),
-	).RunTestWithConfig(t, config).TestContext
-
-	binMod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module()
-	producer := binMod.(android.OutputFileProducer)
-	outputFiles, err := producer.OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_binary outputfiles %s", err)
-	}
-	expectedOutputFiles := []string{"out/soong/.intermediates/foo/android_arm64_armv8-a/validated/foo"}
-	android.AssertPathsRelativeToTopEquals(t, "output files", expectedOutputFiles, outputFiles)
-
-	unStrippedFilePath := binMod.(*Module).UnstrippedOutputFile()
-	expectedUnStrippedFile := "outputbase/execroot/__main__/foo.unstripped"
-	android.AssertStringEquals(t, "Unstripped output file", expectedUnStrippedFile, unStrippedFilePath.String())
-}
-
 func TestBinaryLinkerScripts(t *testing.T) {
 	t.Parallel()
 	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, `
diff --git a/cc/bp2build.go b/cc/bp2build.go
deleted file mode 100644
index 9d90a5b..0000000
--- a/cc/bp2build.go
+++ /dev/null
@@ -1,2023 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package cc
-
-import (
-	"fmt"
-	"path/filepath"
-	"strings"
-	"sync"
-
-	"android/soong/android"
-	"android/soong/bazel"
-	"android/soong/cc/config"
-	"android/soong/genrule"
-
-	"github.com/google/blueprint"
-
-	"github.com/google/blueprint/proptools"
-)
-
-const (
-	cSrcPartition       = "c"
-	asSrcPartition      = "as"
-	asmSrcPartition     = "asm"
-	lSrcPartition       = "l"
-	llSrcPartition      = "ll"
-	cppSrcPartition     = "cpp"
-	protoSrcPartition   = "proto"
-	aidlSrcPartition    = "aidl"
-	syspropSrcPartition = "sysprop"
-
-	yaccSrcPartition = "yacc"
-
-	rScriptSrcPartition = "renderScript"
-
-	xsdSrcPartition = "xsd"
-
-	genrulePartition = "genrule"
-
-	protoFromGenPartition = "proto_gen"
-
-	hdrPartition = "hdr"
-
-	stubsSuffix = "_stub_libs_current"
-)
-
-// staticOrSharedAttributes are the Bazel-ified versions of StaticOrSharedProperties --
-// properties which apply to either the shared or static version of a cc_library module.
-type staticOrSharedAttributes struct {
-	Srcs      bazel.LabelListAttribute
-	Srcs_c    bazel.LabelListAttribute
-	Srcs_as   bazel.LabelListAttribute
-	Srcs_aidl bazel.LabelListAttribute
-	Hdrs      bazel.LabelListAttribute
-	Copts     bazel.StringListAttribute
-
-	Deps                              bazel.LabelListAttribute
-	Implementation_deps               bazel.LabelListAttribute
-	Dynamic_deps                      bazel.LabelListAttribute
-	Implementation_dynamic_deps       bazel.LabelListAttribute
-	Whole_archive_deps                bazel.LabelListAttribute
-	Implementation_whole_archive_deps bazel.LabelListAttribute
-	Runtime_deps                      bazel.LabelListAttribute
-
-	System_dynamic_deps bazel.LabelListAttribute
-
-	Enabled bazel.BoolAttribute
-
-	Native_coverage *bool
-
-	Apex_available []string
-
-	Features bazel.StringListAttribute
-
-	sdkAttributes
-
-	tidyAttributes
-}
-
-type tidyAttributes struct {
-	Tidy                  *string
-	Tidy_flags            []string
-	Tidy_checks           []string
-	Tidy_checks_as_errors []string
-	Tidy_disabled_srcs    bazel.LabelListAttribute
-	Tidy_timeout_srcs     bazel.LabelListAttribute
-}
-
-func (m *Module) convertTidyAttributes(ctx android.BaseMutatorContext, moduleAttrs *tidyAttributes) {
-	for _, f := range m.features {
-		if tidy, ok := f.(*tidyFeature); ok {
-			var tidyAttr *string
-			if tidy.Properties.Tidy != nil {
-				if *tidy.Properties.Tidy {
-					tidyAttr = proptools.StringPtr("local")
-				} else {
-					tidyAttr = proptools.StringPtr("never")
-				}
-			}
-			moduleAttrs.Tidy = tidyAttr
-			moduleAttrs.Tidy_flags = tidy.Properties.Tidy_flags
-			moduleAttrs.Tidy_checks = tidy.Properties.Tidy_checks
-			moduleAttrs.Tidy_checks_as_errors = tidy.Properties.Tidy_checks_as_errors
-		}
-
-	}
-	archVariantProps := m.GetArchVariantProperties(ctx, &BaseCompilerProperties{})
-	for axis, configToProps := range archVariantProps {
-		for cfg, _props := range configToProps {
-			if archProps, ok := _props.(*BaseCompilerProperties); ok {
-				archDisabledSrcs := android.BazelLabelForModuleSrc(ctx, archProps.Tidy_disabled_srcs)
-				moduleAttrs.Tidy_disabled_srcs.SetSelectValue(axis, cfg, archDisabledSrcs)
-				archTimeoutSrcs := android.BazelLabelForModuleSrc(ctx, archProps.Tidy_timeout_srcs)
-				moduleAttrs.Tidy_timeout_srcs.SetSelectValue(axis, cfg, archTimeoutSrcs)
-			}
-		}
-	}
-}
-
-// Returns an unchanged label and a bool indicating whether the dep is a genrule that produces .proto files
-func protoFromGenPartitionMapper(pathCtx android.BazelConversionContext) bazel.LabelMapper {
-	return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
-		mod, exists := ctx.ModuleFromName(label.OriginalModuleName)
-		if !exists {
-			return label.Label, false
-		}
-		gen, isGen := mod.(*genrule.Module)
-		if !isGen {
-			return label.Label, false
-		}
-		if containsProto(ctx, gen.RawOutputFiles(pathCtx)) {
-			// Return unmodified label + true
-			// True will ensure that this module gets dropped from `srcs` of the generated cc_* target. `srcs` is reserved for .cpp files
-			return label.Label, true
-		}
-		return label.Label, false
-	}
-}
-
-// Returns true if srcs contains only .proto files
-// Raises an exception if there is a combination of .proto and non .proto srcs
-func containsProto(ctx bazel.OtherModuleContext, srcs []string) bool {
-	onlyProtos := false
-	for _, src := range srcs {
-		if strings.HasSuffix(src, ".proto") {
-			onlyProtos = true
-		} else if onlyProtos {
-			// This is not a proto file, and we have encountered a .proto file previously
-			ctx.ModuleErrorf("TOOD: Add bp2build support combination of .proto and non .proto files in outs of genrule")
-		}
-	}
-	return onlyProtos
-}
-
-// groupSrcsByExtension partitions `srcs` into groups based on file extension.
-func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute {
-	// Convert filegroup dependencies into extension-specific filegroups filtered in the filegroup.bzl
-	// macro.
-	addSuffixForFilegroup := func(suffix string) bazel.LabelMapper {
-		return func(otherModuleCtx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
-
-			m, exists := otherModuleCtx.ModuleFromName(label.OriginalModuleName)
-			labelStr := label.Label
-			if !exists || !android.IsFilegroup(otherModuleCtx, m) {
-				return labelStr, false
-			}
-			// If the filegroup is already converted to aidl_library or proto_library,
-			// skip creating _c_srcs, _as_srcs, _cpp_srcs filegroups
-			fg, _ := m.(android.FileGroupAsLibrary)
-			if fg.ShouldConvertToAidlLibrary(ctx) || fg.ShouldConvertToProtoLibrary(ctx) {
-				return labelStr, false
-			}
-			return labelStr + suffix, true
-		}
-	}
-
-	// TODO(b/190006308): Handle language detection of sources in a Bazel rule.
-	labels := bazel.LabelPartitions{
-		protoSrcPartition: android.ProtoSrcLabelPartition,
-		cSrcPartition:     bazel.LabelPartition{Extensions: []string{".c"}, LabelMapper: addSuffixForFilegroup("_c_srcs")},
-		asSrcPartition:    bazel.LabelPartition{Extensions: []string{".s", ".S"}, LabelMapper: addSuffixForFilegroup("_as_srcs")},
-		asmSrcPartition:   bazel.LabelPartition{Extensions: []string{".asm"}},
-		aidlSrcPartition:  android.AidlSrcLabelPartition,
-		// TODO(http://b/231968910): If there is ever a filegroup target that
-		// 		contains .l or .ll files we will need to find a way to add a
-		// 		LabelMapper for these that identifies these filegroups and
-		//		converts them appropriately
-		lSrcPartition:         bazel.LabelPartition{Extensions: []string{".l"}},
-		llSrcPartition:        bazel.LabelPartition{Extensions: []string{".ll"}},
-		rScriptSrcPartition:   bazel.LabelPartition{Extensions: []string{".fs", ".rscript"}},
-		xsdSrcPartition:       bazel.LabelPartition{LabelMapper: android.XsdLabelMapper(xsdConfigCppTarget)},
-		protoFromGenPartition: bazel.LabelPartition{LabelMapper: protoFromGenPartitionMapper(ctx)},
-		// C++ is the "catch-all" group, and comprises generated sources because we don't
-		// know the language of these sources until the genrule is executed.
-		cppSrcPartition:     bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true},
-		syspropSrcPartition: bazel.LabelPartition{Extensions: []string{".sysprop"}},
-		yaccSrcPartition:    bazel.LabelPartition{Extensions: []string{".y", "yy"}},
-	}
-
-	return bazel.PartitionLabelListAttribute(ctx, &srcs, labels)
-}
-
-func partitionHeaders(ctx android.BazelConversionPathContext, hdrs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute {
-	labels := bazel.LabelPartitions{
-		xsdSrcPartition:  bazel.LabelPartition{LabelMapper: android.XsdLabelMapper(xsdConfigCppTarget)},
-		genrulePartition: bazel.LabelPartition{LabelMapper: genrule.GenruleCcHeaderLabelMapper},
-		hdrPartition:     bazel.LabelPartition{Keep_remainder: true},
-	}
-	return bazel.PartitionLabelListAttribute(ctx, &hdrs, labels)
-}
-
-// bp2BuildParseLibProps returns the attributes for a variant of a cc_library.
-func bp2BuildParseLibProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) staticOrSharedAttributes {
-	lib, ok := module.compiler.(*libraryDecorator)
-	if !ok {
-		return staticOrSharedAttributes{}
-	}
-	return bp2buildParseStaticOrSharedProps(ctx, module, lib, isStatic)
-}
-
-// bp2buildParseSharedProps returns the attributes for the shared variant of a cc_library.
-func bp2BuildParseSharedProps(ctx android.BazelConversionPathContext, module *Module) staticOrSharedAttributes {
-	return bp2BuildParseLibProps(ctx, module, false)
-}
-
-// bp2buildParseStaticProps returns the attributes for the static variant of a cc_library.
-func bp2BuildParseStaticProps(ctx android.BazelConversionPathContext, module *Module) staticOrSharedAttributes {
-	return bp2BuildParseLibProps(ctx, module, true)
-}
-
-type depsPartition struct {
-	export         bazel.LabelList
-	implementation bazel.LabelList
-}
-
-type bazelLabelForDepsFn func(android.BazelConversionPathContext, []string) bazel.LabelList
-
-func maybePartitionExportedAndImplementationsDeps(ctx android.BazelConversionPathContext, exportsDeps bool, allDeps, exportedDeps []string, fn bazelLabelForDepsFn) depsPartition {
-	if !exportsDeps {
-		return depsPartition{
-			implementation: fn(ctx, allDeps),
-		}
-	}
-
-	implementation, export := android.FilterList(allDeps, exportedDeps)
-
-	return depsPartition{
-		export:         fn(ctx, export),
-		implementation: fn(ctx, implementation),
-	}
-}
-
-type bazelLabelForDepsExcludesFn func(android.BazelConversionPathContext, []string, []string) bazel.LabelList
-
-func maybePartitionExportedAndImplementationsDepsExcludes(ctx android.BazelConversionPathContext, exportsDeps bool, allDeps, excludes, exportedDeps []string, fn bazelLabelForDepsExcludesFn) depsPartition {
-	if !exportsDeps {
-		return depsPartition{
-			implementation: fn(ctx, allDeps, excludes),
-		}
-	}
-	implementation, export := android.FilterList(allDeps, exportedDeps)
-
-	return depsPartition{
-		export:         fn(ctx, export, excludes),
-		implementation: fn(ctx, implementation, excludes),
-	}
-}
-
-func bp2BuildPropParseHelper(ctx android.ArchVariantContext, module *Module, propsType interface{}, parseFunc func(axis bazel.ConfigurationAxis, config string, props interface{})) {
-	for axis, configToProps := range module.GetArchVariantProperties(ctx, propsType) {
-		for cfg, props := range configToProps {
-			parseFunc(axis, cfg, props)
-		}
-	}
-}
-
-// Parses properties common to static and shared libraries. Also used for prebuilt libraries.
-func bp2buildParseStaticOrSharedProps(ctx android.BazelConversionPathContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes {
-	attrs := staticOrSharedAttributes{}
-
-	setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
-		attrs.Copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag, filterOutHiddenVisibility))
-		attrs.Srcs.SetSelectValue(axis, config, android.BazelLabelForModuleSrc(ctx, props.Srcs))
-		attrs.System_dynamic_deps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, props.System_shared_libs))
-
-		staticDeps := maybePartitionExportedAndImplementationsDeps(ctx, true, props.Static_libs, props.Export_static_lib_headers, bazelLabelForStaticDeps)
-		attrs.Deps.SetSelectValue(axis, config, staticDeps.export)
-		attrs.Implementation_deps.SetSelectValue(axis, config, staticDeps.implementation)
-
-		sharedDeps := maybePartitionExportedAndImplementationsDeps(ctx, true, props.Shared_libs, props.Export_shared_lib_headers, bazelLabelForSharedDeps)
-		attrs.Dynamic_deps.SetSelectValue(axis, config, sharedDeps.export)
-		attrs.Implementation_dynamic_deps.SetSelectValue(axis, config, sharedDeps.implementation)
-
-		attrs.Whole_archive_deps.SetSelectValue(axis, config, bazelLabelForWholeDeps(ctx, props.Whole_static_libs))
-		attrs.Enabled.SetSelectValue(axis, config, props.Enabled)
-	}
-	// system_dynamic_deps distinguishes between nil/empty list behavior:
-	//    nil -> use default values
-	//    empty list -> no values specified
-	attrs.System_dynamic_deps.ForceSpecifyEmptyList = true
-
-	var apexAvailable []string
-	if isStatic {
-		apexAvailable = lib.StaticProperties.Static.Apex_available
-		bp2BuildPropParseHelper(ctx, module, &StaticProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
-			if staticOrSharedProps, ok := props.(*StaticProperties); ok {
-				setAttrs(axis, config, staticOrSharedProps.Static)
-			}
-		})
-	} else {
-		apexAvailable = lib.SharedProperties.Shared.Apex_available
-		bp2BuildPropParseHelper(ctx, module, &SharedProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
-			if staticOrSharedProps, ok := props.(*SharedProperties); ok {
-				setAttrs(axis, config, staticOrSharedProps.Shared)
-			}
-		})
-	}
-
-	partitionedSrcs := groupSrcsByExtension(ctx, attrs.Srcs)
-	attrs.Srcs = partitionedSrcs[cppSrcPartition]
-	attrs.Srcs_c = partitionedSrcs[cSrcPartition]
-	attrs.Srcs_as = partitionedSrcs[asSrcPartition]
-
-	attrs.Apex_available = android.ConvertApexAvailableToTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), apexAvailable)
-
-	attrs.Features.Append(convertHiddenVisibilityToFeatureStaticOrShared(ctx, module, isStatic))
-
-	if !partitionedSrcs[protoSrcPartition].IsEmpty() {
-		// TODO(b/208815215): determine whether this is used and add support if necessary
-		ctx.ModuleErrorf("Migrating static/shared only proto srcs is not currently supported")
-	}
-
-	return attrs
-}
-
-// Convenience struct to hold all attributes parsed from prebuilt properties.
-type prebuiltAttributes struct {
-	Src     bazel.LabelAttribute
-	Enabled bazel.BoolAttribute
-}
-
-func parseSrc(ctx android.BazelConversionPathContext, srcLabelAttribute *bazel.LabelAttribute, axis bazel.ConfigurationAxis, config string, srcs []string) {
-	srcFileError := func() {
-		ctx.ModuleErrorf("parseSrc: Expected at most one source file for %s %s\n", axis, config)
-	}
-	if len(srcs) > 1 {
-		srcFileError()
-		return
-	} else if len(srcs) == 0 {
-		return
-	}
-	if srcLabelAttribute.SelectValue(axis, config) != nil {
-		srcFileError()
-		return
-	}
-	srcLabelAttribute.SetSelectValue(axis, config, android.BazelLabelForModuleSrcSingle(ctx, srcs[0]))
-}
-
-// NOTE: Used outside of Soong repo project, in the clangprebuilts.go bootstrap_go_package
-func Bp2BuildParsePrebuiltLibraryProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) prebuiltAttributes {
-
-	var srcLabelAttribute bazel.LabelAttribute
-	bp2BuildPropParseHelper(ctx, module, &prebuiltLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
-		if prebuiltLinkerProperties, ok := props.(*prebuiltLinkerProperties); ok {
-			parseSrc(ctx, &srcLabelAttribute, axis, config, prebuiltLinkerProperties.Srcs)
-		}
-	})
-
-	var enabledLabelAttribute bazel.BoolAttribute
-	parseAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
-		if props.Enabled != nil {
-			enabledLabelAttribute.SetSelectValue(axis, config, props.Enabled)
-		}
-		parseSrc(ctx, &srcLabelAttribute, axis, config, props.Srcs)
-	}
-
-	if isStatic {
-		bp2BuildPropParseHelper(ctx, module, &StaticProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
-			if staticProperties, ok := props.(*StaticProperties); ok {
-				parseAttrs(axis, config, staticProperties.Static)
-			}
-		})
-	} else {
-		bp2BuildPropParseHelper(ctx, module, &SharedProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
-			if sharedProperties, ok := props.(*SharedProperties); ok {
-				parseAttrs(axis, config, sharedProperties.Shared)
-			}
-		})
-	}
-
-	return prebuiltAttributes{
-		Src:     srcLabelAttribute,
-		Enabled: enabledLabelAttribute,
-	}
-}
-
-func bp2BuildParsePrebuiltBinaryProps(ctx android.BazelConversionPathContext, module *Module) prebuiltAttributes {
-	var srcLabelAttribute bazel.LabelAttribute
-	bp2BuildPropParseHelper(ctx, module, &prebuiltLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
-		if props, ok := props.(*prebuiltLinkerProperties); ok {
-			parseSrc(ctx, &srcLabelAttribute, axis, config, props.Srcs)
-		}
-	})
-
-	return prebuiltAttributes{
-		Src: srcLabelAttribute,
-	}
-}
-
-func bp2BuildParsePrebuiltObjectProps(ctx android.BazelConversionPathContext, module *Module) prebuiltAttributes {
-	var srcLabelAttribute bazel.LabelAttribute
-	bp2BuildPropParseHelper(ctx, module, &prebuiltObjectProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
-		if props, ok := props.(*prebuiltObjectProperties); ok {
-			parseSrc(ctx, &srcLabelAttribute, axis, config, props.Srcs)
-		}
-	})
-
-	return prebuiltAttributes{
-		Src: srcLabelAttribute,
-	}
-}
-
-type baseAttributes struct {
-	compilerAttributes
-	linkerAttributes
-
-	// A combination of compilerAttributes.features and linkerAttributes.features, as well as sanitizer features
-	features        bazel.StringListAttribute
-	protoDependency *bazel.LabelAttribute
-	aidlDependency  *bazel.LabelAttribute
-	Native_coverage *bool
-}
-
-// Convenience struct to hold all attributes parsed from compiler properties.
-type compilerAttributes struct {
-	// Options for all languages
-	copts bazel.StringListAttribute
-	// Assembly options and sources
-	asFlags bazel.StringListAttribute
-	asSrcs  bazel.LabelListAttribute
-	asmSrcs bazel.LabelListAttribute
-	// C options and sources
-	conlyFlags bazel.StringListAttribute
-	cSrcs      bazel.LabelListAttribute
-	// C++ options and sources
-	cppFlags bazel.StringListAttribute
-	srcs     bazel.LabelListAttribute
-
-	// xsd config sources
-	xsdSrcs       bazel.LabelListAttribute
-	exportXsdSrcs bazel.LabelListAttribute
-
-	// genrule headers
-	genruleHeaders       bazel.LabelListAttribute
-	exportGenruleHeaders bazel.LabelListAttribute
-
-	// Lex sources and options
-	lSrcs   bazel.LabelListAttribute
-	llSrcs  bazel.LabelListAttribute
-	lexopts bazel.StringListAttribute
-
-	// Sysprop sources
-	syspropSrcs bazel.LabelListAttribute
-
-	// Yacc sources
-	yaccSrc               *bazel.LabelAttribute
-	yaccFlags             bazel.StringListAttribute
-	yaccGenLocationHeader bazel.BoolAttribute
-	yaccGenPositionHeader bazel.BoolAttribute
-
-	rsSrcs bazel.LabelListAttribute
-
-	hdrs bazel.LabelListAttribute
-
-	rtti bazel.BoolAttribute
-
-	// Not affected by arch variants
-	stl    *string
-	cStd   *string
-	cppStd *string
-
-	localIncludes    bazel.StringListAttribute
-	absoluteIncludes bazel.StringListAttribute
-
-	includes BazelIncludes
-
-	protoSrcs   bazel.LabelListAttribute
-	aidlSrcs    bazel.LabelListAttribute
-	rscriptSrcs bazel.LabelListAttribute
-
-	stubsSymbolFile *string
-	stubsVersions   bazel.StringListAttribute
-
-	features bazel.StringListAttribute
-
-	stem   bazel.StringAttribute
-	suffix bazel.StringAttribute
-
-	fdoProfile bazel.LabelAttribute
-}
-
-type filterOutFn func(string) bool
-
-// filterOutHiddenVisibility removes the flag specifying hidden visibility as
-// this flag is converted to a toolchain feature
-func filterOutHiddenVisibility(flag string) bool {
-	return flag == config.VisibilityHiddenFlag
-}
-
-func filterOutStdFlag(flag string) bool {
-	return strings.HasPrefix(flag, "-std=")
-}
-
-func filterOutClangUnknownCflags(flag string) bool {
-	for _, f := range config.ClangUnknownCflags {
-		if f == flag {
-			return true
-		}
-	}
-	return false
-}
-
-func parseCommandLineFlags(soongFlags []string, filterOut ...filterOutFn) []string {
-	var result []string
-	for _, flag := range soongFlags {
-		skipFlag := false
-		for _, filter := range filterOut {
-			if filter != nil && filter(flag) {
-				skipFlag = true
-			}
-		}
-		if skipFlag {
-			continue
-		}
-		// Soong's cflags can contain spaces, like `-include header.h`. For
-		// Bazel's copts, split them up to be compatible with the
-		// no_copts_tokenization feature.
-		result = append(result, strings.Split(flag, " ")...)
-	}
-	return result
-}
-
-func (ca *compilerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, config string, props *BaseCompilerProperties) {
-	// 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.
-	srcsList, ok := parseSrcs(ctx, props)
-
-	if ok {
-		ca.srcs.SetSelectValue(axis, config, srcsList)
-	}
-
-	localIncludeDirs := props.Local_include_dirs
-	if axis == bazel.NoConfigAxis {
-		ca.cStd, ca.cppStd = bp2buildResolveCppStdValue(props.C_std, props.Cpp_std, props.Gnu_extensions)
-		if includeBuildDirectory(props.Include_build_directory) {
-			localIncludeDirs = append(localIncludeDirs, ".")
-		}
-	}
-
-	ca.absoluteIncludes.SetSelectValue(axis, config, props.Include_dirs)
-	ca.localIncludes.SetSelectValue(axis, config, localIncludeDirs)
-
-	instructionSet := proptools.StringDefault(props.Instruction_set, "")
-	if instructionSet == "arm" {
-		ca.features.SetSelectValue(axis, config, []string{"arm_isa_arm"})
-	} else if instructionSet != "" && instructionSet != "thumb" {
-		ctx.ModuleErrorf("Unknown value for instruction_set: %s", instructionSet)
-	}
-
-	// In Soong, cflags occur on the command line before -std=<val> flag, resulting in the value being
-	// overridden. In Bazel we always allow overriding, via flags; however, this can cause
-	// incompatibilities, so we remove "-std=" flags from Cflag properties while leaving it in other
-	// cases.
-	ca.copts.SetSelectValue(axis, config, parseCommandLineFlags(props.Cflags, filterOutStdFlag, filterOutClangUnknownCflags, filterOutHiddenVisibility))
-	ca.asFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Asflags, nil))
-	ca.conlyFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Conlyflags, filterOutClangUnknownCflags))
-	ca.cppFlags.SetSelectValue(axis, config, parseCommandLineFlags(props.Cppflags, filterOutClangUnknownCflags))
-	ca.rtti.SetSelectValue(axis, config, props.Rtti)
-}
-
-func (ca *compilerAttributes) convertStlProps(ctx android.ArchVariantContext, module *Module) {
-	bp2BuildPropParseHelper(ctx, module, &StlProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
-		if stlProps, ok := props.(*StlProperties); ok {
-			if stlProps.Stl == nil {
-				return
-			}
-			if ca.stl == nil {
-				stl := deduplicateStlInput(*stlProps.Stl)
-				ca.stl = &stl
-			} else if ca.stl != stlProps.Stl {
-				ctx.ModuleErrorf("Unsupported conversion: module with different stl for different variants: %s and %s", *ca.stl, stlProps.Stl)
-			}
-		}
-	})
-}
-
-func (ca *compilerAttributes) convertProductVariables(ctx android.BazelConversionPathContext, productVariableProps android.ProductConfigProperties) {
-	productVarPropNameToAttribute := map[string]*bazel.StringListAttribute{
-		"Cflags":   &ca.copts,
-		"Asflags":  &ca.asFlags,
-		"Cppflags": &ca.cppFlags,
-	}
-	for propName, attr := range productVarPropNameToAttribute {
-		if productConfigProps, exists := productVariableProps[propName]; exists {
-			for productConfigProp, prop := range productConfigProps {
-				flags, ok := prop.([]string)
-				if !ok {
-					ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName))
-				}
-				newFlags, _ := bazel.TryVariableSubstitutions(flags, productConfigProp.Name())
-				attr.SetSelectValue(productConfigProp.ConfigurationAxis(), productConfigProp.SelectKey(), newFlags)
-			}
-		}
-	}
-}
-
-func (ca *compilerAttributes) finalize(ctx android.BazelConversionPathContext, implementationHdrs, exportHdrs bazel.LabelListAttribute) {
-	ca.srcs.ResolveExcludes()
-	partitionedSrcs := groupSrcsByExtension(ctx, ca.srcs)
-	partitionedImplHdrs := partitionHeaders(ctx, implementationHdrs)
-	partitionedHdrs := partitionHeaders(ctx, exportHdrs)
-
-	ca.protoSrcs = partitionedSrcs[protoSrcPartition]
-	ca.protoSrcs.Append(partitionedSrcs[protoFromGenPartition])
-	ca.aidlSrcs = partitionedSrcs[aidlSrcPartition]
-
-	for p, lla := range partitionedSrcs {
-		// if there are no sources, there is no need for headers
-		if lla.IsEmpty() {
-			continue
-		}
-		lla.Append(partitionedImplHdrs[hdrPartition])
-		partitionedSrcs[p] = lla
-	}
-
-	ca.hdrs = partitionedHdrs[hdrPartition]
-
-	ca.includesFromHeaders(ctx, partitionedImplHdrs[hdrPartition], partitionedHdrs[hdrPartition])
-
-	xsdSrcs := bazel.SubtractBazelLabelListAttribute(partitionedSrcs[xsdSrcPartition], partitionedHdrs[xsdSrcPartition])
-	xsdSrcs.Append(partitionedImplHdrs[xsdSrcPartition])
-	ca.exportXsdSrcs = partitionedHdrs[xsdSrcPartition]
-	ca.xsdSrcs = bazel.FirstUniqueBazelLabelListAttribute(xsdSrcs)
-
-	ca.genruleHeaders = partitionedImplHdrs[genrulePartition]
-	ca.exportGenruleHeaders = partitionedHdrs[genrulePartition]
-
-	ca.srcs = partitionedSrcs[cppSrcPartition]
-	ca.cSrcs = partitionedSrcs[cSrcPartition]
-	ca.asSrcs = partitionedSrcs[asSrcPartition]
-	ca.asmSrcs = partitionedSrcs[asmSrcPartition]
-	ca.lSrcs = partitionedSrcs[lSrcPartition]
-	ca.llSrcs = partitionedSrcs[llSrcPartition]
-	if yacc := partitionedSrcs[yaccSrcPartition]; !yacc.IsEmpty() {
-		if len(yacc.Value.Includes) > 1 {
-			ctx.PropertyErrorf("srcs", "Found multiple yacc (.y/.yy) files in library")
-		}
-		ca.yaccSrc = bazel.MakeLabelAttribute(yacc.Value.Includes[0].Label)
-	}
-	ca.syspropSrcs = partitionedSrcs[syspropSrcPartition]
-	ca.rscriptSrcs = partitionedSrcs[rScriptSrcPartition]
-
-	ca.absoluteIncludes.DeduplicateAxesFromBase()
-	ca.localIncludes.DeduplicateAxesFromBase()
-}
-
-// Parse srcs from an arch or OS's props value.
-func parseSrcs(ctx android.BazelConversionPathContext, props *BaseCompilerProperties) (bazel.LabelList, bool) {
-	anySrcs := false
-	// Add srcs-like dependencies such as generated files.
-	// First create a LabelList containing these dependencies, then merge the values with srcs.
-	genSrcs := props.Generated_sources
-	generatedSrcsLabelList := android.BazelLabelForModuleDepsExcludes(ctx, genSrcs, props.Exclude_generated_sources)
-	if len(props.Generated_sources) > 0 || len(props.Exclude_generated_sources) > 0 {
-		anySrcs = true
-	}
-
-	allSrcsLabelList := android.BazelLabelForModuleSrcExcludes(ctx, props.Srcs, props.Exclude_srcs)
-
-	if len(props.Srcs) > 0 || len(props.Exclude_srcs) > 0 {
-		anySrcs = true
-	}
-
-	return bazel.AppendBazelLabelLists(allSrcsLabelList, generatedSrcsLabelList), anySrcs
-}
-
-func bp2buildStdVal(std *string, prefix string, useGnu bool) *string {
-	defaultVal := prefix + "_std_default"
-	// If c{,pp}std properties are not specified, don't generate them in the BUILD file.
-	// Defaults are handled by the toolchain definition.
-	// However, if gnu_extensions is false, then the default gnu-to-c version must be specified.
-	stdVal := proptools.StringDefault(std, defaultVal)
-	if stdVal == "experimental" || stdVal == defaultVal {
-		if stdVal == "experimental" {
-			stdVal = prefix + "_std_experimental"
-		}
-		if !useGnu {
-			stdVal += "_no_gnu"
-		}
-	} else if !useGnu {
-		stdVal = gnuToCReplacer.Replace(stdVal)
-	}
-
-	if stdVal == defaultVal {
-		return nil
-	}
-	return &stdVal
-}
-
-func bp2buildResolveCppStdValue(c_std *string, cpp_std *string, gnu_extensions *bool) (*string, *string) {
-	useGnu := useGnuExtensions(gnu_extensions)
-
-	return bp2buildStdVal(c_std, "c", useGnu), bp2buildStdVal(cpp_std, "cpp", useGnu)
-}
-
-// packageFromLabel extracts package from a fully-qualified or relative Label and whether the label
-// is fully-qualified.
-// e.g. fully-qualified "//a/b:foo" -> "a/b", true, relative: ":bar" -> ".", false
-func packageFromLabel(label string) (string, bool) {
-	split := strings.Split(label, ":")
-	if len(split) != 2 {
-		return "", false
-	}
-	if split[0] == "" {
-		return ".", false
-	}
-	// remove leading "//"
-	return split[0][2:], true
-}
-
-// includesFromHeaders gets the include directories needed from generated headers
-func (ca *compilerAttributes) includesFromHeaders(ctx android.BazelConversionPathContext, implHdrs, hdrs bazel.LabelListAttribute) {
-	local, absolute := includesFromLabelListAttribute(implHdrs, ca.localIncludes, ca.absoluteIncludes)
-	localExport, absoluteExport := includesFromLabelListAttribute(hdrs, ca.includes.Includes, ca.includes.AbsoluteIncludes)
-
-	ca.localIncludes = local
-	ca.absoluteIncludes = absolute
-
-	ca.includes.Includes = localExport
-	ca.includes.AbsoluteIncludes = absoluteExport
-}
-
-// includesFromLabelList extracts the packages from a LabelListAttribute that should be includes and
-// combines them with existing local/absolute includes.
-func includesFromLabelListAttribute(attr bazel.LabelListAttribute, existingLocal, existingAbsolute bazel.StringListAttribute) (bazel.StringListAttribute, bazel.StringListAttribute) {
-	localAttr := existingLocal.Clone()
-	absoluteAttr := existingAbsolute.Clone()
-	if !attr.Value.IsEmpty() {
-		l, a := includesFromLabelList(attr.Value, existingLocal.Value, existingAbsolute.Value)
-		localAttr.SetSelectValue(bazel.NoConfigAxis, "", l)
-		absoluteAttr.SetSelectValue(bazel.NoConfigAxis, "", a)
-	}
-	for axis, configToLabels := range attr.ConfigurableValues {
-		for c, labels := range configToLabels {
-			local := existingLocal.SelectValue(axis, c)
-			absolute := existingAbsolute.SelectValue(axis, c)
-			l, a := includesFromLabelList(labels, local, absolute)
-			localAttr.SetSelectValue(axis, c, l)
-			absoluteAttr.SetSelectValue(axis, c, a)
-		}
-	}
-	return *localAttr, *absoluteAttr
-}
-
-// includesFromLabelList extracts relative/absolute includes from a bazel.LabelList.
-func includesFromLabelList(labelList bazel.LabelList, existingRel, existingAbs []string) ([]string, []string) {
-	var relative, absolute []string
-	for _, hdr := range labelList.Includes {
-		if pkg, hasPkg := packageFromLabel(hdr.Label); hasPkg {
-			absolute = append(absolute, pkg)
-		} else if pkg != "" {
-			relative = append(relative, pkg)
-		}
-	}
-	if len(relative)+len(existingRel) != 0 {
-		relative = android.FirstUniqueStrings(append(append([]string{}, existingRel...), relative...))
-	}
-	if len(absolute)+len(existingAbs) != 0 {
-		absolute = android.FirstUniqueStrings(append(append([]string{}, existingAbs...), absolute...))
-	}
-	return relative, absolute
-}
-
-type YasmAttributes struct {
-	Srcs         bazel.LabelListAttribute
-	Flags        bazel.StringListAttribute
-	Include_dirs bazel.StringListAttribute
-}
-
-func bp2BuildYasm(ctx android.Bp2buildMutatorContext, m *Module, ca compilerAttributes) *bazel.LabelAttribute {
-	if ca.asmSrcs.IsEmpty() {
-		return nil
-	}
-
-	// Yasm needs the include directories from both local_includes and
-	// export_include_dirs. We don't care about actually exporting them from the
-	// yasm rule though, because they will also be present on the cc_ rule that
-	// wraps this yasm rule.
-	includes := ca.localIncludes.Clone()
-	bp2BuildPropParseHelper(ctx, m, &FlagExporterProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
-		if flagExporterProperties, ok := props.(*FlagExporterProperties); ok {
-			if len(flagExporterProperties.Export_include_dirs) > 0 {
-				x := bazel.StringListAttribute{}
-				x.SetSelectValue(axis, config, flagExporterProperties.Export_include_dirs)
-				includes.Append(x)
-			}
-		}
-	})
-
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "yasm",
-			Bzl_load_location: "//build/bazel/rules/cc:yasm.bzl",
-		},
-		android.CommonAttributes{Name: m.Name() + "_yasm"},
-		&YasmAttributes{
-			Srcs:         ca.asmSrcs,
-			Flags:        ca.asFlags,
-			Include_dirs: *includes,
-		})
-
-	// We only want to add a dependency on the _yasm target if there are asm
-	// sources in the current configuration. If there are unconfigured asm
-	// sources, always add the dependency. Otherwise, add the dependency only
-	// on the configuration axes and values that had asm sources.
-	if len(ca.asmSrcs.Value.Includes) > 0 {
-		return bazel.MakeLabelAttribute(":" + m.Name() + "_yasm")
-	}
-
-	ret := &bazel.LabelAttribute{}
-	for _, axis := range ca.asmSrcs.SortedConfigurationAxes() {
-		for cfg := range ca.asmSrcs.ConfigurableValues[axis] {
-			ret.SetSelectValue(axis, cfg, bazel.Label{Label: ":" + m.Name() + "_yasm"})
-		}
-	}
-	return ret
-}
-
-// bp2BuildParseBaseProps returns all compiler, linker, library attributes of a cc module..
-func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) baseAttributes {
-	archVariantCompilerProps := module.GetArchVariantProperties(ctx, &BaseCompilerProperties{})
-	archVariantLinkerProps := module.GetArchVariantProperties(ctx, &BaseLinkerProperties{})
-	archVariantLibraryProperties := module.GetArchVariantProperties(ctx, &LibraryProperties{})
-
-	axisToConfigs := map[bazel.ConfigurationAxis]map[string]bool{}
-	allAxesAndConfigs := func(cp android.ConfigurationAxisToArchVariantProperties) {
-		for axis, configMap := range cp {
-			if _, ok := axisToConfigs[axis]; !ok {
-				axisToConfigs[axis] = map[string]bool{}
-			}
-			for cfg := range configMap {
-				axisToConfigs[axis][cfg] = true
-			}
-		}
-	}
-	allAxesAndConfigs(archVariantCompilerProps)
-	allAxesAndConfigs(archVariantLinkerProps)
-	allAxesAndConfigs(archVariantLibraryProperties)
-
-	compilerAttrs := compilerAttributes{}
-	linkerAttrs := linkerAttributes{}
-
-	var aidlLibs bazel.LabelList
-	var implementationHdrs, exportHdrs bazel.LabelListAttribute
-
-	// Iterate through these axes in a deterministic order. This is required
-	// because processing certain dependencies may result in concatenating
-	// elements along other axes. (For example, processing NoConfig may result
-	// in elements being added to InApex). This is thus the only way to ensure
-	// that the order of entries in each list is in a predictable order.
-	for _, axis := range bazel.SortedConfigurationAxes(axisToConfigs) {
-		configs := axisToConfigs[axis]
-		for cfg := range configs {
-			var allHdrs []string
-			if baseCompilerProps, ok := archVariantCompilerProps[axis][cfg].(*BaseCompilerProperties); ok {
-				allHdrs = baseCompilerProps.Generated_headers
-
-				if baseCompilerProps.Lex != nil {
-					compilerAttrs.lexopts.SetSelectValue(axis, cfg, baseCompilerProps.Lex.Flags)
-				}
-				if baseCompilerProps.Yacc != nil {
-					compilerAttrs.yaccFlags.SetSelectValue(axis, cfg, baseCompilerProps.Yacc.Flags)
-					compilerAttrs.yaccGenLocationHeader.SetSelectValue(axis, cfg, baseCompilerProps.Yacc.Gen_location_hh)
-					compilerAttrs.yaccGenPositionHeader.SetSelectValue(axis, cfg, baseCompilerProps.Yacc.Gen_position_hh)
-				}
-				(&compilerAttrs).bp2buildForAxisAndConfig(ctx, axis, cfg, baseCompilerProps)
-				aidlLibs.Append(android.BazelLabelForModuleDeps(ctx, baseCompilerProps.Aidl.Libs))
-			}
-
-			var exportedHdrs []string
-
-			if baseLinkerProps, ok := archVariantLinkerProps[axis][cfg].(*BaseLinkerProperties); ok {
-				exportedHdrs = baseLinkerProps.Export_generated_headers
-				(&linkerAttrs).bp2buildForAxisAndConfig(ctx, module, axis, cfg, baseLinkerProps)
-			}
-
-			headers := maybePartitionExportedAndImplementationsDeps(ctx, !module.Binary(), allHdrs, exportedHdrs, android.BazelLabelForModuleDeps)
-
-			implementationHdrs.SetSelectValue(axis, cfg, headers.implementation)
-			exportHdrs.SetSelectValue(axis, cfg, headers.export)
-
-			if libraryProps, ok := archVariantLibraryProperties[axis][cfg].(*LibraryProperties); ok {
-				if axis == bazel.NoConfigAxis {
-					if libraryProps.Stubs.Symbol_file != nil {
-						compilerAttrs.stubsSymbolFile = libraryProps.Stubs.Symbol_file
-						versions := android.CopyOf(libraryProps.Stubs.Versions)
-						normalizeVersions(ctx, versions)
-						versions = addCurrentVersionIfNotPresent(versions)
-						compilerAttrs.stubsVersions.SetSelectValue(axis, cfg, versions)
-					}
-				}
-				if stem := libraryProps.Stem; stem != nil {
-					compilerAttrs.stem.SetSelectValue(axis, cfg, stem)
-				}
-				if suffix := libraryProps.Suffix; suffix != nil {
-					compilerAttrs.suffix.SetSelectValue(axis, cfg, suffix)
-				}
-			}
-
-		}
-	}
-
-	compilerAttrs.convertStlProps(ctx, module)
-	(&linkerAttrs).convertStripProps(ctx, module)
-
-	var nativeCoverage *bool
-	if module.coverage != nil && module.coverage.Properties.Native_coverage != nil &&
-		!Bool(module.coverage.Properties.Native_coverage) {
-		nativeCoverage = BoolPtr(false)
-	}
-
-	productVariableProps := android.ProductVariableProperties(ctx, ctx.Module())
-
-	(&compilerAttrs).convertProductVariables(ctx, productVariableProps)
-	(&linkerAttrs).convertProductVariables(ctx, productVariableProps)
-
-	(&compilerAttrs).finalize(ctx, implementationHdrs, exportHdrs)
-	(&linkerAttrs).finalize(ctx)
-
-	(&compilerAttrs.srcs).Add(bp2BuildYasm(ctx, module, compilerAttrs))
-
-	(&linkerAttrs).deps.Append(compilerAttrs.exportGenruleHeaders)
-	(&linkerAttrs).implementationDeps.Append(compilerAttrs.genruleHeaders)
-
-	(&linkerAttrs).wholeArchiveDeps.Append(compilerAttrs.exportXsdSrcs)
-	(&linkerAttrs).implementationWholeArchiveDeps.Append(compilerAttrs.xsdSrcs)
-
-	protoDep := bp2buildProto(ctx, module, compilerAttrs.protoSrcs)
-
-	// bp2buildProto will only set wholeStaticLib or implementationWholeStaticLib, but we don't know
-	// which. This will add the newly generated proto library to the appropriate attribute and nothing
-	// to the other
-	(&linkerAttrs).wholeArchiveDeps.Add(protoDep.wholeStaticLib)
-	(&linkerAttrs).implementationWholeArchiveDeps.Add(protoDep.implementationWholeStaticLib)
-
-	aidlDep := bp2buildCcAidlLibrary(
-		ctx, module,
-		compilerAttrs.aidlSrcs,
-		bazel.LabelListAttribute{
-			Value: aidlLibs,
-		},
-		linkerAttrs,
-		compilerAttrs,
-	)
-	if aidlDep != nil {
-		if lib, ok := module.linker.(*libraryDecorator); ok {
-			if proptools.Bool(lib.Properties.Aidl.Export_aidl_headers) {
-				(&linkerAttrs).wholeArchiveDeps.Add(aidlDep)
-			} else {
-				(&linkerAttrs).implementationWholeArchiveDeps.Add(aidlDep)
-			}
-		}
-	}
-
-	// Create a cc_yacc_static_library if srcs contains .y/.yy files
-	// This internal target will produce an .a file that will be statically linked to the parent library
-	if yaccDep := bp2buildCcYaccLibrary(ctx, compilerAttrs, linkerAttrs); yaccDep != nil {
-		(&linkerAttrs).implementationWholeArchiveDeps.Add(yaccDep)
-	}
-
-	convertedLSrcs := bp2BuildLex(ctx, module.Name(), compilerAttrs)
-	(&compilerAttrs).srcs.Add(&convertedLSrcs.srcName)
-	(&compilerAttrs).cSrcs.Add(&convertedLSrcs.cSrcName)
-
-	if module.afdo != nil && module.afdo.Properties.Afdo {
-		fdoProfileDep := bp2buildFdoProfile(ctx, module)
-		if fdoProfileDep != nil {
-			(&compilerAttrs).fdoProfile.SetValue(*fdoProfileDep)
-		}
-	}
-
-	if !compilerAttrs.syspropSrcs.IsEmpty() {
-		(&linkerAttrs).wholeArchiveDeps.Add(bp2buildCcSysprop(ctx, module.Name(), module.Properties.Min_sdk_version, compilerAttrs.syspropSrcs))
-	}
-
-	linkerAttrs.wholeArchiveDeps.Prepend = true
-	linkerAttrs.deps.Prepend = true
-	compilerAttrs.localIncludes.Prepend = true
-	compilerAttrs.absoluteIncludes.Prepend = true
-	compilerAttrs.hdrs.Prepend = true
-
-	convertedRsSrcs, rsAbsIncludes, rsLocalIncludes := bp2buildRScript(ctx, module, compilerAttrs)
-	(&compilerAttrs).srcs.Add(&convertedRsSrcs)
-	(&compilerAttrs).absoluteIncludes.Append(rsAbsIncludes)
-	(&compilerAttrs).localIncludes.Append(rsLocalIncludes)
-	(&compilerAttrs).localIncludes.Value = android.FirstUniqueStrings(compilerAttrs.localIncludes.Value)
-
-	features := compilerAttrs.features.Clone().Append(linkerAttrs.features).Append(bp2buildSanitizerFeatures(ctx, module))
-	features = features.Append(bp2buildLtoFeatures(ctx, module))
-	features = features.Append(convertHiddenVisibilityToFeatureBase(ctx, module))
-	features.DeduplicateAxesFromBase()
-
-	addMuslSystemDynamicDeps(ctx, linkerAttrs)
-
-	return baseAttributes{
-		compilerAttrs,
-		linkerAttrs,
-		*features,
-		protoDep.protoDep,
-		aidlDep,
-		nativeCoverage,
-	}
-}
-
-type ccYaccLibraryAttributes struct {
-	Src                         bazel.LabelAttribute
-	Flags                       bazel.StringListAttribute
-	Gen_location_hh             bazel.BoolAttribute
-	Gen_position_hh             bazel.BoolAttribute
-	Local_includes              bazel.StringListAttribute
-	Implementation_deps         bazel.LabelListAttribute
-	Implementation_dynamic_deps bazel.LabelListAttribute
-}
-
-func bp2buildCcYaccLibrary(ctx android.Bp2buildMutatorContext, ca compilerAttributes, la linkerAttributes) *bazel.LabelAttribute {
-	if ca.yaccSrc == nil {
-		return nil
-	}
-	yaccLibraryLabel := ctx.Module().Name() + "_yacc"
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "cc_yacc_static_library",
-			Bzl_load_location: "//build/bazel/rules/cc:cc_yacc_library.bzl",
-		},
-		android.CommonAttributes{
-			Name: yaccLibraryLabel,
-		},
-		&ccYaccLibraryAttributes{
-			Src:                         *ca.yaccSrc,
-			Flags:                       ca.yaccFlags,
-			Gen_location_hh:             ca.yaccGenLocationHeader,
-			Gen_position_hh:             ca.yaccGenPositionHeader,
-			Local_includes:              ca.localIncludes,
-			Implementation_deps:         la.implementationDeps,
-			Implementation_dynamic_deps: la.implementationDynamicDeps,
-		},
-	)
-
-	yaccLibrary := &bazel.LabelAttribute{
-		Value: &bazel.Label{
-			Label: ":" + yaccLibraryLabel,
-		},
-	}
-	return yaccLibrary
-}
-
-// As a workaround for b/261657184, we are manually adding the default value
-// of system_dynamic_deps for the linux_musl os.
-// TODO: Solve this properly
-func addMuslSystemDynamicDeps(ctx android.Bp2buildMutatorContext, attrs linkerAttributes) {
-	systemDynamicDeps := attrs.systemDynamicDeps.SelectValue(bazel.OsConfigurationAxis, "linux_musl")
-	if attrs.systemDynamicDeps.HasAxisSpecificValues(bazel.OsConfigurationAxis) && systemDynamicDeps.IsNil() {
-		attrs.systemDynamicDeps.SetSelectValue(bazel.OsConfigurationAxis, "linux_musl", android.BazelLabelForModuleDeps(ctx, config.MuslDefaultSharedLibraries))
-	}
-}
-
-type fdoProfileAttributes struct {
-	Absolute_path_profile string
-}
-
-func bp2buildFdoProfile(
-	ctx android.Bp2buildMutatorContext,
-	m *Module,
-) *bazel.Label {
-	for _, project := range globalAfdoProfileProjects {
-		// Ensure handcrafted BUILD file exists in the project
-		BUILDPath := android.ExistentPathForSource(ctx, project, "BUILD")
-		if BUILDPath.Valid() {
-			// We handcraft a BUILD file with fdo_profile targets that use the existing profiles in the project
-			// This implementation is assuming that every afdo profile in globalAfdoProfileProjects already has
-			// an associated fdo_profile target declared in the same package.
-			// TODO(b/260714900): Handle arch-specific afdo profiles (e.g. `<module-name>-arm<64>.afdo`)
-			path := android.ExistentPathForSource(ctx, project, m.Name()+".afdo")
-			if path.Valid() {
-				// FIXME: Some profiles only exist internally and are not released to AOSP.
-				// When generated BUILD files are checked in, we'll run into merge conflict.
-				// The cc_library_shared target in AOSP won't have reference to an fdo_profile target because
-				// the profile doesn't exist. Internally, the same cc_library_shared target will
-				// have reference to the fdo_profile.
-				// For more context, see b/258682955#comment2
-				fdoProfileLabel := "//" + strings.TrimSuffix(project, "/") + ":" + m.Name()
-				return &bazel.Label{
-					Label: fdoProfileLabel,
-				}
-			}
-		}
-	}
-
-	return nil
-}
-
-func bp2buildCcAidlLibrary(
-	ctx android.Bp2buildMutatorContext,
-	m *Module,
-	aidlSrcs bazel.LabelListAttribute,
-	aidlLibs bazel.LabelListAttribute,
-	linkerAttrs linkerAttributes,
-	compilerAttrs compilerAttributes,
-) *bazel.LabelAttribute {
-	var aidlLibsFromSrcs, aidlFiles bazel.LabelListAttribute
-	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), ctx.Module())
-
-	if !aidlSrcs.IsEmpty() {
-		aidlLibsFromSrcs, aidlFiles = aidlSrcs.Partition(func(src bazel.Label) bool {
-			if fg, ok := android.ToFileGroupAsLibrary(ctx, src.OriginalModuleName); ok &&
-				fg.ShouldConvertToAidlLibrary(ctx) {
-				return true
-			}
-			return false
-		})
-
-		if !aidlFiles.IsEmpty() {
-			aidlLibName := m.Name() + "_aidl_library"
-			ctx.CreateBazelTargetModule(
-				bazel.BazelTargetModuleProperties{
-					Rule_class:        "aidl_library",
-					Bzl_load_location: "//build/bazel/rules/aidl:aidl_library.bzl",
-				},
-				android.CommonAttributes{
-					Name: aidlLibName,
-					Tags: apexAvailableTags,
-				},
-				&aidlLibraryAttributes{
-					Srcs: aidlFiles,
-				},
-			)
-			aidlLibsFromSrcs.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + aidlLibName}})
-		}
-	}
-
-	allAidlLibs := aidlLibs.Clone()
-	allAidlLibs.Append(aidlLibsFromSrcs)
-
-	if !allAidlLibs.IsEmpty() {
-		ccAidlLibrarylabel := m.Name() + "_cc_aidl_library"
-		// Since parent cc_library already has these dependencies, we can add them as implementation
-		// deps so that they don't re-export
-		implementationDeps := linkerAttrs.deps.Clone()
-		implementationDeps.Append(linkerAttrs.implementationDeps)
-		implementationDynamicDeps := linkerAttrs.dynamicDeps.Clone()
-		implementationDynamicDeps.Append(linkerAttrs.implementationDynamicDeps)
-
-		sdkAttrs := bp2BuildParseSdkAttributes(m)
-
-		exportedIncludes := bp2BuildParseExportedIncludes(ctx, m, &compilerAttrs.includes)
-		includeAttrs := includesAttributes{
-			Export_includes:          exportedIncludes.Includes,
-			Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
-			Export_system_includes:   exportedIncludes.SystemIncludes,
-			Local_includes:           compilerAttrs.localIncludes,
-			Absolute_includes:        compilerAttrs.absoluteIncludes,
-		}
-
-		ctx.CreateBazelTargetModule(
-			bazel.BazelTargetModuleProperties{
-				Rule_class:        "cc_aidl_library",
-				Bzl_load_location: "//build/bazel/rules/cc:cc_aidl_library.bzl",
-			},
-			android.CommonAttributes{Name: ccAidlLibrarylabel},
-			&ccAidlLibraryAttributes{
-				Deps:                        *allAidlLibs,
-				Implementation_deps:         *implementationDeps,
-				Implementation_dynamic_deps: *implementationDynamicDeps,
-				Tags:                        apexAvailableTags,
-				sdkAttributes:               sdkAttrs,
-				includesAttributes:          includeAttrs,
-			},
-		)
-		label := &bazel.LabelAttribute{
-			Value: &bazel.Label{
-				Label: ":" + ccAidlLibrarylabel,
-			},
-		}
-		return label
-	}
-
-	return nil
-}
-
-func bp2BuildParseSdkAttributes(module *Module) sdkAttributes {
-	return sdkAttributes{
-		Sdk_version:     module.Properties.Sdk_version,
-		Min_sdk_version: module.Properties.Min_sdk_version,
-	}
-}
-
-type sdkAttributes struct {
-	Sdk_version     *string
-	Min_sdk_version *string
-}
-
-// Convenience struct to hold all attributes parsed from linker properties.
-type linkerAttributes struct {
-	deps                             bazel.LabelListAttribute
-	implementationDeps               bazel.LabelListAttribute
-	dynamicDeps                      bazel.LabelListAttribute
-	implementationDynamicDeps        bazel.LabelListAttribute
-	runtimeDeps                      bazel.LabelListAttribute
-	wholeArchiveDeps                 bazel.LabelListAttribute
-	implementationWholeArchiveDeps   bazel.LabelListAttribute
-	systemDynamicDeps                bazel.LabelListAttribute
-	usedSystemDynamicDepAsStaticDep  map[string]bool
-	usedSystemDynamicDepAsDynamicDep map[string]bool
-
-	useVersionLib                 bazel.BoolAttribute
-	linkopts                      bazel.StringListAttribute
-	additionalLinkerInputs        bazel.LabelListAttribute
-	stripKeepSymbols              bazel.BoolAttribute
-	stripKeepSymbolsAndDebugFrame bazel.BoolAttribute
-	stripKeepSymbolsList          bazel.StringListAttribute
-	stripAll                      bazel.BoolAttribute
-	stripNone                     bazel.BoolAttribute
-	features                      bazel.StringListAttribute
-}
-
-var (
-	soongSystemSharedLibs = []string{"libc", "libm", "libdl"}
-	versionLib            = "libbuildversion"
-)
-
-// resolveTargetApex re-adds the shared and static libs in target.apex.exclude_shared|static_libs props to non-apex variant
-// since all libs are already excluded by default
-func (la *linkerAttributes) resolveTargetApexProp(ctx android.BazelConversionPathContext, props *BaseLinkerProperties) {
-	excludeSharedLibs := bazelLabelForSharedDeps(ctx, props.Target.Apex.Exclude_shared_libs)
-	sharedExcludes := bazel.LabelList{Excludes: excludeSharedLibs.Includes}
-	sharedExcludesLabelList := bazel.LabelListAttribute{}
-	sharedExcludesLabelList.SetSelectValue(bazel.InApexAxis, bazel.InApex, sharedExcludes)
-
-	la.dynamicDeps.Append(sharedExcludesLabelList)
-	la.implementationDynamicDeps.Append(sharedExcludesLabelList)
-
-	excludeStaticLibs := bazelLabelForStaticDeps(ctx, props.Target.Apex.Exclude_static_libs)
-	staticExcludes := bazel.LabelList{Excludes: excludeStaticLibs.Includes}
-	staticExcludesLabelList := bazel.LabelListAttribute{}
-	staticExcludesLabelList.SetSelectValue(bazel.InApexAxis, bazel.InApex, staticExcludes)
-
-	la.deps.Append(staticExcludesLabelList)
-	la.implementationDeps.Append(staticExcludesLabelList)
-}
-
-func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, module *Module, axis bazel.ConfigurationAxis, config string, props *BaseLinkerProperties) {
-	isBinary := module.Binary()
-	// Use a single variable to capture usage of nocrt in arch variants, so there's only 1 error message for this module
-	var axisFeatures []string
-
-	wholeStaticLibs := android.FirstUniqueStrings(props.Whole_static_libs)
-	staticLibs := android.FirstUniqueStrings(android.RemoveListFromList(props.Static_libs, wholeStaticLibs))
-	if axis == bazel.NoConfigAxis {
-		la.useVersionLib.SetSelectValue(axis, config, props.Use_version_lib)
-		if proptools.Bool(props.Use_version_lib) {
-			versionLibAlreadyInDeps := android.InList(versionLib, wholeStaticLibs)
-			// remove from static libs so there is no duplicate dependency
-			_, staticLibs = android.RemoveFromList(versionLib, staticLibs)
-			// only add the dep if it is not in progress
-			if !versionLibAlreadyInDeps {
-				wholeStaticLibs = append(wholeStaticLibs, versionLib)
-			}
-		}
-	}
-
-	// Excludes to parallel Soong:
-	// https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=247-249;drc=088b53577dde6e40085ffd737a1ae96ad82fc4b0
-	la.wholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, wholeStaticLibs, props.Exclude_static_libs))
-
-	if isBinary && module.StaticExecutable() {
-		usedSystemStatic := android.FilterListPred(staticLibs, func(s string) bool {
-			return android.InList(s, soongSystemSharedLibs) && !android.InList(s, props.Exclude_static_libs)
-		})
-
-		for _, el := range usedSystemStatic {
-			if la.usedSystemDynamicDepAsStaticDep == nil {
-				la.usedSystemDynamicDepAsStaticDep = map[string]bool{}
-			}
-			la.usedSystemDynamicDepAsStaticDep[el] = true
-		}
-	}
-	staticDeps := maybePartitionExportedAndImplementationsDepsExcludes(
-		ctx,
-		!isBinary,
-		staticLibs,
-		props.Exclude_static_libs,
-		props.Export_static_lib_headers,
-		bazelLabelForStaticDepsExcludes,
-	)
-
-	headerLibs := android.FirstUniqueStrings(props.Header_libs)
-	hDeps := maybePartitionExportedAndImplementationsDeps(ctx, !isBinary, headerLibs, props.Export_header_lib_headers, bazelLabelForHeaderDeps)
-
-	(&hDeps.export).Append(staticDeps.export)
-	la.deps.SetSelectValue(axis, config, hDeps.export)
-
-	(&hDeps.implementation).Append(staticDeps.implementation)
-	la.implementationDeps.SetSelectValue(axis, config, hDeps.implementation)
-
-	systemSharedLibs := props.System_shared_libs
-	// systemSharedLibs distinguishes between nil/empty list behavior:
-	//    nil -> use default values
-	//    empty list -> no values specified
-	if len(systemSharedLibs) > 0 {
-		systemSharedLibs = android.FirstUniqueStrings(systemSharedLibs)
-	}
-	la.systemDynamicDeps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, systemSharedLibs))
-
-	sharedLibs := android.FirstUniqueStrings(props.Shared_libs)
-	excludeSharedLibs := props.Exclude_shared_libs
-	usedSystem := android.FilterListPred(sharedLibs, func(s string) bool {
-		return android.InList(s, soongSystemSharedLibs) && !android.InList(s, excludeSharedLibs)
-	})
-
-	for _, el := range usedSystem {
-		if la.usedSystemDynamicDepAsDynamicDep == nil {
-			la.usedSystemDynamicDepAsDynamicDep = map[string]bool{}
-		}
-		la.usedSystemDynamicDepAsDynamicDep[el] = true
-	}
-
-	sharedDeps := maybePartitionExportedAndImplementationsDepsExcludes(
-		ctx,
-		!isBinary,
-		sharedLibs,
-		props.Exclude_shared_libs,
-		props.Export_shared_lib_headers,
-		bazelLabelForSharedDepsExcludes,
-	)
-	la.dynamicDeps.SetSelectValue(axis, config, sharedDeps.export)
-	la.implementationDynamicDeps.SetSelectValue(axis, config, sharedDeps.implementation)
-	la.resolveTargetApexProp(ctx, props)
-
-	if axis == bazel.NoConfigAxis || (axis == bazel.OsConfigurationAxis && config == bazel.OsAndroid) {
-		// If a dependency in la.implementationDynamicDeps or la.dynamicDeps has stubs, its
-		// stub variant should be used when the dependency is linked in a APEX. The
-		// dependencies in NoConfigAxis and OsConfigurationAxis/OsAndroid are grouped by
-		// having stubs or not, so Bazel select() statement can be used to choose
-		// source/stub variants of them.
-		apexAvailable := module.ApexAvailable()
-		setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0, false)
-		setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1, false)
-		if len(systemSharedLibs) > 0 {
-			setStubsForDynamicDeps(ctx, axis, config, apexAvailable, bazelLabelForSharedDeps(ctx, systemSharedLibs), &la.systemDynamicDeps, 2, true)
-		}
-	}
-
-	if !BoolDefault(props.Pack_relocations, packRelocationsDefault) {
-		axisFeatures = append(axisFeatures, "disable_pack_relocations")
-	}
-
-	if Bool(props.Allow_undefined_symbols) {
-		axisFeatures = append(axisFeatures, "-no_undefined_symbols")
-	}
-
-	var linkerFlags []string
-	if len(props.Ldflags) > 0 {
-		linkerFlags = append(linkerFlags, proptools.NinjaEscapeList(props.Ldflags)...)
-		// binaries remove static flag if -shared is in the linker flags
-		if isBinary && android.InList("-shared", linkerFlags) {
-			axisFeatures = append(axisFeatures, "-static_flag")
-		}
-	}
-
-	if !props.libCrt() {
-		axisFeatures = append(axisFeatures, "-use_libcrt")
-	}
-	if !props.crt() {
-		axisFeatures = append(axisFeatures, "-link_crt")
-	}
-
-	// This must happen before the addition of flags for Version Script and
-	// Dynamic List, as these flags must be split on spaces and those must not
-	linkerFlags = parseCommandLineFlags(linkerFlags, filterOutClangUnknownCflags)
-
-	additionalLinkerInputs := bazel.LabelList{}
-	if props.Version_script != nil {
-		label := android.BazelLabelForModuleSrcSingle(ctx, *props.Version_script)
-		additionalLinkerInputs.Add(&label)
-		linkerFlags = append(linkerFlags, fmt.Sprintf("-Wl,--version-script,$(location %s)", label.Label))
-		axisFeatures = append(axisFeatures, "android_cfi_exports_map")
-	}
-
-	if props.Dynamic_list != nil {
-		label := android.BazelLabelForModuleSrcSingle(ctx, *props.Dynamic_list)
-		additionalLinkerInputs.Add(&label)
-		linkerFlags = append(linkerFlags, fmt.Sprintf("-Wl,--dynamic-list,$(location %s)", label.Label))
-	}
-
-	la.additionalLinkerInputs.SetSelectValue(axis, config, additionalLinkerInputs)
-	if axis == bazel.OsConfigurationAxis && (config == bazel.OsDarwin || config == bazel.OsLinux || config == bazel.OsWindows) {
-		linkerFlags = append(linkerFlags, props.Host_ldlibs...)
-	}
-	la.linkopts.SetSelectValue(axis, config, linkerFlags)
-
-	if axisFeatures != nil {
-		la.features.SetSelectValue(axis, config, axisFeatures)
-	}
-
-	runtimeDeps := android.BazelLabelForModuleDepsExcludes(ctx, props.Runtime_libs, props.Exclude_runtime_libs)
-	if !runtimeDeps.IsEmpty() {
-		la.runtimeDeps.SetSelectValue(axis, config, runtimeDeps)
-	}
-}
-
-var (
-	apiSurfaceModuleLibCurrentPackage = "@api_surfaces//" + android.ModuleLibApi.String() + "/current:"
-)
-
-func availableToSameApexes(a, b []string) bool {
-	if len(a) == 0 && len(b) == 0 {
-		return true
-	}
-	differ, _, _ := android.ListSetDifference(a, b)
-	return !differ
-}
-
-var (
-	apiDomainConfigSettingKey  = android.NewOnceKey("apiDomainConfigSettingKey")
-	apiDomainConfigSettingLock sync.Mutex
-)
-
-func getApiDomainConfigSettingMap(config android.Config) *map[string]bool {
-	return config.Once(apiDomainConfigSettingKey, func() interface{} {
-		return &map[string]bool{}
-	}).(*map[string]bool)
-}
-
-var (
-	testApexNameToApiDomain = map[string]string{
-		"test_broken_com.android.art": "com.android.art",
-	}
-)
-
-// GetApiDomain returns the canonical name of the apex. This is synonymous to the apex_name definition.
-// https://cs.android.com/android/_/android/platform/build/soong/+/e3f0281b8897da1fe23b2f4f3a05f1dc87bcc902:apex/prebuilt.go;l=81-83;drc=2dc7244af985a6ad701b22f1271e606cabba527f;bpv=1;bpt=0
-// For test apexes, it uses a naming convention heuristic to determine the api domain.
-// TODO (b/281548611): Move this build/soong/android
-func GetApiDomain(apexName string) string {
-	if apiDomain, exists := testApexNameToApiDomain[apexName]; exists {
-		return apiDomain
-	}
-	// Remove `test_` prefix
-	return strings.TrimPrefix(apexName, "test_")
-}
-
-// Create a config setting for this apex in build/bazel/rules/apex
-// The use case for this is stub/impl selection in cc libraries
-// Long term, these config_setting(s) should be colocated with the respective apex definitions.
-// Note that this is an anti-pattern: The config_setting should be created from the apex definition
-// and not from a cc_library.
-// This anti-pattern is needed today since not all apexes have been allowlisted.
-func createInApexConfigSetting(ctx android.TopDownMutatorContext, apexName string) {
-	if apexName == android.AvailableToPlatform || apexName == android.AvailableToAnyApex {
-		// These correspond to android-non_apex and android-in_apex
-		return
-	}
-	apiDomainConfigSettingLock.Lock()
-	defer apiDomainConfigSettingLock.Unlock()
-
-	// Return if a config_setting has already been created
-	apiDomain := GetApiDomain(apexName)
-	acsm := getApiDomainConfigSettingMap(ctx.Config())
-	if _, exists := (*acsm)[apiDomain]; exists {
-		return
-	}
-	(*acsm)[apiDomain] = true
-
-	csa := bazel.ConfigSettingAttributes{
-		Flag_values: bazel.StringMapAttribute{
-			"//build/bazel/rules/apex:api_domain": apiDomain,
-		},
-		// Constraint this to android
-		Constraint_values: bazel.MakeLabelListAttribute(
-			bazel.MakeLabelList(
-				[]bazel.Label{
-					bazel.Label{Label: "//build/bazel/platforms/os:android"},
-				},
-			),
-		),
-	}
-	ca := android.CommonAttributes{
-		Name: apiDomain,
-	}
-	ctx.CreateBazelConfigSetting(
-		csa,
-		ca,
-		"build/bazel/rules/apex",
-	)
-}
-
-func inApexConfigSetting(apexAvailable string) string {
-	if apexAvailable == android.AvailableToPlatform {
-		return bazel.AndroidPlatform
-	}
-	if apexAvailable == android.AvailableToAnyApex {
-		return bazel.AndroidAndInApex
-	}
-	apiDomain := GetApiDomain(apexAvailable)
-	return "//build/bazel/rules/apex:" + apiDomain
-}
-
-// Inputs to stub vs impl selection.
-type stubSelectionInfo struct {
-	// Label of the implementation library (e.g. //bionic/libc:libc)
-	impl bazel.Label
-	// Axis containing the implementation library
-	axis bazel.ConfigurationAxis
-	// Axis key containing the implementation library
-	config string
-	// API domain of the apex
-	// For test apexes (test_com.android.foo), this will be the source apex (com.android.foo)
-	apiDomain string
-	// List of dep labels
-	dynamicDeps *bazel.LabelListAttribute
-	// Boolean value for determining if the dep is in the same api domain
-	// If false, the label will be rewritten to to the stub label
-	sameApiDomain bool
-}
-
-func useStubOrImplInApexWithName(ssi stubSelectionInfo) {
-	lib := ssi.impl
-	if !ssi.sameApiDomain {
-		lib = bazel.Label{
-			Label: apiSurfaceModuleLibCurrentPackage + strings.TrimPrefix(lib.OriginalModuleName, ":"),
-		}
-	}
-	// Create a select statement specific to this apex
-	inApexSelectValue := ssi.dynamicDeps.SelectValue(bazel.OsAndInApexAxis, inApexConfigSetting(ssi.apiDomain))
-	(&inApexSelectValue).Append(bazel.MakeLabelList([]bazel.Label{lib}))
-	ssi.dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, inApexConfigSetting(ssi.apiDomain), bazel.FirstUniqueBazelLabelList(inApexSelectValue))
-	// Delete the library from the common config for this apex
-	implDynamicDeps := ssi.dynamicDeps.SelectValue(ssi.axis, ssi.config)
-	implDynamicDeps = bazel.SubtractBazelLabelList(implDynamicDeps, bazel.MakeLabelList([]bazel.Label{ssi.impl}))
-	ssi.dynamicDeps.SetSelectValue(ssi.axis, ssi.config, implDynamicDeps)
-	if ssi.axis == bazel.NoConfigAxis {
-		// Set defaults. Defaults (i.e. host) should use impl and not stubs.
-		defaultSelectValue := ssi.dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey)
-		(&defaultSelectValue).Append(bazel.MakeLabelList([]bazel.Label{ssi.impl}))
-		ssi.dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.FirstUniqueBazelLabelList(defaultSelectValue))
-	}
-}
-
-func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
-	config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) {
-
-	// Create a config_setting for each apex_available.
-	// This will be used to select impl of a dep if dep is available to the same apex.
-	for _, aa := range apexAvailable {
-		createInApexConfigSetting(ctx.(android.TopDownMutatorContext), aa)
-	}
-
-	apiDomainForSelects := []string{}
-	for _, apex := range apexAvailable {
-		apiDomainForSelects = append(apiDomainForSelects, GetApiDomain(apex))
-	}
-	// Always emit a select statement for the platform variant.
-	// This ensures that b build //foo --config=android works
-	// Soong always creates a platform variant even when the library might not be available to platform.
-	if !android.InList(android.AvailableToPlatform, apiDomainForSelects) {
-		apiDomainForSelects = append(apiDomainForSelects, android.AvailableToPlatform)
-	}
-	apiDomainForSelects = android.SortedUniqueStrings(apiDomainForSelects)
-
-	// Create a select for each apex this library could be included in.
-	for _, l := range dynamicLibs.Includes {
-		dep, _ := ctx.ModuleFromName(l.OriginalModuleName)
-		if c, ok := dep.(*Module); !ok || !c.HasStubsVariants() {
-			continue
-		}
-		// TODO (b/280339069): Decrease the verbosity of the generated BUILD files
-		for _, apiDomain := range apiDomainForSelects {
-			var sameApiDomain bool
-			if apiDomain == android.AvailableToPlatform {
-				// Platform variants in Soong use equality of apex_available for stub/impl selection.
-				// https://cs.android.com/android/_/android/platform/build/soong/+/316b0158fe57ee7764235923e7c6f3d530da39c6:cc/cc.go;l=3393-3404;drc=176271a426496fa2688efe2b40d5c74340c63375;bpv=1;bpt=0
-				// One of the factors behind this design choice is cc_test
-				// Tests only have a platform variant, and using equality of apex_available ensures
-				// that tests of an apex library gets its implementation and not stubs.
-				// TODO (b/280343104): Discuss if we can drop this special handling for platform variants.
-				sameApiDomain = availableToSameApexes(apexAvailable, dep.(*Module).ApexAvailable())
-				if linkable, ok := ctx.Module().(LinkableInterface); ok && linkable.Bootstrap() {
-					sameApiDomain = true
-				}
-			} else {
-				sameApiDomain = android.InList(apiDomain, dep.(*Module).ApexAvailable())
-			}
-			ssi := stubSelectionInfo{
-				impl:          l,
-				axis:          axis,
-				config:        config,
-				apiDomain:     apiDomain,
-				dynamicDeps:   dynamicDeps,
-				sameApiDomain: sameApiDomain,
-			}
-			useStubOrImplInApexWithName(ssi)
-		}
-	}
-}
-
-func (la *linkerAttributes) convertStripProps(ctx android.BazelConversionPathContext, module *Module) {
-	bp2BuildPropParseHelper(ctx, module, &StripProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
-		if stripProperties, ok := props.(*StripProperties); ok {
-			la.stripKeepSymbols.SetSelectValue(axis, config, stripProperties.Strip.Keep_symbols)
-			la.stripKeepSymbolsList.SetSelectValue(axis, config, stripProperties.Strip.Keep_symbols_list)
-			la.stripKeepSymbolsAndDebugFrame.SetSelectValue(axis, config, stripProperties.Strip.Keep_symbols_and_debug_frame)
-			la.stripAll.SetSelectValue(axis, config, stripProperties.Strip.All)
-			la.stripNone.SetSelectValue(axis, config, stripProperties.Strip.None)
-		}
-	})
-}
-
-func (la *linkerAttributes) convertProductVariables(ctx android.BazelConversionPathContext, productVariableProps android.ProductConfigProperties) {
-
-	type productVarDep struct {
-		// the name of the corresponding excludes field, if one exists
-		excludesField string
-		// reference to the bazel attribute that should be set for the given product variable config
-		attribute *bazel.LabelListAttribute
-
-		depResolutionFunc func(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList
-	}
-
-	// an intermediate attribute that holds Header_libs info, and will be appended to
-	// implementationDeps at the end, to solve the confliction that both header_libs
-	// and static_libs use implementationDeps.
-	var headerDeps bazel.LabelListAttribute
-
-	productVarToDepFields := map[string]productVarDep{
-		// product variables do not support exclude_shared_libs
-		"Shared_libs":       {attribute: &la.implementationDynamicDeps, depResolutionFunc: bazelLabelForSharedDepsExcludes},
-		"Static_libs":       {"Exclude_static_libs", &la.implementationDeps, bazelLabelForStaticDepsExcludes},
-		"Whole_static_libs": {"Exclude_static_libs", &la.wholeArchiveDeps, bazelLabelForWholeDepsExcludes},
-		"Header_libs":       {attribute: &headerDeps, depResolutionFunc: bazelLabelForHeaderDepsExcludes},
-	}
-
-	for name, dep := range productVarToDepFields {
-		props, exists := productVariableProps[name]
-		excludeProps, excludesExists := productVariableProps[dep.excludesField]
-		// if neither an include nor excludes property exists, then skip it
-		if !exists && !excludesExists {
-			continue
-		}
-		// Collect all the configurations that an include or exclude property exists for.
-		// We want to iterate all configurations rather than either the include or exclude because, for a
-		// particular configuration, we may have either only an include or an exclude to handle.
-		productConfigProps := make(map[android.ProductConfigOrSoongConfigProperty]bool, len(props)+len(excludeProps))
-		for p := range props {
-			productConfigProps[p] = true
-		}
-		for p := range excludeProps {
-			productConfigProps[p] = true
-		}
-
-		for productConfigProp := range productConfigProps {
-			prop, includesExists := props[productConfigProp]
-			excludesProp, excludesExists := excludeProps[productConfigProp]
-			var includes, excludes []string
-			var ok bool
-			// if there was no includes/excludes property, casting fails and that's expected
-			if includes, ok = prop.([]string); includesExists && !ok {
-				ctx.ModuleErrorf("Could not convert product variable %s property", name)
-			}
-			if excludes, ok = excludesProp.([]string); excludesExists && !ok {
-				ctx.ModuleErrorf("Could not convert product variable %s property", dep.excludesField)
-			}
-
-			dep.attribute.EmitEmptyList = productConfigProp.AlwaysEmit()
-			dep.attribute.SetSelectValue(
-				productConfigProp.ConfigurationAxis(),
-				productConfigProp.SelectKey(),
-				dep.depResolutionFunc(ctx, android.FirstUniqueStrings(includes), excludes),
-			)
-		}
-	}
-	la.implementationDeps.Append(headerDeps)
-}
-
-func (la *linkerAttributes) finalize(ctx android.BazelConversionPathContext) {
-	// if system dynamic deps have the default value, any use of a system dynamic library used will
-	// result in duplicate library errors for bionic OSes. Here, we explicitly exclude those libraries
-	// from bionic OSes and the no config case as these libraries only build for bionic OSes.
-	if la.systemDynamicDeps.IsNil() && len(la.usedSystemDynamicDepAsDynamicDep) > 0 {
-		toRemove := bazelLabelForSharedDeps(ctx, android.SortedKeys(la.usedSystemDynamicDepAsDynamicDep))
-		la.dynamicDeps.Exclude(bazel.NoConfigAxis, "", toRemove)
-		la.dynamicDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove)
-		la.dynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove)
-		la.implementationDynamicDeps.Exclude(bazel.NoConfigAxis, "", toRemove)
-		la.implementationDynamicDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove)
-		la.implementationDynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove)
-
-		la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, toRemove)
-		stubsToRemove := make([]bazel.Label, 0, len(la.usedSystemDynamicDepAsDynamicDep))
-		for _, lib := range toRemove.Includes {
-			stubLabelInApiSurfaces := bazel.Label{
-				Label: apiSurfaceModuleLibCurrentPackage + lib.OriginalModuleName,
-			}
-			stubsToRemove = append(stubsToRemove, stubLabelInApiSurfaces)
-		}
-		// system libraries (e.g. libc, libm, libdl) belong the com.android.runtime api domain
-		// dedupe the stubs of these libraries from the other api domains (platform, other_apexes...)
-		for _, aa := range ctx.Module().(*Module).ApexAvailable() {
-			la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, inApexConfigSetting(aa), bazel.MakeLabelList(stubsToRemove))
-		}
-		la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidPlatform, bazel.MakeLabelList(stubsToRemove))
-	}
-	if la.systemDynamicDeps.IsNil() && len(la.usedSystemDynamicDepAsStaticDep) > 0 {
-		toRemove := bazelLabelForStaticDeps(ctx, android.SortedKeys(la.usedSystemDynamicDepAsStaticDep))
-		la.deps.Exclude(bazel.NoConfigAxis, "", toRemove)
-		la.deps.Exclude(bazel.OsConfigurationAxis, "android", toRemove)
-		la.deps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove)
-		la.implementationDeps.Exclude(bazel.NoConfigAxis, "", toRemove)
-		la.implementationDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove)
-		la.implementationDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove)
-	}
-
-	la.deps.ResolveExcludes()
-	la.implementationDeps.ResolveExcludes()
-	la.dynamicDeps.ResolveExcludes()
-	la.implementationDynamicDeps.ResolveExcludes()
-	la.wholeArchiveDeps.ResolveExcludes()
-	la.systemDynamicDeps.ForceSpecifyEmptyList = true
-
-}
-
-// Relativize a list of root-relative paths with respect to the module's
-// directory.
-//
-// include_dirs Soong prop are root-relative (b/183742505), but
-// local_include_dirs, export_include_dirs and export_system_include_dirs are
-// module dir relative. This function makes a list of paths entirely module dir
-// relative.
-//
-// For the `include` attribute, Bazel wants the paths to be relative to the
-// module.
-func bp2BuildMakePathsRelativeToModule(ctx android.BazelConversionPathContext, paths []string) []string {
-	var relativePaths []string
-	for _, path := range paths {
-		// Semantics of filepath.Rel: join(ModuleDir, rel(ModuleDir, path)) == path
-		relativePath, err := filepath.Rel(ctx.ModuleDir(), path)
-		if err != nil {
-			panic(err)
-		}
-		relativePaths = append(relativePaths, relativePath)
-	}
-	return relativePaths
-}
-
-// BazelIncludes contains information about -I and -isystem paths from a module converted to Bazel
-// attributes.
-type BazelIncludes struct {
-	AbsoluteIncludes bazel.StringListAttribute
-	Includes         bazel.StringListAttribute
-	SystemIncludes   bazel.StringListAttribute
-}
-
-func bp2BuildParseExportedIncludes(ctx android.BazelConversionPathContext, module *Module, includes *BazelIncludes) BazelIncludes {
-	var exported BazelIncludes
-	if includes != nil {
-		exported = *includes
-	} else {
-		exported = BazelIncludes{}
-	}
-
-	// cc library Export_include_dirs and Export_system_include_dirs are marked
-	// "variant_prepend" in struct tag, set their prepend property to true to make
-	// sure bp2build generates correct result.
-	exported.Includes.Prepend = true
-	exported.SystemIncludes.Prepend = true
-
-	bp2BuildPropParseHelper(ctx, module, &FlagExporterProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
-		if flagExporterProperties, ok := props.(*FlagExporterProperties); ok {
-			if len(flagExporterProperties.Export_include_dirs) > 0 {
-				exported.Includes.SetSelectValue(axis, config, android.FirstUniqueStrings(append(exported.Includes.SelectValue(axis, config), flagExporterProperties.Export_include_dirs...)))
-			}
-			if len(flagExporterProperties.Export_system_include_dirs) > 0 {
-				exported.SystemIncludes.SetSelectValue(axis, config, android.FirstUniqueStrings(append(exported.SystemIncludes.SelectValue(axis, config), flagExporterProperties.Export_system_include_dirs...)))
-			}
-		}
-	})
-	exported.AbsoluteIncludes.DeduplicateAxesFromBase()
-	exported.Includes.DeduplicateAxesFromBase()
-	exported.SystemIncludes.DeduplicateAxesFromBase()
-
-	return exported
-}
-
-func BazelLabelNameForStaticModule(baseLabel string) string {
-	return baseLabel + "_bp2build_cc_library_static"
-}
-
-func bazelLabelForStaticModule(ctx android.BazelConversionPathContext, m blueprint.Module) string {
-	label := android.BazelModuleLabel(ctx, m)
-	if ccModule, ok := m.(*Module); ok && ccModule.typ() == fullLibrary {
-		return BazelLabelNameForStaticModule(label)
-	}
-	return label
-}
-
-func bazelLabelForSharedModule(ctx android.BazelConversionPathContext, m blueprint.Module) string {
-	// cc_library, at it's root name, propagates the shared library, which depends on the static
-	// library.
-	return android.BazelModuleLabel(ctx, m)
-}
-
-func bazelLabelForStaticWholeModuleDeps(ctx android.BazelConversionPathContext, m blueprint.Module) string {
-	label := bazelLabelForStaticModule(ctx, m)
-	if aModule, ok := m.(android.Module); ok {
-		if android.IsModulePrebuilt(aModule) {
-			label += "_alwayslink"
-		}
-	}
-	return label
-}
-
-func xsdConfigCppTarget(xsd android.XsdConfigBp2buildTargets) string {
-	return xsd.CppBp2buildTargetName()
-}
-
-func bazelLabelForWholeDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticWholeModuleDeps)
-}
-
-func bazelLabelForWholeDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForStaticWholeModuleDeps)
-}
-
-func bazelLabelForStaticDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForStaticModule)
-}
-
-func bazelLabelForStaticDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticModule)
-}
-
-func bazelLabelForSharedDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForSharedModule)
-}
-
-func bazelLabelForHeaderDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
-	// This is not elegant, but bp2build's shared library targets only propagate
-	// their header information as part of the normal C++ provider.
-	return bazelLabelForSharedDeps(ctx, modules)
-}
-
-func bazelLabelForHeaderDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
-	// This is only used when product_variable header_libs is processed, to follow
-	// the pattern of depResolutionFunc
-	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForSharedModule)
-}
-
-func bazelLabelForSharedDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForSharedModule)
-}
-
-type binaryLinkerAttrs struct {
-	Linkshared *bool
-	Stem       bazel.StringAttribute
-	Suffix     bazel.StringAttribute
-}
-
-func bp2buildBinaryLinkerProps(ctx android.BazelConversionPathContext, m *Module) binaryLinkerAttrs {
-	attrs := binaryLinkerAttrs{}
-	bp2BuildPropParseHelper(ctx, m, &BinaryLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
-		linkerProps := props.(*BinaryLinkerProperties)
-		staticExecutable := linkerProps.Static_executable
-		if axis == bazel.NoConfigAxis {
-			if linkBinaryShared := !proptools.Bool(staticExecutable); !linkBinaryShared {
-				attrs.Linkshared = &linkBinaryShared
-			}
-		} else if staticExecutable != nil {
-			// TODO(b/202876379): Static_executable is arch-variant; however, linkshared is a
-			// nonconfigurable attribute. Only 4 AOSP modules use this feature, defer handling
-			ctx.ModuleErrorf("bp2build cannot migrate a module with arch/target-specific static_executable values")
-		}
-		if stem := linkerProps.Stem; stem != nil {
-			attrs.Stem.SetSelectValue(axis, config, stem)
-		}
-		if suffix := linkerProps.Suffix; suffix != nil {
-			attrs.Suffix.SetSelectValue(axis, config, suffix)
-		}
-	})
-
-	return attrs
-}
-
-func bp2buildSanitizerFeatures(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute {
-	sanitizerFeatures := bazel.StringListAttribute{}
-	bp2BuildPropParseHelper(ctx, m, &SanitizeProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
-		var features []string
-		if sanitizerProps, ok := props.(*SanitizeProperties); ok {
-			if sanitizerProps.Sanitize.Integer_overflow != nil && *sanitizerProps.Sanitize.Integer_overflow {
-				features = append(features, "ubsan_integer_overflow")
-			}
-			for _, sanitizer := range sanitizerProps.Sanitize.Misc_undefined {
-				features = append(features, "ubsan_"+sanitizer)
-			}
-			blocklist := sanitizerProps.Sanitize.Blocklist
-			if blocklist != nil {
-				// Format the blocklist name to be used in a feature name
-				blocklistFeatureSuffix := strings.Replace(strings.ToLower(*blocklist), ".", "_", -1)
-				features = append(features, "sanitizer_blocklist_"+blocklistFeatureSuffix)
-			}
-			if sanitizerProps.Sanitize.Cfi != nil && !proptools.Bool(sanitizerProps.Sanitize.Cfi) {
-				features = append(features, "-android_cfi")
-			} else if proptools.Bool(sanitizerProps.Sanitize.Cfi) {
-				features = append(features, "android_cfi")
-				if proptools.Bool(sanitizerProps.Sanitize.Config.Cfi_assembly_support) {
-					features = append(features, "android_cfi_assembly_support")
-				}
-			}
-			sanitizerFeatures.SetSelectValue(axis, config, features)
-		}
-	})
-	return sanitizerFeatures
-}
-
-func bp2buildLtoFeatures(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute {
-	lto_feature_name := "android_thin_lto"
-	ltoBoolFeatures := bazel.BoolAttribute{}
-	bp2BuildPropParseHelper(ctx, m, &LTOProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
-		if ltoProps, ok := props.(*LTOProperties); ok {
-			thinProp := ltoProps.Lto.Thin != nil && *ltoProps.Lto.Thin
-			thinPropSetToFalse := ltoProps.Lto.Thin != nil && !*ltoProps.Lto.Thin
-			neverProp := ltoProps.Lto.Never != nil && *ltoProps.Lto.Never
-			if thinProp {
-				ltoBoolFeatures.SetSelectValue(axis, config, BoolPtr(true))
-				return
-			}
-			if neverProp || thinPropSetToFalse {
-				if thinProp {
-					ctx.ModuleErrorf("lto.thin and lto.never are mutually exclusive but were specified together")
-				} else {
-					ltoBoolFeatures.SetSelectValue(axis, config, BoolPtr(false))
-				}
-				return
-			}
-		}
-		ltoBoolFeatures.SetSelectValue(axis, config, nil)
-	})
-
-	props := m.GetArchVariantProperties(ctx, &LTOProperties{})
-	ltoStringFeatures, err := ltoBoolFeatures.ToStringListAttribute(func(boolPtr *bool, axis bazel.ConfigurationAxis, config string) []string {
-		if boolPtr == nil {
-			return []string{}
-		}
-		if !*boolPtr {
-			return []string{"-" + lto_feature_name}
-		}
-		features := []string{lto_feature_name}
-		if ltoProps, ok := props[axis][config].(*LTOProperties); ok {
-			if ltoProps.Whole_program_vtables != nil && *ltoProps.Whole_program_vtables {
-				features = append(features, "android_thin_lto_whole_program_vtables")
-			}
-		}
-		return features
-	})
-	if err != nil {
-		ctx.ModuleErrorf("Error processing LTO attributes: %s", err)
-	}
-	return ltoStringFeatures
-}
-
-func convertHiddenVisibilityToFeatureBase(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute {
-	visibilityHiddenFeature := bazel.StringListAttribute{}
-	bp2BuildPropParseHelper(ctx, m, &BaseCompilerProperties{}, func(axis bazel.ConfigurationAxis, configString string, props interface{}) {
-		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
-			convertHiddenVisibilityToFeatureHelper(&visibilityHiddenFeature, axis, configString, baseCompilerProps.Cflags)
-		}
-	})
-	return visibilityHiddenFeature
-}
-
-func convertHiddenVisibilityToFeatureStaticOrShared(ctx android.BazelConversionPathContext, m *Module, isStatic bool) bazel.StringListAttribute {
-	visibilityHiddenFeature := bazel.StringListAttribute{}
-	if isStatic {
-		bp2BuildPropParseHelper(ctx, m, &StaticProperties{}, func(axis bazel.ConfigurationAxis, configString string, props interface{}) {
-			if staticProps, ok := props.(*StaticProperties); ok {
-				convertHiddenVisibilityToFeatureHelper(&visibilityHiddenFeature, axis, configString, staticProps.Static.Cflags)
-			}
-		})
-	} else {
-		bp2BuildPropParseHelper(ctx, m, &SharedProperties{}, func(axis bazel.ConfigurationAxis, configString string, props interface{}) {
-			if sharedProps, ok := props.(*SharedProperties); ok {
-				convertHiddenVisibilityToFeatureHelper(&visibilityHiddenFeature, axis, configString, sharedProps.Shared.Cflags)
-			}
-		})
-	}
-
-	return visibilityHiddenFeature
-}
-
-func convertHiddenVisibilityToFeatureHelper(feature *bazel.StringListAttribute, axis bazel.ConfigurationAxis, configString string, cflags []string) {
-	if inList(config.VisibilityHiddenFlag, cflags) {
-		feature.SetSelectValue(axis, configString, []string{"visibility_hidden"})
-	}
-}
diff --git a/cc/builder.go b/cc/builder.go
index f5e0dcc..e78b8c0 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -375,13 +375,14 @@
 	localCppFlags        string
 	localLdFlags         string
 
-	libFlags      string // Flags to add to the linker directly after specifying libraries to link.
-	extraLibFlags string // Flags to add to the linker last.
-	tidyFlags     string // Flags that apply to clang-tidy
-	sAbiFlags     string // Flags that apply to header-abi-dumps
-	aidlFlags     string // Flags that apply to aidl source files
-	rsFlags       string // Flags that apply to renderscript source files
-	toolchain     config.Toolchain
+	noOverrideFlags string // Flags appended at the end so they are not overridden.
+	libFlags        string // Flags to add to the linker directly after specifying libraries to link.
+	extraLibFlags   string // Flags to add to the linker last.
+	tidyFlags       string // Flags that apply to clang-tidy
+	sAbiFlags       string // Flags that apply to header-abi-dumps
+	aidlFlags       string // Flags that apply to aidl source files
+	rsFlags         string // Flags that apply to renderscript source files
+	toolchain       config.Toolchain
 
 	// True if these extra features are enabled.
 	tidy          bool
@@ -485,7 +486,8 @@
 		flags.localCommonFlags + " " +
 		flags.localToolingCFlags + " " +
 		flags.localConlyFlags + " " +
-		flags.systemIncludeFlags
+		flags.systemIncludeFlags + " " +
+		flags.noOverrideFlags
 
 	cflags := flags.globalCommonFlags + " " +
 		flags.globalCFlags + " " +
@@ -493,7 +495,8 @@
 		flags.localCommonFlags + " " +
 		flags.localCFlags + " " +
 		flags.localConlyFlags + " " +
-		flags.systemIncludeFlags
+		flags.systemIncludeFlags + " " +
+		flags.noOverrideFlags
 
 	toolingCppflags := flags.globalCommonFlags + " " +
 		flags.globalToolingCFlags + " " +
@@ -501,7 +504,8 @@
 		flags.localCommonFlags + " " +
 		flags.localToolingCFlags + " " +
 		flags.localToolingCppFlags + " " +
-		flags.systemIncludeFlags
+		flags.systemIncludeFlags + " " +
+		flags.noOverrideFlags
 
 	cppflags := flags.globalCommonFlags + " " +
 		flags.globalCFlags + " " +
@@ -509,7 +513,8 @@
 		flags.localCommonFlags + " " +
 		flags.localCFlags + " " +
 		flags.localCppFlags + " " +
-		flags.systemIncludeFlags
+		flags.systemIncludeFlags + " " +
+		flags.noOverrideFlags
 
 	asflags := flags.globalCommonFlags + " " +
 		flags.globalAsFlags + " " +
@@ -522,26 +527,6 @@
 		sAbiDumpFiles = make(android.Paths, 0, len(srcFiles))
 	}
 
-	cflags += " ${config.NoOverrideGlobalCflags}"
-	toolingCflags += " ${config.NoOverrideGlobalCflags}"
-	cppflags += " ${config.NoOverrideGlobalCflags}"
-	toolingCppflags += " ${config.NoOverrideGlobalCflags}"
-
-	if flags.toolchain.Is64Bit() {
-		cflags += " ${config.NoOverride64GlobalCflags}"
-		toolingCflags += " ${config.NoOverride64GlobalCflags}"
-		cppflags += " ${config.NoOverride64GlobalCflags}"
-		toolingCppflags += " ${config.NoOverride64GlobalCflags}"
-	}
-
-	modulePath := android.PathForModuleSrc(ctx).String()
-	if android.IsThirdPartyPath(modulePath) {
-		cflags += " ${config.NoOverrideExternalGlobalCflags}"
-		toolingCflags += " ${config.NoOverrideExternalGlobalCflags}"
-		cppflags += " ${config.NoOverrideExternalGlobalCflags}"
-		toolingCppflags += " ${config.NoOverrideExternalGlobalCflags}"
-	}
-
 	// Multiple source files have build rules usually share the same cFlags or tidyFlags.
 	// Define only one version in this module and share it in multiple build rules.
 	// To simplify the code, the shared variables are all named as $flags<nnn>.
@@ -681,16 +666,11 @@
 			tidyCmd := "${config.ClangBin}/clang-tidy"
 
 			rule := clangTidy
-			reducedCFlags := moduleFlags
 			if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CLANG_TIDY") {
 				rule = clangTidyRE
-				// b/248371171, work around RBE input processor problem
-				// some cflags rejected by input processor, but usually
-				// do not affect included files or clang-tidy
-				reducedCFlags = config.TidyReduceCFlags(reducedCFlags)
 			}
 
-			sharedCFlags := shareFlags("cFlags", reducedCFlags)
+			sharedCFlags := shareFlags("cFlags", moduleFlags)
 			srcRelPath := srcFile.Rel()
 
 			// Add the .tidy rule
@@ -874,13 +854,15 @@
 // Generate a rule to combine .dump sAbi dump files from multiple source files
 // into a single .ldump sAbi dump file
 func transformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths, soFile android.Path,
-	baseName, exportedHeaderFlags string, symbolFile android.OptionalPath,
-	excludedSymbolVersions, excludedSymbolTags []string) android.OptionalPath {
+	baseName string, exportedIncludeDirs []string, symbolFile android.OptionalPath,
+	excludedSymbolVersions, excludedSymbolTags, includedSymbolTags []string,
+	api string, isLlndk bool) android.Path {
 
 	outputFile := android.PathForModuleOut(ctx, baseName+".lsdump")
 
 	implicits := android.Paths{soFile}
 	symbolFilterStr := "-so " + soFile.String()
+	exportedHeaderFlags := android.JoinWithPrefix(exportedIncludeDirs, "-I")
 
 	if symbolFile.Valid() {
 		implicits = append(implicits, symbolFile.Path())
@@ -892,6 +874,17 @@
 	for _, tag := range excludedSymbolTags {
 		symbolFilterStr += " --exclude-symbol-tag " + tag
 	}
+	for _, tag := range includedSymbolTags {
+		symbolFilterStr += " --include-symbol-tag " + tag
+	}
+	if isLlndk {
+		symbolFilterStr += " --symbol-tag-policy MatchTagOnly"
+	}
+	apiLevelsJson := android.GetApiLevelsJson(ctx)
+	implicits = append(implicits, apiLevelsJson)
+	symbolFilterStr += " --api-map " + apiLevelsJson.String()
+	symbolFilterStr += " --api " + api
+
 	rule := sAbiLink
 	args := map[string]string{
 		"symbolFilter":        symbolFilterStr,
@@ -900,13 +893,7 @@
 	}
 	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ABI_LINKER") {
 		rule = sAbiLinkRE
-		rbeImplicits := implicits.Strings()
-		for _, p := range strings.Split(exportedHeaderFlags, " ") {
-			if len(p) > 2 {
-				// Exclude the -I prefix.
-				rbeImplicits = append(rbeImplicits, p[2:])
-			}
-		}
+		rbeImplicits := append(implicits.Strings(), exportedIncludeDirs...)
 		args["implicitInputs"] = strings.Join(rbeImplicits, ",")
 	}
 	ctx.Build(pctx, android.BuildParams{
@@ -917,7 +904,7 @@
 		Implicits:   implicits,
 		Args:        args,
 	})
-	return android.OptionalPathForPath(outputFile)
+	return outputFile
 }
 
 func transformAbiDumpToAbiDiff(ctx android.ModuleContext, inputDump, referenceDump android.Path,
@@ -1051,6 +1038,9 @@
 	if flags.StripKeepSymbolsAndDebugFrame {
 		args += " --keep-symbols-and-debug-frame"
 	}
+	if ctx.Windows() {
+		args += " --windows"
+	}
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        strip,
diff --git a/cc/cc.go b/cc/cc.go
index 3b92696..e3954d7 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -24,19 +24,17 @@
 	"strconv"
 	"strings"
 
-	"android/soong/ui/metrics/bp2build_metrics_proto"
+	"android/soong/testing"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/aidl_library"
 	"android/soong/android"
-	"android/soong/bazel/cquery"
 	"android/soong/cc/config"
 	"android/soong/fuzz"
 	"android/soong/genrule"
 	"android/soong/multitree"
-	"android/soong/snapshot"
 )
 
 func init() {
@@ -56,7 +54,6 @@
 		ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel()
 		ctx.BottomUp("version", versionMutator).Parallel()
 		ctx.BottomUp("begin", BeginMutator).Parallel()
-		ctx.BottomUp("fdo_profile", fdoProfileMutator)
 	})
 
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
@@ -69,16 +66,13 @@
 
 		ctx.TopDown("fuzz_deps", fuzzMutatorDeps)
 
-		ctx.BottomUp("coverage", coverageMutator).Parallel()
+		ctx.Transition("coverage", &coverageTransitionMutator{})
 
-		ctx.TopDown("afdo_deps", afdoDepsMutator)
-		ctx.BottomUp("afdo", afdoMutator).Parallel()
+		ctx.Transition("afdo", &afdoTransitionMutator{})
 
-		ctx.TopDown("orderfile_deps", orderfileDepsMutator)
-		ctx.BottomUp("orderfile", orderfileMutator).Parallel()
+		ctx.Transition("orderfile", &orderfileTransitionMutator{})
 
-		ctx.TopDown("lto_deps", ltoDepsMutator)
-		ctx.BottomUp("lto", ltoMutator).Parallel()
+		ctx.Transition("lto", &ltoTransitionMutator{})
 
 		ctx.BottomUp("check_linktype", checkLinkTypeMutator).Parallel()
 		ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
@@ -140,6 +134,14 @@
 
 	// List of libs that need to be excluded for APEX variant
 	ExcludeLibsForApex []string
+	// List of libs that need to be excluded for non-APEX variant
+	ExcludeLibsForNonApex []string
+
+	// LLNDK headers for the ABI checker to check LLNDK implementation library.
+	// An LLNDK implementation is the core variant. LLNDK header libs are reexported by the vendor variant.
+	// The core variant cannot depend on the vendor variant because of the order of CreateVariations.
+	// Instead, the LLNDK implementation depends on the LLNDK header libs.
+	LlndkHeaderLibs []string
 }
 
 // PathDeps is a struct containing file paths to dependencies of a module.
@@ -195,6 +197,10 @@
 
 	// Paths to direct srcs and transitive include dirs from direct aidl_library deps
 	AidlLibraryInfos []aidl_library.AidlLibraryInfo
+
+	// LLNDK headers for the ABI checker to check LLNDK implementation library.
+	LlndkIncludeDirs       android.Paths
+	LlndkSystemIncludeDirs android.Paths
 }
 
 // LocalOrGlobalFlags contains flags that need to have values set globally by the build system or locally by the module
@@ -218,7 +224,8 @@
 	// Local flags (which individual modules are responsible for). These may override global flags.
 	Local LocalOrGlobalFlags
 	// Global flags (which build system or toolchain is responsible for).
-	Global LocalOrGlobalFlags
+	Global          LocalOrGlobalFlags
+	NoOverrideFlags []string // Flags applied to the end of list of flags so they are not overridden
 
 	aidlFlags     []string // Flags that apply to aidl source files
 	rsFlags       []string // Flags that apply to renderscript source files
@@ -300,8 +307,8 @@
 	// Set by DepsMutator.
 	AndroidMkSystemSharedLibs []string `blueprint:"mutated"`
 
-	// The name of the image this module is built for, suffixed with a '.'
-	ImageVariationPrefix string `blueprint:"mutated"`
+	// The name of the image this module is built for
+	ImageVariation string `blueprint:"mutated"`
 
 	// The VNDK version this module is built against. If empty, the module is not
 	// build against the VNDK.
@@ -349,11 +356,6 @@
 	// see soong/cc/config/vndk.go
 	MustUseVendorVariant bool `blueprint:"mutated"`
 
-	// Used by vendor snapshot to record dependencies from snapshot modules.
-	SnapshotSharedLibs  []string `blueprint:"mutated"`
-	SnapshotStaticLibs  []string `blueprint:"mutated"`
-	SnapshotRuntimeLibs []string `blueprint:"mutated"`
-
 	Installable *bool `android:"arch_variant"`
 
 	// Set by factories of module types that can only be referenced from variants compiled against
@@ -366,20 +368,6 @@
 	// variant to have a ".sdk" suffix.
 	SdkAndPlatformVariantVisibleToMake bool `blueprint:"mutated"`
 
-	// Normally Soong uses the directory structure to decide which modules
-	// should be included (framework) or excluded (non-framework) from the
-	// different snapshots (vendor, recovery, etc.), but this property
-	// allows a partner to exclude a module normally thought of as a
-	// framework module from the vendor snapshot.
-	Exclude_from_vendor_snapshot *bool
-
-	// Normally Soong uses the directory structure to decide which modules
-	// should be included (framework) or excluded (non-framework) from the
-	// different snapshots (vendor, recovery, etc.), but this property
-	// allows a partner to exclude a module normally thought of as a
-	// framework module from the recovery snapshot.
-	Exclude_from_recovery_snapshot *bool
-
 	// List of APEXes that this module has private access to for testing purpose. The module
 	// can depend on libraries that are not exported by the APEXes and use private symbols
 	// from the exported libraries.
@@ -524,11 +512,11 @@
 	inRamdisk() bool
 	inVendorRamdisk() bool
 	inRecovery() bool
+	InVendorOrProduct() bool
 	selectedStl() string
 	baseModuleName() string
 	getVndkExtendsModuleName() string
-	isAfdoCompile() bool
-	isPgoCompile() bool
+	isAfdoCompile(ctx ModuleContext) bool
 	isOrderfileCompile() bool
 	isCfi() bool
 	isFuzzer() bool
@@ -544,6 +532,7 @@
 	isPreventInstall() bool
 	isCfiAssemblySupportEnabled() bool
 	getSharedFlags() *SharedFlags
+	notInPlatform() bool
 }
 
 type SharedFlags struct {
@@ -617,12 +606,15 @@
 	link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path
 	appendLdflags([]string)
 	unstrippedOutputFilePath() android.Path
+	strippedAllOutputFilePath() android.Path
 
 	nativeCoverage() bool
 	coverageOutputFilePath() android.OptionalPath
 
 	// Get the deps that have been explicitly specified in the properties.
 	linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps
+
+	moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON)
 }
 
 // specifiedDeps is a tuple struct representing dependencies of a linked binary owned by the linker.
@@ -726,6 +718,8 @@
 
 	// Whether or not this dependency has to be followed for the apex variants
 	excludeInApex bool
+	// Whether or not this dependency has to be followed for the non-apex variants
+	excludeInNonApex bool
 
 	// If true, don't automatically export symbols from the static library into a shared library.
 	unexportedSymbols bool
@@ -763,6 +757,12 @@
 
 var _ android.InstallNeededDependencyTag = libraryDependencyTag{}
 
+func (d libraryDependencyTag) PropagateAconfigValidation() bool {
+	return d.static()
+}
+
+var _ android.PropagateAconfigValidationDependencyTag = libraryDependencyTag{}
+
 // dependencyTag is used for tagging miscellaneous dependency types that don't fit into
 // libraryDependencyTag.  Each tag object is created globally and reused for multiple
 // dependencies (although since the object contains no references, assigning a tag to a
@@ -799,6 +799,7 @@
 	JniFuzzLibTag         = dependencyTag{name: "jni_fuzz_lib_tag"}
 	FdoProfileTag         = dependencyTag{name: "fdo_profile"}
 	aidlLibraryTag        = dependencyTag{name: "aidl_library"}
+	llndkHeaderLibTag     = dependencyTag{name: "llndk_header_lib"}
 )
 
 func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
@@ -825,19 +826,6 @@
 	return ok && ccDepTag == testPerSrcDepTag
 }
 
-// bazelHandler is the interface for a helper object related to deferring to Bazel for
-// processing a cc module (during Bazel mixed builds). Individual module types should define
-// their own bazel handler if they support being handled by Bazel.
-type BazelHandler interface {
-	// QueueBazelCall invokes request-queueing functions on the BazelContext
-	//so that these requests are handled when Bazel's cquery is invoked.
-	QueueBazelCall(ctx android.BaseModuleContext, label string)
-
-	// ProcessBazelQueryResponse uses information retrieved from Bazel to set properties
-	// on the current module with given label.
-	ProcessBazelQueryResponse(ctx android.ModuleContext, label string)
-}
-
 // Module contains the properties and members used by all C/C++ module types, and implements
 // the blueprint.Module interface.  It delegates to compiler, linker, and installer interfaces
 // to construct the output file.  Behavior can be customized with a Customizer, or "decorator",
@@ -855,15 +843,14 @@
 type Module struct {
 	fuzz.FuzzModule
 
-	android.BazelModuleBase
-
 	VendorProperties VendorProperties
 	Properties       BaseProperties
+	sourceProperties android.SourceProperties
 
 	// initialize before calling Init
-	hod       android.HostOrDeviceSupported
-	multilib  android.Multilib
-	bazelable bool
+	hod        android.HostOrDeviceSupported
+	multilib   android.Multilib
+	testModule bool
 
 	// Allowable SdkMemberTypes of this module type.
 	sdkMemberTypes []android.SdkMemberType
@@ -873,22 +860,20 @@
 	// type-specific logic. These members may reference different objects or the same object.
 	// Functions of these decorators will be invoked to initialize and register type-specific
 	// build statements.
-	generators   []Generator
-	compiler     compiler
-	linker       linker
-	installer    installer
-	bazelHandler BazelHandler
+	generators []Generator
+	compiler   compiler
+	linker     linker
+	installer  installer
 
-	features []feature
-	stl      *stl
-	sanitize *sanitize
-	coverage *coverage
-	fuzzer   *fuzzer
-	sabi     *sabi
-	vndkdep  *vndkdep
-	lto      *lto
-	afdo     *afdo
-	pgo      *pgo
+	features  []feature
+	stl       *stl
+	sanitize  *sanitize
+	coverage  *coverage
+	fuzzer    *fuzzer
+	sabi      *sabi
+	vndkdep   *vndkdep
+	lto       *lto
+	afdo      *afdo
 	orderfile *orderfile
 
 	library libraryInterface
@@ -920,6 +905,9 @@
 	apexSdkVersion android.ApiLevel
 
 	hideApexVariantFromMake bool
+
+	// Aconfig files for all transitive deps.  Also exposed via TransitiveDeclarationsInfo
+	mergedAconfigFiles map[string]android.Paths
 }
 
 func (c *Module) AddJSONData(d *map[string]interface{}) {
@@ -964,8 +952,6 @@
 		"IsVndkSp":               c.IsVndkSp(),
 		"IsLlndk":                c.IsLlndk(),
 		"IsLlndkPublic":          c.IsLlndkPublic(),
-		"IsSnapshotLibrary":      c.IsSnapshotLibrary(),
-		"IsSnapshotPrebuilt":     c.IsSnapshotPrebuilt(),
 		"IsVendorPublicLibrary":  c.IsVendorPublicLibrary(),
 		"ApexSdkVersion":         c.apexSdkVersion,
 		"TestFor":                c.TestFor(),
@@ -1104,6 +1090,16 @@
 	return false
 }
 
+func (c *Module) IsNdkPrebuiltStl() bool {
+	if c.linker == nil {
+		return false
+	}
+	if _, ok := c.linker.(*ndkPrebuiltStlLinker); ok {
+		return true
+	}
+	return false
+}
+
 func (c *Module) RlibStd() bool {
 	panic(fmt.Errorf("RlibStd called on non-Rust module: %q", c.BaseModuleName()))
 }
@@ -1261,20 +1257,18 @@
 	if c.afdo != nil {
 		c.AddProperties(c.afdo.props()...)
 	}
-	if c.pgo != nil {
-		c.AddProperties(c.pgo.props()...)
-	}
 	if c.orderfile != nil {
 		c.AddProperties(c.orderfile.props()...)
 	}
 	for _, feature := range c.features {
 		c.AddProperties(feature.props()...)
 	}
+	// Allow test-only on libraries that are not cc_test_library
+	if c.library != nil && !c.testLibrary() {
+		c.AddProperties(&c.sourceProperties)
+	}
 
 	android.InitAndroidArchModule(c, c.hod, c.multilib)
-	if c.bazelable {
-		android.InitBazelModule(c)
-	}
 	android.InitApexModule(c)
 	android.InitDefaultableModule(c)
 
@@ -1289,7 +1283,7 @@
 
 func (c *Module) canUseSdk() bool {
 	return c.Os() == android.Android && c.Target().NativeBridge == android.NativeBridgeDisabled &&
-		!c.UseVndk() && !c.InRamdisk() && !c.InRecovery() && !c.InVendorRamdisk()
+		!c.InVendorOrProduct() && !c.InRamdisk() && !c.InRecovery() && !c.InVendorRamdisk()
 }
 
 func (c *Module) UseSdk() bool {
@@ -1386,16 +1380,9 @@
 	return false
 }
 
-func (c *Module) isAfdoCompile() bool {
+func (c *Module) isAfdoCompile(ctx ModuleContext) bool {
 	if afdo := c.afdo; afdo != nil {
-		return afdo.Properties.FdoProfilePath != nil
-	}
-	return false
-}
-
-func (c *Module) isPgoCompile() bool {
-	if pgo := c.pgo; pgo != nil {
-		return pgo.Properties.PgoCompile
+		return afdo.isAfdoCompile(ctx)
 	}
 	return false
 }
@@ -1520,14 +1507,6 @@
 	return false
 }
 
-func (c *Module) ExcludeFromVendorSnapshot() bool {
-	return Bool(c.Properties.Exclude_from_vendor_snapshot)
-}
-
-func (c *Module) ExcludeFromRecoverySnapshot() bool {
-	return Bool(c.Properties.Exclude_from_recovery_snapshot)
-}
-
 func isBionic(name string) bool {
 	switch name {
 	case "libc", "libm", "libdl", "libdl_android", "linker":
@@ -1537,8 +1516,6 @@
 }
 
 func InstallToBootstrap(name string, config android.Config) bool {
-	// NOTE: also update //build/bazel/rules/apex/cc.bzl#_installed_to_bootstrap
-	// if this list is updated.
 	if name == "libclang_rt.hwasan" || name == "libc_hwasan" {
 		return true
 	}
@@ -1620,9 +1597,10 @@
 
 func (ctx *moduleContextImpl) sdkVersion() string {
 	if ctx.ctx.Device() {
-		if ctx.useVndk() {
+		config := ctx.ctx.Config()
+		if !config.IsVndkDeprecated() && ctx.useVndk() {
 			vndkVer := ctx.mod.VndkVersion()
-			if inList(vndkVer, ctx.ctx.Config().PlatformVersionActiveCodenames()) {
+			if inList(vndkVer, config.PlatformVersionActiveCodenames()) {
 				return "current"
 			}
 			return vndkVer
@@ -1640,6 +1618,17 @@
 	if ver == "apex_inherit" || ver == "" {
 		ver = ctx.sdkVersion()
 	}
+
+	if ctx.ctx.Device() {
+		config := ctx.ctx.Config()
+		if config.IsVndkDeprecated() && ctx.inVendor() {
+			// If building for vendor with final API, then use the latest _stable_ API as "current".
+			if config.VendorApiLevelFrozen() && (ver == "" || ver == "current") {
+				ver = config.PlatformSdkVersion().String()
+			}
+		}
+	}
+
 	// For crt objects, the meaning of min_sdk_version is very different from other types of
 	// module. For them, min_sdk_version defines the oldest version that the build system will
 	// create versioned variants for. For example, if min_sdk_version is 16, then sdk variant of
@@ -1680,6 +1669,10 @@
 	return ctx.mod.UseVndk()
 }
 
+func (ctx *moduleContextImpl) InVendorOrProduct() bool {
+	return ctx.mod.InVendorOrProduct()
+}
+
 func (ctx *moduleContextImpl) isNdk(config android.Config) bool {
 	return ctx.mod.IsNdk(config)
 }
@@ -1704,12 +1697,8 @@
 	return ctx.mod.IsVndk()
 }
 
-func (ctx *moduleContextImpl) isAfdoCompile() bool {
-	return ctx.mod.isAfdoCompile()
-}
-
-func (ctx *moduleContextImpl) isPgoCompile() bool {
-	return ctx.mod.isPgoCompile()
+func (ctx *moduleContextImpl) isAfdoCompile(mctx ModuleContext) bool {
+	return ctx.mod.isAfdoCompile(mctx)
 }
 
 func (ctx *moduleContextImpl) isOrderfileCompile() bool {
@@ -1756,7 +1745,7 @@
 }
 
 func (ctx *moduleContextImpl) baseModuleName() string {
-	return ctx.mod.ModuleBase.BaseModuleName()
+	return ctx.mod.BaseModuleName()
 }
 
 func (ctx *moduleContextImpl) getVndkExtendsModuleName() string {
@@ -1764,11 +1753,13 @@
 }
 
 func (ctx *moduleContextImpl) isForPlatform() bool {
-	return ctx.ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
+	apexInfo, _ := android.ModuleProvider(ctx.ctx, android.ApexInfoProvider)
+	return apexInfo.IsForPlatform()
 }
 
 func (ctx *moduleContextImpl) apexVariationName() string {
-	return ctx.ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).ApexVariationName
+	apexInfo, _ := android.ModuleProvider(ctx.ctx, android.ApexInfoProvider)
+	return apexInfo.ApexVariationName
 }
 
 func (ctx *moduleContextImpl) apexSdkVersion() android.ApiLevel {
@@ -1804,6 +1795,10 @@
 	return ctx.mod.isCfiAssemblySupportEnabled()
 }
 
+func (ctx *moduleContextImpl) notInPlatform() bool {
+	return ctx.mod.NotInPlatform()
+}
+
 func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
 	return &Module{
 		hod:      hod,
@@ -1824,7 +1819,6 @@
 	module.vndkdep = &vndkdep{}
 	module.lto = &lto{}
 	module.afdo = &afdo{}
-	module.pgo = &pgo{}
 	module.orderfile = &orderfile{}
 	return module
 }
@@ -1876,7 +1870,6 @@
 func getNameSuffixWithVndkVersion(ctx android.ModuleContext, c LinkableInterface) string {
 	// Returns the name suffix for product and vendor variants. If the VNDK version is not
 	// "current", it will append the VNDK version to the name suffix.
-	var vndkVersion string
 	var nameSuffix string
 	if c.InProduct() {
 		if c.ProductSpecific() {
@@ -1884,16 +1877,11 @@
 			// do not add a name suffix because it is a base module.
 			return ""
 		}
-		vndkVersion = ctx.DeviceConfig().ProductVndkVersion()
-		nameSuffix = ProductSuffix
+		return ProductSuffix
 	} else {
-		vndkVersion = ctx.DeviceConfig().VndkVersion()
 		nameSuffix = VendorSuffix
 	}
-	if vndkVersion == "current" {
-		vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
-	}
-	if c.VndkVersion() != vndkVersion && c.VndkVersion() != "" {
+	if c.VndkVersion() != "" {
 		// add version suffix only if the module is using different vndk version than the
 		// version in product or vendor partition.
 		nameSuffix += "." + c.VndkVersion()
@@ -1909,7 +1897,7 @@
 	}
 
 	llndk := c.IsLlndk()
-	if llndk || (c.UseVndk() && c.HasNonSystemVariants()) {
+	if llndk || (c.InVendorOrProduct() && c.HasNonSystemVariants()) {
 		// .vendor.{version} suffix is added for vendor variant or .product.{version} suffix is
 		// added for product variant only when we have vendor and product variants with core
 		// variant. The suffix is not added for vendor-only or product-only module.
@@ -1940,170 +1928,6 @@
 	return subName
 }
 
-var _ android.MixedBuildBuildable = (*Module)(nil)
-
-func (c *Module) getBazelModuleLabel(ctx android.BaseModuleContext) string {
-	var bazelModuleLabel string
-	if c.typ() == fullLibrary && c.static() {
-		// cc_library is a special case in bp2build; two targets are generated -- one for each
-		// of the shared and static variants. The shared variant keeps the module name, but the
-		// static variant uses a different suffixed name.
-		bazelModuleLabel = bazelLabelForStaticModule(ctx, c)
-	} else {
-		bazelModuleLabel = c.GetBazelLabel(ctx, c)
-	}
-	labelNoPrebuilt := bazelModuleLabel
-	if c.IsPrebuilt() {
-		labelNoPrebuilt = android.RemoveOptionalPrebuiltPrefixFromBazelLabel(bazelModuleLabel)
-	}
-	return labelNoPrebuilt
-}
-
-func (c *Module) QueueBazelCall(ctx android.BaseModuleContext) {
-	c.bazelHandler.QueueBazelCall(ctx, c.getBazelModuleLabel(ctx))
-}
-
-// IsMixedBuildSupported returns true if the module should be analyzed by Bazel
-// in any of the --bazel-mode(s).
-func (c *Module) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
-	if !allEnabledSanitizersSupportedByBazel(ctx, c) {
-		//TODO(b/278772861) support sanitizers in Bazel rules
-		return false
-	}
-	if !imageVariantSupportedByBazel(c) {
-		return false
-	}
-	if c.IsSdkVariant() {
-		return false
-	}
-	return c.bazelHandler != nil
-}
-
-func imageVariantSupportedByBazel(c *Module) bool {
-	if c.IsLlndk() {
-		return false
-	}
-	if c.InVendor() {
-		return false
-	}
-	if c.InProduct() {
-		return false
-	}
-	if c.InRamdisk() {
-		return false
-	}
-	if c.InVendorRamdisk() {
-		return false
-	}
-	if c.InRecovery() {
-		return false
-	}
-	return true
-}
-
-func allEnabledSanitizersSupportedByBazel(ctx android.BaseModuleContext, c *Module) bool {
-	if c.sanitize == nil {
-		return true
-	}
-	sanitizeProps := &c.sanitize.Properties.SanitizeMutated
-
-	unsupportedSanitizers := []*bool{
-		sanitizeProps.Safestack,
-		sanitizeProps.Scudo,
-		BoolPtr(len(c.sanitize.Properties.Sanitize.Recover) > 0),
-	}
-	for _, san := range unsupportedSanitizers {
-		if Bool(san) {
-			return false
-		}
-	}
-
-	for _, san := range Sanitizers {
-		if san == intOverflow {
-			// TODO(b/261058727): enable mixed builds for all modules with UBSan
-			// Currently we can only support ubsan when minimum runtime is used.
-			ubsanEnabled := Bool(sanitizeProps.Integer_overflow) || len(sanitizeProps.Misc_undefined) > 0
-			if !ubsanEnabled || c.MinimalRuntimeNeeded() {
-				continue
-			}
-		} else if san == cfi {
-			apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
-			// Only allow cfi if this is an apex variant
-			if !apexInfo.IsForPlatform() {
-				continue
-			}
-		}
-		if c.sanitize.isSanitizerEnabled(san) {
-			return false
-		}
-	}
-
-	return true
-}
-
-func GetApexConfigKey(ctx android.BaseModuleContext) *android.ApexConfigKey {
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
-	if !apexInfo.IsForPlatform() {
-		apexKey := android.ApexConfigKey{
-			WithinApex:     true,
-			ApexSdkVersion: findApexSdkVersion(ctx, apexInfo).String(),
-			ApiDomain:      findApiDomain(apexInfo),
-		}
-		return &apexKey
-	}
-
-	return nil
-}
-
-// Returns the api domain of a module for an apexInfo group
-// Input:
-// ai.InApexModules: [com.android.foo, test_com.android.foo, com.google.android.foo]
-// Return:
-// com.android.foo
-
-// If a module is included in multiple api domains (collated by min_sdk_version), it will return
-// the first match. The other matches have the same build actions since they share a min_sdk_version, so returning
-// the first match is fine.
-func findApiDomain(ai android.ApexInfo) string {
-	// Remove any test apexes
-	matches, _ := android.FilterList(ai.InApexModules, ai.TestApexes)
-	// Remove any google apexes. Rely on naming convention.
-	pred := func(s string) bool { return !strings.HasPrefix(s, "com.google") }
-	matches = android.FilterListPred(matches, pred)
-	if len(matches) > 0 {
-		// Return the first match
-		return android.SortedUniqueStrings(matches)[0]
-	} else {
-		// No apex in the tree has a dependency on this module
-		return ""
-	}
-}
-
-func (c *Module) ProcessBazelQueryResponse(ctx android.ModuleContext) {
-	bazelModuleLabel := c.getBazelModuleLabel(ctx)
-	c.bazelHandler.ProcessBazelQueryResponse(ctx, bazelModuleLabel)
-
-	c.Properties.SubName = GetSubnameProperty(ctx, c)
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
-	if !apexInfo.IsForPlatform() {
-		c.hideApexVariantFromMake = true
-	}
-
-	c.makeLinkType = GetMakeLinkType(ctx, c)
-
-	mctx := &moduleContext{
-		ModuleContext: ctx,
-		moduleContextImpl: moduleContextImpl{
-			mod: c,
-		},
-	}
-	mctx.ctx = mctx
-
-	// TODO(b/244432500): Get the tradefed config from the bazel target instead
-	// of generating it with Soong.
-	c.maybeInstall(mctx, apexInfo)
-}
-
 func moduleContextFromAndroidModuleContext(actx android.ModuleContext, c *Module) ModuleContext {
 	ctx := &moduleContext{
 		ModuleContext: actx,
@@ -2126,6 +1950,7 @@
 		"libdl_android": true,
 		"libm":          true,
 		"libdl":         true,
+		"libz":          true,
 		// art apex
 		"libandroidio":    true,
 		"libdexfile":      true,
@@ -2165,7 +1990,25 @@
 	return false
 }
 
+func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	android.CollectDependencyAconfigFiles(ctx, &d.mergedAconfigFiles)
+}
+
 func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
+	ctx := moduleContextFromAndroidModuleContext(actx, c)
+
+	// If Test_only is set on a module in bp file, respect the setting, otherwise
+	// see if is a known test module type.
+	testOnly := c.testModule || c.testLibrary()
+	if c.sourceProperties.Test_only != nil {
+		testOnly = Bool(c.sourceProperties.Test_only)
+	}
+	// Keep before any early returns.
+	android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
+		TestOnly:       testOnly,
+		TopLevelTarget: c.testModule,
+	})
+
 	// Handle the case of a test module split by `test_per_src` mutator.
 	//
 	// The `test_per_src` mutator adds an extra variation named "", depending on all the other
@@ -2177,15 +2020,13 @@
 	}
 
 	c.Properties.SubName = GetSubnameProperty(actx, c)
-	apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(actx, android.ApexInfoProvider)
 	if !apexInfo.IsForPlatform() {
 		c.hideApexVariantFromMake = true
 	}
 
 	c.makeLinkType = GetMakeLinkType(actx, c)
 
-	ctx := moduleContextFromAndroidModuleContext(actx, c)
-
 	deps := c.depsToPaths(ctx)
 	if ctx.Failed() {
 		return
@@ -2251,9 +2092,6 @@
 	if c.afdo != nil {
 		flags = c.afdo.flags(ctx, flags)
 	}
-	if c.pgo != nil {
-		flags = c.pgo.flags(ctx, flags)
-	}
 	if c.orderfile != nil {
 		flags = c.orderfile.flags(ctx, flags)
 	}
@@ -2310,17 +2148,49 @@
 		c.outputFile = android.OptionalPathForPath(outputFile)
 
 		c.maybeUnhideFromMake()
-
-		// glob exported headers for snapshot, if BOARD_VNDK_VERSION is current or
-		// RECOVERY_SNAPSHOT_VERSION is current.
-		if i, ok := c.linker.(snapshotLibraryInterface); ok {
-			if ShouldCollectHeadersForSnapshot(ctx, c, apexInfo) {
-				i.collectHeadersForSnapshot(ctx)
-			}
-		}
+	}
+	if c.testModule {
+		android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 	}
 
+	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: deps.GeneratedSources.Strings()})
+
+	android.CollectDependencyAconfigFiles(ctx, &c.mergedAconfigFiles)
+
 	c.maybeInstall(ctx, apexInfo)
+
+	if c.linker != nil {
+		moduleInfoJSON := ctx.ModuleInfoJSON()
+		c.linker.moduleInfoJSON(ctx, moduleInfoJSON)
+		moduleInfoJSON.SharedLibs = c.Properties.AndroidMkSharedLibs
+		moduleInfoJSON.StaticLibs = c.Properties.AndroidMkStaticLibs
+		moduleInfoJSON.SystemSharedLibs = c.Properties.AndroidMkSystemSharedLibs
+		moduleInfoJSON.RuntimeDependencies = c.Properties.AndroidMkRuntimeLibs
+
+		moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, c.Properties.AndroidMkSharedLibs...)
+		moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, c.Properties.AndroidMkStaticLibs...)
+		moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, c.Properties.AndroidMkHeaderLibs...)
+		moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, c.Properties.AndroidMkWholeStaticLibs...)
+
+		if c.sanitize != nil && len(moduleInfoJSON.Class) > 0 &&
+			(moduleInfoJSON.Class[0] == "STATIC_LIBRARIES" || moduleInfoJSON.Class[0] == "HEADER_LIBRARIES") {
+			if Bool(c.sanitize.Properties.SanitizeMutated.Cfi) {
+				moduleInfoJSON.SubName += ".cfi"
+			}
+			if Bool(c.sanitize.Properties.SanitizeMutated.Hwaddress) {
+				moduleInfoJSON.SubName += ".hwasan"
+			}
+			if Bool(c.sanitize.Properties.SanitizeMutated.Scs) {
+				moduleInfoJSON.SubName += ".scs"
+			}
+		}
+		moduleInfoJSON.SubName += c.Properties.SubName
+
+		if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
+			moduleInfoJSON.Uninstallable = true
+		}
+
+	}
 }
 
 func (c *Module) maybeUnhideFromMake() {
@@ -2332,16 +2202,15 @@
 	// is explicitly referenced via .bootstrap suffix or the module is marked with
 	// 'bootstrap: true').
 	if c.HasStubsVariants() && c.NotInPlatform() && !c.InRamdisk() &&
-		!c.InRecovery() && !c.UseVndk() && !c.static() && !c.isCoverageVariant() &&
+		!c.InRecovery() && !c.InVendorOrProduct() && !c.static() && !c.isCoverageVariant() &&
 		c.IsStubs() && !c.InVendorRamdisk() {
 		c.Properties.HideFromMake = false // unhide
 		// Note: this is still non-installable
 	}
 }
 
-// maybeInstall is called at the end of both GenerateAndroidBuildActions and
-// ProcessBazelQueryResponse to run the install hooks for installable modules,
-// like binaries and tests.
+// maybeInstall is called at the end of both GenerateAndroidBuildActions to run the
+// install hooks for installable modules, like binaries and tests.
 func (c *Module) maybeInstall(ctx ModuleContext, apexInfo android.ApexInfo) {
 	if !proptools.BoolDefault(c.Installable(), true) {
 		// If the module has been specifically configure to not be installed then
@@ -2364,12 +2233,6 @@
 	}
 }
 
-func (c *Module) setAndroidMkVariablesFromCquery(info cquery.CcAndroidMkInfo) {
-	c.Properties.AndroidMkSharedLibs = info.LocalSharedLibs
-	c.Properties.AndroidMkStaticLibs = info.LocalStaticLibs
-	c.Properties.AndroidMkWholeStaticLibs = info.LocalWholeStaticLibs
-}
-
 func (c *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain {
 	if c.cachedToolchain == nil {
 		c.cachedToolchain = config.FindToolchainWithContext(ctx)
@@ -2396,15 +2259,15 @@
 	if c.coverage != nil {
 		c.coverage.begin(ctx)
 	}
+	if c.afdo != nil {
+		c.afdo.begin(ctx)
+	}
 	if c.lto != nil {
 		c.lto.begin(ctx)
 	}
 	if c.orderfile != nil {
 		c.orderfile.begin(ctx)
 	}
-	if c.pgo != nil {
-		c.pgo.begin(ctx)
-	}
 	if ctx.useSdk() && c.IsSdkVariant() {
 		version, err := nativeApiLevelFromUser(ctx, ctx.sdkVersion())
 		if err != nil {
@@ -2442,6 +2305,7 @@
 	deps.LateSharedLibs = android.LastUniqueStrings(deps.LateSharedLibs)
 	deps.HeaderLibs = android.LastUniqueStrings(deps.HeaderLibs)
 	deps.RuntimeLibs = android.LastUniqueStrings(deps.RuntimeLibs)
+	deps.LlndkHeaderLibs = android.LastUniqueStrings(deps.LlndkHeaderLibs)
 
 	for _, lib := range deps.ReexportSharedLibHeaders {
 		if !inList(lib, deps.SharedLibs) {
@@ -2479,10 +2343,6 @@
 	}
 	ctx.ctx = ctx
 
-	if !actx.Host() || !ctx.static() || ctx.staticBinary() {
-		c.afdo.addDep(ctx, actx)
-	}
-
 	c.begin(ctx)
 }
 
@@ -2558,9 +2418,9 @@
 		if actx.OtherModuleExists("api_imports") {
 			apiImportModule = actx.AddDependency(c, nil, "api_imports")
 			if len(apiImportModule) > 0 && apiImportModule[0] != nil {
-				apiInfo := actx.OtherModuleProvider(apiImportModule[0], multitree.ApiImportsProvider).(multitree.ApiImportInfo)
+				apiInfo, _ := android.OtherModuleProvider(actx, apiImportModule[0], multitree.ApiImportsProvider)
 				apiImportInfo = apiInfo
-				actx.SetProvider(multitree.ApiImportsProvider, apiInfo)
+				android.SetProvider(actx, multitree.ApiImportsProvider, apiInfo)
 			}
 		}
 	}
@@ -2568,31 +2428,6 @@
 	return apiImportInfo
 }
 
-func GetSnapshot(c LinkableInterface, snapshotInfo **SnapshotInfo, actx android.BottomUpMutatorContext) SnapshotInfo {
-	// Only device modules with BOARD_VNDK_VERSION uses snapshot.  Others use the zero value of
-	// SnapshotInfo, which provides no mappings.
-	if *snapshotInfo == nil && c.Device() {
-		// Only retrieve the snapshot on demand in order to avoid circular dependencies
-		// between the modules in the snapshot and the snapshot itself.
-		var snapshotModule []blueprint.Module
-		if c.InVendor() && c.VndkVersion() == actx.DeviceConfig().VndkVersion() {
-			snapshotModule = actx.AddVariationDependencies(nil, nil, "vendor_snapshot")
-		} else if recoverySnapshotVersion := actx.DeviceConfig().RecoverySnapshotVersion(); recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" && c.InRecovery() {
-			snapshotModule = actx.AddVariationDependencies(nil, nil, "recovery_snapshot")
-		}
-		if len(snapshotModule) > 0 && snapshotModule[0] != nil {
-			snapshot := actx.OtherModuleProvider(snapshotModule[0], SnapshotInfoProvider).(SnapshotInfo)
-			*snapshotInfo = &snapshot
-			// republish the snapshot for use in later mutators on this module
-			actx.SetProvider(SnapshotInfoProvider, snapshot)
-		}
-	}
-	if *snapshotInfo == nil {
-		*snapshotInfo = &SnapshotInfo{}
-	}
-	return **snapshotInfo
-}
-
 func GetReplaceModuleName(lib string, replaceMap map[string]string) string {
 	if snapshot, ok := replaceMap[lib]; ok {
 		return snapshot
@@ -2601,44 +2436,35 @@
 	return lib
 }
 
-// RewriteLibs takes a list of names of shared libraries and scans it for three types
+// FilterNdkLibs takes a list of names of shared libraries and scans it for two types
 // of names:
 //
-// 1. Name of an NDK library that refers to a prebuilt module.
-//
-//	For each of these, it adds the name of the prebuilt module (which will be in
-//	prebuilts/ndk) to the list of nonvariant libs.
-//
-// 2. Name of an NDK library that refers to an ndk_library module.
+// 1. Name of an NDK library that refers to an ndk_library module.
 //
 //	For each of these, it adds the name of the ndk_library module to the list of
 //	variant libs.
 //
-// 3. Anything else (so anything that isn't an NDK library).
+// 2. Anything else (so anything that isn't an NDK library).
 //
 //	It adds these to the nonvariantLibs list.
 //
 // The caller can then know to add the variantLibs dependencies differently from the
 // nonvariantLibs
-func RewriteLibs(c LinkableInterface, snapshotInfo **SnapshotInfo, actx android.BottomUpMutatorContext, config android.Config, list []string) (nonvariantLibs []string, variantLibs []string) {
+func FilterNdkLibs(c LinkableInterface, config android.Config, list []string) (nonvariantLibs []string, variantLibs []string) {
 	variantLibs = []string{}
 
 	nonvariantLibs = []string{}
 	for _, entry := range list {
 		// strip #version suffix out
 		name, _ := StubsLibNameAndVersion(entry)
-		if c.InRecovery() {
-			nonvariantLibs = append(nonvariantLibs, GetReplaceModuleName(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs))
-		} else if c.UseSdk() && inList(name, *getNDKKnownLibs(config)) {
+		if c.UseSdk() && inList(name, *getNDKKnownLibs(config)) {
 			variantLibs = append(variantLibs, name+ndkLibrarySuffix)
-		} else if c.UseVndk() {
-			nonvariantLibs = append(nonvariantLibs, GetReplaceModuleName(entry, GetSnapshot(c, snapshotInfo, actx).SharedLibs))
 		} else {
-			// put name#version back
 			nonvariantLibs = append(nonvariantLibs, entry)
 		}
 	}
 	return nonvariantLibs, variantLibs
+
 }
 
 func rewriteLibsForApiImports(c LinkableInterface, libs []string, replaceList map[string]string, config android.Config) ([]string, []string) {
@@ -2710,18 +2536,12 @@
 
 	c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs
 
-	var snapshotInfo *SnapshotInfo
-
 	variantNdkLibs := []string{}
 	variantLateNdkLibs := []string{}
 	if ctx.Os() == android.Android {
-		deps.SharedLibs, variantNdkLibs = RewriteLibs(c, &snapshotInfo, actx, ctx.Config(), deps.SharedLibs)
-		deps.LateSharedLibs, variantLateNdkLibs = RewriteLibs(c, &snapshotInfo, actx, ctx.Config(), deps.LateSharedLibs)
-		deps.ReexportSharedLibHeaders, _ = RewriteLibs(c, &snapshotInfo, actx, ctx.Config(), deps.ReexportSharedLibHeaders)
-
-		for idx, lib := range deps.RuntimeLibs {
-			deps.RuntimeLibs[idx] = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).SharedLibs)
-		}
+		deps.SharedLibs, variantNdkLibs = FilterNdkLibs(c, ctx.Config(), deps.SharedLibs)
+		deps.LateSharedLibs, variantLateNdkLibs = FilterNdkLibs(c, ctx.Config(), deps.LateSharedLibs)
+		deps.ReexportSharedLibHeaders, _ = FilterNdkLibs(c, ctx.Config(), deps.ReexportSharedLibHeaders)
 	}
 
 	for _, lib := range deps.HeaderLibs {
@@ -2734,7 +2554,6 @@
 		if c.shouldUseApiSurface() {
 			lib = GetReplaceModuleName(lib, apiImportInfo.HeaderLibs)
 		}
-		lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).HeaderLibs)
 
 		if c.isNDKStubLibrary() {
 			// ndk_headers do not have any variations
@@ -2757,11 +2576,18 @@
 		), stubImplementation, c.BaseModuleName())
 	}
 
+	// If this module is an LLNDK implementation library, let it depend on LlndkHeaderLibs.
+	if c.ImageVariation().Variation == android.CoreVariation && c.Device() &&
+		c.Target().NativeBridge == android.NativeBridgeDisabled {
+		actx.AddVariationDependencies(
+			[]blueprint.Variation{{Mutator: "image", Variation: VendorVariation}},
+			llndkHeaderLibTag,
+			deps.LlndkHeaderLibs...)
+	}
+
 	for _, lib := range deps.WholeStaticLibs {
 		depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true, reexportFlags: true}
 
-		lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)
-
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
 		}, depTag, lib)
@@ -2776,8 +2602,6 @@
 			depTag.excludeInApex = true
 		}
 
-		lib = GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs)
-
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
 		}, depTag, lib)
@@ -2790,7 +2614,7 @@
 		depTag := libraryDependencyTag{Kind: staticLibraryDependency, staticUnwinder: true}
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
-		}, depTag, GetReplaceModuleName(staticUnwinder(actx), GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
+		}, depTag, staticUnwinder(actx))
 	}
 
 	// shared lib names without the #version suffix
@@ -2804,6 +2628,9 @@
 		if inList(lib, deps.ExcludeLibsForApex) {
 			depTag.excludeInApex = true
 		}
+		if inList(lib, deps.ExcludeLibsForNonApex) {
+			depTag.excludeInNonApex = true
+		}
 
 		name, version := StubsLibNameAndVersion(lib)
 		if apiLibraryName, ok := apiImportInfo.SharedLibs[name]; ok && !ctx.OtherModuleExists(name) {
@@ -2828,14 +2655,14 @@
 		depTag := libraryDependencyTag{Kind: staticLibraryDependency, Order: lateLibraryDependency}
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
-		}, depTag, GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
+		}, depTag, lib)
 	}
 
 	for _, lib := range deps.UnexportedStaticLibs {
 		depTag := libraryDependencyTag{Kind: staticLibraryDependency, Order: lateLibraryDependency, unexportedSymbols: true}
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
-		}, depTag, GetReplaceModuleName(lib, GetSnapshot(c, &snapshotInfo, actx).StaticLibs))
+		}, depTag, lib)
 	}
 
 	for _, lib := range deps.LateSharedLibs {
@@ -2876,11 +2703,11 @@
 	actx.AddVariationDependencies(crtVariations, objDepTag, deps.ObjFiles...)
 	for _, crt := range deps.CrtBegin {
 		actx.AddVariationDependencies(crtVariations, CrtBeginDepTag,
-			GetReplaceModuleName(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
+			crt)
 	}
 	for _, crt := range deps.CrtEnd {
 		actx.AddVariationDependencies(crtVariations, CrtEndDepTag,
-			GetReplaceModuleName(crt, GetSnapshot(c, &snapshotInfo, actx).Objects))
+			crt)
 	}
 	if deps.DynamicLinker != "" {
 		actx.AddDependency(c, dynamicLinkerDepTag, deps.DynamicLinker)
@@ -2913,7 +2740,7 @@
 			actx.AddVariationDependencies([]blueprint.Variation{
 				c.ImageVariation(),
 				{Mutator: "link", Variation: "shared"},
-			}, vndkExtDepTag, GetReplaceModuleName(vndkdep.getVndkExtendsModuleName(), GetSnapshot(c, &snapshotInfo, actx).SharedLibs))
+			}, vndkExtDepTag, vndkdep.getVndkExtendsModuleName())
 		}
 	}
 
@@ -3105,6 +2932,9 @@
 		if depTag == stubImplDepTag {
 			return false
 		}
+		if depTag == android.RequiredDepTag {
+			return false
+		}
 
 		// Even if target lib has no vendor variant, keep checking dependency
 		// graph in case it depends on vendor_available or product_available
@@ -3169,7 +2999,7 @@
 		depPaths.ReexportedGeneratedHeaders = append(depPaths.ReexportedGeneratedHeaders, exporter.GeneratedHeaders...)
 	}
 
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	c.apexSdkVersion = findApexSdkVersion(ctx, apexInfo)
 
 	skipModuleList := map[string]bool{}
@@ -3179,7 +3009,7 @@
 
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		if dep.Name() == "api_imports" {
-			apiImportInfo = ctx.OtherModuleProvider(dep, multitree.ApiImportsProvider).(multitree.ApiImportInfo)
+			apiImportInfo, _ = android.OtherModuleProvider(ctx, dep, multitree.ApiImportsProvider)
 			hasApiImportInfo = true
 		}
 	})
@@ -3230,12 +3060,10 @@
 		}
 
 		if depTag == aidlLibraryTag {
-			if ctx.OtherModuleHasProvider(dep, aidl_library.AidlLibraryProvider) {
+			if aidlLibraryInfo, ok := android.OtherModuleProvider(ctx, dep, aidl_library.AidlLibraryProvider); ok {
 				depPaths.AidlLibraryInfos = append(
 					depPaths.AidlLibraryInfos,
-					ctx.OtherModuleProvider(
-						dep,
-						aidl_library.AidlLibraryProvider).(aidl_library.AidlLibraryInfo),
+					aidlLibraryInfo,
 				)
 			}
 		}
@@ -3284,6 +3112,10 @@
 			return
 		}
 
+		if depTag == android.RequiredDepTag {
+			return
+		}
+
 		if dep.Target().Os != ctx.Os() {
 			ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName)
 			return
@@ -3300,15 +3132,21 @@
 			// version mutator, so the stubs variant is created from the shared variant that
 			// already has the reuseObjTag dependency on the static variant.
 			if !c.library.buildStubs() {
-				staticAnalogue := ctx.OtherModuleProvider(dep, StaticLibraryInfoProvider).(StaticLibraryInfo)
+				staticAnalogue, _ := android.OtherModuleProvider(ctx, dep, StaticLibraryInfoProvider)
 				objs := staticAnalogue.ReuseObjects
 				depPaths.Objs = depPaths.Objs.Append(objs)
-				depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
+				depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider)
 				reexportExporter(depExporterInfo)
 			}
 			return
 		}
 
+		if depTag == llndkHeaderLibTag {
+			depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider)
+			depPaths.LlndkIncludeDirs = append(depPaths.LlndkIncludeDirs, depExporterInfo.IncludeDirs...)
+			depPaths.LlndkSystemIncludeDirs = append(depPaths.LlndkSystemIncludeDirs, depExporterInfo.SystemIncludeDirs...)
+		}
+
 		linkFile := ccDep.OutputFile()
 
 		if libDepTag, ok := depTag.(libraryDependencyTag); ok {
@@ -3320,8 +3158,11 @@
 			if !apexInfo.IsForPlatform() && libDepTag.excludeInApex {
 				return
 			}
+			if apexInfo.IsForPlatform() && libDepTag.excludeInNonApex {
+				return
+			}
 
-			depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
+			depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider)
 
 			var ptr *android.Paths
 			var depPtr *android.Paths
@@ -3330,7 +3171,7 @@
 
 			switch {
 			case libDepTag.header():
-				if !ctx.OtherModuleHasProvider(dep, HeaderLibraryInfoProvider) {
+				if _, isHeaderLib := android.OtherModuleProvider(ctx, dep, HeaderLibraryInfoProvider); !isHeaderLib {
 					if !ctx.Config().AllowMissingDependencies() {
 						ctx.ModuleErrorf("module %q is not a header library", depName)
 					} else {
@@ -3339,7 +3180,7 @@
 					return
 				}
 			case libDepTag.shared():
-				if !ctx.OtherModuleHasProvider(dep, SharedLibraryInfoProvider) {
+				if _, isSharedLib := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider); !isSharedLib {
 					if !ctx.Config().AllowMissingDependencies() {
 						ctx.ModuleErrorf("module %q is not a shared library", depName)
 					} else {
@@ -3376,7 +3217,8 @@
 					panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
 				}
 			case libDepTag.static():
-				if !ctx.OtherModuleHasProvider(dep, StaticLibraryInfoProvider) {
+				staticLibraryInfo, isStaticLib := android.OtherModuleProvider(ctx, dep, StaticLibraryInfoProvider)
+				if !isStaticLib {
 					if !ctx.Config().AllowMissingDependencies() {
 						ctx.ModuleErrorf("module %q is not a static library", depName)
 					} else {
@@ -3391,7 +3233,6 @@
 					break
 				}
 
-				staticLibraryInfo := ctx.OtherModuleProvider(dep, StaticLibraryInfoProvider).(StaticLibraryInfo)
 				linkFile = android.OptionalPathForPath(staticLibraryInfo.StaticLibrary)
 				if libDepTag.wholeStatic {
 					ptr = &depPaths.WholeStaticLibs
@@ -3485,13 +3326,13 @@
 				// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
 				// Re-exported shared library headers must be included as well since they can help us with type information
 				// about template instantiations (instantiated from their headers).
-				// -isystem headers are not included since for bionic libraries, abi-filtering is taken care of by version
-				// scripts.
 				c.sabi.Properties.ReexportedIncludes = append(
 					c.sabi.Properties.ReexportedIncludes, depExporterInfo.IncludeDirs.Strings()...)
+				c.sabi.Properties.ReexportedSystemIncludes = append(
+					c.sabi.Properties.ReexportedSystemIncludes, depExporterInfo.SystemIncludeDirs.Strings()...)
 			}
 
-			makeLibName := MakeLibName(ctx, c, ccDep, depName) + libDepTag.makeSuffix
+			makeLibName := MakeLibName(ctx, c, ccDep, ccDep.BaseModuleName()) + libDepTag.makeSuffix
 			switch {
 			case libDepTag.header():
 				c.Properties.AndroidMkHeaderLibs = append(
@@ -3501,7 +3342,7 @@
 					if lib.buildStubs() && dep.(android.ApexModule).InAnyApex() {
 						// Add the dependency to the APEX(es) providing the library so that
 						// m <module> can trigger building the APEXes as well.
-						depApexInfo := ctx.OtherModuleProvider(dep, android.ApexInfoProvider).(android.ApexInfo)
+						depApexInfo, _ := android.OtherModuleProvider(ctx, dep, android.ApexInfoProvider)
 						for _, an := range depApexInfo.InApexVariants {
 							c.Properties.ApexesProvidingSharedLibs = append(
 								c.Properties.ApexesProvidingSharedLibs, an)
@@ -3513,8 +3354,6 @@
 				// they merely serve as Make dependencies and do not affect this lib itself.
 				c.Properties.AndroidMkSharedLibs = append(
 					c.Properties.AndroidMkSharedLibs, makeLibName)
-				// Record BaseLibName for snapshots.
-				c.Properties.SnapshotSharedLibs = append(c.Properties.SnapshotSharedLibs, BaseLibName(depName))
 			case libDepTag.static():
 				if libDepTag.wholeStatic {
 					c.Properties.AndroidMkWholeStaticLibs = append(
@@ -3523,8 +3362,6 @@
 					c.Properties.AndroidMkStaticLibs = append(
 						c.Properties.AndroidMkStaticLibs, makeLibName)
 				}
-				// Record BaseLibName for snapshots.
-				c.Properties.SnapshotStaticLibs = append(c.Properties.SnapshotStaticLibs, BaseLibName(depName))
 			}
 		} else if !c.IsStubs() {
 			// Stubs lib doesn't link to the runtime lib, object, crt, etc. dependencies.
@@ -3532,9 +3369,7 @@
 			switch depTag {
 			case runtimeDepTag:
 				c.Properties.AndroidMkRuntimeLibs = append(
-					c.Properties.AndroidMkRuntimeLibs, MakeLibName(ctx, c, ccDep, depName)+libDepTag.makeSuffix)
-				// Record BaseLibName for snapshots.
-				c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, BaseLibName(depName))
+					c.Properties.AndroidMkRuntimeLibs, MakeLibName(ctx, c, ccDep, ccDep.BaseModuleName())+libDepTag.makeSuffix)
 			case objDepTag:
 				depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path())
 			case CrtBeginDepTag:
@@ -3565,6 +3400,7 @@
 
 	if c.sabi != nil {
 		c.sabi.Properties.ReexportedIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludes)
+		c.sabi.Properties.ReexportedSystemIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedSystemIncludes)
 	}
 
 	return depPaths
@@ -3577,20 +3413,20 @@
 		panic(fmt.Errorf("Not an APEX module: %q", ctx.ModuleName()))
 	}
 
-	useVndk := false
+	inVendorOrProduct := false
 	bootstrap := false
 	if linkable, ok := ctx.Module().(LinkableInterface); !ok {
 		panic(fmt.Errorf("Not a Linkable module: %q", ctx.ModuleName()))
 	} else {
-		useVndk = linkable.UseVndk()
+		inVendorOrProduct = linkable.InVendorOrProduct()
 		bootstrap = linkable.Bootstrap()
 	}
 
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 
 	useStubs := false
 
-	if lib := moduleLibraryInterface(dep); lib.buildStubs() && useVndk { // LLNDK
+	if lib := moduleLibraryInterface(dep); lib.buildStubs() && inVendorOrProduct { // LLNDK
 		if !apexInfo.IsForPlatform() {
 			// For platform libraries, use current version of LLNDK
 			// If this is for use_vendor apex we will apply the same rules
@@ -3620,7 +3456,7 @@
 			// Another exception: if this module is a test for an APEX, then
 			// it is linked with the non-stub variant of a module in the APEX
 			// as if this is part of the APEX.
-			testFor := ctx.Provider(android.ApexTestForInfoProvider).(android.ApexTestForInfo)
+			testFor, _ := android.ModuleProvider(ctx, android.ApexTestForInfoProvider)
 			for _, apexContents := range testFor.ApexContents {
 				if apexContents.DirectlyInApex(depName) {
 					useStubs = false
@@ -3666,9 +3502,9 @@
 		panic(fmt.Errorf("Unexpected dependency tag: %T", depTag))
 	}
 
-	sharedLibraryInfo := ctx.OtherModuleProvider(dep, SharedLibraryInfoProvider).(SharedLibraryInfo)
-	depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
-	sharedLibraryStubsInfo := ctx.OtherModuleProvider(dep, SharedLibraryStubsProvider).(SharedLibraryStubsInfo)
+	sharedLibraryInfo, _ := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider)
+	depExporterInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider)
+	sharedLibraryStubsInfo, _ := android.OtherModuleProvider(ctx, dep, SharedLibraryStubsProvider)
 
 	if !libDepTag.explicitlyVersioned && len(sharedLibraryStubsInfo.SharedStubLibraries) > 0 {
 		// when to use (unspecified) stubs, use the latest one.
@@ -3742,7 +3578,7 @@
 		// The vendor module is a no-vendor-variant VNDK library.  Depend on the
 		// core module instead.
 		return libName
-	} else if ccDep.UseVndk() && nonSystemVariantsExist {
+	} else if ccDep.InVendorOrProduct() && nonSystemVariantsExist {
 		// The vendor and product modules in Make will have been renamed to not conflict with the
 		// core module, so update the dependency name here accordingly.
 		return libName + ccDep.SubName()
@@ -3819,6 +3655,11 @@
 			return android.PathsIfNonNil(c.linker.unstrippedOutputFilePath()), nil
 		}
 		return nil, nil
+	case "stripped_all":
+		if c.linker != nil {
+			return android.PathsIfNonNil(c.linker.strippedAllOutputFilePath()), nil
+		}
+		return nil, nil
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
@@ -3913,8 +3754,16 @@
 	return false
 }
 
+func (m *Module) Dylib() bool {
+	return false
+}
+
+func (m *Module) Rlib() bool {
+	return false
+}
+
 func GetMakeLinkType(actx android.ModuleContext, c LinkableInterface) string {
-	if c.UseVndk() {
+	if c.InVendorOrProduct() {
 		if c.IsLlndk() {
 			if !c.IsLlndkPublic() {
 				return "native:vndk_private"
@@ -4144,8 +3993,6 @@
 	return nil
 }
 
-var _ snapshot.RelativeInstallPath = (*Module)(nil)
-
 type moduleType int
 
 const (
@@ -4158,6 +4005,7 @@
 	headerLibrary
 	testBin // testBinary already declared
 	ndkLibrary
+	ndkPrebuiltStl
 )
 
 func (c *Module) typ() moduleType {
@@ -4196,78 +4044,20 @@
 		return sharedLibrary
 	} else if c.isNDKStubLibrary() {
 		return ndkLibrary
+	} else if c.IsNdkPrebuiltStl() {
+		return ndkPrebuiltStl
 	}
 	return unknownType
 }
 
-// ConvertWithBp2build converts Module to Bazel for bp2build.
-func (c *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	prebuilt := c.IsPrebuilt()
-	switch c.typ() {
-	case binary:
-		if prebuilt {
-			prebuiltBinaryBp2Build(ctx, c)
-		} else {
-			binaryBp2build(ctx, c)
-		}
-	case testBin:
-		if !prebuilt {
-			testBinaryBp2build(ctx, c)
-		}
-	case object:
-		if prebuilt {
-			prebuiltObjectBp2Build(ctx, c)
-		} else {
-			objectBp2Build(ctx, c)
-		}
-	case fullLibrary:
-		if !prebuilt {
-			libraryBp2Build(ctx, c)
-		} else {
-			prebuiltLibraryBp2Build(ctx, c)
-		}
-	case headerLibrary:
-		libraryHeadersBp2Build(ctx, c)
-	case staticLibrary:
-		if prebuilt {
-			prebuiltLibraryStaticBp2Build(ctx, c, false)
-		} else {
-			sharedOrStaticLibraryBp2Build(ctx, c, true)
-		}
-	case sharedLibrary:
-		if prebuilt {
-			prebuiltLibrarySharedBp2Build(ctx, c)
-		} else {
-			sharedOrStaticLibraryBp2Build(ctx, c, false)
-		}
-	default:
-		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
-	}
-}
-
-var _ android.ApiProvider = (*Module)(nil)
-
-func (c *Module) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
-	if c.IsPrebuilt() {
-		return
-	}
-	switch c.typ() {
-	case fullLibrary:
-		apiContributionBp2Build(ctx, c)
-	case sharedLibrary:
-		apiContributionBp2Build(ctx, c)
-	case headerLibrary:
-		// Aggressively generate api targets for all header modules
-		// This is necessary since the header module does not know if it is a dep of API surface stub library
-		apiLibraryHeadersBp2Build(ctx, c)
-	}
-}
-
 // Defaults
 type Defaults struct {
 	android.ModuleBase
 	android.DefaultsModuleBase
 	android.ApexModuleBase
+
+	// Aconfig files for all transitive deps.  Also exposed via TransitiveDeclarationsInfo
+	mergedAconfigFiles map[string]android.Paths
 }
 
 // cc_defaults provides a set of properties that can be inherited by other cc
@@ -4309,7 +4099,6 @@
 		&VndkProperties{},
 		&LTOProperties{},
 		&AfdoProperties{},
-		&PgoProperties{},
 		&OrderfileProperties{},
 		&android.ProtoProperties{},
 		// RustBindgenProperties is included here so that cc_defaults can be used for rust_bindgen modules.
@@ -4360,6 +4149,18 @@
 	return ""
 }
 
+type sourceModuleName interface {
+	sourceModuleName() string
+}
+
+func (c *Module) BaseModuleName() string {
+	if smn, ok := c.linker.(sourceModuleName); ok && smn.sourceModuleName() != "" {
+		// if the prebuilt module sets a source_module_name in Android.bp, use that
+		return smn.sourceModuleName()
+	}
+	return c.ModuleBase.BaseModuleName()
+}
+
 var Bool = proptools.Bool
 var BoolDefault = proptools.BoolDefault
 var BoolPtr = proptools.BoolPtr
diff --git a/cc/cc_test.go b/cc/cc_test.go
index d95ed3f..3d75bf5 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -17,7 +17,6 @@
 import (
 	"fmt"
 	"os"
-	"path/filepath"
 	"reflect"
 	"regexp"
 	"runtime"
@@ -26,7 +25,8 @@
 
 	"android/soong/aidl_library"
 	"android/soong/android"
-	"android/soong/bazel/cquery"
+
+	"github.com/google/blueprint"
 )
 
 func init() {
@@ -38,35 +38,21 @@
 }
 
 var prepareForCcTest = android.GroupFixturePreparers(
-	PrepareForTestWithCcIncludeVndk,
+	PrepareForIntegrationTestWithCc,
 	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-		variables.DeviceVndkVersion = StringPtr("current")
-		variables.ProductVndkVersion = StringPtr("current")
-		variables.Platform_vndk_version = StringPtr("29")
+		variables.VendorApiLevel = StringPtr("202404")
 	}),
 )
 
-var ccLibInApex = "cc_lib_in_apex"
 var apexVariationName = "apex28"
 var apexVersion = "28"
 
 func registerTestMutators(ctx android.RegistrationContext) {
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("apex", testApexMutator).Parallel()
-		ctx.BottomUp("mixed_builds_prep", mixedBuildsPrepareMutator).Parallel()
 	})
 }
 
-func mixedBuildsPrepareMutator(ctx android.BottomUpMutatorContext) {
-	if m := ctx.Module(); m.Enabled() {
-		if mixedBuildMod, ok := m.(android.MixedBuildBuildable); ok {
-			if mixedBuildMod.IsMixedBuildSupported(ctx) && android.MixedBuildsEnabled(ctx) == android.MixedBuildEnabled {
-				mixedBuildMod.QueueBazelCall(ctx)
-			}
-		}
-	}
-}
-
 func testApexMutator(mctx android.BottomUpMutatorContext) {
 	modules := mctx.CreateVariations(apexVariationName)
 	apexInfo := android.ApexInfo{
@@ -104,33 +90,6 @@
 	return result.TestContext
 }
 
-// testCcNoVndk runs tests using the prepareForCcTest
-//
-// See testCc for an explanation as to how to stop using this deprecated method.
-//
-// deprecated
-func testCcNoVndk(t *testing.T, bp string) *android.TestContext {
-	t.Helper()
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-
-	return testCcWithConfig(t, config)
-}
-
-// testCcNoProductVndk runs tests using the prepareForCcTest
-//
-// See testCc for an explanation as to how to stop using this deprecated method.
-//
-// deprecated
-func testCcNoProductVndk(t *testing.T, bp string) *android.TestContext {
-	t.Helper()
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-
-	return testCcWithConfig(t, config)
-}
-
 // testCcErrorWithConfig runs tests using the prepareForCcTest
 //
 // See testCc for an explanation as to how to stop using this deprecated method.
@@ -152,31 +111,14 @@
 func testCcError(t *testing.T, pattern string, bp string) {
 	t.Helper()
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	testCcErrorWithConfig(t, pattern, config)
-	return
-}
-
-// testCcErrorProductVndk runs tests using the prepareForCcTest
-//
-// See testCc for an explanation as to how to stop using this deprecated method.
-//
-// deprecated
-func testCcErrorProductVndk(t *testing.T, pattern string, bp string) {
-	t.Helper()
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	testCcErrorWithConfig(t, pattern, config)
 	return
 }
 
 const (
 	coreVariant     = "android_arm64_armv8-a_shared"
-	vendorVariant   = "android_vendor.29_arm64_armv8-a_shared"
-	productVariant  = "android_product.29_arm64_armv8-a_shared"
+	vendorVariant   = "android_vendor_arm64_armv8-a_shared"
+	productVariant  = "android_product_arm64_armv8-a_shared"
 	recoveryVariant = "android_recovery_arm64_armv8-a_shared"
 )
 
@@ -235,13 +177,13 @@
 		}
 	}
 	socSpecific := func(m *Module) bool {
-		return m.SocSpecific() || m.socSpecificModuleContext()
+		return m.SocSpecific() || m.InstallInVendor()
 	}
 	deviceSpecific := func(m *Module) bool {
-		return m.DeviceSpecific() || m.deviceSpecificModuleContext()
+		return m.DeviceSpecific() || m.InstallInOdm()
 	}
 	productSpecific := func(m *Module) bool {
-		return m.ProductSpecific() || m.productSpecificModuleContext()
+		return m.ProductSpecific() || m.InstallInProduct()
 	}
 	systemExtSpecific := func(m *Module) bool {
 		return m.SystemExtSpecific()
@@ -332,388 +274,13 @@
 	checkInstallPartition(t, ctx, "libproduct_odmavailable", vendorVariant, "odm")
 }
 
-func checkVndkModule(t *testing.T, ctx *android.TestContext, name, subDir string,
-	isVndkSp bool, extends string, variant string) {
-
+func checkWriteFileOutput(t *testing.T, ctx *android.TestContext, params android.TestingBuildParams, expected []string) {
 	t.Helper()
-
-	mod := ctx.ModuleForTests(name, variant).Module().(*Module)
-
-	// Check library properties.
-	lib, ok := mod.compiler.(*libraryDecorator)
-	if !ok {
-		t.Errorf("%q must have libraryDecorator", name)
-	} else if lib.baseInstaller.subDir != subDir {
-		t.Errorf("%q must use %q as subdir but it is using %q", name, subDir,
-			lib.baseInstaller.subDir)
-	}
-
-	// Check VNDK properties.
-	if mod.vndkdep == nil {
-		t.Fatalf("%q must have `vndkdep`", name)
-	}
-	if !mod.IsVndk() {
-		t.Errorf("%q IsVndk() must equal to true", name)
-	}
-	if mod.IsVndkSp() != isVndkSp {
-		t.Errorf("%q IsVndkSp() must equal to %t", name, isVndkSp)
-	}
-
-	// Check VNDK extension properties.
-	isVndkExt := extends != ""
-	if mod.IsVndkExt() != isVndkExt {
-		t.Errorf("%q IsVndkExt() must equal to %t", name, isVndkExt)
-	}
-
-	if actualExtends := mod.getVndkExtendsModuleName(); actualExtends != extends {
-		t.Errorf("%q must extend from %q but get %q", name, extends, actualExtends)
-	}
-}
-
-func checkWriteFileOutput(t *testing.T, params android.TestingBuildParams, expected []string) {
-	t.Helper()
-	content := android.ContentFromFileRuleForTests(t, params)
+	content := android.ContentFromFileRuleForTests(t, ctx, params)
 	actual := strings.FieldsFunc(content, func(r rune) bool { return r == '\n' })
 	assertArrayString(t, actual, expected)
 }
 
-func checkVndkOutput(t *testing.T, ctx *android.TestContext, output string, expected []string) {
-	t.Helper()
-	vndkSnapshot := ctx.SingletonForTests("vndk-snapshot")
-	checkWriteFileOutput(t, vndkSnapshot.Output(output), expected)
-}
-
-func checkVndkLibrariesOutput(t *testing.T, ctx *android.TestContext, module string, expected []string) {
-	t.Helper()
-	got := ctx.ModuleForTests(module, "android_common").Module().(*vndkLibrariesTxt).fileNames
-	assertArrayString(t, got, expected)
-}
-
-func TestVndk(t *testing.T) {
-	t.Parallel()
-	bp := `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_private",
-			vendor_available: true,
-			vndk: {
-				enabled: true,
-				private: true,
-			},
-			nocrt: true,
-			stem: "libvndk-private",
-		}
-
-		cc_library {
-			name: "libvndk_product",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-			target: {
-				vendor: {
-					cflags: ["-DTEST"],
-				},
-				product: {
-					cflags: ["-DTEST"],
-				},
-			},
-		}
-
-		cc_library {
-			name: "libvndk_sp",
-			vendor_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			nocrt: true,
-			suffix: "-x",
-		}
-
-		cc_library {
-			name: "libvndk_sp_private",
-			vendor_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-				private: true,
-			},
-			nocrt: true,
-			target: {
-				vendor: {
-					suffix: "-x",
-				},
-			},
-		}
-
-		cc_library {
-			name: "libvndk_sp_product_private",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-				private: true,
-			},
-			nocrt: true,
-			target: {
-				vendor: {
-					suffix: "-x",
-				},
-				product: {
-					suffix: "-x",
-				},
-			},
-		}
-
-		cc_library {
-			name: "libllndk",
-			llndk: {
-				symbol_file: "libllndk.map.txt",
-				export_llndk_headers: ["libllndk_headers"],
-			}
-		}
-
-		cc_library {
-			name: "libclang_rt.hwasan-llndk",
-			llndk: {
-				symbol_file: "libclang_rt.hwasan.map.txt",
-			}
-		}
-
-		cc_library_headers {
-			name: "libllndk_headers",
-			llndk: {
-				llndk_headers: true,
-			},
-			export_include_dirs: ["include"],
-		}
-
-		llndk_libraries_txt {
-			name: "llndk.libraries.txt",
-		}
-		vndkcore_libraries_txt {
-			name: "vndkcore.libraries.txt",
-		}
-		vndksp_libraries_txt {
-			name: "vndksp.libraries.txt",
-		}
-		vndkprivate_libraries_txt {
-			name: "vndkprivate.libraries.txt",
-		}
-		vndkproduct_libraries_txt {
-			name: "vndkproduct.libraries.txt",
-		}
-		vndkcorevariant_libraries_txt {
-			name: "vndkcorevariant.libraries.txt",
-			insert_vndk_version: false,
-		}
-	`
-
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-
-	ctx := testCcWithConfig(t, config)
-
-	// subdir == "" because VNDK libs are not supposed to be installed separately.
-	// They are installed as part of VNDK APEX instead.
-	checkVndkModule(t, ctx, "libvndk", "", false, "", vendorVariant)
-	checkVndkModule(t, ctx, "libvndk_private", "", false, "", vendorVariant)
-	checkVndkModule(t, ctx, "libvndk_product", "", false, "", vendorVariant)
-	checkVndkModule(t, ctx, "libvndk_sp", "", true, "", vendorVariant)
-	checkVndkModule(t, ctx, "libvndk_sp_private", "", true, "", vendorVariant)
-	checkVndkModule(t, ctx, "libvndk_sp_product_private", "", true, "", vendorVariant)
-
-	checkVndkModule(t, ctx, "libvndk_product", "", false, "", productVariant)
-	checkVndkModule(t, ctx, "libvndk_sp_product_private", "", true, "", productVariant)
-
-	// Check VNDK snapshot output.
-	snapshotDir := "vndk-snapshot"
-	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
-
-	vndkLibPath := filepath.Join(snapshotVariantPath, fmt.Sprintf("arch-%s-%s",
-		"arm64", "armv8-a"))
-	vndkLib2ndPath := filepath.Join(snapshotVariantPath, fmt.Sprintf("arch-%s-%s",
-		"arm", "armv7-a-neon"))
-
-	vndkCoreLibPath := filepath.Join(vndkLibPath, "shared", "vndk-core")
-	vndkSpLibPath := filepath.Join(vndkLibPath, "shared", "vndk-sp")
-	llndkLibPath := filepath.Join(vndkLibPath, "shared", "llndk-stub")
-
-	vndkCoreLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-core")
-	vndkSpLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "vndk-sp")
-	llndkLib2ndPath := filepath.Join(vndkLib2ndPath, "shared", "llndk-stub")
-
-	variant := "android_vendor.29_arm64_armv8-a_shared"
-	variant2nd := "android_vendor.29_arm_armv7-a-neon_shared"
-
-	snapshotSingleton := ctx.SingletonForTests("vndk-snapshot")
-
-	CheckSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", vndkCoreLibPath, variant)
-	CheckSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", vndkCoreLib2ndPath, variant2nd)
-	CheckSnapshot(t, ctx, snapshotSingleton, "libvndk_product", "libvndk_product.so", vndkCoreLibPath, variant)
-	CheckSnapshot(t, ctx, snapshotSingleton, "libvndk_product", "libvndk_product.so", vndkCoreLib2ndPath, variant2nd)
-	CheckSnapshot(t, ctx, snapshotSingleton, "libvndk_sp", "libvndk_sp-x.so", vndkSpLibPath, variant)
-	CheckSnapshot(t, ctx, snapshotSingleton, "libvndk_sp", "libvndk_sp-x.so", vndkSpLib2ndPath, variant2nd)
-	CheckSnapshot(t, ctx, snapshotSingleton, "libllndk", "libllndk.so", llndkLibPath, variant)
-	CheckSnapshot(t, ctx, snapshotSingleton, "libllndk", "libllndk.so", llndkLib2ndPath, variant2nd)
-
-	snapshotConfigsPath := filepath.Join(snapshotVariantPath, "configs")
-	CheckSnapshot(t, ctx, snapshotSingleton, "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "android_common")
-	CheckSnapshot(t, ctx, snapshotSingleton, "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "android_common")
-	CheckSnapshot(t, ctx, snapshotSingleton, "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "android_common")
-	CheckSnapshot(t, ctx, snapshotSingleton, "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "android_common")
-	CheckSnapshot(t, ctx, snapshotSingleton, "vndkproduct.libraries.txt", "vndkproduct.libraries.txt", snapshotConfigsPath, "android_common")
-
-	checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{
-		"LLNDK: libc.so",
-		"LLNDK: libdl.so",
-		"LLNDK: libft2.so",
-		"LLNDK: libllndk.so",
-		"LLNDK: libm.so",
-		"VNDK-SP: libc++.so",
-		"VNDK-SP: libvndk_sp-x.so",
-		"VNDK-SP: libvndk_sp_private-x.so",
-		"VNDK-SP: libvndk_sp_product_private-x.so",
-		"VNDK-core: libvndk-private.so",
-		"VNDK-core: libvndk.so",
-		"VNDK-core: libvndk_product.so",
-		"VNDK-private: libft2.so",
-		"VNDK-private: libvndk-private.so",
-		"VNDK-private: libvndk_sp_private-x.so",
-		"VNDK-private: libvndk_sp_product_private-x.so",
-		"VNDK-product: libc++.so",
-		"VNDK-product: libvndk_product.so",
-		"VNDK-product: libvndk_sp_product_private-x.so",
-	})
-	checkVndkLibrariesOutput(t, ctx, "llndk.libraries.txt", []string{"libc.so", "libclang_rt.hwasan-llndk.so", "libdl.so", "libft2.so", "libllndk.so", "libm.so"})
-	checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt", []string{"libvndk-private.so", "libvndk.so", "libvndk_product.so"})
-	checkVndkLibrariesOutput(t, ctx, "vndksp.libraries.txt", []string{"libc++.so", "libvndk_sp-x.so", "libvndk_sp_private-x.so", "libvndk_sp_product_private-x.so"})
-	checkVndkLibrariesOutput(t, ctx, "vndkprivate.libraries.txt", []string{"libft2.so", "libvndk-private.so", "libvndk_sp_private-x.so", "libvndk_sp_product_private-x.so"})
-	checkVndkLibrariesOutput(t, ctx, "vndkproduct.libraries.txt", []string{"libc++.so", "libvndk_product.so", "libvndk_sp_product_private-x.so"})
-	checkVndkLibrariesOutput(t, ctx, "vndkcorevariant.libraries.txt", nil)
-}
-
-func TestVndkWithHostSupported(t *testing.T) {
-	t.Parallel()
-	ctx := testCc(t, `
-		cc_library {
-			name: "libvndk_host_supported",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			host_supported: true,
-		}
-
-		cc_library {
-			name: "libvndk_host_supported_but_disabled_on_device",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			host_supported: true,
-			enabled: false,
-			target: {
-				host: {
-					enabled: true,
-				}
-			}
-		}
-
-		vndkcore_libraries_txt {
-			name: "vndkcore.libraries.txt",
-		}
-	`)
-
-	checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt", []string{"libvndk_host_supported.so"})
-}
-
-func TestVndkLibrariesTxtAndroidMk(t *testing.T) {
-	t.Parallel()
-	bp := `
-		llndk_libraries_txt {
-			name: "llndk.libraries.txt",
-			insert_vndk_version: true,
-		}`
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	ctx := testCcWithConfig(t, config)
-
-	module := ctx.ModuleForTests("llndk.libraries.txt", "android_common")
-	entries := android.AndroidMkEntriesForTest(t, ctx, module.Module())[0]
-	assertArrayString(t, entries.EntryMap["LOCAL_MODULE_STEM"], []string{"llndk.libraries.29.txt"})
-}
-
-func TestVndkUsingCoreVariant(t *testing.T) {
-	t.Parallel()
-	bp := `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk2",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				private: true,
-			},
-			nocrt: true,
-		}
-
-		vndkcorevariant_libraries_txt {
-			name: "vndkcorevariant.libraries.txt",
-			insert_vndk_version: false,
-		}
-	`
-
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
-
-	setVndkMustUseVendorVariantListForTest(config, []string{"libvndk"})
-
-	ctx := testCcWithConfig(t, config)
-
-	checkVndkLibrariesOutput(t, ctx, "vndkcorevariant.libraries.txt", []string{"libc++.so", "libvndk2.so", "libvndk_sp.so"})
-}
-
 func TestDataLibs(t *testing.T) {
 	t.Parallel()
 	bp := `
@@ -731,9 +298,6 @@
  `
 
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
 
 	ctx := testCcWithConfig(t, config)
 	module := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon").Module()
@@ -748,7 +312,7 @@
 		return
 	}
 	if len(testBinary.dataPaths()) != 1 {
-		t.Errorf("expected exactly one test data file. test data files: [%s]", testBinary.dataPaths())
+		t.Errorf("expected exactly one test data file. test data files: [%v]", testBinary.dataPaths())
 		return
 	}
 
@@ -790,9 +354,6 @@
  `
 
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
 
 	ctx := testCcWithConfig(t, config)
 	module := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon").Module()
@@ -805,7 +366,7 @@
 		t.Fatalf("expected exactly one output file. output files: [%s]", outputFiles)
 	}
 	if len(testBinary.dataPaths()) != 2 {
-		t.Fatalf("expected exactly one test data file. test data files: [%s]", testBinary.dataPaths())
+		t.Fatalf("expected exactly one test data file. test data files: [%v]", testBinary.dataPaths())
 	}
 
 	outputPath := outputFiles[0].String()
@@ -888,300 +449,9 @@
 	}
 }
 
-func TestVndkWhenVndkVersionIsNotSet(t *testing.T) {
-	t.Parallel()
-	ctx := testCcNoVndk(t, `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-		cc_library {
-			name: "libvndk-private",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				private: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libllndk",
-			llndk: {
-				symbol_file: "libllndk.map.txt",
-				export_llndk_headers: ["libllndk_headers"],
-			}
-		}
-
-		cc_library_headers {
-			name: "libllndk_headers",
-			llndk: {
-				symbol_file: "libllndk.map.txt",
-			},
-			export_include_dirs: ["include"],
-		}
-	`)
-
-	checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{
-		"LLNDK: libc.so",
-		"LLNDK: libdl.so",
-		"LLNDK: libft2.so",
-		"LLNDK: libllndk.so",
-		"LLNDK: libm.so",
-		"VNDK-SP: libc++.so",
-		"VNDK-core: libvndk-private.so",
-		"VNDK-core: libvndk.so",
-		"VNDK-private: libft2.so",
-		"VNDK-private: libvndk-private.so",
-		"VNDK-product: libc++.so",
-		"VNDK-product: libvndk-private.so",
-		"VNDK-product: libvndk.so",
-	})
-}
-
-func TestVndkModuleError(t *testing.T) {
-	t.Parallel()
-	// Check the error message for vendor_available and product_available properties.
-	testCcErrorProductVndk(t, "vndk: vendor_available must be set to true when `vndk: {enabled: true}`", `
-		cc_library {
-			name: "libvndk",
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-	`)
-
-	testCcErrorProductVndk(t, "vndk: vendor_available must be set to true when `vndk: {enabled: true}`", `
-		cc_library {
-			name: "libvndk",
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-	`)
-
-	testCcErrorProductVndk(t, "product properties must have the same values with the vendor properties for VNDK modules", `
-		cc_library {
-			name: "libvndkprop",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-			target: {
-				vendor: {
-					cflags: ["-DTEST",],
-				},
-			},
-		}
-	`)
-}
-
-func TestVndkDepError(t *testing.T) {
-	t.Parallel()
-	// Check whether an error is emitted when a VNDK lib depends on a system lib.
-	testCcError(t, "dependency \".*\" of \".*\" missing variant", `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			shared_libs: ["libfwk"],  // Cause error
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libfwk",
-			nocrt: true,
-		}
-	`)
-
-	// Check whether an error is emitted when a VNDK lib depends on a vendor lib.
-	testCcError(t, "dependency \".*\" of \".*\" missing variant", `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			shared_libs: ["libvendor"],  // Cause error
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvendor",
-			vendor: true,
-			nocrt: true,
-		}
-	`)
-
-	// Check whether an error is emitted when a VNDK-SP lib depends on a system lib.
-	testCcError(t, "dependency \".*\" of \".*\" missing variant", `
-		cc_library {
-			name: "libvndk_sp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			shared_libs: ["libfwk"],  // Cause error
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libfwk",
-			nocrt: true,
-		}
-	`)
-
-	// Check whether an error is emitted when a VNDK-SP lib depends on a vendor lib.
-	testCcError(t, "dependency \".*\" of \".*\" missing variant", `
-		cc_library {
-			name: "libvndk_sp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			shared_libs: ["libvendor"],  // Cause error
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvendor",
-			vendor: true,
-			nocrt: true,
-		}
-	`)
-
-	// Check whether an error is emitted when a VNDK-SP lib depends on a VNDK lib.
-	testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
-		cc_library {
-			name: "libvndk_sp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			shared_libs: ["libvndk"],  // Cause error
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-	`)
-
-	// Check whether an error is emitted when a VNDK lib depends on a non-VNDK lib.
-	testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			shared_libs: ["libnonvndk"],
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libnonvndk",
-			vendor_available: true,
-			nocrt: true,
-		}
-	`)
-
-	// Check whether an error is emitted when a VNDK-private lib depends on a non-VNDK lib.
-	testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
-		cc_library {
-			name: "libvndkprivate",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				private: true,
-			},
-			shared_libs: ["libnonvndk"],
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libnonvndk",
-			vendor_available: true,
-			nocrt: true,
-		}
-	`)
-
-	// Check whether an error is emitted when a VNDK-sp lib depends on a non-VNDK lib.
-	testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
-		cc_library {
-			name: "libvndksp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			shared_libs: ["libnonvndk"],
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libnonvndk",
-			vendor_available: true,
-			nocrt: true,
-		}
-	`)
-
-	// Check whether an error is emitted when a VNDK-sp-private lib depends on a non-VNDK lib.
-	testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
-		cc_library {
-			name: "libvndkspprivate",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-				private: true,
-			},
-			shared_libs: ["libnonvndk"],
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libnonvndk",
-			vendor_available: true,
-			nocrt: true,
-		}
-	`)
-}
-
 func TestDoubleLoadbleDep(t *testing.T) {
 	t.Parallel()
-	// okay to link : LLNDK -> double_loadable VNDK
+	// okay to link : LLNDK -> double_loadable
 	testCc(t, `
 		cc_library {
 			name: "libllndk",
@@ -1195,32 +465,9 @@
 			name: "libdoubleloadable",
 			vendor_available: true,
 			product_available: true,
-			vndk: {
-				enabled: true,
-			},
 			double_loadable: true,
 		}
 	`)
-	// okay to link : LLNDK -> VNDK-SP
-	testCc(t, `
-		cc_library {
-			name: "libllndk",
-			shared_libs: ["libvndksp"],
-			llndk: {
-				symbol_file: "libllndk.map.txt",
-			}
-		}
-
-		cc_library {
-			name: "libvndksp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-		}
-	`)
 	// okay to link : double_loadable -> double_loadable
 	testCc(t, `
 		cc_library {
@@ -1236,15 +483,12 @@
 			double_loadable: true,
 		}
 	`)
-	// okay to link : double_loadable VNDK -> double_loadable VNDK private
+	// okay to link : double_loadable -> double_loadable
 	testCc(t, `
 		cc_library {
 			name: "libdoubleloadable",
 			vendor_available: true,
 			product_available: true,
-			vndk: {
-				enabled: true,
-			},
 			double_loadable: true,
 			shared_libs: ["libnondoubleloadable"],
 		}
@@ -1253,10 +497,6 @@
 			name: "libnondoubleloadable",
 			vendor_available: true,
 			product_available: true,
-			vndk: {
-				enabled: true,
-				private: true,
-			},
 			double_loadable: true,
 		}
 	`)
@@ -1286,7 +526,7 @@
 
 func TestDoubleLoadableDepError(t *testing.T) {
 	t.Parallel()
-	// Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib.
+	// Check whether an error is emitted when a LLNDK depends on a non-double_loadable lib.
 	testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", `
 		cc_library {
 			name: "libllndk",
@@ -1300,9 +540,6 @@
 			name: "libnondoubleloadable",
 			vendor_available: true,
 			product_available: true,
-			vndk: {
-				enabled: true,
-			},
 		}
 	`)
 
@@ -1367,1062 +604,13 @@
 	`)
 }
 
-func TestCheckVndkMembershipBeforeDoubleLoadable(t *testing.T) {
-	t.Parallel()
-	testCcError(t, "module \"libvndksp\" variant .*: .*: VNDK-SP must only depend on VNDK-SP", `
-		cc_library {
-			name: "libvndksp",
-			shared_libs: ["libanothervndksp"],
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			}
-		}
-
-		cc_library {
-			name: "libllndk",
-			shared_libs: ["libanothervndksp"],
-		}
-
-		cc_library {
-			name: "libanothervndksp",
-			vendor_available: true,
-		}
-	`)
-}
-
-func TestVndkExt(t *testing.T) {
-	t.Parallel()
-	// This test checks the VNDK-Ext properties.
-	bp := `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-		cc_library {
-			name: "libvndk2",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			target: {
-				vendor: {
-					suffix: "-suffix",
-				},
-				product: {
-					suffix: "-suffix",
-				},
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk2_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk2",
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext_product",
-			product_specific: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk2_ext_product",
-			product_specific: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk2",
-			},
-			nocrt: true,
-		}
-	`
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-
-	ctx := testCcWithConfig(t, config)
-
-	checkVndkModule(t, ctx, "libvndk_ext", "vndk", false, "libvndk", vendorVariant)
-	checkVndkModule(t, ctx, "libvndk_ext_product", "vndk", false, "libvndk", productVariant)
-
-	mod_vendor := ctx.ModuleForTests("libvndk2_ext", vendorVariant).Module().(*Module)
-	assertString(t, mod_vendor.outputFile.Path().Base(), "libvndk2-suffix.so")
-
-	mod_product := ctx.ModuleForTests("libvndk2_ext_product", productVariant).Module().(*Module)
-	assertString(t, mod_product.outputFile.Path().Base(), "libvndk2-suffix.so")
-}
-
-func TestVndkExtWithoutBoardVndkVersion(t *testing.T) {
-	t.Parallel()
-	// This test checks the VNDK-Ext properties when BOARD_VNDK_VERSION is not set.
-	ctx := testCcNoVndk(t, `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-	`)
-
-	// Ensures that the core variant of "libvndk_ext" can be found.
-	mod := ctx.ModuleForTests("libvndk_ext", coreVariant).Module().(*Module)
-	if extends := mod.getVndkExtendsModuleName(); extends != "libvndk" {
-		t.Errorf("\"libvndk_ext\" must extend from \"libvndk\" but get %q", extends)
-	}
-}
-
-func TestVndkExtWithoutProductVndkVersion(t *testing.T) {
-	t.Parallel()
-	// This test checks the VNDK-Ext properties when PRODUCT_PRODUCT_VNDK_VERSION is not set.
-	ctx := testCcNoProductVndk(t, `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext_product",
-			product_specific: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-	`)
-
-	// Ensures that the core variant of "libvndk_ext_product" can be found.
-	mod := ctx.ModuleForTests("libvndk_ext_product", coreVariant).Module().(*Module)
-	if extends := mod.getVndkExtendsModuleName(); extends != "libvndk" {
-		t.Errorf("\"libvndk_ext_product\" must extend from \"libvndk\" but get %q", extends)
-	}
-}
-
-func TestVndkExtError(t *testing.T) {
-	t.Parallel()
-	// This test ensures an error is emitted in ill-formed vndk-ext definition.
-	testCcError(t, "must set `vendor: true` or `product_specific: true` to set `extends: \".*\"`", `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext",
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-	`)
-
-	testCcError(t, "must set `extends: \"\\.\\.\\.\"` to vndk extension", `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-	`)
-
-	testCcErrorProductVndk(t, "must set `extends: \"\\.\\.\\.\"` to vndk extension", `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext_product",
-			product_specific: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-	`)
-
-	testCcErrorProductVndk(t, "must not set at the same time as `vndk: {extends: \"\\.\\.\\.\"}`", `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext_product",
-			product_specific: true,
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-	`)
-}
-
-func TestVndkExtInconsistentSupportSystemProcessError(t *testing.T) {
-	t.Parallel()
-	// This test ensures an error is emitted for inconsistent support_system_process.
-	testCcError(t, "module \".*\" with mismatched support_system_process", `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-				support_system_process: true,
-			},
-			nocrt: true,
-		}
-	`)
-
-	testCcError(t, "module \".*\" with mismatched support_system_process", `
-		cc_library {
-			name: "libvndk_sp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk_sp",
-			},
-			nocrt: true,
-		}
-	`)
-}
-
-func TestVndkExtVendorAvailableFalseError(t *testing.T) {
-	t.Parallel()
-	// This test ensures an error is emitted when a VNDK-Ext library extends a VNDK library
-	// with `private: true`.
-	testCcError(t, "`extends` refers module \".*\" which has `private: true`", `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				private: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-	`)
-
-	testCcErrorProductVndk(t, "`extends` refers module \".*\" which has `private: true`", `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				private: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext_product",
-			product_specific: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-	`)
-}
-
-func TestVendorModuleUseVndkExt(t *testing.T) {
-	t.Parallel()
-	// This test ensures a vendor module can depend on a VNDK-Ext library.
-	testCc(t, `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk_sp",
-				support_system_process: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvendor",
-			vendor: true,
-			shared_libs: ["libvndk_ext", "libvndk_sp_ext"],
-			nocrt: true,
-		}
-	`)
-}
-
-func TestVndkExtUseVendorLib(t *testing.T) {
-	t.Parallel()
-	// This test ensures a VNDK-Ext library can depend on a vendor library.
-	testCc(t, `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			shared_libs: ["libvendor"],
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvendor",
-			vendor: true,
-			nocrt: true,
-		}
-	`)
-
-	// This test ensures a VNDK-SP-Ext library can depend on a vendor library.
-	testCc(t, `
-		cc_library {
-			name: "libvndk_sp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk_sp",
-				support_system_process: true,
-			},
-			shared_libs: ["libvendor"],  // Cause an error
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvendor",
-			vendor: true,
-			nocrt: true,
-		}
-	`)
-}
-
-func TestProductVndkExtDependency(t *testing.T) {
-	t.Parallel()
-	bp := `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext_product",
-			product_specific: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			shared_libs: ["libproduct_for_vndklibs"],
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp_ext_product",
-			product_specific: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk_sp",
-				support_system_process: true,
-			},
-			shared_libs: ["libproduct_for_vndklibs"],
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libproduct",
-			product_specific: true,
-			shared_libs: ["libvndk_ext_product", "libvndk_sp_ext_product"],
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libproduct_for_vndklibs",
-			product_specific: true,
-			nocrt: true,
-		}
-	`
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-
-	testCcWithConfig(t, config)
-}
-
-func TestVndkSpExtUseVndkError(t *testing.T) {
-	t.Parallel()
-	// This test ensures an error is emitted if a VNDK-SP-Ext library depends on a VNDK
-	// library.
-	testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk_sp",
-				support_system_process: true,
-			},
-			shared_libs: ["libvndk"],  // Cause an error
-			nocrt: true,
-		}
-	`)
-
-	// This test ensures an error is emitted if a VNDK-SP-Ext library depends on a VNDK-Ext
-	// library.
-	testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk_sp",
-				support_system_process: true,
-			},
-			shared_libs: ["libvndk_ext"],  // Cause an error
-			nocrt: true,
-		}
-	`)
-}
-
-func TestVndkUseVndkExtError(t *testing.T) {
-	t.Parallel()
-	// This test ensures an error is emitted if a VNDK/VNDK-SP library depends on a
-	// VNDK-Ext/VNDK-SP-Ext library.
-	testCcError(t, "dependency \".*\" of \".*\" missing variant", `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk2",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			shared_libs: ["libvndk_ext"],
-			nocrt: true,
-		}
-	`)
-
-	testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk2",
-			vendor_available: true,
-			vndk: {
-				enabled: true,
-			},
-			target: {
-				vendor: {
-					shared_libs: ["libvndk_ext"],
-				},
-			},
-			nocrt: true,
-		}
-	`)
-
-	testCcError(t, "dependency \".*\" of \".*\" missing variant", `
-		cc_library {
-			name: "libvndk_sp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk_sp",
-				support_system_process: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp_2",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			shared_libs: ["libvndk_sp_ext"],
-			nocrt: true,
-		}
-	`)
-
-	testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
-		cc_library {
-			name: "libvndk_sp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk_sp",
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_sp2",
-			vendor_available: true,
-			vndk: {
-				enabled: true,
-			},
-			target: {
-				vendor: {
-					shared_libs: ["libvndk_sp_ext"],
-				},
-			},
-			nocrt: true,
-		}
-	`)
-}
-
-func TestEnforceProductVndkVersion(t *testing.T) {
-	t.Parallel()
-	bp := `
-		cc_library {
-			name: "libllndk",
-			llndk: {
-				symbol_file: "libllndk.map.txt",
-			}
-		}
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-		cc_library {
-			name: "libvndk_sp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-			nocrt: true,
-		}
-		cc_library {
-			name: "libva",
-			vendor_available: true,
-			nocrt: true,
-		}
-		cc_library {
-			name: "libpa",
-			product_available: true,
-			nocrt: true,
-		}
-		cc_library {
-			name: "libboth_available",
-			vendor_available: true,
-			product_available: true,
-			nocrt: true,
-			srcs: ["foo.c"],
-			target: {
-				vendor: {
-					suffix: "-vendor",
-				},
-				product: {
-					suffix: "-product",
-				},
-			}
-		}
-		cc_library {
-			name: "libproduct_va",
-			product_specific: true,
-			vendor_available: true,
-			nocrt: true,
-		}
-		cc_library {
-			name: "libprod",
-			product_specific: true,
-			shared_libs: [
-				"libllndk",
-				"libvndk",
-				"libvndk_sp",
-				"libpa",
-				"libboth_available",
-				"libproduct_va",
-			],
-			nocrt: true,
-		}
-		cc_library {
-			name: "libvendor",
-			vendor: true,
-			shared_libs: [
-				"libllndk",
-				"libvndk",
-				"libvndk_sp",
-				"libva",
-				"libboth_available",
-				"libproduct_va",
-			],
-			nocrt: true,
-		}
-	`
-
-	ctx := prepareForCcTest.RunTestWithBp(t, bp).TestContext
-
-	checkVndkModule(t, ctx, "libvndk", "", false, "", productVariant)
-	checkVndkModule(t, ctx, "libvndk_sp", "", true, "", productVariant)
-
-	mod_vendor := ctx.ModuleForTests("libboth_available", vendorVariant).Module().(*Module)
-	assertString(t, mod_vendor.outputFile.Path().Base(), "libboth_available-vendor.so")
-
-	mod_product := ctx.ModuleForTests("libboth_available", productVariant).Module().(*Module)
-	assertString(t, mod_product.outputFile.Path().Base(), "libboth_available-product.so")
-
-	ensureStringContains := func(t *testing.T, str string, substr string) {
-		t.Helper()
-		if !strings.Contains(str, substr) {
-			t.Errorf("%q is not found in %v", substr, str)
-		}
-	}
-	ensureStringNotContains := func(t *testing.T, str string, substr string) {
-		t.Helper()
-		if strings.Contains(str, substr) {
-			t.Errorf("%q is found in %v", substr, str)
-		}
-	}
-
-	// _static variant is used since _shared reuses *.o from the static variant
-	vendor_static := ctx.ModuleForTests("libboth_available", strings.Replace(vendorVariant, "_shared", "_static", 1))
-	product_static := ctx.ModuleForTests("libboth_available", strings.Replace(productVariant, "_shared", "_static", 1))
-
-	vendor_cflags := vendor_static.Rule("cc").Args["cFlags"]
-	ensureStringContains(t, vendor_cflags, "-D__ANDROID_VNDK__")
-	ensureStringContains(t, vendor_cflags, "-D__ANDROID_VENDOR__")
-	ensureStringNotContains(t, vendor_cflags, "-D__ANDROID_PRODUCT__")
-
-	product_cflags := product_static.Rule("cc").Args["cFlags"]
-	ensureStringContains(t, product_cflags, "-D__ANDROID_VNDK__")
-	ensureStringContains(t, product_cflags, "-D__ANDROID_PRODUCT__")
-	ensureStringNotContains(t, product_cflags, "-D__ANDROID_VENDOR__")
-}
-
-func TestEnforceProductVndkVersionErrors(t *testing.T) {
-	t.Parallel()
-	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", `
-		cc_library {
-			name: "libprod",
-			product_specific: true,
-			shared_libs: [
-				"libvendor",
-			],
-			nocrt: true,
-		}
-		cc_library {
-			name: "libvendor",
-			vendor: true,
-			nocrt: true,
-		}
-	`)
-	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", `
-		cc_library {
-			name: "libprod",
-			product_specific: true,
-			shared_libs: [
-				"libsystem",
-			],
-			nocrt: true,
-		}
-		cc_library {
-			name: "libsystem",
-			nocrt: true,
-		}
-	`)
-	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", `
-		cc_library {
-			name: "libprod",
-			product_specific: true,
-			shared_libs: [
-				"libva",
-			],
-			nocrt: true,
-		}
-		cc_library {
-			name: "libva",
-			vendor_available: true,
-			nocrt: true,
-		}
-	`)
-	testCcErrorProductVndk(t, "non-VNDK module should not link to \".*\" which has `private: true`", `
-		cc_library {
-			name: "libprod",
-			product_specific: true,
-			shared_libs: [
-				"libvndk_private",
-			],
-			nocrt: true,
-		}
-		cc_library {
-			name: "libvndk_private",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				private: true,
-			},
-			nocrt: true,
-		}
-	`)
-	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:product.29", `
-		cc_library {
-			name: "libprod",
-			product_specific: true,
-			shared_libs: [
-				"libsystem_ext",
-			],
-			nocrt: true,
-		}
-		cc_library {
-			name: "libsystem_ext",
-			system_ext_specific: true,
-			nocrt: true,
-		}
-	`)
-	testCcErrorProductVndk(t, "dependency \".*\" of \".*\" missing variant:\n.*image:", `
-		cc_library {
-			name: "libsystem",
-			shared_libs: [
-				"libproduct_va",
-			],
-			nocrt: true,
-		}
-		cc_library {
-			name: "libproduct_va",
-			product_specific: true,
-			vendor_available: true,
-			nocrt: true,
-		}
-	`)
-}
-
 func TestMakeLinkType(t *testing.T) {
 	t.Parallel()
 	bp := `
 		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-		}
-		cc_library {
-			name: "libvndksp",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
-		}
-		cc_library {
-			name: "libvndkprivate",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				private: true,
-			},
-		}
-		cc_library {
 			name: "libvendor",
 			vendor: true,
 		}
-		cc_library {
-			name: "libvndkext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-		}
 		vndk_prebuilt_shared {
 			name: "prevndk",
 			version: "27",
@@ -2452,40 +640,15 @@
 				private: true,
 			}
 		}
-
 		llndk_libraries_txt {
 			name: "llndk.libraries.txt",
 		}
-		vndkcore_libraries_txt {
-			name: "vndkcore.libraries.txt",
-		}
-		vndksp_libraries_txt {
-			name: "vndksp.libraries.txt",
-		}
-		vndkprivate_libraries_txt {
-			name: "vndkprivate.libraries.txt",
-		}
-		vndkcorevariant_libraries_txt {
-			name: "vndkcorevariant.libraries.txt",
-			insert_vndk_version: false,
-		}
 	`
 
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	// native:vndk
 	ctx := testCcWithConfig(t, config)
 
-	checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt",
-		[]string{"libvndk.so", "libvndkprivate.so"})
-	checkVndkLibrariesOutput(t, ctx, "vndksp.libraries.txt",
-		[]string{"libc++.so", "libvndksp.so"})
-	checkVndkLibrariesOutput(t, ctx, "llndk.libraries.txt",
-		[]string{"libc.so", "libdl.so", "libft2.so", "libllndk.so", "libllndkprivate.so", "libm.so"})
-	checkVndkLibrariesOutput(t, ctx, "vndkprivate.libraries.txt",
-		[]string{"libft2.so", "libllndkprivate.so", "libvndkprivate.so"})
-
 	vendorVariant27 := "android_vendor.27_arm64_armv8-a_shared"
 
 	tests := []struct {
@@ -2493,15 +656,9 @@
 		name     string
 		expected string
 	}{
-		{vendorVariant, "libvndk", "native:vndk"},
-		{vendorVariant, "libvndksp", "native:vndk"},
-		{vendorVariant, "libvndkprivate", "native:vndk_private"},
 		{vendorVariant, "libvendor", "native:vendor"},
-		{vendorVariant, "libvndkext", "native:vendor"},
 		{vendorVariant, "libllndk", "native:vndk"},
 		{vendorVariant27, "prevndk.vndk.27.arm.binder32", "native:vndk"},
-		{coreVariant, "libvndk", "native:platform"},
-		{coreVariant, "libvndkprivate", "native:platform"},
 		{coreVariant, "libllndk", "native:platform"},
 	}
 	for _, test := range tests {
@@ -2700,8 +857,8 @@
 
 	variant := "android_arm64_armv8-a_static"
 	moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
-	actual := android.Paths(ctx.ModuleProvider(moduleA, StaticLibraryInfoProvider).(StaticLibraryInfo).
-		TransitiveStaticLibrariesForOrdering.ToList()).RelativeToTop()
+	staticLibInfo, _ := android.SingletonModuleProvider(ctx, moduleA, StaticLibraryInfoProvider)
+	actual := android.Paths(staticLibInfo.TransitiveStaticLibrariesForOrdering.ToList()).RelativeToTop()
 	expected := GetOutputPaths(ctx, variant, []string{"a", "c", "b", "d"})
 
 	if !reflect.DeepEqual(actual, expected) {
@@ -2736,8 +893,8 @@
 
 	variant := "android_arm64_armv8-a_static"
 	moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
-	actual := android.Paths(ctx.ModuleProvider(moduleA, StaticLibraryInfoProvider).(StaticLibraryInfo).
-		TransitiveStaticLibrariesForOrdering.ToList()).RelativeToTop()
+	staticLibInfo, _ := android.SingletonModuleProvider(ctx, moduleA, StaticLibraryInfoProvider)
+	actual := android.Paths(staticLibInfo.TransitiveStaticLibrariesForOrdering.ToList()).RelativeToTop()
 	expected := GetOutputPaths(ctx, variant, []string{"a", "c", "b"})
 
 	if !reflect.DeepEqual(actual, expected) {
@@ -2796,10 +953,12 @@
 		name: "libexternal_headers",
 		export_include_dirs: ["include"],
 		vendor_available: true,
+		product_available: true,
 	}
 	cc_library_headers {
 		name: "libexternal_llndk_headers",
 		export_include_dirs: ["include_llndk"],
+		export_system_include_dirs: ["include_system_llndk"],
 		llndk: {
 			symbol_file: "libllndk.map.txt",
 		},
@@ -2815,39 +974,74 @@
 		},
 		export_include_dirs: ["include"],
 	}
+
+	cc_library {
+		name: "libllndk_with_system_headers",
+		llndk: {
+			symbol_file: "libllndk.map.txt",
+			export_llndk_headers: ["libexternal_llndk_headers"],
+			export_headers_as_system: true,
+		},
+		export_include_dirs: ["include"],
+		export_system_include_dirs: ["include_system"],
+	}
 	`)
 	actual := result.ModuleVariantsForTests("libllndk")
 	for i := 0; i < len(actual); i++ {
-		if !strings.HasPrefix(actual[i], "android_vendor.29_") {
+		if !strings.HasPrefix(actual[i], "android_vendor_") {
 			actual = append(actual[:i], actual[i+1:]...)
 			i--
 		}
 	}
 	expected := []string{
-		"android_vendor.29_arm64_armv8-a_shared_current",
-		"android_vendor.29_arm64_armv8-a_shared",
-		"android_vendor.29_arm_armv7-a-neon_shared_current",
-		"android_vendor.29_arm_armv7-a-neon_shared",
+		"android_vendor_arm64_armv8-a_shared",
+		"android_vendor_arm_armv7-a-neon_shared",
 	}
 	android.AssertArrayString(t, "variants for llndk stubs", expected, actual)
 
-	params := result.ModuleForTests("libllndk", "android_vendor.29_arm_armv7-a-neon_shared").Description("generate stub")
-	android.AssertSame(t, "use VNDK version for default stubs", "current", params.Args["apiLevel"])
+	params := result.ModuleForTests("libllndk", "android_vendor_arm_armv7-a-neon_shared").Description("generate stub")
+	android.AssertSame(t, "use Vendor API level for default stubs", "202404", params.Args["apiLevel"])
 
-	checkExportedIncludeDirs := func(module, variant string, expectedDirs ...string) {
+	checkExportedIncludeDirs := func(module, variant string, expectedSystemDirs []string, expectedDirs ...string) {
 		t.Helper()
 		m := result.ModuleForTests(module, variant).Module()
-		f := result.ModuleProvider(m, FlagExporterInfoProvider).(FlagExporterInfo)
+		f, _ := android.SingletonModuleProvider(result, m, FlagExporterInfoProvider)
 		android.AssertPathsRelativeToTopEquals(t, "exported include dirs for "+module+"["+variant+"]",
 			expectedDirs, f.IncludeDirs)
+		android.AssertPathsRelativeToTopEquals(t, "exported include dirs for "+module+"["+variant+"]",
+			expectedSystemDirs, f.SystemIncludeDirs)
 	}
 
-	checkExportedIncludeDirs("libllndk", "android_arm64_armv8-a_shared", "include")
-	checkExportedIncludeDirs("libllndk", "android_vendor.29_arm64_armv8-a_shared", "include")
-	checkExportedIncludeDirs("libllndk_with_external_headers", "android_arm64_armv8-a_shared", "include")
-	checkExportedIncludeDirs("libllndk_with_external_headers", "android_vendor.29_arm64_armv8-a_shared", "include_llndk")
-	checkExportedIncludeDirs("libllndk_with_override_headers", "android_arm64_armv8-a_shared", "include")
-	checkExportedIncludeDirs("libllndk_with_override_headers", "android_vendor.29_arm64_armv8-a_shared", "include_llndk")
+	checkExportedIncludeDirs("libllndk", coreVariant, nil, "include")
+	checkExportedIncludeDirs("libllndk", vendorVariant, nil, "include")
+	checkExportedIncludeDirs("libllndk_with_external_headers", coreVariant, nil, "include")
+	checkExportedIncludeDirs("libllndk_with_external_headers", vendorVariant,
+		[]string{"include_system_llndk"}, "include_llndk")
+	checkExportedIncludeDirs("libllndk_with_override_headers", coreVariant, nil, "include")
+	checkExportedIncludeDirs("libllndk_with_override_headers", vendorVariant, nil, "include_llndk")
+	checkExportedIncludeDirs("libllndk_with_system_headers", coreVariant, []string{"include_system"}, "include")
+	checkExportedIncludeDirs("libllndk_with_system_headers", vendorVariant,
+		[]string{"include_system", "include", "include_system_llndk"}, "include_llndk")
+
+	checkAbiLinkerIncludeDirs := func(module string) {
+		t.Helper()
+		coreModule := result.ModuleForTests(module, coreVariant)
+		abiCheckFlags := ""
+		for _, output := range coreModule.AllOutputs() {
+			if strings.HasSuffix(output, ".so.llndk.lsdump") {
+				abiCheckFlags = coreModule.Output(output).Args["exportedHeaderFlags"]
+			}
+		}
+		vendorModule := result.ModuleForTests(module, vendorVariant).Module()
+		vendorInfo, _ := android.SingletonModuleProvider(result, vendorModule, FlagExporterInfoProvider)
+		vendorDirs := android.Concat(vendorInfo.IncludeDirs, vendorInfo.SystemIncludeDirs)
+		android.AssertStringEquals(t, module+" has different exported include dirs for vendor variant and ABI check",
+			android.JoinPathsWithPrefix(vendorDirs, "-I"), abiCheckFlags)
+	}
+	checkAbiLinkerIncludeDirs("libllndk")
+	checkAbiLinkerIncludeDirs("libllndk_with_override_headers")
+	checkAbiLinkerIncludeDirs("libllndk_with_external_headers")
+	checkAbiLinkerIncludeDirs("libllndk_with_system_headers")
 }
 
 func TestLlndkHeaders(t *testing.T) {
@@ -2879,7 +1073,7 @@
 	`)
 
 	// _static variant is used since _shared reuses *.o from the static variant
-	cc := ctx.ModuleForTests("libvendor", "android_vendor.29_arm_armv7-a-neon_static").Rule("cc")
+	cc := ctx.ModuleForTests("libvendor", "android_vendor_arm_armv7-a-neon_static").Rule("cc")
 	cflags := cc.Args["cFlags"]
 	if !strings.Contains(cflags, "-Imy_include") {
 		t.Errorf("cflags for libvendor must contain -Imy_include, but was %#v.", cflags)
@@ -3001,7 +1195,7 @@
 
 	// runtime_libs for vendor variants have '.vendor' suffixes if the modules have both core
 	// and vendor variants.
-	variant = "android_vendor.29_arm64_armv8-a_shared"
+	variant = "android_vendor_arm64_armv8-a_shared"
 
 	module = ctx.ModuleForTests("libvendor_available1", variant).Module().(*Module)
 	checkRuntimeLibs(t, []string{"liball_available.vendor"}, module)
@@ -3011,7 +1205,7 @@
 
 	// runtime_libs for product variants have '.product' suffixes if the modules have both core
 	// and product variants.
-	variant = "android_product.29_arm64_armv8-a_shared"
+	variant = "android_product_arm64_armv8-a_shared"
 
 	module = ctx.ModuleForTests("libproduct_available1", variant).Module().(*Module)
 	checkRuntimeLibs(t, []string{"liball_available.product"}, module)
@@ -3028,29 +1222,11 @@
 	module := ctx.ModuleForTests("libvendor_available2", variant).Module().(*Module)
 	checkRuntimeLibs(t, []string{"liball_available"}, module)
 
-	variant = "android_vendor.29_arm64_armv8-a_shared"
+	variant = "android_vendor_arm64_armv8-a_shared"
 	module = ctx.ModuleForTests("libvendor_available2", variant).Module().(*Module)
 	checkRuntimeLibs(t, nil, module)
 }
 
-func TestRuntimeLibsNoVndk(t *testing.T) {
-	t.Parallel()
-	ctx := testCcNoVndk(t, runtimeLibAndroidBp)
-
-	// If DeviceVndkVersion is not defined, then runtime_libs are copied as-is.
-
-	variant := "android_arm64_armv8-a_shared"
-
-	module := ctx.ModuleForTests("libvendor_available1", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available"}, module)
-
-	module = ctx.ModuleForTests("libvendor2", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available", "libvendor1", "libproduct_vendor"}, module)
-
-	module = ctx.ModuleForTests("libproduct2", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available", "libproduct1", "libproduct_vendor"}, module)
-}
-
 func checkStaticLibs(t *testing.T, expected []string, module *Module) {
 	t.Helper()
 	actual := module.Properties.AndroidMkStaticLibs
@@ -3090,258 +1266,6 @@
 	checkStaticLibs(t, []string{"lib1", "libc++_static", "libc++demangle", "libclang_rt.builtins"}, module)
 }
 
-func TestLibDepAndroidMkExportInMixedBuilds(t *testing.T) {
-	bp := `
-		cc_library {
-			name: "static_dep",
-		}
-		cc_library {
-			name: "whole_static_dep",
-		}
-		cc_library {
-			name: "shared_dep",
-		}
-		cc_library {
-			name: "lib",
-			bazel_module: { label: "//:lib" },
-			static_libs: ["static_dep"],
-			whole_static_libs: ["whole_static_dep"],
-			shared_libs: ["shared_dep"],
-		}
-		cc_test {
-			name: "test",
-			bazel_module: { label: "//:test" },
-			static_libs: ["static_dep"],
-			whole_static_libs: ["whole_static_dep"],
-			shared_libs: ["shared_dep"],
-			gtest: false,
-			sanitize: {
-				// cc_test modules default to memtag_heap: true,
-				// but this adds extra dependencies that we don't care about
-				never: true,
-			}
-		}
-		cc_binary {
-			name: "binary",
-			bazel_module: { label: "//:binary" },
-			static_libs: ["static_dep"],
-			whole_static_libs: ["whole_static_dep"],
-			shared_libs: ["shared_dep"],
-		}
-		cc_library_headers {
-			name: "lib_headers",
-			bazel_module: { label: "//:lib_headers" },
-			static_libs: ["static_dep"],
-			whole_static_libs: ["whole_static_dep"],
-			shared_libs: ["shared_dep"],
-		}
-		cc_prebuilt_library {
-			name: "lib_prebuilt",
-			bazel_module: { label: "//:lib_prebuilt" },
-			static_libs: ["static_dep"],
-			whole_static_libs: ["whole_static_dep"],
-			shared_libs: ["shared_dep"],
-		}
-	`
-
-	testCases := []struct {
-		name          string
-		moduleName    string
-		variant       string
-		androidMkInfo cquery.CcAndroidMkInfo
-	}{
-		{
-			name:       "shared lib",
-			moduleName: "lib",
-			variant:    "android_arm64_armv8-a_shared",
-			androidMkInfo: cquery.CcAndroidMkInfo{
-				LocalStaticLibs:      []string{"static_dep"},
-				LocalWholeStaticLibs: []string{"whole_static_dep"},
-				LocalSharedLibs:      []string{"shared_dep"},
-			},
-		},
-		{
-			name:       "static lib",
-			moduleName: "lib",
-			variant:    "android_arm64_armv8-a_static",
-			androidMkInfo: cquery.CcAndroidMkInfo{
-				LocalStaticLibs:      []string{"static_dep"},
-				LocalWholeStaticLibs: []string{"whole_static_dep"},
-				LocalSharedLibs:      []string{"shared_dep"},
-			},
-		},
-		{
-			name:       "cc_test arm64",
-			moduleName: "test",
-			variant:    "android_arm64_armv8-a",
-			androidMkInfo: cquery.CcAndroidMkInfo{
-				LocalStaticLibs:      []string{"static_dep"},
-				LocalWholeStaticLibs: []string{"whole_static_dep"},
-				LocalSharedLibs:      []string{"shared_dep"},
-			},
-		},
-		{
-			name:       "cc_test arm",
-			moduleName: "test",
-			variant:    "android_arm_armv7-a-neon",
-			androidMkInfo: cquery.CcAndroidMkInfo{
-				LocalStaticLibs:      []string{"static_dep"},
-				LocalWholeStaticLibs: []string{"whole_static_dep"},
-				LocalSharedLibs:      []string{"shared_dep"},
-			},
-		},
-		{
-			name:       "cc_binary",
-			moduleName: "binary",
-			variant:    "android_arm64_armv8-a",
-			androidMkInfo: cquery.CcAndroidMkInfo{
-				LocalStaticLibs:      []string{"static_dep"},
-				LocalWholeStaticLibs: []string{"whole_static_dep"},
-				LocalSharedLibs:      []string{"shared_dep"},
-			},
-		},
-		{
-			name:       "cc_library_headers",
-			moduleName: "lib_headers",
-			variant:    "android_arm64_armv8-a",
-			androidMkInfo: cquery.CcAndroidMkInfo{
-				LocalStaticLibs:      []string{"static_dep"},
-				LocalWholeStaticLibs: []string{"whole_static_dep"},
-				LocalSharedLibs:      []string{"shared_dep"},
-			},
-		},
-		{
-			name:       "prebuilt lib static",
-			moduleName: "lib_prebuilt",
-			variant:    "android_arm64_armv8-a_static",
-			androidMkInfo: cquery.CcAndroidMkInfo{
-				LocalStaticLibs:      []string{"static_dep"},
-				LocalWholeStaticLibs: []string{"whole_static_dep"},
-				LocalSharedLibs:      []string{"shared_dep"},
-			},
-		},
-		{
-			name:       "prebuilt lib shared",
-			moduleName: "lib_prebuilt",
-			variant:    "android_arm64_armv8-a_shared",
-			androidMkInfo: cquery.CcAndroidMkInfo{
-				LocalStaticLibs:      []string{"static_dep"},
-				LocalWholeStaticLibs: []string{"whole_static_dep"},
-				LocalSharedLibs:      []string{"shared_dep"},
-			},
-		},
-	}
-
-	outputBaseDir := "out/bazel"
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			result := android.GroupFixturePreparers(
-				prepareForCcTest,
-				android.FixtureModifyConfig(func(config android.Config) {
-					config.BazelContext = android.MockBazelContext{
-						OutputBaseDir: outputBaseDir,
-						LabelToCcInfo: map[string]cquery.CcInfo{
-							"//:lib": cquery.CcInfo{
-								CcAndroidMkInfo:      tc.androidMkInfo,
-								RootDynamicLibraries: []string{""},
-							},
-							"//:lib_bp2build_cc_library_static": cquery.CcInfo{
-								CcAndroidMkInfo:    tc.androidMkInfo,
-								RootStaticArchives: []string{""},
-							},
-							"//:lib_headers": cquery.CcInfo{
-								CcAndroidMkInfo: tc.androidMkInfo,
-								OutputFiles:     []string{""},
-							},
-							"//:lib_prebuilt": cquery.CcInfo{
-								CcAndroidMkInfo: tc.androidMkInfo,
-							},
-							"//:lib_prebuilt_bp2build_cc_library_static": cquery.CcInfo{
-								CcAndroidMkInfo: tc.androidMkInfo,
-							},
-						},
-						LabelToCcBinary: map[string]cquery.CcUnstrippedInfo{
-							"//:test__tf_internal": cquery.CcUnstrippedInfo{
-								CcAndroidMkInfo: tc.androidMkInfo,
-							},
-							"//:binary": cquery.CcUnstrippedInfo{
-								CcAndroidMkInfo: tc.androidMkInfo,
-							},
-						},
-					}
-				}),
-			).RunTestWithBp(t, bp)
-			ctx := result.TestContext
-
-			module := ctx.ModuleForTests(tc.moduleName, tc.variant).Module().(*Module)
-			entries := android.AndroidMkEntriesForTest(t, ctx, module)[0]
-			if !reflect.DeepEqual(module.Properties.AndroidMkStaticLibs, tc.androidMkInfo.LocalStaticLibs) {
-				t.Errorf("incorrect static_libs"+
-					"\nactual:   %v"+
-					"\nexpected: %v",
-					module.Properties.AndroidMkStaticLibs,
-					tc.androidMkInfo.LocalStaticLibs,
-				)
-			}
-			staticDepsDiffer, missingStaticDeps, additionalStaticDeps := android.ListSetDifference(
-				entries.EntryMap["LOCAL_STATIC_LIBRARIES"],
-				tc.androidMkInfo.LocalStaticLibs,
-			)
-			if staticDepsDiffer {
-				t.Errorf(
-					"expected LOCAL_STATIC_LIBRARIES to be %q but was %q; missing: %q; extra %q",
-					tc.androidMkInfo.LocalStaticLibs,
-					entries.EntryMap["LOCAL_STATIC_LIBRARIES"],
-					missingStaticDeps,
-					additionalStaticDeps,
-				)
-			}
-
-			if !reflect.DeepEqual(module.Properties.AndroidMkWholeStaticLibs, tc.androidMkInfo.LocalWholeStaticLibs) {
-				t.Errorf("expected module.Properties.AndroidMkWholeStaticLibs to be %q, but was %q",
-					tc.androidMkInfo.LocalWholeStaticLibs,
-					module.Properties.AndroidMkWholeStaticLibs,
-				)
-			}
-			wholeStaticDepsDiffer, missingWholeStaticDeps, additionalWholeStaticDeps := android.ListSetDifference(
-				entries.EntryMap["LOCAL_WHOLE_STATIC_LIBRARIES"],
-				tc.androidMkInfo.LocalWholeStaticLibs,
-			)
-			if wholeStaticDepsDiffer {
-				t.Errorf(
-					"expected LOCAL_WHOLE_STATIC_LIBRARIES to be %q but was %q; missing: %q; extra %q",
-					tc.androidMkInfo.LocalWholeStaticLibs,
-					entries.EntryMap["LOCAL_WHOLE_STATIC_LIBRARIES"],
-					missingWholeStaticDeps,
-					additionalWholeStaticDeps,
-				)
-			}
-
-			if !reflect.DeepEqual(module.Properties.AndroidMkSharedLibs, tc.androidMkInfo.LocalSharedLibs) {
-				t.Errorf("incorrect shared_libs"+
-					"\nactual:   %v"+
-					"\nexpected: %v",
-					module.Properties.AndroidMkSharedLibs,
-					tc.androidMkInfo.LocalSharedLibs,
-				)
-			}
-			sharedDepsDiffer, missingSharedDeps, additionalSharedDeps := android.ListSetDifference(
-				entries.EntryMap["LOCAL_SHARED_LIBRARIES"],
-				tc.androidMkInfo.LocalSharedLibs,
-			)
-			if sharedDepsDiffer {
-				t.Errorf(
-					"expected LOCAL_SHARED_LIBRARIES to be %q but was %q; missing %q; extra %q",
-					tc.androidMkInfo.LocalSharedLibs,
-					entries.EntryMap["LOCAL_SHARED_LIBRARIES"],
-					missingSharedDeps,
-					additionalSharedDeps,
-				)
-			}
-		})
-	}
-}
-
 var compilerFlagsTestCases = []struct {
 	in  string
 	out bool
@@ -3481,9 +1405,6 @@
  `
 
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
 
 	ctx := testCcWithConfig(t, config)
 	module := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon").Module()
@@ -3496,7 +1417,7 @@
 		t.Errorf("expected exactly one output file. output files: [%s]", outputFiles)
 	}
 	if len(testBinary.dataPaths()) != 1 {
-		t.Errorf("expected exactly one test data file. test data files: [%s]", testBinary.dataPaths())
+		t.Errorf("expected exactly one test data file. test data files: [%v]", testBinary.dataPaths())
 	}
 
 	outputPath := outputFiles[0].String()
@@ -3683,130 +1604,6 @@
 	}
 }
 
-func TestMixedBuildUsesStubs(t *testing.T) {
-	t.Parallel()
-	bp := `
-		cc_library_shared {
-			name: "libFoo",
-			bazel_module: { label: "//:libFoo" },
-			srcs: ["foo.c"],
-			stubs: {
-				symbol_file: "foo.map.txt",
-				versions: ["current"],
-			},
-			apex_available: ["bar", "a1"],
-		}
-
-		cc_library_shared {
-			name: "libBar",
-			srcs: ["bar.c"],
-			shared_libs: ["libFoo"],
-			apex_available: ["a1"],
-		}
-
-		cc_library_shared {
-			name: "libA1",
-			srcs: ["a1.c"],
-			shared_libs: ["libFoo"],
-			apex_available: ["a1"],
-		}
-
-		cc_library_shared {
-			name: "libBarA1",
-			srcs: ["bara1.c"],
-			shared_libs: ["libFoo"],
-			apex_available: ["bar", "a1"],
-		}
-
-		cc_library_shared {
-			name: "libAnyApex",
-			srcs: ["anyApex.c"],
-			shared_libs: ["libFoo"],
-			apex_available: ["//apex_available:anyapex"],
-		}
-
-		cc_library_shared {
-			name: "libBaz",
-			srcs: ["baz.c"],
-			shared_libs: ["libFoo"],
-			apex_available: ["baz"],
-		}
-
-		cc_library_shared {
-			name: "libQux",
-			srcs: ["qux.c"],
-			shared_libs: ["libFoo"],
-			apex_available: ["qux", "bar"],
-		}`
-
-	result := android.GroupFixturePreparers(
-		prepareForCcTest,
-		android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: "out/bazel",
-				LabelToCcInfo: map[string]cquery.CcInfo{
-					"//:libFoo": {
-						RootDynamicLibraries: []string{"libFoo.so"},
-					},
-					"//:libFoo_stub_libs-current": {
-						RootDynamicLibraries: []string{"libFoo_stub_libs-current.so"},
-					},
-				},
-			}
-		}),
-	).RunTestWithBp(t, bp)
-	ctx := result.TestContext
-
-	variants := ctx.ModuleVariantsForTests("libFoo")
-	expectedVariants := []string{
-		"android_arm64_armv8-a_shared",
-		"android_arm64_armv8-a_shared_current",
-		"android_arm_armv7-a-neon_shared",
-		"android_arm_armv7-a-neon_shared_current",
-	}
-	variantsMismatch := false
-	if len(variants) != len(expectedVariants) {
-		variantsMismatch = true
-	} else {
-		for _, v := range expectedVariants {
-			if !inList(v, variants) {
-				variantsMismatch = false
-			}
-		}
-	}
-	if variantsMismatch {
-		t.Errorf("variants of libFoo expected:\n")
-		for _, v := range expectedVariants {
-			t.Errorf("%q\n", v)
-		}
-		t.Errorf(", but got:\n")
-		for _, v := range variants {
-			t.Errorf("%q\n", v)
-		}
-	}
-
-	linkAgainstFoo := []string{"libBarA1"}
-	linkAgainstFooStubs := []string{"libBar", "libA1", "libBaz", "libQux", "libAnyApex"}
-
-	libFooPath := "out/bazel/execroot/__main__/libFoo.so"
-	for _, lib := range linkAgainstFoo {
-		libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld")
-		libFlags := libLinkRule.Args["libFlags"]
-		if !strings.Contains(libFlags, libFooPath) {
-			t.Errorf("%q: %q is not found in %q", lib, libFooPath, libFlags)
-		}
-	}
-
-	libFooStubPath := "out/bazel/execroot/__main__/libFoo_stub_libs-current.so"
-	for _, lib := range linkAgainstFooStubs {
-		libLinkRule := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld")
-		libFlags := libLinkRule.Args["libFlags"]
-		if !strings.Contains(libFlags, libFooStubPath) {
-			t.Errorf("%q: %q is not found in %q", lib, libFooStubPath, libFlags)
-		}
-	}
-}
-
 func TestVersioningMacro(t *testing.T) {
 	t.Parallel()
 	for _, tc := range []struct{ moduleName, expected string }{
@@ -4180,9 +1977,6 @@
 			shared: {
 				srcs: ["baz.c"],
 			},
-			bazel_module: {
-				bp2build_available: true,
-			},
 		}
 
 		cc_library_static {
@@ -4466,7 +2260,7 @@
 		libfoo.Rule("aidl_library").Implicits,
 	)
 
-	manifest := android.RuleBuilderSboxProtoForTests(t, libfoo.Output("aidl_library.sbox.textproto"))
+	manifest := android.RuleBuilderSboxProtoForTests(t, ctx, libfoo.Output("aidl_library.sbox.textproto"))
 	aidlCommand := manifest.Commands[0].GetCommand()
 
 	expectedAidlFlags := "-Ipackage_foo/a -Ipackage_bar/x"
@@ -4501,7 +2295,7 @@
 	`)
 
 	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static")
-	manifest := android.RuleBuilderSboxProtoForTests(t, libfoo.Output("aidl.sbox.textproto"))
+	manifest := android.RuleBuilderSboxProtoForTests(t, ctx.TestContext, libfoo.Output("aidl.sbox.textproto"))
 	aidlCommand := manifest.Commands[0].GetCommand()
 	expectedAidlFlag := "-Werror"
 	if !strings.Contains(aidlCommand, expectedAidlFlag) {
@@ -4552,7 +2346,7 @@
 				}
 			`)
 			libfoo := ctx.ModuleForTests("libfoo", tc.variant)
-			manifest := android.RuleBuilderSboxProtoForTests(t, libfoo.Output("aidl.sbox.textproto"))
+			manifest := android.RuleBuilderSboxProtoForTests(t, ctx, libfoo.Output("aidl.sbox.textproto"))
 			aidlCommand := manifest.Commands[0].GetCommand()
 			expectedAidlFlag := "--min_sdk_version=" + tc.expected
 			if !strings.Contains(aidlCommand, expectedAidlFlag) {
@@ -4666,7 +2460,7 @@
 
 	checkIncludeDirs := func(t *testing.T, ctx *android.TestContext, module android.Module, checkers ...exportedChecker) {
 		t.Helper()
-		exported := ctx.ModuleProvider(module, FlagExporterInfoProvider).(FlagExporterInfo)
+		exported, _ := android.SingletonModuleProvider(ctx, module, FlagExporterInfoProvider)
 		name := module.Name()
 
 		for _, checker := range checkers {
@@ -4982,7 +2776,7 @@
 
 	cflags := []string{"-Werror", "-std=candcpp"}
 	cstd := []string{"-std=gnu17", "-std=conly"}
-	cppstd := []string{"-std=gnu++17", "-std=cpp", "-fno-rtti"}
+	cppstd := []string{"-std=gnu++20", "-std=cpp", "-fno-rtti"}
 
 	lastIncludes := []string{
 		"out/soong/ndk/sysroot/usr/include",
@@ -5312,308 +3106,115 @@
 	}
 }
 
-func TestDclaLibraryInApex(t *testing.T) {
+func TestStrippedAllOutputFile(t *testing.T) {
 	t.Parallel()
 	bp := `
-	cc_library_shared {
-		name: "cc_lib_in_apex",
-		srcs: ["foo.cc"],
-    apex_available: ["myapex"],
-		bazel_module: { label: "//foo/bar:bar" },
-	}`
-	label := "//foo/bar:bar"
-	arch64 := "arm64_armv8-a"
-	arch32 := "arm_armv7-a-neon"
-	apexCfgKey := android.ApexConfigKey{
-		WithinApex:     true,
-		ApexSdkVersion: "28",
-	}
-
-	result := android.GroupFixturePreparers(
-		prepareForCcTest,
-		android.FixtureRegisterWithContext(registerTestMutators),
-		android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: "outputbase",
-				LabelToCcInfo: map[string]cquery.CcInfo{
-					android.BuildMockBazelContextResultKey(label, arch32, android.Android, apexCfgKey): cquery.CcInfo{
-						RootDynamicLibraries: []string{"foo.so"},
-					},
-					android.BuildMockBazelContextResultKey(label, arch64, android.Android, apexCfgKey): cquery.CcInfo{
-						RootDynamicLibraries: []string{"foo.so"},
-					},
-				},
-				BazelRequests: make(map[string]bool),
+		cc_library {
+			name: "test_lib",
+			srcs: ["test_lib.cpp"],
+			dist: {
+				targets: [ "dist_target" ],
+				tag: "stripped_all",
 			}
-		}),
-	).RunTestWithBp(t, bp)
-	ctx := result.TestContext
-
-	// Test if the bazel request is queued correctly
-	key := android.BuildMockBazelContextRequestKey(label, cquery.GetCcInfo, arch32, android.Android, apexCfgKey)
-	if !ctx.Config().BazelContext.(android.MockBazelContext).BazelRequests[key] {
-		t.Errorf("Bazel request was not queued: %s", key)
-	}
-
-	sharedFoo := ctx.ModuleForTests(ccLibInApex, "android_arm_armv7-a-neon_shared_"+apexVariationName).Module()
-	producer := sharedFoo.(android.OutputFileProducer)
-	outputFiles, err := producer.OutputFiles("")
+		}
+ `
+	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
+	ctx := testCcWithConfig(t, config)
+	module := ctx.ModuleForTests("test_lib", "android_arm_armv7-a-neon_shared").Module()
+	outputFile, err := module.(android.OutputFileProducer).OutputFiles("stripped_all")
 	if err != nil {
-		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+		t.Errorf("Expected cc_library to produce output files, error: %s", err)
+		return
 	}
-	expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.so"}
-	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
+	if !strings.HasSuffix(outputFile.Strings()[0], "/stripped_all/test_lib.so") {
+		t.Errorf("Unexpected output file: %s", outputFile.Strings()[0])
+		return
+	}
 }
 
-func TestDisableSanitizerVariantsInMixedBuilds(t *testing.T) {
+func TestImageVariants(t *testing.T) {
 	t.Parallel()
+
 	bp := `
-		cc_library_static {
-			name: "foo_ubsan_minimal",
-			srcs: ["foo.cc"],
-			bazel_module: { label: "//foo_ubsan_minimal" },
-			sanitize: {
-				all_undefined: true,
-				integer_overflow: true,
-			},
+	cc_binary {
+		name: "binfoo",
+		srcs: ["binfoo.cc"],
+		vendor_available: true,
+		product_available: true,
+		shared_libs: ["libbar"]
+	}
+	cc_library {
+		name: "libbar",
+		srcs: ["libbar.cc"],
+		vendor_available: true,
+		product_available: true,
+	}
+	`
+
+	ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+	hasDep := func(m android.Module, wantDep android.Module) bool {
+		t.Helper()
+		var found bool
+		ctx.VisitDirectDeps(m, func(dep blueprint.Module) {
+			if dep == wantDep {
+				found = true
+			}
+		})
+		return found
+	}
+
+	testDepWithVariant := func(imageVariant string) {
+		imageVariantStr := ""
+		if imageVariant != "core" {
+			imageVariantStr = "_" + imageVariant
 		}
-		cc_library_static {
-			name: "foo",
-			srcs: ["foo.cc"],
-			bazel_module: { label: "//foo" },
-			sanitize: {
-				address: true,
-				hwaddress: true,
-				fuzzer: true,
-				integer_overflow: true,
-				scs: true,
-			},
+		binFooModule := ctx.ModuleForTests("binfoo", "android"+imageVariantStr+"_arm64_armv8-a").Module()
+		libBarModule := ctx.ModuleForTests("libbar", "android"+imageVariantStr+"_arm64_armv8-a_shared").Module()
+		android.AssertBoolEquals(t, "binfoo should have dependency on libbar with image variant "+imageVariant, true, hasDep(binFooModule, libBarModule))
+	}
+
+	testDepWithVariant("core")
+	testDepWithVariant("vendor")
+	testDepWithVariant("product")
+}
+
+func TestVendorSdkVersion(t *testing.T) {
+	t.Parallel()
+
+	bp := `
+		cc_library {
+			name: "libfoo",
+			srcs: ["libfoo.cc"],
+			vendor_available: true,
 		}
-		cc_library_static {
-			name: "foo_tsan",
-			srcs: ["foo.cc"],
-			bazel_module: { label: "//foo_tsan" },
-			sanitize: {
-				thread: true,
-			},
-		}
-		cc_library_static {
-			name: "foo_cfi",
-			srcs: ["foo.cc"],
-			bazel_module: { label: "//foo_cfi" },
-			sanitize: {
-				cfi: true,
-			},
-		}
-		cc_library_static {
-			name: "foo_memtag_stack",
-			srcs: ["foo.cc"],
-			bazel_module: { label: "//foo_memtag_stack" },
-			sanitize: {
-				memtag_stack: true,
-			},
-		}
-		cc_library_static {
-			name: "foo_memtag_heap",
-			srcs: ["foo.cc"],
-			bazel_module: { label: "//foo_memtag_heap" },
-			sanitize: {
-				memtag_heap: true,
-			},
-		}
-		cc_library_static {
-			name: "foo_safestack",
-			srcs: ["foo.cc"],
-			bazel_module: { label: "//foo_safestack" },
-			sanitize: {
-				safestack: true,
-			},
-		}
-		cc_library_static {
-			name: "foo_scudo",
-			srcs: ["foo.cc"],
-			bazel_module: { label: "//foo_scudo" },
-			sanitize: {
-				scudo: true,
-			},
+
+		cc_library {
+			name: "libbar",
+			srcs: ["libbar.cc"],
+			vendor_available: true,
+			min_sdk_version: "29",
 		}
 	`
-	testcases := []struct {
-		name                string
-		variant             string
-		expectedOutputPaths []string
-	}{
-		{
-			name:    "foo_ubsan_minimal",
-			variant: "android_arm64_armv8-a_static_apex28",
-			expectedOutputPaths: []string{
-				"outputbase/execroot/__main__/foo_ubsan_minimal.a",
-			},
-		},
-		{
-			name:    "foo",
-			variant: "android_arm64_armv8-a_static_apex28",
-			expectedOutputPaths: []string{
-				"outputbase/execroot/__main__/foo.a",
-			},
-		},
-		{
-			name:    "foo",
-			variant: "android_arm_armv7-a-neon_static_asan_apex28",
-			expectedOutputPaths: []string{
-				"out/soong/.intermediates/foo/android_arm_armv7-a-neon_static_asan_apex28/foo.a",
-			},
-		},
-		{
-			name:    "foo",
-			variant: "android_arm64_armv8-a_static_hwasan_apex28",
-			expectedOutputPaths: []string{
-				"out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_apex28/foo.a",
-			},
-		},
-		{
-			name:    "foo",
-			variant: "android_arm64_armv8-a_static_fuzzer_apex28",
-			expectedOutputPaths: []string{
-				"out/soong/.intermediates/foo/android_arm64_armv8-a_static_fuzzer_apex28/foo.a",
-			},
-		},
-		{
-			name:    "foo",
-			variant: "android_arm_armv7-a-neon_static_asan_fuzzer_apex28",
-			expectedOutputPaths: []string{
-				"out/soong/.intermediates/foo/android_arm_armv7-a-neon_static_asan_fuzzer_apex28/foo.a",
-			},
-		},
-		{
-			name:    "foo",
-			variant: "android_arm64_armv8-a_static_hwasan_fuzzer_apex28",
-			expectedOutputPaths: []string{
-				"out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_fuzzer_apex28/foo.a",
-			},
-		},
-		{
-			name:    "foo",
-			variant: "android_arm64_armv8-a_static_scs_apex28",
-			expectedOutputPaths: []string{
-				"out/soong/.intermediates/foo/android_arm64_armv8-a_static_scs_apex28/foo.a",
-			},
-		},
-		{
-			name:    "foo",
-			variant: "android_arm64_armv8-a_static_hwasan_scs_apex28",
-			expectedOutputPaths: []string{
-				"out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_scs_apex28/foo.a",
-			},
-		},
-		{
-			name:    "foo",
-			variant: "android_arm64_armv8-a_static_hwasan_scs_fuzzer_apex28",
-			expectedOutputPaths: []string{
-				"out/soong/.intermediates/foo/android_arm64_armv8-a_static_hwasan_scs_fuzzer_apex28/foo.a",
-			},
-		},
-		{
-			name:    "foo_tsan",
-			variant: "android_arm64_armv8-a_static_apex28",
-			expectedOutputPaths: []string{
-				"outputbase/execroot/__main__/foo_tsan.a",
-			},
-		},
-		{
-			name:    "foo_tsan",
-			variant: "android_arm64_armv8-a_static_tsan_apex28",
-			expectedOutputPaths: []string{
-				"out/soong/.intermediates/foo_tsan/android_arm64_armv8-a_static_tsan_apex28/foo_tsan.a",
-			},
-		},
-		{
-			name:    "foo_cfi",
-			variant: "android_arm64_armv8-a_static_apex28",
-			expectedOutputPaths: []string{
-				"outputbase/execroot/__main__/foo_cfi.a",
-			},
-		},
-		{
-			name:    "foo_cfi",
-			variant: "android_arm64_armv8-a_static_cfi_apex28",
-			expectedOutputPaths: []string{
-				"outputbase/execroot/__main__/foo_cfi.a",
-			},
-		},
-		{
-			name:    "foo_memtag_stack",
-			variant: "android_arm64_armv8-a_static_apex28",
-			expectedOutputPaths: []string{
-				"out/soong/.intermediates/foo_memtag_stack/android_arm64_armv8-a_static_apex28/foo_memtag_stack.a",
-			},
-		},
-		{
-			name:    "foo_memtag_heap",
-			variant: "android_arm64_armv8-a_static_apex28",
-			expectedOutputPaths: []string{
-				"out/soong/.intermediates/foo_memtag_heap/android_arm64_armv8-a_static_apex28/foo_memtag_heap.a",
-			},
-		},
-		{
-			name:    "foo_safestack",
-			variant: "android_arm64_armv8-a_static_apex28",
-			expectedOutputPaths: []string{
-				"out/soong/.intermediates/foo_safestack/android_arm64_armv8-a_static_apex28/foo_safestack.a",
-			},
-		},
-		{
-			name:    "foo_scudo",
-			variant: "android_arm64_armv8-a_static_apex28",
-			expectedOutputPaths: []string{
-				"out/soong/.intermediates/foo_scudo/android_arm64_armv8-a_static_apex28/foo_scudo.a",
-			},
-		},
+
+	ctx := prepareForCcTest.RunTestWithBp(t, bp)
+	testSdkVersionFlag := func(module, version string) {
+		flags := ctx.ModuleForTests(module, "android_vendor_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
+		android.AssertStringDoesContain(t, "min sdk version", flags, "-target aarch64-linux-android"+version)
 	}
 
-	ctx := android.GroupFixturePreparers(
+	testSdkVersionFlag("libfoo", "10000")
+	testSdkVersionFlag("libbar", "29")
+
+	ctx = android.GroupFixturePreparers(
 		prepareForCcTest,
-		prepareForAsanTest,
-		android.FixtureRegisterWithContext(registerTestMutators),
-		android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: "outputbase",
-				LabelToCcInfo: map[string]cquery.CcInfo{
-					"//foo_ubsan_minimal": {
-						RootStaticArchives: []string{"foo_ubsan_minimal.a"},
-					},
-					"//foo": {
-						RootStaticArchives: []string{"foo.a"},
-					},
-					"//foo_tsan": {
-						RootStaticArchives: []string{"foo_tsan.a"},
-					},
-					"//foo_cfi": {
-						RootStaticArchives: []string{"foo_cfi.a"},
-					},
-					"//foo_memtag_stack": {
-						RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
-					},
-					"//foo_memtag_heap": {
-						RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
-					},
-					"//foo_safestack": {
-						RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
-					},
-					"//foo_scudo": {
-						RootStaticArchives: []string{"INVALID_ARCHIVE.a"},
-					},
-				},
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			if variables.BuildFlags == nil {
+				variables.BuildFlags = make(map[string]string)
 			}
+			variables.BuildFlags["RELEASE_BOARD_API_LEVEL_FROZEN"] = "true"
 		}),
-	).RunTestWithBp(t, bp).TestContext
-
-	for _, tc := range testcases {
-		fooMod := ctx.ModuleForTests(tc.name, tc.variant).Module()
-		outputFiles, err := fooMod.(android.OutputFileProducer).OutputFiles("")
-		if err != nil {
-			t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
-		}
-		android.AssertPathsRelativeToTopEquals(t, "output files", tc.expectedOutputPaths, outputFiles)
-	}
+	).RunTestWithBp(t, bp)
+	testSdkVersionFlag("libfoo", "30")
+	testSdkVersionFlag("libbar", "29")
 }
diff --git a/cc/cc_test_only_property_test.go b/cc/cc_test_only_property_test.go
new file mode 100644
index 0000000..c14f34e
--- /dev/null
+++ b/cc/cc_test_only_property_test.go
@@ -0,0 +1,219 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"android/soong/android"
+	"android/soong/android/team_proto"
+	"log"
+	"strings"
+	"testing"
+
+	"github.com/google/blueprint"
+	"google.golang.org/protobuf/proto"
+)
+
+func TestTestOnlyProvider(t *testing.T) {
+	t.Parallel()
+	ctx := android.GroupFixturePreparers(
+		prepareForCcTest,
+		android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+			ctx.RegisterModuleType("cc_test_host", TestHostFactory)
+		}),
+	).RunTestWithBp(t, `
+                // These should be test-only
+                cc_fuzz { name: "cc-fuzz" }
+                cc_test { name: "cc-test", gtest:false }
+                cc_benchmark { name: "cc-benchmark" }
+                cc_library { name: "cc-library-forced",
+                             test_only: true }
+                cc_test_library {name: "cc-test-library", gtest: false}
+                cc_test_host {name: "cc-test-host", gtest: false}
+
+                // These should not be.
+                cc_genrule { name: "cc_genrule", cmd: "echo foo", out: ["out"] }
+                cc_library { name: "cc_library" }
+                cc_library { name: "cc_library_false", test_only: false }
+                cc_library_static { name: "cc_static" }
+                cc_library_shared { name: "cc_library_shared" }
+
+                cc_object { name: "cc-object" }
+	`)
+
+	// Visit all modules and ensure only the ones that should
+	// marked as test-only are marked as test-only.
+
+	actualTestOnly := []string{}
+	ctx.VisitAllModules(func(m blueprint.Module) {
+		if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, android.TestOnlyProviderKey); ok {
+			if provider.TestOnly {
+				actualTestOnly = append(actualTestOnly, m.Name())
+			}
+		}
+	})
+	expectedTestOnlyModules := []string{
+		"cc-test",
+		"cc-library-forced",
+		"cc-fuzz",
+		"cc-benchmark",
+		"cc-test-library",
+		"cc-test-host",
+	}
+
+	notEqual, left, right := android.ListSetDifference(expectedTestOnlyModules, actualTestOnly)
+	if notEqual {
+		t.Errorf("test-only: Expected but not found: %v, Found but not expected: %v", left, right)
+	}
+}
+
+func TestTestOnlyValueWithTestPerSrcProp(t *testing.T) {
+	t.Parallel()
+	ctx := android.GroupFixturePreparers(
+		prepareForCcTest,
+	).RunTestWithBp(t, `
+                // These should be test-only
+                cc_test { name: "cc-test",
+                          gtest: false,
+                          test_per_src: true,
+                          srcs: ["foo_test.cpp"],
+                          test_options: { unit_test: false, },
+                         }
+	`)
+
+	// Ensure all variation of test-per-src tests are marked test-only.
+	ctx.VisitAllModules(func(m blueprint.Module) {
+		testOnly := false
+		if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, android.TestOnlyProviderKey); ok {
+			if provider.TestOnly {
+				testOnly = true
+			}
+		}
+		if module, ok := m.(*Module); ok {
+			if testModule, ok := module.installer.(*testBinary); ok {
+				if !testOnly && *testModule.Properties.Test_per_src {
+					t.Errorf("%v is not test-only but should be", m)
+				}
+			}
+		}
+	})
+}
+
+func TestTestOnlyInTeamsProto(t *testing.T) {
+	t.Parallel()
+	ctx := android.GroupFixturePreparers(
+		android.PrepareForTestWithTeamBuildComponents,
+		prepareForCcTest,
+		android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+			ctx.RegisterParallelSingletonType("all_teams", android.AllTeamsFactory)
+			ctx.RegisterModuleType("cc_test_host", TestHostFactory)
+
+		}),
+	).RunTestWithBp(t, `
+                package { default_team: "someteam"}
+
+                // These should be test-only
+                cc_fuzz { name: "cc-fuzz" }
+                cc_test { name: "cc-test", gtest:false }
+                cc_benchmark { name: "cc-benchmark" }
+                cc_library { name: "cc-library-forced",
+                             test_only: true }
+                cc_test_library {name: "cc-test-library", gtest: false}
+                cc_test_host {name: "cc-test-host", gtest: false}
+
+                // These should not be.
+                cc_genrule { name: "cc_genrule", cmd: "echo foo", out: ["out"] }
+                cc_library { name: "cc_library" }
+                cc_library_static { name: "cc_static" }
+                cc_library_shared { name: "cc_library_shared" }
+
+                cc_object { name: "cc-object" }
+		team {
+			name: "someteam",
+			trendy_team_id: "cool_team",
+		}
+	`)
+
+	var teams *team_proto.AllTeams
+	teams = getTeamProtoOutput(t, ctx)
+
+	// map of module name -> trendy team name.
+	actualTrueModules := []string{}
+	for _, teamProto := range teams.Teams {
+		if Bool(teamProto.TestOnly) {
+			actualTrueModules = append(actualTrueModules, teamProto.GetTargetName())
+		}
+	}
+	expectedTestOnlyModules := []string{
+		"cc-test",
+		"cc-library-forced",
+		"cc-fuzz",
+		"cc-benchmark",
+		"cc-test-library",
+		"cc-test-host",
+	}
+
+	notEqual, left, right := android.ListSetDifference(expectedTestOnlyModules, actualTrueModules)
+	if notEqual {
+		t.Errorf("test-only: Expected but not found: %v, Found but not expected: %v", left, right)
+	}
+}
+
+// Don't allow setting test-only on things that are always tests or never tests.
+func TestInvalidTestOnlyTargets(t *testing.T) {
+	testCases := []string{
+		` cc_test {  name: "cc-test", test_only: true, gtest: false, srcs: ["foo.cc"],  } `,
+		` cc_binary {  name: "cc-binary", test_only: true, srcs: ["foo.cc"],  } `,
+		` cc_test_library {name: "cc-test-library", test_only: true, gtest: false} `,
+		` cc_test_host {name: "cc-test-host", test_only: true, gtest: false} `,
+		` cc_defaults {name: "cc-defaults", test_only: true} `,
+	}
+
+	for i, bp := range testCases {
+		ctx := android.GroupFixturePreparers(
+			prepareForCcTest,
+			android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+				ctx.RegisterModuleType("cc_test_host", TestHostFactory)
+			})).
+			ExtendWithErrorHandler(android.FixtureIgnoreErrors).
+			RunTestWithBp(t, bp)
+		if len(ctx.Errs) == 0 {
+			t.Errorf("Expected err setting test_only in testcase #%d", i)
+		}
+		if len(ctx.Errs) > 1 {
+			t.Errorf("Too many errs: [%s] %v", bp, ctx.Errs)
+		}
+
+		if len(ctx.Errs) == 1 {
+			if !strings.Contains(ctx.Errs[0].Error(), "unrecognized property \"test_only\"") {
+				t.Errorf("ERR: %s bad bp: %s", ctx.Errs[0], bp)
+			}
+		}
+	}
+}
+
+func getTeamProtoOutput(t *testing.T, ctx *android.TestResult) *team_proto.AllTeams {
+	teams := new(team_proto.AllTeams)
+	config := ctx.SingletonForTests("all_teams")
+	allOutputs := config.AllOutputs()
+
+	protoPath := allOutputs[0]
+
+	out := config.MaybeOutput(protoPath)
+	outProto := []byte(android.ContentFromFileRuleForTests(t, ctx.TestContext, out))
+	if err := proto.Unmarshal(outProto, teams); err != nil {
+		log.Fatalln("Failed to parse teams proto:", err)
+	}
+	return teams
+}
diff --git a/cc/check.go b/cc/check.go
index 58ff5b2..32d1f06 100644
--- a/cc/check.go
+++ b/cc/check.go
@@ -45,6 +45,8 @@
 				ctx.PropertyErrorf(prop, "-Weverything is not allowed in Android.bp files.  "+
 					"Build with `m ANDROID_TEMPORARILY_ALLOW_WEVERYTHING=true` to experiment locally with -Weverything.")
 			}
+		} else if strings.HasPrefix(flag, "-target") || strings.HasPrefix(flag, "--target") {
+			ctx.PropertyErrorf(prop, "Bad flag: `%s`, use the correct target soong rule.", flag)
 		} else if strings.Contains(flag, " ") {
 			args := strings.Split(flag, " ")
 			if args[0] == "-include" {
diff --git a/cc/compdb.go b/cc/compdb.go
index 617be1a..da28183 100644
--- a/cc/compdb.go
+++ b/cc/compdb.go
@@ -164,6 +164,7 @@
 		args = append(args, expandAllVars(ctx, ccModule.flags.Local.ConlyFlags)...)
 	}
 	args = append(args, expandAllVars(ctx, ccModule.flags.SystemIncludeFlags)...)
+	args = append(args, expandAllVars(ctx, ccModule.flags.NoOverrideFlags)...)
 	args = append(args, src.String())
 	return args
 }
diff --git a/cc/compiler.go b/cc/compiler.go
index 5bed8a7..9a961cf 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -116,6 +116,10 @@
 	// if set to false, use -std=c++* instead of -std=gnu++*
 	Gnu_extensions *bool
 
+	// cc Build rules targeting BPF must set this to true. The correct fix is to
+	// ban targeting bpf in cc rules instead use bpf_rules. (b/323415017)
+	Bpf_target *bool
+
 	Yacc *YaccProperties
 	Lex  *LexProperties
 
@@ -339,7 +343,7 @@
 // per-target values, module type values, and per-module Blueprints properties
 func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
 	tc := ctx.toolchain()
-	modulePath := android.PathForModuleSrc(ctx).String()
+	modulePath := ctx.ModuleDir()
 
 	compiler.srcsBeforeGen = android.PathsForModuleSrcExcludes(ctx, compiler.Properties.Srcs, compiler.Properties.Exclude_srcs)
 	compiler.srcsBeforeGen = append(compiler.srcsBeforeGen, deps.GeneratedSources...)
@@ -385,7 +389,7 @@
 		flags.Local.YasmFlags = append(flags.Local.YasmFlags, "-I"+modulePath)
 	}
 
-	if !(ctx.useSdk() || ctx.useVndk()) || ctx.Host() {
+	if !(ctx.useSdk() || ctx.InVendorOrProduct()) || ctx.Host() {
 		flags.SystemIncludeFlags = append(flags.SystemIncludeFlags,
 			"${config.CommonGlobalIncludes}",
 			tc.IncludeFlags())
@@ -402,10 +406,19 @@
 			"-isystem "+getCurrentIncludePath(ctx).Join(ctx, config.NDKTriple(tc)).String())
 	}
 
-	if ctx.useVndk() {
+	if ctx.InVendorOrProduct() {
 		flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_VNDK__")
 		if ctx.inVendor() {
 			flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_VENDOR__")
+
+			vendorApiLevel := ctx.Config().VendorApiLevel()
+			if vendorApiLevel == "" {
+				// TODO(b/314036847): This is a fallback for UDC targets.
+				// This must be a build failure when UDC is no longer built
+				// from this source tree.
+				vendorApiLevel = ctx.Config().PlatformSdkVersion().String()
+			}
+			flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_VENDOR_API__="+vendorApiLevel)
 		} else if ctx.inProduct() {
 			flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_PRODUCT__")
 		}
@@ -470,10 +483,15 @@
 			target += strconv.Itoa(android.FutureApiLevelInt)
 		} else {
 			apiLevel := nativeApiLevelOrPanic(ctx, version)
-			target += apiLevel.String()
+			target += strconv.Itoa(apiLevel.FinalOrFutureInt())
 		}
 	}
 
+	// bpf targets don't need the default target triple. b/308826679
+	if proptools.Bool(compiler.Properties.Bpf_target) {
+		target = "--target=bpf"
+	}
+
 	flags.Global.CFlags = append(flags.Global.CFlags, target)
 	flags.Global.AsFlags = append(flags.Global.AsFlags, target)
 	flags.Global.LdFlags = append(flags.Global.LdFlags, target)
@@ -489,8 +507,12 @@
 
 	flags.Global.AsFlags = append(flags.Global.AsFlags, tc.Asflags())
 	flags.Global.CppFlags = append([]string{"${config.CommonGlobalCppflags}"}, flags.Global.CppFlags...)
+
+	// bpf targets don't need the target specific toolchain cflags. b/308826679
+	if !proptools.Bool(compiler.Properties.Bpf_target) {
+		flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.Cflags())
+	}
 	flags.Global.CommonFlags = append(flags.Global.CommonFlags,
-		tc.Cflags(),
 		"${config.CommonGlobalCflags}",
 		fmt.Sprintf("${config.%sGlobalCflags}", hod))
 
@@ -512,7 +534,10 @@
 
 	flags.Global.YasmFlags = append(flags.Global.YasmFlags, tc.YasmFlags())
 
-	flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.ToolchainCflags())
+	// bpf targets don't need the target specific toolchain cflags. b/308826679
+	if !proptools.Bool(compiler.Properties.Bpf_target) {
+		flags.Global.CommonFlags = append(flags.Global.CommonFlags, tc.ToolchainCflags())
+	}
 
 	cStd := parseCStd(compiler.Properties.C_std)
 	cppStd := parseCppStd(compiler.Properties.Cpp_std)
@@ -645,6 +670,16 @@
 		flags.Local.CFlags = append(flags.Local.CFlags, "-DDO_NOT_CHECK_MANUAL_BINDER_INTERFACES")
 	}
 
+	flags.NoOverrideFlags = append(flags.NoOverrideFlags, "${config.NoOverrideGlobalCflags}")
+
+	if flags.Toolchain.Is64Bit() {
+		flags.NoOverrideFlags = append(flags.NoOverrideFlags, "${config.NoOverride64GlobalCflags}")
+	}
+
+	if android.IsThirdPartyPath(ctx.ModuleDir()) {
+		flags.NoOverrideFlags = append(flags.NoOverrideFlags, "${config.NoOverrideExternalGlobalCflags}")
+	}
+
 	return flags
 }
 
@@ -711,7 +746,7 @@
 
 	// Compile files listed in c.Properties.Srcs into objects
 	objs := compileObjs(ctx, buildFlags, "", srcs,
-		android.PathsForModuleSrc(ctx, compiler.Properties.Tidy_disabled_srcs),
+		append(android.PathsForModuleSrc(ctx, compiler.Properties.Tidy_disabled_srcs), compiler.generatedSources...),
 		android.PathsForModuleSrc(ctx, compiler.Properties.Tidy_timeout_srcs),
 		pathDeps, compiler.cFlagsDeps)
 
diff --git a/cc/config/OWNERS b/cc/config/OWNERS
index 580f215..c78b6d5 100644
--- a/cc/config/OWNERS
+++ b/cc/config/OWNERS
@@ -1,3 +1,3 @@
 per-file vndk.go = smoreland@google.com, victoryang@google.com
-per-file clang.go,global.go,tidy.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com
+per-file clang.go,global.go,tidy.go = appujee@google.com, pirama@google.com, srhines@google.com, yabinc@google.com, yikong@google.com, zijunzhao@google.com
 
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 12722a7..beb68e1 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -49,8 +49,8 @@
 	}
 
 	arm64Ldflags = []string{
-		"-Wl,--hash-style=gnu",
 		"-Wl,-z,separate-code",
+		"-Wl,-z,separate-loadable-segments",
 	}
 
 	arm64Lldflags = arm64Ldflags
@@ -91,43 +91,39 @@
 )
 
 func init() {
-	exportedVars.ExportStringListStaticVariable("Arm64Ldflags", arm64Ldflags)
+	pctx.StaticVariable("Arm64Ldflags", strings.Join(arm64Ldflags, " "))
 
-	exportedVars.ExportStringList("Arm64Lldflags", arm64Lldflags)
 	pctx.VariableFunc("Arm64Lldflags", func(ctx android.PackageVarContext) string {
 		maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported()
 		flags := append(arm64Lldflags, maxPageSizeFlag)
 		return strings.Join(flags, " ")
 	})
 
-	exportedVars.ExportStringList("Arm64Cflags", arm64Cflags)
 	pctx.VariableFunc("Arm64Cflags", func(ctx android.PackageVarContext) string {
 		flags := arm64Cflags
-		if ctx.Config().PageSizeAgnostic() {
+		if ctx.Config().NoBionicPageSizeMacro() {
 			flags = append(flags, "-D__BIONIC_NO_PAGE_SIZE_MACRO")
+		} else {
+			flags = append(flags, "-D__BIONIC_DEPRECATED_PAGE_SIZE_MACRO")
 		}
 		return strings.Join(flags, " ")
 	})
 
-	exportedVars.ExportStringListStaticVariable("Arm64Cppflags", arm64Cppflags)
+	pctx.StaticVariable("Arm64Cppflags", strings.Join(arm64Cppflags, " "))
 
-	exportedVars.ExportVariableReferenceDict("Arm64ArchVariantCflags", arm64ArchVariantCflagsVar)
-	exportedVars.ExportVariableReferenceDict("Arm64CpuVariantCflags", arm64CpuVariantCflagsVar)
-	exportedVars.ExportVariableReferenceDict("Arm64CpuVariantLdflags", arm64CpuVariantLdflags)
+	pctx.StaticVariable("Arm64Armv8ACflags", strings.Join(arm64ArchVariantCflags["armv8-a"], " "))
+	pctx.StaticVariable("Arm64Armv8ABranchProtCflags", strings.Join(arm64ArchVariantCflags["armv8-a-branchprot"], " "))
+	pctx.StaticVariable("Arm64Armv82ACflags", strings.Join(arm64ArchVariantCflags["armv8-2a"], " "))
+	pctx.StaticVariable("Arm64Armv82ADotprodCflags", strings.Join(arm64ArchVariantCflags["armv8-2a-dotprod"], " "))
+	pctx.StaticVariable("Arm64Armv9ACflags", strings.Join(arm64ArchVariantCflags["armv9-a"], " "))
 
-	exportedVars.ExportStringListStaticVariable("Arm64Armv8ACflags", arm64ArchVariantCflags["armv8-a"])
-	exportedVars.ExportStringListStaticVariable("Arm64Armv8ABranchProtCflags", arm64ArchVariantCflags["armv8-a-branchprot"])
-	exportedVars.ExportStringListStaticVariable("Arm64Armv82ACflags", arm64ArchVariantCflags["armv8-2a"])
-	exportedVars.ExportStringListStaticVariable("Arm64Armv82ADotprodCflags", arm64ArchVariantCflags["armv8-2a-dotprod"])
-	exportedVars.ExportStringListStaticVariable("Arm64Armv9ACflags", arm64ArchVariantCflags["armv9-a"])
+	pctx.StaticVariable("Arm64CortexA53Cflags", strings.Join(arm64CpuVariantCflags["cortex-a53"], " "))
+	pctx.StaticVariable("Arm64CortexA55Cflags", strings.Join(arm64CpuVariantCflags["cortex-a55"], " "))
+	pctx.StaticVariable("Arm64KryoCflags", strings.Join(arm64CpuVariantCflags["kryo"], " "))
+	pctx.StaticVariable("Arm64ExynosM1Cflags", strings.Join(arm64CpuVariantCflags["exynos-m1"], " "))
+	pctx.StaticVariable("Arm64ExynosM2Cflags", strings.Join(arm64CpuVariantCflags["exynos-m2"], " "))
 
-	exportedVars.ExportStringListStaticVariable("Arm64CortexA53Cflags", arm64CpuVariantCflags["cortex-a53"])
-	exportedVars.ExportStringListStaticVariable("Arm64CortexA55Cflags", arm64CpuVariantCflags["cortex-a55"])
-	exportedVars.ExportStringListStaticVariable("Arm64KryoCflags", arm64CpuVariantCflags["kryo"])
-	exportedVars.ExportStringListStaticVariable("Arm64ExynosM1Cflags", arm64CpuVariantCflags["exynos-m1"])
-	exportedVars.ExportStringListStaticVariable("Arm64ExynosM2Cflags", arm64CpuVariantCflags["exynos-m2"])
-
-	exportedVars.ExportStringListStaticVariable("Arm64FixCortexA53Ldflags", []string{"-Wl,--fix-cortex-a53-843419"})
+	pctx.StaticVariable("Arm64FixCortexA53Ldflags", "-Wl,--fix-cortex-a53-843419")
 }
 
 var (
diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go
index 9f5124b..438e0e6 100644
--- a/cc/config/arm64_linux_host.go
+++ b/cc/config/arm64_linux_host.go
@@ -42,10 +42,13 @@
 		"-Wl,-z,now",
 		"-Wl,--build-id=md5",
 		"-Wl,--fatal-warnings",
-		"-Wl,--hash-style=gnu",
 		"-Wl,--no-undefined-version",
 	}
 
+	linuxCrossLldflags = append(linuxCrossLdflags,
+		"-Wl,--compress-debug-sections=zstd",
+	)
+
 	// Embed the linker into host bionic binaries. This is needed to support host bionic,
 	// as the linux kernel requires that the ELF interpreter referenced by PT_INTERP be
 	// either an absolute path, or relative from CWD. To work around this, we extract
@@ -58,8 +61,9 @@
 )
 
 func init() {
-	exportedVars.ExportStringListStaticVariable("LinuxBionicArm64Cflags", linuxCrossCflags)
-	exportedVars.ExportStringListStaticVariable("LinuxBionicArm64Ldflags", linuxCrossLdflags)
+	pctx.StaticVariable("LinuxBionicArm64Cflags", strings.Join(linuxCrossCflags, " "))
+	pctx.StaticVariable("LinuxBionicArm64Ldflags", strings.Join(linuxCrossLdflags, " "))
+	pctx.StaticVariable("LinuxBionicArm64Lldflags", strings.Join(linuxCrossLldflags, " "))
 }
 
 // toolchain config for ARM64 Linux CrossHost. Almost everything is the same as the ARM64 Android
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 3397e3d..3cb1909 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -28,13 +28,19 @@
 
 	armCflags = []string{
 		"-fomit-frame-pointer",
+		// Revert this after b/322359235 is fixed
+		"-mllvm", "-enable-shrink-wrap=false",
 	}
 
-	armCppflags = []string{}
+	armCppflags = []string{
+		// Revert this after b/322359235 is fixed
+		"-mllvm", "-enable-shrink-wrap=false",
+	}
 
 	armLdflags = []string{
-		"-Wl,--hash-style=gnu",
 		"-Wl,-m,armelf",
+		// Revert this after b/322359235 is fixed
+		"-Wl,-mllvm", "-Wl,-enable-shrink-wrap=false",
 	}
 
 	armLldflags = armLdflags
@@ -179,48 +185,37 @@
 )
 
 func init() {
-	// Just exported. Not created as a Ninja static variable.
-	exportedVars.ExportString("ArmClangTriple", clangTriple)
+	pctx.StaticVariable("ArmLdflags", strings.Join(armLdflags, " "))
+	pctx.StaticVariable("ArmLldflags", strings.Join(armLldflags, " "))
 
-	exportedVars.ExportStringListStaticVariable("ArmLdflags", armLdflags)
-	exportedVars.ExportStringList("ArmLldflags", armLldflags)
-	pctx.VariableFunc("ArmLldflags", func(ctx android.PackageVarContext) string {
-		maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported()
-		flags := append(armLldflags, maxPageSizeFlag)
-		return strings.Join(flags, " ")
-	})
-
-	exportedVars.ExportStringListStaticVariable("ArmFixCortexA8LdFlags", armFixCortexA8LdFlags)
-	exportedVars.ExportStringListStaticVariable("ArmNoFixCortexA8LdFlags", armNoFixCortexA8LdFlags)
+	pctx.StaticVariable("ArmFixCortexA8LdFlags", strings.Join(armFixCortexA8LdFlags, " "))
+	pctx.StaticVariable("ArmNoFixCortexA8LdFlags", strings.Join(armNoFixCortexA8LdFlags, " "))
 
 	// Clang cflags
-	exportedVars.ExportStringListStaticVariable("ArmToolchainCflags", armToolchainCflags)
-	exportedVars.ExportStringListStaticVariable("ArmCflags", armCflags)
-	exportedVars.ExportStringListStaticVariable("ArmCppflags", armCppflags)
+	pctx.StaticVariable("ArmToolchainCflags", strings.Join(armToolchainCflags, " "))
+	pctx.StaticVariable("ArmCflags", strings.Join(armCflags, " "))
+	pctx.StaticVariable("ArmCppflags", strings.Join(armCppflags, " "))
 
 	// Clang ARM vs. Thumb instruction set cflags
-	exportedVars.ExportStringListStaticVariable("ArmArmCflags", armArmCflags)
-	exportedVars.ExportStringListStaticVariable("ArmThumbCflags", armThumbCflags)
-
-	exportedVars.ExportVariableReferenceDict("ArmArchVariantCflags", armArchVariantCflagsVar)
-	exportedVars.ExportVariableReferenceDict("ArmCpuVariantCflags", armCpuVariantCflagsVar)
+	pctx.StaticVariable("ArmArmCflags", strings.Join(armArmCflags, " "))
+	pctx.StaticVariable("ArmThumbCflags", strings.Join(armThumbCflags, " "))
 
 	// Clang arch variant cflags
-	exportedVars.ExportStringListStaticVariable("ArmArmv7ACflags", armArchVariantCflags["armv7-a"])
-	exportedVars.ExportStringListStaticVariable("ArmArmv7ANeonCflags", armArchVariantCflags["armv7-a-neon"])
-	exportedVars.ExportStringListStaticVariable("ArmArmv8ACflags", armArchVariantCflags["armv8-a"])
-	exportedVars.ExportStringListStaticVariable("ArmArmv82ACflags", armArchVariantCflags["armv8-2a"])
+	pctx.StaticVariable("ArmArmv7ACflags", strings.Join(armArchVariantCflags["armv7-a"], " "))
+	pctx.StaticVariable("ArmArmv7ANeonCflags", strings.Join(armArchVariantCflags["armv7-a-neon"], " "))
+	pctx.StaticVariable("ArmArmv8ACflags", strings.Join(armArchVariantCflags["armv8-a"], " "))
+	pctx.StaticVariable("ArmArmv82ACflags", strings.Join(armArchVariantCflags["armv8-2a"], " "))
 
 	// Clang cpu variant cflags
-	exportedVars.ExportStringListStaticVariable("ArmGenericCflags", armCpuVariantCflags[""])
-	exportedVars.ExportStringListStaticVariable("ArmCortexA7Cflags", armCpuVariantCflags["cortex-a7"])
-	exportedVars.ExportStringListStaticVariable("ArmCortexA8Cflags", armCpuVariantCflags["cortex-a8"])
-	exportedVars.ExportStringListStaticVariable("ArmCortexA15Cflags", armCpuVariantCflags["cortex-a15"])
-	exportedVars.ExportStringListStaticVariable("ArmCortexA32Cflags", armCpuVariantCflags["cortex-a32"])
-	exportedVars.ExportStringListStaticVariable("ArmCortexA53Cflags", armCpuVariantCflags["cortex-a53"])
-	exportedVars.ExportStringListStaticVariable("ArmCortexA55Cflags", armCpuVariantCflags["cortex-a55"])
-	exportedVars.ExportStringListStaticVariable("ArmKraitCflags", armCpuVariantCflags["krait"])
-	exportedVars.ExportStringListStaticVariable("ArmKryoCflags", armCpuVariantCflags["kryo"])
+	pctx.StaticVariable("ArmGenericCflags", strings.Join(armCpuVariantCflags[""], " "))
+	pctx.StaticVariable("ArmCortexA7Cflags", strings.Join(armCpuVariantCflags["cortex-a7"], " "))
+	pctx.StaticVariable("ArmCortexA8Cflags", strings.Join(armCpuVariantCflags["cortex-a8"], " "))
+	pctx.StaticVariable("ArmCortexA15Cflags", strings.Join(armCpuVariantCflags["cortex-a15"], " "))
+	pctx.StaticVariable("ArmCortexA32Cflags", strings.Join(armCpuVariantCflags["cortex-a32"], " "))
+	pctx.StaticVariable("ArmCortexA53Cflags", strings.Join(armCpuVariantCflags["cortex-a53"], " "))
+	pctx.StaticVariable("ArmCortexA55Cflags", strings.Join(armCpuVariantCflags["cortex-a55"], " "))
+	pctx.StaticVariable("ArmKraitCflags", strings.Join(armCpuVariantCflags["krait"], " "))
+	pctx.StaticVariable("ArmKryoCflags", strings.Join(armCpuVariantCflags["kryo"], " "))
 }
 
 var (
diff --git a/cc/config/arm_linux_host.go b/cc/config/arm_linux_host.go
index 525fb5d..e7c7bc4 100644
--- a/cc/config/arm_linux_host.go
+++ b/cc/config/arm_linux_host.go
@@ -14,7 +14,10 @@
 
 package config
 
-import "android/soong/android"
+import (
+	"android/soong/android"
+	"strings"
+)
 
 var (
 	linuxArmCflags = []string{
@@ -27,19 +30,27 @@
 		"-march=armv7a",
 	}
 
+	linuxArmLldflags = append(linuxArmLdflags,
+		"-Wl,--compress-debug-sections=zstd",
+	)
+
 	linuxArm64Ldflags = []string{}
+
+	linuxArm64Lldflags = append(linuxArm64Ldflags,
+		"-Wl,--compress-debug-sections=zstd",
+	)
 )
 
 func init() {
-	exportedVars.ExportStringListStaticVariable("LinuxArmCflags", linuxArmCflags)
-	exportedVars.ExportStringListStaticVariable("LinuxArm64Cflags", linuxArm64Cflags)
-	exportedVars.ExportStringListStaticVariable("LinuxArmLdflags", linuxArmLdflags)
-	exportedVars.ExportStringListStaticVariable("LinuxArmLldflags", linuxArmLdflags)
-	exportedVars.ExportStringListStaticVariable("LinuxArm64Ldflags", linuxArm64Ldflags)
-	exportedVars.ExportStringListStaticVariable("LinuxArm64Lldflags", linuxArm64Ldflags)
+	pctx.StaticVariable("LinuxArmCflags", strings.Join(linuxArmCflags, " "))
+	pctx.StaticVariable("LinuxArm64Cflags", strings.Join(linuxArm64Cflags, " "))
+	pctx.StaticVariable("LinuxArmLdflags", strings.Join(linuxArmLdflags, " "))
+	pctx.StaticVariable("LinuxArmLldflags", strings.Join(linuxArmLldflags, " "))
+	pctx.StaticVariable("LinuxArm64Ldflags", strings.Join(linuxArm64Ldflags, " "))
+	pctx.StaticVariable("LinuxArm64Lldflags", strings.Join(linuxArm64Lldflags, " "))
 
-	exportedVars.ExportStringListStaticVariable("LinuxArmYasmFlags", []string{"-f elf32 -m arm"})
-	exportedVars.ExportStringListStaticVariable("LinuxArm64YasmFlags", []string{"-f elf64 -m aarch64"})
+	pctx.StaticVariable("LinuxArmYasmFlags", "-f elf32 -m arm")
+	pctx.StaticVariable("LinuxArm64YasmFlags", "-f elf64 -m aarch64")
 
 }
 
diff --git a/cc/config/bionic.go b/cc/config/bionic.go
index a1e3851..ed724f5 100644
--- a/cc/config/bionic.go
+++ b/cc/config/bionic.go
@@ -24,6 +24,7 @@
 	bionicCrtBeginStaticBinary, bionicCrtEndStaticBinary   = []string{"crtbegin_static"}, []string{"crtend_android"}
 	bionicCrtBeginSharedBinary, bionicCrtEndSharedBinary   = []string{"crtbegin_dynamic"}, []string{"crtend_android"}
 	bionicCrtBeginSharedLibrary, bionicCrtEndSharedLibrary = []string{"crtbegin_so"}, []string{"crtend_so"}
+	bionicCrtPadSegmentSharedLibrary                       = []string{"crt_pad_segment"}
 )
 
 func (toolchainBionic) Bionic() bool { return true }
@@ -36,9 +37,10 @@
 
 func (toolchainBionic) AvailableLibraries() []string { return nil }
 
-func (toolchainBionic) CrtBeginStaticBinary() []string  { return bionicCrtBeginStaticBinary }
-func (toolchainBionic) CrtBeginSharedBinary() []string  { return bionicCrtBeginSharedBinary }
-func (toolchainBionic) CrtBeginSharedLibrary() []string { return bionicCrtBeginSharedLibrary }
-func (toolchainBionic) CrtEndStaticBinary() []string    { return bionicCrtEndStaticBinary }
-func (toolchainBionic) CrtEndSharedBinary() []string    { return bionicCrtEndSharedBinary }
-func (toolchainBionic) CrtEndSharedLibrary() []string   { return bionicCrtEndSharedLibrary }
+func (toolchainBionic) CrtBeginStaticBinary() []string       { return bionicCrtBeginStaticBinary }
+func (toolchainBionic) CrtBeginSharedBinary() []string       { return bionicCrtBeginSharedBinary }
+func (toolchainBionic) CrtBeginSharedLibrary() []string      { return bionicCrtBeginSharedLibrary }
+func (toolchainBionic) CrtEndStaticBinary() []string         { return bionicCrtEndStaticBinary }
+func (toolchainBionic) CrtEndSharedBinary() []string         { return bionicCrtEndSharedBinary }
+func (toolchainBionic) CrtEndSharedLibrary() []string        { return bionicCrtEndSharedLibrary }
+func (toolchainBionic) CrtPadSegmentSharedLibrary() []string { return bionicCrtPadSegmentSharedLibrary }
diff --git a/cc/config/darwin_host.go b/cc/config/darwin_host.go
index 2cabdc8..47c61b0 100644
--- a/cc/config/darwin_host.go
+++ b/cc/config/darwin_host.go
@@ -29,11 +29,6 @@
 		"-fPIC",
 		"-funwind-tables",
 
-		// Workaround differences in inttypes.h between host and target.
-		//See bug 12708004.
-		"-D__STDC_FORMAT_MACROS",
-		"-D__STDC_CONSTANT_MACROS",
-
 		"-isysroot ${macSdkRoot}",
 		"-mmacosx-version-min=${macMinVersion}",
 		"-DMACOSX_DEPLOYMENT_TARGET=${macMinVersion}",
@@ -79,7 +74,7 @@
 	pctx.VariableFunc("macSdkRoot", func(ctx android.PackageVarContext) string {
 		return getMacTools(ctx).sdkRoot
 	})
-	pctx.StaticVariable("macMinVersion", "10.13")
+	pctx.StaticVariable("macMinVersion", "10.14")
 	pctx.VariableFunc("MacArPath", func(ctx android.PackageVarContext) string {
 		return getMacTools(ctx).arPath
 	})
diff --git a/cc/config/global.go b/cc/config/global.go
index ff5ab05..16b5e09 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -16,6 +16,7 @@
 
 import (
 	"runtime"
+	"slices"
 	"strings"
 
 	"android/soong/android"
@@ -23,96 +24,129 @@
 )
 
 var (
-	pctx         = android.NewPackageContext("android/soong/cc/config")
-	exportedVars = android.NewExportedVariables(pctx)
+	pctx = android.NewPackageContext("android/soong/cc/config")
 
 	// Flags used by lots of devices.  Putting them in package static variables
 	// will save bytes in build.ninja so they aren't repeated for every file
 	commonGlobalCflags = []string{
-		"-DANDROID",
-		"-fmessage-length=0",
-		"-W",
+		// Enable some optimization by default.
+		"-O2",
+
+		// Warnings enabled by default. Reference:
+		// https://clang.llvm.org/docs/DiagnosticsReference.html
 		"-Wall",
-		"-Wno-unused",
+		"-Wextra",
 		"-Winit-self",
 		"-Wpointer-arith",
-		"-Wunreachable-code-loop-increment",
+		"-Wunguarded-availability",
 
-		// Make paths in deps files relative
-		"-no-canonical-prefixes",
+		// Warnings treated as errors by default.
+		// See also noOverrideGlobalCflags for errors that cannot be disabled
+		// from Android.bp files.
 
-		"-DNDEBUG",
-		"-UDEBUG",
-
-		"-fno-exceptions",
-		"-Wno-multichar",
-
-		"-O2",
-		"-fdebug-default-version=5",
-
-		"-fno-strict-aliasing",
-
+		// Using __DATE__/__TIME__ causes build nondeterminism.
 		"-Werror=date-time",
+		// Detects forgotten */& that usually cause a crash
+		"-Werror=int-conversion",
+		// Detects unterminated alignment modification pragmas, which often lead
+		// to ABI mismatch between modules and hard-to-debug crashes.
 		"-Werror=pragma-pack",
+		// Same as above, but detects alignment pragmas around a header
+		// inclusion.
 		"-Werror=pragma-pack-suspicious-include",
+		// Detects dividing an array size by itself, which is a common typo that
+		// leads to bugs.
+		"-Werror=sizeof-array-div",
+		// Detects a typo that cuts off a prefix from a string literal.
 		"-Werror=string-plus-int",
+		// Detects for loops that will never execute more than once (for example
+		// due to unconditional break), but have a non-empty loop increment
+		// clause. Often a mistake/bug.
 		"-Werror=unreachable-code-loop-increment",
 
-		// Force deprecation warnings to be warnings for code that compiles with -Werror.
-		// Making deprecated usages an error causes extreme pain when trying to deprecate anything.
+		// Warnings that should not be errors even for modules with -Werror.
+
+		// Making deprecated usages an error causes extreme pain when trying to
+		// deprecate anything.
 		"-Wno-error=deprecated-declarations",
 
+		// Warnings disabled by default.
+
+		// Designated initializer syntax is recommended by the Google C++ style
+		// and is OK to use even if not formally supported by the chosen C++
+		// version.
+		"-Wno-c99-designator",
+		// Detects uses of a GNU C extension equivalent to a limited form of
+		// constexpr. Enabling this would require replacing many constants with
+		// macros, which is not a good trade-off.
+		"-Wno-gnu-folding-constant",
+		// AIDL generated code redeclares pure virtual methods in each
+		// subsequent version of an interface, so this warning is currently
+		// infeasible to enable.
+		"-Wno-inconsistent-missing-override",
+		// Detects designated initializers that are in a different order than
+		// the fields in the initialized type, which causes the side effects
+		// of initializers to occur out of order with the source code.
+		// In practice, this warning has extremely poor signal to noise ratio,
+		// because it is triggered even for initializers with no side effects.
+		// Individual modules can still opt into it via cflags.
+		"-Wno-error=reorder-init-list",
+		"-Wno-reorder-init-list",
+		// Incompatible with the Google C++ style guidance to use 'int' for loop
+		// indices; poor signal to noise ratio.
+		"-Wno-sign-compare",
+		// Poor signal to noise ratio.
+		"-Wno-unused",
+
+		// Global preprocessor constants.
+
+		"-DANDROID",
+		"-DNDEBUG",
+		"-UDEBUG",
 		"-D__compiler_offsetof=__builtin_offsetof",
+		// Allows the bionic versioning.h to indirectly determine whether the
+		// option -Wunguarded-availability is on or not.
+		"-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__",
+
+		// -f and -g options.
 
 		// Emit address-significance table which allows linker to perform safe ICF. Clang does
 		// not emit the table by default on Android since NDK still uses GNU binutils.
 		"-faddrsig",
 
-		// Turn on -fcommon explicitly, since Clang now defaults to -fno-common. The cleanup bug
-		// tracking this is http://b/151457797.
-		"-fcommon",
-
-		// Help catch common 32/64-bit errors.
-		"-Werror=int-conversion",
-
-		// Disable overly aggressive warning for macros defined with a leading underscore
-		// This happens in AndroidConfig.h, which is included nearly everywhere.
-		// TODO: can we remove this now?
-		"-Wno-reserved-id-macro",
+		// Emit debugging data in a modern format (DWARF v5).
+		"-fdebug-default-version=5",
 
 		// Force clang to always output color diagnostics. Ninja will strip the ANSI
 		// color codes if it is not running in a terminal.
 		"-fcolor-diagnostics",
 
-		// Warnings from clang-7.0
-		"-Wno-sign-compare",
-
-		// Disable -Winconsistent-missing-override until we can clean up the existing
-		// codebase for it.
-		"-Wno-inconsistent-missing-override",
-
-		// Warnings from clang-10
-		// Nested and array designated initialization is nice to have.
-		"-Wno-c99-designator",
-
-		// Many old files still have GNU designator syntax.
-		"-Wno-gnu-designator",
-
-		// Warnings from clang-12
-		"-Wno-gnu-folding-constant",
-
-		// Calls to the APIs that are newer than the min sdk version of the caller should be
-		// guarded with __builtin_available.
-		"-Wunguarded-availability",
-		// This macro allows the bionic versioning.h to indirectly determine whether the
-		// option -Wunguarded-availability is on or not.
-		"-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__",
-
 		// Turn off FMA which got enabled by default in clang-r445002 (http://b/218805949)
 		"-ffp-contract=off",
 
+		// Google C++ style does not allow exceptions, turn them off by default.
+		"-fno-exceptions",
+
+		// Disable optimizations based on strict aliasing by default.
+		// The performance benefit of enabling them currently does not outweigh
+		// the risk of hard-to-reproduce bugs.
+		"-fno-strict-aliasing",
+
+		// Disable line wrapping for error messages - it interferes with
+		// displaying logs in web browsers.
+		"-fmessage-length=0",
+
 		// Using simple template names reduces the size of debug builds.
 		"-gsimple-template-names",
+
+		// Use zstd to compress debug data.
+		"-gz=zstd",
+
+		// Make paths in deps files relative.
+		"-no-canonical-prefixes",
+
+		// http://b/315250603 temporarily disabled
+		"-Wno-error=format",
 	}
 
 	commonGlobalConlyflags = []string{}
@@ -124,6 +158,7 @@
 		"-fdebug-default-version=4",
 	}
 
+	// Compilation flags for device code; not applied to host code.
 	deviceGlobalCflags = []string{
 		"-ffunction-sections",
 		"-fdata-sections",
@@ -156,6 +191,7 @@
 		"-fvisibility-inlines-hidden",
 	}
 
+	// Linking flags for device code; not applied to host binaries.
 	deviceGlobalLdflags = []string{
 		"-Wl,-z,noexecstack",
 		"-Wl,-z,relro",
@@ -171,7 +207,9 @@
 		"-Wl,--exclude-libs,libunwind.a",
 	}
 
-	deviceGlobalLldflags = append(deviceGlobalLdflags, commonGlobalLldflags...)
+	deviceGlobalLldflags = append(append(deviceGlobalLdflags, commonGlobalLldflags...),
+		"-Wl,--compress-debug-sections=zstd",
+	)
 
 	hostGlobalCflags = []string{}
 
@@ -182,8 +220,6 @@
 	hostGlobalLldflags = commonGlobalLldflags
 
 	commonGlobalCppflags = []string{
-		"-Wsign-promo",
-
 		// -Wimplicit-fallthrough is not enabled by -Wall.
 		"-Wimplicit-fallthrough",
 
@@ -194,6 +230,16 @@
 		"-Wno-gnu-include-next",
 	}
 
+	// These flags are appended after the module's cflags, so they cannot be
+	// overridden from Android.bp files.
+	//
+	// NOTE: if you need to disable a warning to unblock a compiler upgrade
+	// and it is only triggered by third party code, add it to
+	// extraExternalCflags (if possible) or noOverrideExternalGlobalCflags
+	// (if the former doesn't work). If the new warning also occurs in first
+	// party code, try adding it to commonGlobalCflags first. Adding it here
+	// should be the last resort, because it prevents all code in Android from
+	// opting into the warning.
 	noOverrideGlobalCflags = []string{
 		"-Werror=bool-operation",
 		"-Werror=format-insufficient-args",
@@ -209,8 +255,15 @@
 		// http://b/161386391 for -Wno-pointer-to-int-cast
 		"-Wno-pointer-to-int-cast",
 		"-Werror=fortify-source",
+		// http://b/315246135 temporarily disabled
+		"-Wno-unused-variable",
+		// Disabled because it produces many false positives. http://b/323050926
+		"-Wno-missing-field-initializers",
+		// http://b/323050889
+		"-Wno-packed-non-pod",
 
 		"-Werror=address-of-temporary",
+		"-Werror=incompatible-function-pointer-types",
 		"-Werror=null-dereference",
 		"-Werror=return-type",
 
@@ -218,8 +271,6 @@
 		// new warnings are fixed.
 		"-Wno-tautological-constant-compare",
 		"-Wno-tautological-type-limit-compare",
-		// http://b/145210666
-		"-Wno-reorder-init-list",
 		// http://b/145211066
 		"-Wno-implicit-int-float-conversion",
 		// New warnings to be fixed after clang-r377782.
@@ -229,7 +280,8 @@
 		"-Wno-range-loop-construct",                 // http://b/153747076
 		"-Wno-zero-as-null-pointer-constant",        // http://b/68236239
 		"-Wno-deprecated-anon-enum-enum-conversion", // http://b/153746485
-		"-Wno-pessimizing-move",                     // http://b/154270751
+		"-Wno-deprecated-enum-enum-conversion",
+		"-Wno-pessimizing-move", // http://b/154270751
 		// New warnings to be fixed after clang-r399163
 		"-Wno-non-c-typedef-for-linkage", // http://b/161304145
 		// New warnings to be fixed after clang-r428724
@@ -243,26 +295,20 @@
 		// New warnings to be fixed after clang-r475365
 		"-Wno-error=single-bit-bitfield-constant-conversion", // http://b/243965903
 		"-Wno-error=enum-constexpr-conversion",               // http://b/243964282
+
+		// Irrelevant on Android because _we_ don't use exceptions, but causes
+		// lots of build noise because libcxx/libcxxabi do. This can probably
+		// go away when we're on a new enough libc++, but has to be global
+		// until then because it causes warnings in the _callers_, not the
+		// project itself.
+		"-Wno-deprecated-dynamic-exception-spec",
 	}
 
 	noOverride64GlobalCflags = []string{}
 
-	noOverrideExternalGlobalCflags = []string{
-		// http://b/191699019
-		"-Wno-format-insufficient-args",
-		"-Wno-sizeof-array-div",
-		"-Wno-incompatible-function-pointer-types",
-		"-Wno-unused-but-set-variable",
-		"-Wno-unused-but-set-parameter",
-		"-Wno-unqualified-std-cast-call",
-		"-Wno-bitwise-instead-of-logical",
-		"-Wno-misleading-indentation",
-		"-Wno-array-parameter",
-		"-Wno-gnu-offsetof-extensions",
-	}
-
-	// Extra cflags for external third-party projects to disable warnings that
-	// are infeasible to fix in all the external projects and their upstream repos.
+	// Extra cflags applied to third-party code (anything for which
+	// IsThirdPartyPath() in build/soong/android/paths.go returns true;
+	// includes external/, most of vendor/ and most of hardware/)
 	extraExternalCflags = []string{
 		"-Wno-enum-compare",
 		"-Wno-enum-compare-switch",
@@ -290,26 +336,58 @@
 
 		// http://b/239661264
 		"-Wno-deprecated-non-prototype",
+
+		"-Wno-unused",
+		"-Wno-deprecated",
+	}
+
+	// Similar to noOverrideGlobalCflags, but applies only to third-party code
+	// (see extraExternalCflags).
+	// This section can unblock compiler upgrades when a third party module that
+	// enables -Werror and some group of warnings explicitly triggers newly
+	// added warnings.
+	noOverrideExternalGlobalCflags = []string{
+		// http://b/151457797
+		"-fcommon",
+		// http://b/191699019
+		"-Wno-format-insufficient-args",
+		// http://b/296321508
+		// Introduced in response to a critical security vulnerability and
+		// should be a hard error - it requires only whitespace changes to fix.
+		"-Wno-misleading-indentation",
+		// Triggered by old LLVM code in external/llvm. Likely not worth
+		// enabling since it's a cosmetic issue.
+		"-Wno-bitwise-instead-of-logical",
+
+		"-Wno-unused",
+		"-Wno-unused-parameter",
+		"-Wno-unused-but-set-parameter",
+		"-Wno-unqualified-std-cast-call",
+		"-Wno-array-parameter",
+		"-Wno-gnu-offsetof-extensions",
+		// TODO: Enable this warning http://b/315245071
+		"-Wno-fortify-source",
 	}
 
 	llvmNextExtraCommonGlobalCflags = []string{
 		// Do not report warnings when testing with the top of trunk LLVM.
-		"-Wno-error",
+		"-Wno-everything",
 	}
 
+	// Flags that must not appear in any command line.
 	IllegalFlags = []string{
 		"-w",
 	}
 
 	CStdVersion               = "gnu17"
-	CppStdVersion             = "gnu++17"
+	CppStdVersion             = "gnu++20"
 	ExperimentalCStdVersion   = "gnu2x"
-	ExperimentalCppStdVersion = "gnu++2a"
+	ExperimentalCppStdVersion = "gnu++2b"
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r498229"
-	ClangDefaultShortVersion = "17"
+	ClangDefaultVersion      = "clang-r510928"
+	ClangDefaultShortVersion = "18"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
@@ -323,35 +401,22 @@
 	VisibilityDefaultFlag = "-fvisibility=default"
 )
 
-// BazelCcToolchainVars generates bzl file content containing variables for
-// Bazel's cc_toolchain configuration.
-func BazelCcToolchainVars(config android.Config) string {
-	return android.BazelToolchainVars(config, exportedVars)
-}
-
-func ExportStringList(name string, value []string) {
-	exportedVars.ExportStringList(name, value)
-}
-
 func init() {
 	if runtime.GOOS == "linux" {
 		commonGlobalCflags = append(commonGlobalCflags, "-fdebug-prefix-map=/proc/self/cwd=")
 	}
 
-	exportedVars.ExportStringListStaticVariable("CommonGlobalConlyflags", commonGlobalConlyflags)
-	exportedVars.ExportStringListStaticVariable("CommonGlobalAsflags", commonGlobalAsflags)
-	exportedVars.ExportStringListStaticVariable("DeviceGlobalCppflags", deviceGlobalCppflags)
-	exportedVars.ExportStringListStaticVariable("DeviceGlobalLdflags", deviceGlobalLdflags)
-	exportedVars.ExportStringListStaticVariable("DeviceGlobalLldflags", deviceGlobalLldflags)
-	exportedVars.ExportStringListStaticVariable("HostGlobalCppflags", hostGlobalCppflags)
-	exportedVars.ExportStringListStaticVariable("HostGlobalLdflags", hostGlobalLdflags)
-	exportedVars.ExportStringListStaticVariable("HostGlobalLldflags", hostGlobalLldflags)
-
-	// Export the static default CommonGlobalCflags to Bazel.
-	exportedVars.ExportStringList("CommonGlobalCflags", commonGlobalCflags)
+	pctx.StaticVariable("CommonGlobalConlyflags", strings.Join(commonGlobalConlyflags, " "))
+	pctx.StaticVariable("CommonGlobalAsflags", strings.Join(commonGlobalAsflags, " "))
+	pctx.StaticVariable("DeviceGlobalCppflags", strings.Join(deviceGlobalCppflags, " "))
+	pctx.StaticVariable("DeviceGlobalLdflags", strings.Join(deviceGlobalLdflags, " "))
+	pctx.StaticVariable("DeviceGlobalLldflags", strings.Join(deviceGlobalLldflags, " "))
+	pctx.StaticVariable("HostGlobalCppflags", strings.Join(hostGlobalCppflags, " "))
+	pctx.StaticVariable("HostGlobalLdflags", strings.Join(hostGlobalLdflags, " "))
+	pctx.StaticVariable("HostGlobalLldflags", strings.Join(hostGlobalLldflags, " "))
 
 	pctx.VariableFunc("CommonGlobalCflags", func(ctx android.PackageVarContext) string {
-		flags := commonGlobalCflags
+		flags := slices.Clone(commonGlobalCflags)
 
 		// http://b/131390872
 		// Automatically initialize any uninitialized stack variables.
@@ -395,39 +460,24 @@
 		return strings.Join(flags, " ")
 	})
 
-	// Export the static default DeviceGlobalCflags to Bazel.
-	// TODO(187086342): handle cflags that are set in VariableFuncs.
-	exportedVars.ExportStringList("DeviceGlobalCflags", deviceGlobalCflags)
-
 	pctx.VariableFunc("DeviceGlobalCflags", func(ctx android.PackageVarContext) string {
 		return strings.Join(deviceGlobalCflags, " ")
 	})
 
-	// Export the static default NoOverrideGlobalCflags to Bazel.
-	exportedVars.ExportStringList("NoOverrideGlobalCflags", noOverrideGlobalCflags)
 	pctx.VariableFunc("NoOverrideGlobalCflags", func(ctx android.PackageVarContext) string {
 		flags := noOverrideGlobalCflags
 		if ctx.Config().IsEnvTrue("LLVM_NEXT") {
 			flags = append(noOverrideGlobalCflags, llvmNextExtraCommonGlobalCflags...)
+			IllegalFlags = []string{} // Don't fail build while testing a new compiler.
 		}
 		return strings.Join(flags, " ")
 	})
 
-	exportedVars.ExportStringListStaticVariable("NoOverride64GlobalCflags", noOverride64GlobalCflags)
-	exportedVars.ExportStringListStaticVariable("HostGlobalCflags", hostGlobalCflags)
-	exportedVars.ExportStringListStaticVariable("NoOverrideExternalGlobalCflags", noOverrideExternalGlobalCflags)
-	exportedVars.ExportStringListStaticVariable("CommonGlobalCppflags", commonGlobalCppflags)
-	exportedVars.ExportStringListStaticVariable("ExternalCflags", extraExternalCflags)
-
-	exportedVars.ExportString("CStdVersion", CStdVersion)
-	exportedVars.ExportString("CppStdVersion", CppStdVersion)
-	exportedVars.ExportString("ExperimentalCStdVersion", ExperimentalCStdVersion)
-	exportedVars.ExportString("ExperimentalCppStdVersion", ExperimentalCppStdVersion)
-
-	exportedVars.ExportString("VersionScriptFlagPrefix", VersionScriptFlagPrefix)
-
-	exportedVars.ExportString("VisibilityHiddenFlag", VisibilityHiddenFlag)
-	exportedVars.ExportString("VisibilityDefaultFlag", VisibilityDefaultFlag)
+	pctx.StaticVariable("NoOverride64GlobalCflags", strings.Join(noOverride64GlobalCflags, " "))
+	pctx.StaticVariable("HostGlobalCflags", strings.Join(hostGlobalCflags, " "))
+	pctx.StaticVariable("NoOverrideExternalGlobalCflags", strings.Join(noOverrideExternalGlobalCflags, " "))
+	pctx.StaticVariable("CommonGlobalCppflags", strings.Join(commonGlobalCppflags, " "))
+	pctx.StaticVariable("ExternalCflags", strings.Join(extraExternalCflags, " "))
 
 	// Everything in these lists is a crime against abstraction and dependency tracking.
 	// Do not add anything to this list.
@@ -442,11 +492,10 @@
 		"frameworks/native/opengl/include",
 		"frameworks/av/include",
 	}
-	exportedVars.ExportStringList("CommonGlobalIncludes", commonGlobalIncludes)
 	pctx.PrefixedExistentPathsForSourcesVariable("CommonGlobalIncludes", "-I", commonGlobalIncludes)
 
-	exportedVars.ExportStringStaticVariable("CLANG_DEFAULT_VERSION", ClangDefaultVersion)
-	exportedVars.ExportStringStaticVariable("CLANG_DEFAULT_SHORT_VERSION", ClangDefaultShortVersion)
+	pctx.StaticVariable("CLANG_DEFAULT_VERSION", ClangDefaultVersion)
+	pctx.StaticVariable("CLANG_DEFAULT_SHORT_VERSION", ClangDefaultShortVersion)
 
 	pctx.StaticVariableWithEnvOverride("ClangBase", "LLVM_PREBUILTS_BASE", ClangDefaultBase)
 	pctx.StaticVariableWithEnvOverride("ClangVersion", "LLVM_PREBUILTS_VERSION", ClangDefaultVersion)
@@ -456,7 +505,7 @@
 	pctx.StaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion)
 	pctx.StaticVariable("ClangAsanLibDir", "${ClangBase}/linux-x86/${ClangVersion}/lib/clang/${ClangShortVersion}/lib/linux")
 
-	exportedVars.ExportStringListStaticVariable("WarningAllowedProjects", WarningAllowedProjects)
+	pctx.StaticVariable("WarningAllowedProjects", strings.Join(WarningAllowedProjects, " "))
 
 	// These are tied to the version of LLVM directly in external/llvm, so they might trail the host prebuilts
 	// being used for the rest of the build process.
@@ -471,7 +520,6 @@
 		"frameworks/rs/script_api/include",
 	}
 	pctx.PrefixedExistentPathsForSourcesVariable("RsGlobalIncludes", "-I", rsGlobalIncludes)
-	exportedVars.ExportStringList("RsGlobalIncludes", rsGlobalIncludes)
 
 	pctx.VariableFunc("CcWrapper", func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv("CC_WRAPPER"); override != "" {
@@ -489,7 +537,7 @@
 	pctx.StaticVariableWithEnvOverride("REAbiLinkerExecStrategy", "RBE_ABI_LINKER_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
 }
 
-var HostPrebuiltTag = exportedVars.ExportVariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS)
+var HostPrebuiltTag = pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS)
 
 func ClangPath(ctx android.PathContext, file string) android.SourcePath {
 	type clangToolKey string
diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go
index 40919c0..724676a 100644
--- a/cc/config/riscv64_device.go
+++ b/cc/config/riscv64_device.go
@@ -23,22 +23,34 @@
 
 var (
 	riscv64Cflags = []string{
-		// Help catch common 32/64-bit errors.
+		// Help catch common 32/64-bit errors. (This is duplicated in all 64-bit
+		// architectures' cflags.)
 		"-Werror=implicit-function-declaration",
-		"-fno-emulated-tls",
-		"-march=rv64gc_zba_zbb_zbs",
+		// This is already the driver's Android default, but duplicated here (and
+		// below) for ease of experimentation with additional extensions.
+		"-march=rv64gcv_zba_zbb_zbs",
+		// TODO: move to driver (https://github.com/google/android-riscv64/issues/111)
+		"-mno-strict-align",
+		// TODO: remove when qemu V works (https://gitlab.com/qemu-project/qemu/-/issues/1976)
+		// (Note that we'll probably want to wait for berberis to be good enough
+		// that most people don't care about qemu's V performance either!)
+		"-mno-implicit-float",
+		// TODO: remove when clang default changed (https://github.com/google/android-riscv64/issues/124)
+		"-mllvm -jump-is-expensive=false",
 	}
 
 	riscv64ArchVariantCflags = map[string][]string{}
 
 	riscv64Ldflags = []string{
-		"-Wl,--hash-style=gnu",
-		"-march=rv64gc_zba_zbb_zbs",
+		// This is already the driver's Android default, but duplicated here (and
+		// above) for ease of experimentation with additional extensions.
+		"-march=rv64gcv_zba_zbb_zbs",
+		// TODO: remove when clang default changed (https://github.com/google/android-riscv64/issues/124)
+		"-Wl,-mllvm -Wl,-jump-is-expensive=false",
 	}
 
 	riscv64Lldflags = append(riscv64Ldflags,
 		"-Wl,-z,max-page-size=4096",
-		"-Wl,-plugin-opt,-emulated-tls=0",
 	)
 
 	riscv64Cppflags = []string{}
@@ -50,15 +62,11 @@
 
 func init() {
 
-	exportedVars.ExportStringListStaticVariable("Riscv64Ldflags", riscv64Ldflags)
-	exportedVars.ExportStringListStaticVariable("Riscv64Lldflags", riscv64Lldflags)
+	pctx.StaticVariable("Riscv64Ldflags", strings.Join(riscv64Ldflags, " "))
+	pctx.StaticVariable("Riscv64Lldflags", strings.Join(riscv64Lldflags, " "))
 
-	exportedVars.ExportStringListStaticVariable("Riscv64Cflags", riscv64Cflags)
-	exportedVars.ExportStringListStaticVariable("Riscv64Cppflags", riscv64Cppflags)
-
-	exportedVars.ExportVariableReferenceDict("Riscv64ArchVariantCflags", riscv64ArchVariantCflagsVar)
-	exportedVars.ExportVariableReferenceDict("Riscv64CpuVariantCflags", riscv64CpuVariantCflagsVar)
-	exportedVars.ExportVariableReferenceDict("Riscv64CpuVariantLdflags", riscv64CpuVariantLdflags)
+	pctx.StaticVariable("Riscv64Cflags", strings.Join(riscv64Cflags, " "))
+	pctx.StaticVariable("Riscv64Cppflags", strings.Join(riscv64Cppflags, " "))
 }
 
 var (
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index efa4549..46d5d90 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -16,7 +16,6 @@
 
 import (
 	"android/soong/android"
-	"regexp"
 	"strings"
 )
 
@@ -88,7 +87,7 @@
 	// The global default tidy checks should include clang-tidy
 	// default checks and tested groups, but exclude known noisy checks.
 	// See https://clang.llvm.org/extra/clang-tidy/checks/list.html
-	exportedVars.ExportVariableConfigMethod("TidyDefaultGlobalChecks", func(config android.Config) string {
+	pctx.VariableConfigMethod("TidyDefaultGlobalChecks", func(config android.Config) string {
 		if override := config.Getenv("DEFAULT_GLOBAL_TIDY_CHECKS"); override != "" {
 			return override
 		}
@@ -150,7 +149,7 @@
 	// There are too many clang-tidy warnings in external and vendor projects, so we only
 	// enable some google checks for these projects. Users can add more checks locally with the
 	// "tidy_checks" list in .bp files, or the "Checks" list in .clang-tidy config files.
-	exportedVars.ExportVariableConfigMethod("TidyExternalVendorChecks", func(config android.Config) string {
+	pctx.VariableConfigMethod("TidyExternalVendorChecks", func(config android.Config) string {
 		if override := config.Getenv("DEFAULT_EXTERNAL_VENDOR_TIDY_CHECKS"); override != "" {
 			return override
 		}
@@ -164,25 +163,21 @@
 		}, ",")
 	})
 
-	exportedVars.ExportVariableFuncVariable("TidyGlobalNoChecks", func() string {
-		return strings.Join(globalNoCheckList, ",")
-	})
+	pctx.StaticVariable("TidyGlobalNoChecks", strings.Join(globalNoCheckList, ","))
 
-	exportedVars.ExportVariableFuncVariable("TidyGlobalNoErrorChecks", func() string {
-		return strings.Join(globalNoErrorCheckList, ",")
-	})
+	pctx.StaticVariable("TidyGlobalNoErrorChecks", strings.Join(globalNoErrorCheckList, ","))
 
-	exportedVars.ExportStringListStaticVariable("TidyExtraArgFlags", extraArgFlags)
+	pctx.StaticVariable("TidyExtraArgFlags", strings.Join(extraArgFlags, " "))
 
 	// To reduce duplicate warnings from the same header files,
 	// header-filter will contain only the module directory and
 	// those specified by DEFAULT_TIDY_HEADER_DIRS.
-	exportedVars.ExportVariableConfigMethod("TidyDefaultHeaderDirs", func(config android.Config) string {
+	pctx.VariableConfigMethod("TidyDefaultHeaderDirs", func(config android.Config) string {
 		return config.Getenv("DEFAULT_TIDY_HEADER_DIRS")
 	})
 
 	// Use WTIH_TIDY_FLAGS to pass extra global default clang-tidy flags.
-	exportedVars.ExportVariableConfigMethod("TidyWithTidyFlags", func(config android.Config) string {
+	pctx.VariableConfigMethod("TidyWithTidyFlags", func(config android.Config) string {
 		return config.Getenv("WITH_TIDY_FLAGS")
 	})
 }
@@ -281,11 +276,3 @@
 	}
 	return flags
 }
-
-var (
-	removedCFlags = regexp.MustCompile(" -fsanitize=[^ ]*memtag-[^ ]* ")
-)
-
-func TidyReduceCFlags(flags string) string {
-	return removedCFlags.ReplaceAllString(flags, " ")
-}
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index 62f75d1..7dc990b 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -16,14 +16,15 @@
 
 import (
 	"fmt"
+	"strings"
 
 	"android/soong/android"
 )
 
 func init() {
-	exportedVars.ExportStringListStaticVariable("DarwinAvailableLibraries", darwinAvailableLibraries)
-	exportedVars.ExportStringListStaticVariable("LinuxAvailableLibraries", linuxAvailableLibraries)
-	exportedVars.ExportStringListStaticVariable("WindowsAvailableLibraries", windowsAvailableLibraries)
+	pctx.StaticVariable("DarwinAvailableLibraries", strings.Join(darwinAvailableLibraries, " "))
+	pctx.StaticVariable("LinuxAvailableLibraries", strings.Join(linuxAvailableLibraries, " "))
+	pctx.StaticVariable("WindowsAvailableLibraries", strings.Join(windowsAvailableLibraries, " "))
 }
 
 type toolchainFactory func(arch android.Arch) Toolchain
@@ -100,6 +101,7 @@
 	CrtEndStaticBinary() []string
 	CrtEndSharedBinary() []string
 	CrtEndSharedLibrary() []string
+	CrtPadSegmentSharedLibrary() []string
 
 	// DefaultSharedLibraries returns the list of shared libraries that will be added to all
 	// targets unless they explicitly specify system_shared_libs.
@@ -155,12 +157,13 @@
 
 type toolchainNoCrt struct{}
 
-func (toolchainNoCrt) CrtBeginStaticBinary() []string  { return nil }
-func (toolchainNoCrt) CrtBeginSharedBinary() []string  { return nil }
-func (toolchainNoCrt) CrtBeginSharedLibrary() []string { return nil }
-func (toolchainNoCrt) CrtEndStaticBinary() []string    { return nil }
-func (toolchainNoCrt) CrtEndSharedBinary() []string    { return nil }
-func (toolchainNoCrt) CrtEndSharedLibrary() []string   { return nil }
+func (toolchainNoCrt) CrtBeginStaticBinary() []string       { return nil }
+func (toolchainNoCrt) CrtBeginSharedBinary() []string       { return nil }
+func (toolchainNoCrt) CrtBeginSharedLibrary() []string      { return nil }
+func (toolchainNoCrt) CrtEndStaticBinary() []string         { return nil }
+func (toolchainNoCrt) CrtEndSharedBinary() []string         { return nil }
+func (toolchainNoCrt) CrtEndSharedLibrary() []string        { return nil }
+func (toolchainNoCrt) CrtPadSegmentSharedLibrary() []string { return nil }
 
 func (toolchainBase) DefaultSharedLibraries() []string {
 	return nil
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index 9f093bb..5aa2a7e 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -30,9 +30,11 @@
 	x86_64Cppflags = []string{}
 
 	x86_64Ldflags = []string{
-		"-Wl,--hash-style=gnu",
+		"-Wl,-z,separate-loadable-segments",
 	}
 
+	X86_64Lldflags = x86_64Ldflags
+
 	x86_64ArchVariantCflags = map[string][]string{
 		"": []string{
 			"-march=x86-64",
@@ -47,6 +49,11 @@
 		"goldmont-plus": []string{
 			"-march=goldmont-plus",
 		},
+		"goldmont-without-sha-xsaves": []string{
+			"-march=goldmont",
+			"-mno-sha",
+			"-mno-xsaves",
+		},
 		"haswell": []string{
 			"-march=core-avx2",
 		},
@@ -90,26 +97,31 @@
 )
 
 func init() {
-	exportedVars.ExportStringListStaticVariable("X86_64ToolchainCflags", []string{"-m64"})
-	exportedVars.ExportStringListStaticVariable("X86_64ToolchainLdflags", []string{"-m64"})
+	pctx.StaticVariable("X86_64ToolchainCflags", "-m64")
+	pctx.StaticVariable("X86_64ToolchainLdflags", "-m64")
 
-	exportedVars.ExportStringListStaticVariable("X86_64Ldflags", x86_64Ldflags)
-	exportedVars.ExportStringListStaticVariable("X86_64Lldflags", x86_64Ldflags)
-
-	// Clang cflags
-	exportedVars.ExportStringListStaticVariable("X86_64Cflags", x86_64Cflags)
-	exportedVars.ExportStringListStaticVariable("X86_64Cppflags", x86_64Cppflags)
-
-	// Yasm flags
-	exportedVars.ExportStringListStaticVariable("X86_64YasmFlags", []string{
-		"-f elf64",
-		"-m amd64",
+	pctx.StaticVariable("X86_64Ldflags", strings.Join(x86_64Ldflags, " "))
+	pctx.VariableFunc("X86_64Lldflags", func(ctx android.PackageVarContext) string {
+		maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported()
+		flags := append(X86_64Lldflags, maxPageSizeFlag)
+		return strings.Join(flags, " ")
 	})
 
-	// Extended cflags
+	// Clang cflags
+	pctx.VariableFunc("X86_64Cflags", func(ctx android.PackageVarContext) string {
+		flags := x86_64Cflags
+		if ctx.Config().NoBionicPageSizeMacro() {
+			flags = append(flags, "-D__BIONIC_NO_PAGE_SIZE_MACRO")
+		} else {
+			flags = append(flags, "-D__BIONIC_DEPRECATED_PAGE_SIZE_MACRO")
+		}
+		return strings.Join(flags, " ")
+	})
 
-	exportedVars.ExportStringListDict("X86_64ArchVariantCflags", x86_64ArchVariantCflags)
-	exportedVars.ExportStringListDict("X86_64ArchFeatureCflags", x86_64ArchFeatureCflags)
+	pctx.StaticVariable("X86_64Cppflags", strings.Join(x86_64Cppflags, " "))
+
+	// Yasm flags
+	pctx.StaticVariable("X86_64YasmFlags", "-f elf64 -m amd64")
 
 	// Architecture variant cflags
 	for variant, cflags := range x86_64ArchVariantCflags {
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index c826d3c..4b0041c 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -33,9 +33,7 @@
 
 	x86Cppflags = []string{}
 
-	x86Ldflags = []string{
-		"-Wl,--hash-style=gnu",
-	}
+	x86Ldflags = []string{}
 
 	x86ArchVariantCflags = map[string][]string{
 		"": []string{
@@ -56,6 +54,11 @@
 		"goldmont-plus": []string{
 			"-march=goldmont-plus",
 		},
+		"goldmont-without-sha-xsaves": []string{
+			"-march=goldmont",
+			"-mno-sha",
+			"-mno-xsaves",
+		},
 		"haswell": []string{
 			"-march=core-avx2",
 		},
@@ -98,25 +101,18 @@
 )
 
 func init() {
-	exportedVars.ExportStringListStaticVariable("X86ToolchainCflags", []string{"-m32"})
-	exportedVars.ExportStringListStaticVariable("X86ToolchainLdflags", []string{"-m32"})
+	pctx.StaticVariable("X86ToolchainCflags", "-m32")
+	pctx.StaticVariable("X86ToolchainLdflags", "-m32")
 
-	exportedVars.ExportStringListStaticVariable("X86Ldflags", x86Ldflags)
-	exportedVars.ExportStringListStaticVariable("X86Lldflags", x86Ldflags)
+	pctx.StaticVariable("X86Ldflags", strings.Join(x86Ldflags, " "))
+	pctx.StaticVariable("X86Lldflags", strings.Join(x86Ldflags, " "))
 
 	// Clang cflags
-	exportedVars.ExportStringListStaticVariable("X86Cflags", x86Cflags)
-	exportedVars.ExportStringListStaticVariable("X86Cppflags", x86Cppflags)
+	pctx.StaticVariable("X86Cflags", strings.Join(x86Cflags, " "))
+	pctx.StaticVariable("X86Cppflags", strings.Join(x86Cppflags, " "))
 
 	// Yasm flags
-	exportedVars.ExportStringListStaticVariable("X86YasmFlags", []string{
-		"-f elf32",
-		"-m x86",
-	})
-
-	// Extended cflags
-	exportedVars.ExportStringListDict("X86ArchVariantCflags", x86ArchVariantCflags)
-	exportedVars.ExportStringListDict("X86ArchFeatureCflags", x86ArchFeatureCflags)
+	pctx.StaticVariable("X86YasmFlags", "-f elf32 -m x86")
 
 	// Architecture variant cflags
 	for variant, cflags := range x86ArchVariantCflags {
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index e006471..515cb21 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+	"strings"
 )
 
 var (
@@ -46,13 +47,16 @@
 		"-Wl,-z,now",
 		"-Wl,--build-id=md5",
 		"-Wl,--fatal-warnings",
-		"-Wl,--hash-style=gnu",
 		"-Wl,--no-undefined-version",
 
 		// Use the device gcc toolchain
 		"--gcc-toolchain=${LinuxBionicGccRoot}",
 	}
 
+	linuxBionicLldflags = append(linuxBionicLdflags,
+		"-Wl,--compress-debug-sections=zstd",
+	)
+
 	// Embed the linker into host bionic binaries. This is needed to support host bionic,
 	// as the linux kernel requires that the ELF interpreter referenced by PT_INTERP be
 	// either an absolute path, or relative from CWD. To work around this, we extract
@@ -69,13 +73,13 @@
 )
 
 func init() {
-	exportedVars.ExportStringListStaticVariable("LinuxBionicCflags", linuxBionicCflags)
-	exportedVars.ExportStringListStaticVariable("LinuxBionicLdflags", linuxBionicLdflags)
-	exportedVars.ExportStringListStaticVariable("LinuxBionicLldflags", linuxBionicLdflags)
+	pctx.StaticVariable("LinuxBionicCflags", strings.Join(linuxBionicCflags, " "))
+	pctx.StaticVariable("LinuxBionicLdflags", strings.Join(linuxBionicLdflags, " "))
+	pctx.StaticVariable("LinuxBionicLldflags", strings.Join(linuxBionicLldflags, " "))
 
 	// Use the device gcc toolchain for now
-	exportedVars.ExportStringStaticVariable("LinuxBionicGccVersion", x86_64GccVersion)
-	exportedVars.ExportSourcePathVariable("LinuxBionicGccRoot",
+	pctx.StaticVariable("LinuxBionicGccVersion", x86_64GccVersion)
+	pctx.SourcePathVariable("LinuxBionicGccRoot",
 		"prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${LinuxBionicGccVersion}")
 }
 
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index 93aa82e..7f22377 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -30,11 +30,6 @@
 		"-D_FORTIFY_SOURCE=2",
 		"-fstack-protector",
 
-		// Workaround differences in inttypes.h between host and target.
-		//See bug 12708004.
-		"-D__STDC_FORMAT_MACROS",
-		"-D__STDC_CONSTANT_MACROS",
-
 		"--gcc-toolchain=${LinuxGccRoot}",
 		"-fstack-protector-strong",
 	}
@@ -59,6 +54,10 @@
 		"--gcc-toolchain=${LinuxGccRoot}",
 	}
 
+	linuxLldflags = append(linuxLdflags,
+		"-Wl,--compress-debug-sections=zstd",
+	)
+
 	linuxGlibcLdflags = []string{
 		"--sysroot ${LinuxGccRoot}/sysroot",
 	}
@@ -121,40 +120,40 @@
 )
 
 func init() {
-	exportedVars.ExportStringStaticVariable("LinuxGccVersion", linuxGccVersion)
-	exportedVars.ExportStringStaticVariable("LinuxGlibcVersion", linuxGlibcVersion)
+	pctx.StaticVariable("LinuxGccVersion", linuxGccVersion)
+	pctx.StaticVariable("LinuxGlibcVersion", linuxGlibcVersion)
 
 	// Most places use the full GCC version. A few only use up to the first two numbers.
 	if p := strings.Split(linuxGccVersion, "."); len(p) > 2 {
-		exportedVars.ExportStringStaticVariable("ShortLinuxGccVersion", strings.Join(p[:2], "."))
+		pctx.StaticVariable("ShortLinuxGccVersion", strings.Join(p[:2], "."))
 	} else {
-		exportedVars.ExportStringStaticVariable("ShortLinuxGccVersion", linuxGccVersion)
+		pctx.StaticVariable("ShortLinuxGccVersion", linuxGccVersion)
 	}
 
-	exportedVars.ExportSourcePathVariable("LinuxGccRoot",
+	pctx.SourcePathVariable("LinuxGccRoot",
 		"prebuilts/gcc/linux-x86/host/x86_64-linux-glibc${LinuxGlibcVersion}-${ShortLinuxGccVersion}")
 
-	exportedVars.ExportStringListStaticVariable("LinuxGccTriple", []string{"x86_64-linux"})
+	pctx.StaticVariable("LinuxGccTriple", "x86_64-linux")
 
-	exportedVars.ExportStringListStaticVariable("LinuxCflags", linuxCflags)
-	exportedVars.ExportStringListStaticVariable("LinuxLdflags", linuxLdflags)
-	exportedVars.ExportStringListStaticVariable("LinuxLldflags", linuxLdflags)
-	exportedVars.ExportStringListStaticVariable("LinuxGlibcCflags", linuxGlibcCflags)
-	exportedVars.ExportStringListStaticVariable("LinuxGlibcLdflags", linuxGlibcLdflags)
-	exportedVars.ExportStringListStaticVariable("LinuxGlibcLldflags", linuxGlibcLdflags)
-	exportedVars.ExportStringListStaticVariable("LinuxMuslCflags", linuxMuslCflags)
-	exportedVars.ExportStringListStaticVariable("LinuxMuslLdflags", linuxMuslLdflags)
-	exportedVars.ExportStringListStaticVariable("LinuxMuslLldflags", linuxMuslLdflags)
+	pctx.StaticVariable("LinuxCflags", strings.Join(linuxCflags, " "))
+	pctx.StaticVariable("LinuxLdflags", strings.Join(linuxLdflags, " "))
+	pctx.StaticVariable("LinuxLldflags", strings.Join(linuxLldflags, " "))
+	pctx.StaticVariable("LinuxGlibcCflags", strings.Join(linuxGlibcCflags, " "))
+	pctx.StaticVariable("LinuxGlibcLdflags", strings.Join(linuxGlibcLdflags, " "))
+	pctx.StaticVariable("LinuxGlibcLldflags", strings.Join(linuxGlibcLdflags, " "))
+	pctx.StaticVariable("LinuxMuslCflags", strings.Join(linuxMuslCflags, " "))
+	pctx.StaticVariable("LinuxMuslLdflags", strings.Join(linuxMuslLdflags, " "))
+	pctx.StaticVariable("LinuxMuslLldflags", strings.Join(linuxMuslLdflags, " "))
 
-	exportedVars.ExportStringListStaticVariable("LinuxX86Cflags", linuxX86Cflags)
-	exportedVars.ExportStringListStaticVariable("LinuxX8664Cflags", linuxX8664Cflags)
-	exportedVars.ExportStringListStaticVariable("LinuxX86Ldflags", linuxX86Ldflags)
-	exportedVars.ExportStringListStaticVariable("LinuxX86Lldflags", linuxX86Ldflags)
-	exportedVars.ExportStringListStaticVariable("LinuxX8664Ldflags", linuxX8664Ldflags)
-	exportedVars.ExportStringListStaticVariable("LinuxX8664Lldflags", linuxX8664Ldflags)
+	pctx.StaticVariable("LinuxX86Cflags", strings.Join(linuxX86Cflags, " "))
+	pctx.StaticVariable("LinuxX8664Cflags", strings.Join(linuxX8664Cflags, " "))
+	pctx.StaticVariable("LinuxX86Ldflags", strings.Join(linuxX86Ldflags, " "))
+	pctx.StaticVariable("LinuxX86Lldflags", strings.Join(linuxX86Ldflags, " "))
+	pctx.StaticVariable("LinuxX8664Ldflags", strings.Join(linuxX8664Ldflags, " "))
+	pctx.StaticVariable("LinuxX8664Lldflags", strings.Join(linuxX8664Ldflags, " "))
 	// Yasm flags
-	exportedVars.ExportStringListStaticVariable("LinuxX86YasmFlags", []string{"-f elf32 -m x86"})
-	exportedVars.ExportStringListStaticVariable("LinuxX8664YasmFlags", []string{"-f elf64 -m amd64"})
+	pctx.StaticVariable("LinuxX86YasmFlags", "-f elf32 -m x86")
+	pctx.StaticVariable("LinuxX8664YasmFlags", "-f elf64 -m amd64")
 }
 
 type toolchainLinux struct {
@@ -324,12 +323,13 @@
 
 func (toolchainMusl) Musl() bool { return true }
 
-func (toolchainMusl) CrtBeginStaticBinary() []string  { return muslCrtBeginStaticBinary }
-func (toolchainMusl) CrtBeginSharedBinary() []string  { return muslCrtBeginSharedBinary }
-func (toolchainMusl) CrtBeginSharedLibrary() []string { return muslCrtBeginSharedLibrary }
-func (toolchainMusl) CrtEndStaticBinary() []string    { return muslCrtEndStaticBinary }
-func (toolchainMusl) CrtEndSharedBinary() []string    { return muslCrtEndSharedBinary }
-func (toolchainMusl) CrtEndSharedLibrary() []string   { return muslCrtEndSharedLibrary }
+func (toolchainMusl) CrtBeginStaticBinary() []string       { return muslCrtBeginStaticBinary }
+func (toolchainMusl) CrtBeginSharedBinary() []string       { return muslCrtBeginSharedBinary }
+func (toolchainMusl) CrtBeginSharedLibrary() []string      { return muslCrtBeginSharedLibrary }
+func (toolchainMusl) CrtEndStaticBinary() []string         { return muslCrtEndStaticBinary }
+func (toolchainMusl) CrtEndSharedBinary() []string         { return muslCrtEndSharedBinary }
+func (toolchainMusl) CrtEndSharedLibrary() []string        { return muslCrtEndSharedLibrary }
+func (toolchainMusl) CrtPadSegmentSharedLibrary() []string { return nil }
 
 func (toolchainMusl) DefaultSharedLibraries() []string { return MuslDefaultSharedLibraries }
 
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index 561c500..1e61b01 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -27,9 +27,8 @@
 		"-DWIN32_LEAN_AND_MEAN",
 		"-Wno-unused-parameter",
 
-		// Workaround differences in inttypes.h between host and target.
-		//See bug 12708004.
-		"-D__STDC_FORMAT_MACROS",
+		// Workaround differences in <stdint.h> between host and target.
+		// Context: http://b/12708004
 		"-D__STDC_CONSTANT_MACROS",
 
 		// Use C99-compliant printf functions (%zd).
diff --git a/cc/coverage.go b/cc/coverage.go
index cbd8a6f..f6092e4 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -22,6 +22,29 @@
 	"android/soong/android"
 )
 
+var (
+ 	clangCoverageHostLdFlags = []string{
+ 		"-Wl,--no-as-needed",
+ 		"-Wl,--wrap,open",
+ 	}
+ 	clangContinuousCoverageFlags = []string{
+ 		"-mllvm",
+ 		"-runtime-counter-relocation",
+ 	}
+ 	clangCoverageCFlags = []string{
+ 		"-Wno-frame-larger-than=",
+ 	}
+ 	clangCoverageCommonFlags = []string{
+ 		"-fcoverage-mapping",
+ 		"-Wno-pass-failed",
+ 		"-D__ANDROID_CLANG_COVERAGE__",
+ 	}
+ 	clangCoverageHWASanFlags = []string{
+ 		"-mllvm",
+ 		"-hwasan-globals=0",
+ 	}
+)
+
 const profileInstrFlag = "-fprofile-instr-generate=/data/misc/trace/clang-%p-%m.profraw"
 
 type CoverageProperties struct {
@@ -68,7 +91,7 @@
 }
 
 func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
-	if cov.Properties.NeedCoverageVariant {
+	if cov.Properties.NeedCoverageVariant && ctx.Device() {
 		ctx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
 		}, CoverageDepTag, getGcovProfileLibraryName(ctx))
@@ -102,19 +125,19 @@
 			// flags that the module may use.
 			flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0")
 		} else if clangCoverage {
-			flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag,
-				"-fcoverage-mapping", "-Wno-pass-failed", "-D__ANDROID_CLANG_COVERAGE__")
+			flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag)
+			flags.Local.CommonFlags = append(flags.Local.CommonFlags, clangCoverageCommonFlags...)
 			// Override -Wframe-larger-than.  We can expect frame size increase after
 			// coverage instrumentation.
-			flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=")
+			flags.Local.CFlags = append(flags.Local.CFlags, clangCoverageCFlags...)
 			if EnableContinuousCoverage(ctx) {
-				flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-mllvm", "-runtime-counter-relocation")
+				flags.Local.CommonFlags = append(flags.Local.CommonFlags, clangContinuousCoverageFlags...)
 			}
 
 			// http://b/248022906, http://b/247941801  enabling coverage and hwasan-globals
 			// instrumentation together causes duplicate-symbol errors for __llvm_profile_filename.
 			if c, ok := ctx.Module().(*Module); ok && c.sanitize.isSanitizerEnabled(Hwasan) {
-				flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-mllvm", "-hwasan-globals=0")
+				flags.Local.CommonFlags = append(flags.Local.CommonFlags, clangCoverageHWASanFlags...)
 			}
 		}
 	}
@@ -161,19 +184,22 @@
 		if gcovCoverage {
 			flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage")
 
-			coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), CoverageDepTag).(*Module)
-			deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
-
-			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv")
+			if ctx.Device() {
+				coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), CoverageDepTag).(*Module)
+				deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
+				flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv")
+			}
 		} else if clangCoverage {
 			flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrFlag)
 			if EnableContinuousCoverage(ctx) {
 				flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm=-runtime-counter-relocation")
 			}
 
-			coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module)
-			deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
-			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,open")
+			if ctx.Device() {
+				coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module)
+				deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
+				flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,open")
+			}
 		}
 	}
 
@@ -181,7 +207,7 @@
 }
 
 func (cov *coverage) begin(ctx BaseModuleContext) {
-	if ctx.Host() {
+	if ctx.Host() && !ctx.Os().Linux() {
 		// TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a
 		// Just turn off for now.
 	} else {
@@ -223,7 +249,7 @@
 
 type UseCoverage interface {
 	android.Module
-	IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool
+	IsNativeCoverageNeeded(ctx android.IncomingTransitionContext) bool
 }
 
 // Coverage is an interface for non-CC modules to implement to be mutated for coverage
@@ -235,43 +261,86 @@
 	EnableCoverageIfNeeded()
 }
 
-func coverageMutator(mctx android.BottomUpMutatorContext) {
-	if c, ok := mctx.Module().(*Module); ok && c.coverage != nil {
-		needCoverageVariant := c.coverage.Properties.NeedCoverageVariant
-		needCoverageBuild := c.coverage.Properties.NeedCoverageBuild
-		if needCoverageVariant {
-			m := mctx.CreateVariations("", "cov")
+type coverageTransitionMutator struct{}
 
-			// Setup the non-coverage version and set HideFromMake and
-			// PreventInstall to true.
-			m[0].(*Module).coverage.Properties.CoverageEnabled = false
-			m[0].(*Module).coverage.Properties.IsCoverageVariant = false
-			m[0].(*Module).Properties.HideFromMake = true
-			m[0].(*Module).Properties.PreventInstall = true
+var _ android.TransitionMutator = (*coverageTransitionMutator)(nil)
 
-			// The coverage-enabled version inherits HideFromMake,
-			// PreventInstall from the original module.
-			m[1].(*Module).coverage.Properties.CoverageEnabled = needCoverageBuild
-			m[1].(*Module).coverage.Properties.IsCoverageVariant = true
+func (c coverageTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+	if c, ok := ctx.Module().(*Module); ok && c.coverage != nil {
+		if c.coverage.Properties.NeedCoverageVariant {
+			return []string{"", "cov"}
 		}
-	} else if cov, ok := mctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(mctx) {
+	} else if cov, ok := ctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(ctx) {
 		// APEX and Rust modules fall here
 
 		// Note: variant "" is also created because an APEX can be depended on by another
 		// module which are split into "" and "cov" variants. e.g. when cc_test refers
 		// to an APEX via 'data' property.
-		m := mctx.CreateVariations("", "cov")
-		m[0].(Coverage).MarkAsCoverageVariant(false)
-		m[0].(Coverage).SetPreventInstall()
-		m[0].(Coverage).HideFromMake()
-
-		m[1].(Coverage).MarkAsCoverageVariant(true)
-		m[1].(Coverage).EnableCoverageIfNeeded()
-	} else if cov, ok := mctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(mctx) {
+		return []string{"", "cov"}
+	} else if cov, ok := ctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(ctx) {
 		// Module itself doesn't have to have "cov" variant, but it should use "cov" variants of
 		// deps.
-		mctx.CreateVariations("cov")
-		mctx.AliasVariation("cov")
+		return []string{"cov"}
+	}
+
+	return []string{""}
+}
+
+func (c coverageTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+	return sourceVariation
+}
+
+func (c coverageTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+	if c, ok := ctx.Module().(*Module); ok && c.coverage != nil {
+		if !c.coverage.Properties.NeedCoverageVariant {
+			return ""
+		}
+	} else if cov, ok := ctx.Module().(Coverage); ok {
+		if !cov.IsNativeCoverageNeeded(ctx) {
+			return ""
+		}
+	} else if cov, ok := ctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(ctx) {
+		// Module only has a "cov" variation, so all incoming variations should use "cov".
+		return "cov"
+	} else {
+		return ""
+	}
+
+	return incomingVariation
+}
+
+func (c coverageTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+	if c, ok := ctx.Module().(*Module); ok && c.coverage != nil {
+		if variation == "" && c.coverage.Properties.NeedCoverageVariant {
+			// Setup the non-coverage version and set HideFromMake and
+			// PreventInstall to true.
+			c.coverage.Properties.CoverageEnabled = false
+			c.coverage.Properties.IsCoverageVariant = false
+			c.Properties.HideFromMake = true
+			c.Properties.PreventInstall = true
+		} else if variation == "cov" {
+			// The coverage-enabled version inherits HideFromMake,
+			// PreventInstall from the original module.
+			c.coverage.Properties.CoverageEnabled = c.coverage.Properties.NeedCoverageBuild
+			c.coverage.Properties.IsCoverageVariant = true
+		}
+	} else if cov, ok := ctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(ctx) {
+		// APEX and Rust modules fall here
+
+		// Note: variant "" is also created because an APEX can be depended on by another
+		// module which are split into "" and "cov" variants. e.g. when cc_test refers
+		// to an APEX via 'data' property.
+		if variation == "" {
+			cov.MarkAsCoverageVariant(false)
+			cov.SetPreventInstall()
+			cov.HideFromMake()
+		} else if variation == "cov" {
+			cov.MarkAsCoverageVariant(true)
+			cov.EnableCoverageIfNeeded()
+		}
+	} else if cov, ok := ctx.Module().(UseCoverage); ok && cov.IsNativeCoverageNeeded(ctx) {
+		// Module itself doesn't have to have "cov" variant, but it should use "cov" variants of
+		// deps.
 	}
 }
 
diff --git a/cc/fdo_profile.go b/cc/fdo_profile.go
index 7fbe719..1a33957 100644
--- a/cc/fdo_profile.go
+++ b/cc/fdo_profile.go
@@ -16,7 +16,6 @@
 
 import (
 	"android/soong/android"
-
 	"github.com/google/blueprint"
 )
 
@@ -25,7 +24,7 @@
 }
 
 func RegisterFdoProfileBuildComponents(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("fdo_profile", fdoProfileFactory)
+	ctx.RegisterModuleType("fdo_profile", FdoProfileFactory)
 }
 
 type fdoProfile struct {
@@ -44,40 +43,19 @@
 }
 
 // FdoProfileProvider is used to provide path to an fdo profile
-var FdoProfileProvider = blueprint.NewMutatorProvider(FdoProfileInfo{}, "fdo_profile")
-
-// FdoProfileMutatorInterface is the interface implemented by fdo_profile module type
-// module types that can depend on an fdo_profile module
-type FdoProfileMutatorInterface interface {
-	// FdoProfileMutator eithers set or get FdoProfileProvider
-	fdoProfileMutator(ctx android.BottomUpMutatorContext)
-}
-
-var _ FdoProfileMutatorInterface = (*fdoProfile)(nil)
+var FdoProfileProvider = blueprint.NewProvider[FdoProfileInfo]()
 
 // GenerateAndroidBuildActions of fdo_profile does not have any build actions
-func (fp *fdoProfile) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
-
-// FdoProfileMutator sets FdoProfileProvider to fdo_profile module
-// or sets afdo.Properties.FdoProfilePath to path in FdoProfileProvider of the depended fdo_profile
-func (fp *fdoProfile) fdoProfileMutator(ctx android.BottomUpMutatorContext) {
+func (fp *fdoProfile) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if fp.properties.Profile != nil {
 		path := android.PathForModuleSrc(ctx, *fp.properties.Profile)
-		ctx.SetProvider(FdoProfileProvider, FdoProfileInfo{
+		android.SetProvider(ctx, FdoProfileProvider, FdoProfileInfo{
 			Path: path,
 		})
 	}
 }
 
-// fdoProfileMutator calls the generic fdoProfileMutator function of fdoProfileMutator
-// which is implemented by cc and cc.FdoProfile
-func fdoProfileMutator(ctx android.BottomUpMutatorContext) {
-	if f, ok := ctx.Module().(FdoProfileMutatorInterface); ok {
-		f.fdoProfileMutator(ctx)
-	}
-}
-
-func fdoProfileFactory() android.Module {
+func FdoProfileFactory() android.Module {
 	m := &fdoProfile{}
 	m.AddProperties(&m.properties)
 	android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibBoth)
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 227fe8b..2436f33 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -96,6 +96,7 @@
 // your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree.
 func LibFuzzFactory() android.Module {
 	module := NewFuzzer(android.HostAndDeviceSupported)
+	module.testModule = true
 	return module.Init()
 }
 
@@ -105,6 +106,7 @@
 	fuzzPackagedModule  fuzz.FuzzPackagedModule
 	installedSharedDeps []string
 	sharedLibraries     android.RuleBuilderInstalls
+	data                []android.DataPath
 }
 
 func (fuzz *fuzzBinary) fuzzBinary() bool {
@@ -142,25 +144,35 @@
 }
 
 func (fuzz *fuzzBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+	subdir := "lib"
+	if ctx.inVendor() {
+		subdir = "lib/vendor"
+	}
+
 	flags = fuzz.binaryDecorator.linkerFlags(ctx, flags)
 	// RunPaths on devices isn't instantiated by the base linker. `../lib` for
 	// installed fuzz targets (both host and device), and `./lib` for fuzz
 	// target packages.
-	flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/lib`)
+	flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/`+subdir)
 
 	// When running on device, fuzz targets with vendor: true set will be in
 	// fuzzer_name/vendor/fuzzer_name (note the extra 'vendor' and thus need to
 	// link with libraries in ../../lib/. Non-vendor binaries only need to look
 	// one level up, in ../lib/.
 	if ctx.inVendor() {
-		flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../../lib`)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../../`+subdir)
 	} else {
-		flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../lib`)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, `-Wl,-rpath,\$$ORIGIN/../`+subdir)
 	}
 
 	return flags
 }
 
+func (fuzz *fuzzBinary) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+	fuzz.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+	moduleInfoJSON.Class = []string{"EXECUTABLES"}
+}
+
 // IsValidSharedDependency takes a module and determines if it is a unique shared library
 // that should be installed in the fuzz target output directories. This function
 // returns true, unless:
@@ -214,75 +226,91 @@
 }
 
 func SharedLibraryInstallLocation(
-	libraryBase string, isHost bool, fuzzDir string, archString string) string {
+	libraryBase string, isHost bool, isVendor bool, fuzzDir string, archString string) string {
 	installLocation := "$(PRODUCT_OUT)/data"
 	if isHost {
 		installLocation = "$(HOST_OUT)"
 	}
+	subdir := "lib"
+	if isVendor {
+		subdir = "lib/vendor"
+	}
 	installLocation = filepath.Join(
-		installLocation, fuzzDir, archString, "lib", libraryBase)
+		installLocation, fuzzDir, archString, subdir, libraryBase)
 	return installLocation
 }
 
 // Get the device-only shared library symbols install directory.
-func SharedLibrarySymbolsInstallLocation(libraryBase string, fuzzDir string, archString string) string {
-	return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, "/lib/", libraryBase)
+func SharedLibrarySymbolsInstallLocation(libraryBase string, isVendor bool, fuzzDir string, archString string) string {
+	subdir := "lib"
+	if isVendor {
+		subdir = "lib/vendor"
+	}
+	return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, subdir, libraryBase)
 }
 
 func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) {
-	installBase := "fuzz"
-
-	fuzzBin.binaryDecorator.baseInstaller.dir = filepath.Join(
-		installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
-	fuzzBin.binaryDecorator.baseInstaller.dir64 = filepath.Join(
-		installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
-	fuzzBin.binaryDecorator.baseInstaller.install(ctx, file)
-
 	fuzzBin.fuzzPackagedModule = PackageFuzzModule(ctx, fuzzBin.fuzzPackagedModule, pctx)
 
+	installBase := "fuzz"
+
 	// Grab the list of required shared libraries.
 	fuzzBin.sharedLibraries, _ = CollectAllSharedDependencies(ctx)
 
+	// TODO: does not mirror Android linkernamespaces
+	// the logic here has special cases for vendor, but it would need more work to
+	// work in arbitrary partitions, so just surface errors early for a few cases
+	//
+	// Even without these, there are certain situations across linkernamespaces
+	// that this won't support. For instance, you might have:
+	//
+	//     my_fuzzer (vendor) -> libbinder_ndk (core) -> libbinder (vendor)
+	//
+	// This dependency chain wouldn't be possible to express in the current
+	// logic because all the deps currently match the variant of the source
+	// module.
+
 	for _, ruleBuilderInstall := range fuzzBin.sharedLibraries {
 		install := ruleBuilderInstall.To
 		fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
 			SharedLibraryInstallLocation(
-				install, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
+				install, ctx.Host(), ctx.inVendor(), installBase, ctx.Arch().ArchType.String()))
 
 		// Also add the dependency on the shared library symbols dir.
 		if !ctx.Host() {
 			fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
-				SharedLibrarySymbolsInstallLocation(install, installBase, ctx.Arch().ArchType.String()))
+				SharedLibrarySymbolsInstallLocation(install, ctx.inVendor(), installBase, ctx.Arch().ArchType.String()))
 		}
 	}
+
+	for _, d := range fuzzBin.fuzzPackagedModule.Corpus {
+		fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, RelativeInstallPath: "corpus", WithoutRel: true})
+	}
+
+	for _, d := range fuzzBin.fuzzPackagedModule.Data {
+		fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, RelativeInstallPath: "data"})
+	}
+
+	if d := fuzzBin.fuzzPackagedModule.Dictionary; d != nil {
+		fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, WithoutRel: true})
+	}
+
+	if d := fuzzBin.fuzzPackagedModule.Config; d != nil {
+		fuzzBin.data = append(fuzzBin.data, android.DataPath{SrcPath: d, WithoutRel: true})
+	}
+
+	fuzzBin.binaryDecorator.baseInstaller.dir = filepath.Join(
+		installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
+	fuzzBin.binaryDecorator.baseInstaller.dir64 = filepath.Join(
+		installBase, ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
+	fuzzBin.binaryDecorator.baseInstaller.installTestData(ctx, fuzzBin.data)
+	fuzzBin.binaryDecorator.baseInstaller.install(ctx, file)
 }
 
 func PackageFuzzModule(ctx android.ModuleContext, fuzzPackagedModule fuzz.FuzzPackagedModule, pctx android.PackageContext) fuzz.FuzzPackagedModule {
 	fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Corpus)
-	intermediateDir := android.PathForModuleOut(ctx, "corpus")
-
-	// Create one rule per file to avoid MAX_ARG_STRLEN hardlimit.
-	for _, entry := range fuzzPackagedModule.Corpus {
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   android.Cp,
-			Output: intermediateDir.Join(ctx, entry.Base()),
-			Input:  entry,
-		})
-	}
-	fuzzPackagedModule.CorpusIntermediateDir = intermediateDir
 
 	fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Data)
-	intermediateDir = android.PathForModuleOut(ctx, "data")
-
-	// Create one rule per file to avoid MAX_ARG_STRLEN hardlimit.
-	for _, entry := range fuzzPackagedModule.Data {
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   android.Cp,
-			Output: intermediateDir.Join(ctx, entry.Rel()),
-			Input:  entry,
-		})
-	}
-	fuzzPackagedModule.DataIntermediateDir = intermediateDir
 
 	if fuzzPackagedModule.FuzzProperties.Dictionary != nil {
 		fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzzPackagedModule.FuzzProperties.Dictionary)
@@ -302,7 +330,7 @@
 }
 
 func NewFuzzer(hod android.HostOrDeviceSupported) *Module {
-	module, binary := newBinary(hod, false)
+	module, binary := newBinary(hod)
 	baseInstallerPath := "fuzz"
 
 	binary.baseInstaller = NewBaseInstaller(baseInstallerPath, baseInstallerPath, InstallInData)
@@ -357,10 +385,10 @@
 // their architecture & target/host specific zip file.
 type ccRustFuzzPackager struct {
 	fuzz.FuzzPackager
-	fuzzPackagingArchModules         			string
-	fuzzTargetSharedDepsInstallPairs 			string
-	allFuzzTargetsName               			string
-	onlyIncludePresubmits						bool
+	fuzzPackagingArchModules         string
+	fuzzTargetSharedDepsInstallPairs string
+	allFuzzTargetsName               string
+	onlyIncludePresubmits            bool
 }
 
 func fuzzPackagingFactory() android.Singleton {
@@ -369,7 +397,7 @@
 		fuzzPackagingArchModules:         "SOONG_FUZZ_PACKAGING_ARCH_MODULES",
 		fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
 		allFuzzTargetsName:               "ALL_FUZZ_TARGETS",
-		onlyIncludePresubmits:			  false,
+		onlyIncludePresubmits:            false,
 	}
 	return fuzzPackager
 }
@@ -380,7 +408,7 @@
 		fuzzPackagingArchModules:         "SOONG_PRESUBMIT_FUZZ_PACKAGING_ARCH_MODULES",
 		fuzzTargetSharedDepsInstallPairs: "PRESUBMIT_FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
 		allFuzzTargetsName:               "ALL_PRESUBMIT_FUZZ_TARGETS",
-		onlyIncludePresubmits:			  true,
+		onlyIncludePresubmits:            true,
 	}
 	return fuzzPackager
 }
@@ -410,6 +438,10 @@
 		}
 
 		sharedLibsInstallDirPrefix := "lib"
+		if ccModule.InVendor() {
+			sharedLibsInstallDirPrefix = "lib/vendor"
+		}
+
 		if !ccModule.IsFuzzModule() {
 			return
 		}
@@ -451,7 +483,7 @@
 			if fpm.FuzzProperties.Fuzz_config == nil {
 				return
 			}
-			if !BoolDefault(fpm.FuzzProperties.Fuzz_config.Use_for_presubmit, false){
+			if !BoolDefault(fpm.FuzzProperties.Fuzz_config.Use_for_presubmit, false) {
 				return
 			}
 		}
@@ -502,7 +534,7 @@
 		// install it to the output directory. Setup the install destination here,
 		// which will be used by $(copy-many-files) in the Make backend.
 		installDestination := SharedLibraryInstallLocation(
-			install, module.Host(), fuzzDir, archString)
+			install, module.Host(), module.InVendor(), fuzzDir, archString)
 		if (*sharedLibraryInstalled)[installDestination] {
 			continue
 		}
@@ -520,7 +552,7 @@
 		// we want symbolization tools (like `stack`) to be able to find the symbols
 		// in $ANDROID_PRODUCT_OUT/symbols automagically.
 		if !module.Host() {
-			symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, fuzzDir, archString)
+			symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, module.InVendor(), fuzzDir, archString)
 			symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
 			s.SharedLibInstallStrings = append(s.SharedLibInstallStrings,
 				library.String()+":"+symbolsInstallDestination)
@@ -547,7 +579,8 @@
 		if !IsValidSharedDependency(dep) {
 			return
 		}
-		if !ctx.OtherModuleHasProvider(dep, SharedLibraryInfoProvider) {
+		sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider)
+		if !hasSharedLibraryInfo {
 			return
 		}
 		if seen[ctx.OtherModuleName(dep)] {
@@ -556,7 +589,6 @@
 		seen[ctx.OtherModuleName(dep)] = true
 		deps = append(deps, dep)
 
-		sharedLibraryInfo := ctx.OtherModuleProvider(dep, SharedLibraryInfoProvider).(SharedLibraryInfo)
 		installDestination := sharedLibraryInfo.SharedLibrary.Base()
 		ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, dep, "unstripped"), installDestination}
 		sharedLibraries = append(sharedLibraries, ruleBuilderInstall)
@@ -577,14 +609,14 @@
 		if !IsValidSharedDependency(child) {
 			return false
 		}
-		if !ctx.OtherModuleHasProvider(child, SharedLibraryInfoProvider) {
+		sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, child, SharedLibraryInfoProvider)
+		if !hasSharedLibraryInfo {
 			return false
 		}
 		if !seen[ctx.OtherModuleName(child)] {
 			seen[ctx.OtherModuleName(child)] = true
 			deps = append(deps, child)
 
-			sharedLibraryInfo := ctx.OtherModuleProvider(child, SharedLibraryInfoProvider).(SharedLibraryInfo)
 			installDestination := sharedLibraryInfo.SharedLibrary.Base()
 			ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, child, "unstripped"), installDestination}
 			sharedLibraries = append(sharedLibraries, ruleBuilderInstall)
diff --git a/cc/gen.go b/cc/gen.go
index b15f164..e351fdd 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -19,8 +19,6 @@
 	"strings"
 
 	"android/soong/aidl_library"
-	"android/soong/bazel"
-
 	"github.com/google/blueprint"
 
 	"android/soong/android"
@@ -180,41 +178,6 @@
 	})
 }
 
-type LexAttrs struct {
-	Srcs    bazel.LabelListAttribute
-	Lexopts bazel.StringListAttribute
-}
-
-type LexNames struct {
-	cSrcName bazel.LabelAttribute
-	srcName  bazel.LabelAttribute
-}
-
-func bp2BuildLex(ctx android.Bp2buildMutatorContext, moduleName string, ca compilerAttributes) LexNames {
-	names := LexNames{}
-	if !ca.lSrcs.IsEmpty() {
-		names.cSrcName = createLexTargetModule(ctx, moduleName+"_genlex_l", ca.lSrcs, ca.lexopts)
-	}
-	if !ca.llSrcs.IsEmpty() {
-		names.srcName = createLexTargetModule(ctx, moduleName+"_genlex_ll", ca.llSrcs, ca.lexopts)
-	}
-	return names
-}
-
-func createLexTargetModule(ctx android.Bp2buildMutatorContext, name string, srcs bazel.LabelListAttribute, opts bazel.StringListAttribute) bazel.LabelAttribute {
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "genlex",
-			Bzl_load_location: "//build/bazel/rules/cc:flex.bzl",
-		},
-		android.CommonAttributes{Name: name},
-		&LexAttrs{
-			Srcs:    srcs,
-			Lexopts: opts,
-		})
-	return bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + name}}
-}
-
 func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Paths) {
 	headerFile := android.PathForModuleGen(ctx, "sysprop", "include", syspropFile.Rel()+".h")
 	publicHeaderFile := android.PathForModuleGen(ctx, "sysprop/public", "include", syspropFile.Rel()+".h")
@@ -239,34 +202,6 @@
 	return cppFile, headers.Paths()
 }
 
-func bp2buildCcSysprop(ctx android.Bp2buildMutatorContext, moduleName string, minSdkVersion *string, srcs bazel.LabelListAttribute) *bazel.LabelAttribute {
-	labels := SyspropLibraryLabels{
-		SyspropLibraryLabel: moduleName + "_sysprop_library",
-		StaticLibraryLabel:  moduleName + "_cc_sysprop_library_static",
-	}
-	Bp2buildSysprop(ctx, labels, srcs, minSdkVersion)
-	return createLabelAttributeCorrespondingToSrcs(":"+labels.StaticLibraryLabel, srcs)
-}
-
-// Creates a LabelAttribute for a given label where the value is only set for
-// the same config values that have values in a given LabelListAttribute
-func createLabelAttributeCorrespondingToSrcs(baseLabelName string, srcs bazel.LabelListAttribute) *bazel.LabelAttribute {
-	baseLabel := bazel.Label{Label: baseLabelName}
-	label := bazel.LabelAttribute{}
-	if !srcs.Value.IsNil() && !srcs.Value.IsEmpty() {
-		label.Value = &baseLabel
-		return &label
-	}
-	for axis, configToSrcs := range srcs.ConfigurableValues {
-		for config, val := range configToSrcs {
-			if !val.IsNil() && !val.IsEmpty() {
-				label.SetSelectValue(axis, config, baseLabel)
-			}
-		}
-	}
-	return &label
-}
-
 // Used to communicate information from the genSources method back to the library code that uses
 // it.
 type generatedSourceInfo struct {
@@ -290,6 +225,10 @@
 	// The files that can be used as order only dependencies in order to ensure that the sysprop
 	// header files are up to date.
 	syspropOrderOnlyDeps android.Paths
+
+	// List of generated code path.
+	//   ex) '*.cpp' files generated from '*.ll / *.yy'.
+	generatedSources android.Paths
 }
 
 func genSources(
@@ -319,30 +258,37 @@
 		return yaccRule_
 	}
 
+	var generatedSources android.Paths = nil
+
 	for i, srcFile := range srcFiles {
 		switch srcFile.Ext() {
 		case ".y":
 			cFile := android.GenPathWithExt(ctx, "yacc", srcFile, "c")
 			srcFiles[i] = cFile
 			deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cFile, buildFlags.yacc)...)
+			generatedSources = append(generatedSources, cFile)
 		case ".yy":
 			cppFile := android.GenPathWithExt(ctx, "yacc", srcFile, "cpp")
 			srcFiles[i] = cppFile
 			deps = append(deps, genYacc(ctx, yaccRule(), srcFile, cppFile, buildFlags.yacc)...)
+			generatedSources = append(generatedSources, cppFile)
 		case ".l":
 			cFile := android.GenPathWithExt(ctx, "lex", srcFile, "c")
 			srcFiles[i] = cFile
 			genLex(ctx, srcFile, cFile, buildFlags.lex)
+			generatedSources = append(generatedSources, cFile)
 		case ".ll":
 			cppFile := android.GenPathWithExt(ctx, "lex", srcFile, "cpp")
 			srcFiles[i] = cppFile
 			genLex(ctx, srcFile, cppFile, buildFlags.lex)
+			generatedSources = append(generatedSources, cppFile)
 		case ".proto":
 			ccFile, headerFile := genProto(ctx, srcFile, buildFlags)
 			srcFiles[i] = ccFile
 			info.protoHeaders = append(info.protoHeaders, headerFile)
 			// Use the generated header as an order only dep to ensure that it is up to date when needed.
 			info.protoOrderOnlyDeps = append(info.protoOrderOnlyDeps, headerFile)
+			generatedSources = append(generatedSources, ccFile)
 		case ".aidl":
 			if aidlRule == nil {
 				aidlRule = android.NewRuleBuilder(pctx, ctx).Sbox(android.PathForModuleGen(ctx, "aidl"),
@@ -364,10 +310,12 @@
 			// needed.
 			// TODO: Reduce the size of the ninja file by using one order only dep for the whole rule
 			info.aidlOrderOnlyDeps = append(info.aidlOrderOnlyDeps, aidlHeaders...)
+			generatedSources = append(generatedSources, cppFile)
 		case ".rscript", ".fs":
 			cppFile := rsGeneratedCppFile(ctx, srcFile)
 			rsFiles = append(rsFiles, srcFiles[i])
 			srcFiles[i] = cppFile
+			generatedSources = append(generatedSources, cppFile)
 		case ".sysprop":
 			cppFile, headerFiles := genSysprop(ctx, srcFile)
 			srcFiles[i] = cppFile
@@ -375,9 +323,12 @@
 			// Use the generated headers as order only deps to ensure that they are up to date when
 			// needed.
 			info.syspropOrderOnlyDeps = append(info.syspropOrderOnlyDeps, headerFiles...)
+			generatedSources = append(generatedSources, cppFile)
 		}
 	}
 
+	info.generatedSources = generatedSources
+
 	for _, aidlLibraryInfo := range aidlLibraryInfos {
 		if aidlLibraryRule == nil {
 			aidlLibraryRule = android.NewRuleBuilder(pctx, ctx).Sbox(
diff --git a/cc/gen_test.go b/cc/gen_test.go
index 85df333..439f0a9 100644
--- a/cc/gen_test.go
+++ b/cc/gen_test.go
@@ -67,7 +67,7 @@
 			t.Errorf("missing aidl includes in global flags")
 		}
 
-		aidlCommand := android.RuleBuilderSboxProtoForTests(t, aidlManifest).Commands[0].GetCommand()
+		aidlCommand := android.RuleBuilderSboxProtoForTests(t, ctx, aidlManifest).Commands[0].GetCommand()
 		if !strings.Contains(aidlCommand, "-Isub") {
 			t.Errorf("aidl command for c.aidl should contain \"-Isub\", but was %q", aidlCommand)
 		}
diff --git a/cc/generated_cc_library.go b/cc/generated_cc_library.go
index 55e19f9..b1084e4 100644
--- a/cc/generated_cc_library.go
+++ b/cc/generated_cc_library.go
@@ -28,10 +28,6 @@
 		staticAndSharedLibrarySdkMemberType,
 	}
 
-	//	TODO: Need to be bazelable
-	//	module.bazelable = true
-	//	module.bazelHandler = &ccLibraryBazelHandler{module: module}
-
 	module.generators = append(module.generators, callbacks)
 
 	return module.Init()
diff --git a/cc/genrule.go b/cc/genrule.go
index d1c4c2a..431a01c 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -19,7 +19,6 @@
 
 	"android/soong/android"
 	"android/soong/genrule"
-	"android/soong/snapshot"
 )
 
 func init() {
@@ -62,7 +61,6 @@
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibBoth)
 
 	android.InitApexModule(module)
-	android.InitBazelModule(module)
 
 	return module
 }
@@ -80,15 +78,7 @@
 func (g *GenruleExtraProperties) ImageMutatorBegin(ctx android.BaseModuleContext) {}
 
 func (g *GenruleExtraProperties) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
-	if ctx.DeviceConfig().VndkVersion() == "" {
-		return true
-	}
-
-	if ctx.DeviceConfig().ProductVndkVersion() != "" && ctx.ProductSpecific() {
-		return false
-	}
-
-	return !(ctx.SocSpecific() || ctx.DeviceSpecific())
+	return !(ctx.SocSpecific() || ctx.DeviceSpecific() || ctx.ProductSpecific())
 }
 
 func (g *GenruleExtraProperties) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
@@ -106,43 +96,19 @@
 func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
 	// If the build is using a snapshot, the recovery variant under AOSP directories
 	// is not needed.
-	recoverySnapshotVersion := ctx.DeviceConfig().RecoverySnapshotVersion()
-	if recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" &&
-		!snapshot.IsRecoveryProprietaryModule(ctx) {
-		return false
-	} else {
-		return Bool(g.Recovery_available)
-	}
+	return Bool(g.Recovery_available)
 }
 
 func (g *GenruleExtraProperties) ExtraImageVariations(ctx android.BaseModuleContext) []string {
-	if ctx.DeviceConfig().VndkVersion() == "" {
-		return nil
-	}
-
 	var variants []string
-	if Bool(g.Vendor_available) || Bool(g.Odm_available) || ctx.SocSpecific() || ctx.DeviceSpecific() {
-		vndkVersion := ctx.DeviceConfig().VndkVersion()
-		// If vndkVersion is current, we can always use PlatformVndkVersion.
-		// If not, we assume modules under proprietary paths are compatible for
-		// BOARD_VNDK_VERSION. The other modules are regarded as AOSP, that is
-		// PLATFORM_VNDK_VERSION.
-		if vndkVersion == "current" || !snapshot.IsVendorProprietaryModule(ctx) {
-			variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
-		} else {
-			variants = append(variants, VendorVariationPrefix+vndkVersion)
-		}
-	}
+	vendorVariantRequired := Bool(g.Vendor_available) || Bool(g.Odm_available) || ctx.SocSpecific() || ctx.DeviceSpecific()
+	productVariantRequired := Bool(g.Product_available) || ctx.ProductSpecific()
 
-	if ctx.DeviceConfig().ProductVndkVersion() == "" {
-		return variants
+	if vendorVariantRequired {
+		variants = append(variants, VendorVariation)
 	}
-
-	if Bool(g.Product_available) || ctx.ProductSpecific() {
-		variants = append(variants, ProductVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
-		if vndkVersion := ctx.DeviceConfig().ProductVndkVersion(); vndkVersion != "current" {
-			variants = append(variants, ProductVariationPrefix+vndkVersion)
-		}
+	if productVariantRequired {
+		variants = append(variants, ProductVariation)
 	}
 
 	return variants
diff --git a/cc/genrule_test.go b/cc/genrule_test.go
index 0d16e62..b3d5116 100644
--- a/cc/genrule_test.go
+++ b/cc/genrule_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"reflect"
+	"slices"
 	"testing"
 
 	"android/soong/android"
@@ -178,7 +179,7 @@
 				android.OptionalFixturePreparer(tt.preparer),
 			).RunTestWithBp(t, bp)
 			gen := result.ModuleForTests("gen", tt.variant)
-			sboxProto := android.RuleBuilderSboxProtoForTests(t, gen.Output("genrule.sbox.textproto"))
+			sboxProto := android.RuleBuilderSboxProtoForTests(t, result.TestContext, gen.Output("genrule.sbox.textproto"))
 			cmd := *sboxProto.Commands[0].Command
 			android.AssertStringDoesContain(t, "incorrect CC_ARCH", cmd, "CC_ARCH="+tt.arch+" ")
 			android.AssertStringDoesContain(t, "incorrect CC_NATIVE_BRIDGE", cmd, "CC_NATIVE_BRIDGE="+tt.nativeBridge+" ")
@@ -186,3 +187,70 @@
 		})
 	}
 }
+
+func TestVendorProductVariantGenrule(t *testing.T) {
+	bp := `
+	cc_genrule {
+		name: "gen",
+		tool_files: ["tool"],
+		cmd: "$(location tool) $(in) $(out)",
+		out: ["out"],
+		vendor_available: true,
+		product_available: true,
+	}
+	`
+	t.Helper()
+	ctx := PrepareForIntegrationTestWithCc.RunTestWithBp(t, bp)
+
+	variants := ctx.ModuleVariantsForTests("gen")
+	if !slices.Contains(variants, "android_vendor_arm64_armv8-a") {
+		t.Errorf(`expected vendor variant, but does not exist in %v`, variants)
+	}
+	if !slices.Contains(variants, "android_product_arm64_armv8-a") {
+		t.Errorf(`expected product variant, but does not exist in %v`, variants)
+	}
+}
+
+// cc_genrule is initialized to android.InitAndroidArchModule
+// that is an architecture-specific Android module.
+// So testing properties tagged with `android:"arch_variant"`
+// for cc_genrule.
+func TestMultilibGenruleOut(t *testing.T) {
+	bp := `
+	cc_genrule {
+		name: "gen",
+		cmd: "cp $(in) $(out)",
+		srcs: ["foo"],
+		multilib: {
+			lib32: {
+				out: [
+					"subdir32/external-module32",
+				],
+			},
+			lib64: {
+				out: [
+					"subdir64/external-module64",
+				],
+			},
+		},
+	}
+	`
+	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, bp)
+	gen_32bit := result.ModuleForTests("gen", "android_arm_armv7-a-neon").OutputFiles(t, "")
+	android.AssertPathsEndWith(t,
+		"genrule_out",
+		[]string{
+			"subdir32/external-module32",
+		},
+		gen_32bit,
+	)
+
+	gen_64bit := result.ModuleForTests("gen", "android_arm64_armv8-a").OutputFiles(t, "")
+	android.AssertPathsEndWith(t,
+		"genrule_out",
+		[]string{
+			"subdir64/external-module64",
+		},
+		gen_64bit,
+	)
+}
diff --git a/cc/image.go b/cc/image.go
index f91762a..f8c5ca5 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -22,7 +22,8 @@
 	"strings"
 
 	"android/soong/android"
-	"android/soong/snapshot"
+
+	"github.com/google/blueprint/proptools"
 )
 
 var _ android.ImageInterface = (*Module)(nil)
@@ -40,27 +41,23 @@
 )
 
 const (
+	// VendorVariation is the variant name used for /vendor code that does not
+	// compile against the VNDK.
+	VendorVariation = "vendor"
+
 	// VendorVariationPrefix is the variant prefix used for /vendor code that compiles
 	// against the VNDK.
 	VendorVariationPrefix = "vendor."
 
+	// ProductVariation is the variant name used for /product code that does not
+	// compile against the VNDK.
+	ProductVariation = "product"
+
 	// ProductVariationPrefix is the variant prefix used for /product code that compiles
 	// against the VNDK.
 	ProductVariationPrefix = "product."
 )
 
-func (ctx *moduleContext) ProductSpecific() bool {
-	return ctx.ModuleContext.ProductSpecific() || ctx.mod.productSpecificModuleContext()
-}
-
-func (ctx *moduleContext) SocSpecific() bool {
-	return ctx.ModuleContext.SocSpecific() || ctx.mod.socSpecificModuleContext()
-}
-
-func (ctx *moduleContext) DeviceSpecific() bool {
-	return ctx.ModuleContext.DeviceSpecific() || ctx.mod.deviceSpecificModuleContext()
-}
-
 func (ctx *moduleContextImpl) inProduct() bool {
 	return ctx.mod.InProduct()
 }
@@ -81,20 +78,20 @@
 	return ctx.mod.InRecovery()
 }
 
-func (c *Module) productSpecificModuleContext() bool {
+func (c *Module) InstallInProduct() bool {
 	// Additionally check if this module is inProduct() that means it is a "product" variant of a
 	// module. As well as product specific modules, product variants must be installed to /product.
 	return c.InProduct()
 }
 
-func (c *Module) socSpecificModuleContext() bool {
+func (c *Module) InstallInVendor() bool {
 	// Additionally check if this module is inVendor() that means it is a "vendor" variant of a
 	// module. As well as SoC specific modules, vendor variants must be installed to /vendor
 	// unless they have "odm_available: true".
 	return c.HasVendorVariant() && c.InVendor() && !c.VendorVariantToOdm()
 }
 
-func (c *Module) deviceSpecificModuleContext() bool {
+func (c *Module) InstallInOdm() bool {
 	// Some vendor variants want to be installed to /odm by setting "odm_available: true".
 	return c.InVendor() && c.VendorVariantToOdm()
 }
@@ -122,12 +119,18 @@
 
 // Returns true if the module is "product" variant. Usually these modules are installed in /product
 func (c *Module) InProduct() bool {
-	return c.Properties.ImageVariationPrefix == ProductVariationPrefix
+	return c.Properties.ImageVariation == ProductVariation
 }
 
 // Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor
 func (c *Module) InVendor() bool {
-	return c.Properties.ImageVariationPrefix == VendorVariationPrefix
+	return c.Properties.ImageVariation == VendorVariation
+}
+
+// Returns true if the module is "vendor" or "product" variant. This replaces previous UseVndk usages
+// which were misused to check if the module variant is vendor or product.
+func (c *Module) InVendorOrProduct() bool {
+	return c.InVendor() || c.InProduct()
 }
 
 func (c *Module) InRamdisk() bool {
@@ -425,61 +428,26 @@
 	var vendorVariants []string
 	var productVariants []string
 
-	platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
-	boardVndkVersion := mctx.DeviceConfig().VndkVersion()
-	productVndkVersion := mctx.DeviceConfig().ProductVndkVersion()
-	recoverySnapshotVersion := mctx.DeviceConfig().RecoverySnapshotVersion()
-	usingRecoverySnapshot := recoverySnapshotVersion != "current" &&
-		recoverySnapshotVersion != ""
 	needVndkVersionVendorVariantForLlndk := false
-	if boardVndkVersion != "" {
-		boardVndkApiLevel, err := android.ApiLevelFromUser(mctx, boardVndkVersion)
-		if err == nil && !boardVndkApiLevel.IsPreview() {
-			// VNDK snapshot newer than v30 has LLNDK stub libraries.
-			// Only the VNDK version less than or equal to v30 requires generating the vendor
-			// variant of the VNDK version from the source tree.
-			needVndkVersionVendorVariantForLlndk = boardVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(mctx, "30"))
-		}
-	}
-	if boardVndkVersion == "current" {
-		boardVndkVersion = platformVndkVersion
-	}
-	if productVndkVersion == "current" {
-		productVndkVersion = platformVndkVersion
-	}
 
 	if m.NeedsLlndkVariants() {
 		// This is an LLNDK library.  The implementation of the library will be on /system,
 		// and vendor and product variants will be created with LLNDK stubs.
 		// The LLNDK libraries need vendor variants even if there is no VNDK.
 		coreVariantNeeded = true
-		if platformVndkVersion != "" {
-			vendorVariants = append(vendorVariants, platformVndkVersion)
-			productVariants = append(productVariants, platformVndkVersion)
-		}
+		vendorVariants = append(vendorVariants, "")
+		productVariants = append(productVariants, "")
 		// Generate vendor variants for boardVndkVersion only if the VNDK snapshot does not
 		// provide the LLNDK stub libraries.
 		if needVndkVersionVendorVariantForLlndk {
-			vendorVariants = append(vendorVariants, boardVndkVersion)
-		}
-		if productVndkVersion != "" {
-			productVariants = append(productVariants, productVndkVersion)
+			vendorVariants = append(vendorVariants, "")
 		}
 	} else if m.NeedsVendorPublicLibraryVariants() {
 		// A vendor public library has the implementation on /vendor, with stub variants
 		// for system and product.
 		coreVariantNeeded = true
-		vendorVariants = append(vendorVariants, boardVndkVersion)
-		if platformVndkVersion != "" {
-			productVariants = append(productVariants, platformVndkVersion)
-		}
-		if productVndkVersion != "" {
-			productVariants = append(productVariants, productVndkVersion)
-		}
-	} else if boardVndkVersion == "" {
-		// If the device isn't compiling against the VNDK, we always
-		// use the core mode.
-		coreVariantNeeded = true
+		vendorVariants = append(vendorVariants, "")
+		productVariants = append(productVariants, "")
 	} else if m.IsSnapshotPrebuilt() {
 		// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
 		// PRODUCT_EXTRA_VNDK_VERSIONS.
@@ -497,40 +465,16 @@
 		// BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or
 		// PLATFORM_VNDK_VERSION.
 		if m.HasVendorVariant() {
-			if snapshot.IsVendorProprietaryModule(mctx) {
-				vendorVariants = append(vendorVariants, boardVndkVersion)
-			} else {
-				vendorVariants = append(vendorVariants, platformVndkVersion)
-			}
+			vendorVariants = append(vendorVariants, "")
 		}
 
 		// product_available modules are available to /product.
 		if m.HasProductVariant() {
-			productVariants = append(productVariants, platformVndkVersion)
-			// VNDK is always PLATFORM_VNDK_VERSION
-			if !m.IsVndk() {
-				productVariants = append(productVariants, productVndkVersion)
-			}
+			productVariants = append(productVariants, "")
 		}
 	} else if vendorSpecific && m.SdkVersion() == "" {
 		// This will be available in /vendor (or /odm) only
-
-		// kernel_headers is a special module type whose exported headers
-		// are coming from DeviceKernelHeaders() which is always vendor
-		// dependent. They'll always have both vendor variants.
-		// For other modules, we assume that modules under proprietary
-		// paths are compatible for BOARD_VNDK_VERSION. The other modules
-		// are regarded as AOSP, which is PLATFORM_VNDK_VERSION.
-		if m.KernelHeadersDecorator() {
-			vendorVariants = append(vendorVariants,
-				platformVndkVersion,
-				boardVndkVersion,
-			)
-		} else if snapshot.IsVendorProprietaryModule(mctx) {
-			vendorVariants = append(vendorVariants, boardVndkVersion)
-		} else {
-			vendorVariants = append(vendorVariants, platformVndkVersion)
-		}
+		vendorVariants = append(vendorVariants, "")
 	} else {
 		// This is either in /system (or similar: /data), or is a
 		// module built with the NDK. Modules built with the NDK
@@ -538,17 +482,10 @@
 		coreVariantNeeded = true
 	}
 
-	if boardVndkVersion != "" && productVndkVersion != "" {
-		if coreVariantNeeded && productSpecific && m.SdkVersion() == "" {
-			// The module has "product_specific: true" that does not create core variant.
-			coreVariantNeeded = false
-			productVariants = append(productVariants, productVndkVersion)
-		}
-	} else {
-		// Unless PRODUCT_PRODUCT_VNDK_VERSION is set, product partition has no
-		// restriction to use system libs.
-		// No product variants defined in this case.
-		productVariants = []string{}
+	if coreVariantNeeded && productSpecific && m.SdkVersion() == "" {
+		// The module has "product_specific: true" that does not create core variant.
+		coreVariantNeeded = false
+		productVariants = append(productVariants, "")
 	}
 
 	if m.RamdiskAvailable() {
@@ -578,21 +515,20 @@
 		coreVariantNeeded = false
 	}
 
-	// If using a snapshot, the recovery variant under AOSP directories is not needed,
-	// except for kernel headers, which needs all variants.
-	if !m.KernelHeadersDecorator() &&
-		!m.IsSnapshotPrebuilt() &&
-		usingRecoverySnapshot &&
-		!snapshot.IsRecoveryProprietaryModule(mctx) {
-		recoveryVariantNeeded = false
-	}
-
 	for _, variant := range android.FirstUniqueStrings(vendorVariants) {
-		m.AppendExtraVariant(VendorVariationPrefix + variant)
+		if variant == "" {
+			m.AppendExtraVariant(VendorVariation)
+		} else {
+			m.AppendExtraVariant(VendorVariationPrefix + variant)
+		}
 	}
 
 	for _, variant := range android.FirstUniqueStrings(productVariants) {
-		m.AppendExtraVariant(ProductVariationPrefix + variant)
+		if variant == "" {
+			m.AppendExtraVariant(ProductVariation)
+		} else {
+			m.AppendExtraVariant(ProductVariationPrefix + variant)
+		}
 	}
 
 	m.SetRamdiskVariantNeeded(ramdiskVariantNeeded)
@@ -643,6 +579,10 @@
 
 		lib.baseCompiler.Properties.Exclude_generated_sources = append(lib.baseCompiler.Properties.Exclude_generated_sources,
 			lib.baseCompiler.Properties.Target.Vendor.Exclude_generated_sources...)
+
+		if lib.Properties.Target.Vendor.No_stubs {
+			proptools.Clear(&lib.Properties.Stubs)
+		}
 	}
 }
 
@@ -656,6 +596,10 @@
 
 		lib.baseCompiler.Properties.Exclude_generated_sources = append(lib.baseCompiler.Properties.Exclude_generated_sources,
 			lib.baseCompiler.Properties.Target.Product.Exclude_generated_sources...)
+
+		if lib.Properties.Target.Product.No_stubs {
+			proptools.Clear(&lib.Properties.Stubs)
+		}
 	}
 }
 
@@ -695,21 +639,18 @@
 	} else if variant == android.RecoveryVariation {
 		m.MakeAsPlatform()
 		squashRecoverySrcs(m)
-	} else if strings.HasPrefix(variant, VendorVariationPrefix) {
-		m.Properties.ImageVariationPrefix = VendorVariationPrefix
-		m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix)
-		squashVendorSrcs(m)
+	} else if strings.HasPrefix(variant, VendorVariation) {
+		m.Properties.ImageVariation = VendorVariation
 
-		// Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION.
-		// Hide other vendor variants to avoid collision.
-		vndkVersion := ctx.DeviceConfig().VndkVersion()
-		if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion {
-			m.Properties.HideFromMake = true
-			m.HideFromMake()
+		if strings.HasPrefix(variant, VendorVariationPrefix) {
+			m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix)
 		}
-	} else if strings.HasPrefix(variant, ProductVariationPrefix) {
-		m.Properties.ImageVariationPrefix = ProductVariationPrefix
-		m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix)
+		squashVendorSrcs(m)
+	} else if strings.HasPrefix(variant, ProductVariation) {
+		m.Properties.ImageVariation = ProductVariation
+		if strings.HasPrefix(variant, ProductVariationPrefix) {
+			m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix)
+		}
 		squashProductSrcs(m)
 	}
 
diff --git a/cc/installer.go b/cc/installer.go
index e2c0e7b..30f9612 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -59,6 +59,8 @@
 	relative string
 	location installLocation
 
+	installDeps android.InstallPaths
+
 	path android.InstallPath
 }
 
@@ -85,7 +87,7 @@
 	} else if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
 		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
 	}
-	if installer.location == InstallInData && ctx.useVndk() {
+	if installer.location == InstallInData && ctx.InVendorOrProduct() {
 		if ctx.inProduct() {
 			dir = filepath.Join(dir, "product")
 		} else {
@@ -97,7 +99,12 @@
 }
 
 func (installer *baseInstaller) install(ctx ModuleContext, file android.Path) {
-	installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file)
+	installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file, installer.installDeps...)
+}
+
+func (installer *baseInstaller) installTestData(ctx ModuleContext, data []android.DataPath) {
+	installedData := ctx.InstallTestData(installer.installDir(ctx), data)
+	installer.installDeps = append(installer.installDeps, installedData...)
 }
 
 func (installer *baseInstaller) everInstallable() bool {
diff --git a/cc/kernel_headers.go b/cc/kernel_headers.go
index 9ea988a..4f685be 100644
--- a/cc/kernel_headers.go
+++ b/cc/kernel_headers.go
@@ -34,7 +34,7 @@
 // kernel_headers retrieves the list of kernel headers directories from
 // TARGET_BOARD_KERNEL_HEADERS and TARGET_PRODUCT_KERNEL_HEADERS variables in
 // a makefile for compilation. See
-// https://android.googlesource.com/platform/build/+/master/core/config.mk
+// https://android.googlesource.com/platform/build/+/main/core/config.mk
 // for more details on them.
 func kernelHeadersFactory() android.Module {
 	module, library := NewLibrary(android.HostAndDeviceSupported)
diff --git a/cc/library.go b/cc/library.go
index df1dbc5..a436649 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -24,28 +24,12 @@
 	"sync"
 
 	"android/soong/android"
-	"android/soong/bazel"
-	"android/soong/bazel/cquery"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 	"github.com/google/blueprint/proptools"
 )
 
-var (
-	alwaysLinkLibraries = map[string]bool{
-		// Coverage libraries are _always_ added as a whole_static_dep. By converting as these as
-		// alwayslink = True, we can add these as to deps (e.g. as a regular static dep) in Bazel
-		// without any extra complications in cc_shared_library roots to prevent linking the same
-		// library repeatedly.
-		"libprofile-extras_ndk":               true,
-		"libprofile-extras":                   true,
-		"libprofile-clang-extras_ndk":         true,
-		"libprofile-clang-extras_cfi_support": true,
-		"libprofile-clang-extras":             true,
-	}
-)
-
 // LibraryProperties is a collection of properties shared by cc library rules/cc.
 type LibraryProperties struct {
 	// local file name to pass to the linker as -unexported_symbols_list
@@ -107,6 +91,13 @@
 			Suffix *string `android:"arch_variant"`
 
 			Header_abi_checker headerAbiCheckerProperties
+
+			// Disable stubs for vendor/product variants
+			// This is a workaround to keep `stubs` only for "core" variant (not product/vendor).
+			// It would be nice if we could put `stubs` into a `target: { core: {} }`
+			// block but it's not supported in soong yet. This could be removed/simplified once we have
+			// a better syntax.
+			No_stubs bool
 		}
 
 		Platform struct {
@@ -228,434 +219,6 @@
 	ctx.RegisterModuleType("cc_library_host_shared", LibraryHostSharedFactory)
 }
 
-// TODO(b/199902614): Can this be factored to share with the other Attributes?
-// For bp2build conversion.
-type bazelCcLibraryAttributes struct {
-	// Attributes pertaining to both static and shared variants.
-	Srcs    bazel.LabelListAttribute
-	Srcs_c  bazel.LabelListAttribute
-	Srcs_as bazel.LabelListAttribute
-
-	Copts      bazel.StringListAttribute
-	Cppflags   bazel.StringListAttribute
-	Conlyflags bazel.StringListAttribute
-	Asflags    bazel.StringListAttribute
-
-	Hdrs bazel.LabelListAttribute
-
-	Deps                              bazel.LabelListAttribute
-	Implementation_deps               bazel.LabelListAttribute
-	Dynamic_deps                      bazel.LabelListAttribute
-	Implementation_dynamic_deps       bazel.LabelListAttribute
-	Whole_archive_deps                bazel.LabelListAttribute
-	Implementation_whole_archive_deps bazel.LabelListAttribute
-	System_dynamic_deps               bazel.LabelListAttribute
-
-	Export_includes        bazel.StringListAttribute
-	Export_system_includes bazel.StringListAttribute
-	Local_includes         bazel.StringListAttribute
-	Absolute_includes      bazel.StringListAttribute
-	Linkopts               bazel.StringListAttribute
-	Rtti                   bazel.BoolAttribute
-
-	Stl     *string
-	Cpp_std *string
-	C_std   *string
-
-	// This is shared only.
-	Additional_linker_inputs bazel.LabelListAttribute
-
-	// Common properties shared between both shared and static variants.
-	Shared staticOrSharedAttributes
-	Static staticOrSharedAttributes
-
-	Strip stripAttributes
-
-	Features bazel.StringListAttribute
-}
-
-type aidlLibraryAttributes struct {
-	Srcs        bazel.LabelListAttribute
-	Include_dir *string
-	Tags        bazel.StringListAttribute
-}
-
-type ccAidlLibraryAttributes struct {
-	Deps                        bazel.LabelListAttribute
-	Implementation_deps         bazel.LabelListAttribute
-	Implementation_dynamic_deps bazel.LabelListAttribute
-	Tags                        bazel.StringListAttribute
-
-	sdkAttributes
-	includesAttributes
-}
-
-type stripAttributes struct {
-	Keep_symbols                 bazel.BoolAttribute
-	Keep_symbols_and_debug_frame bazel.BoolAttribute
-	Keep_symbols_list            bazel.StringListAttribute
-	All                          bazel.BoolAttribute
-	None                         bazel.BoolAttribute
-}
-
-func stripAttrsFromLinkerAttrs(la *linkerAttributes) stripAttributes {
-	return stripAttributes{
-		Keep_symbols:                 la.stripKeepSymbols,
-		Keep_symbols_and_debug_frame: la.stripKeepSymbolsAndDebugFrame,
-		Keep_symbols_list:            la.stripKeepSymbolsList,
-		All:                          la.stripAll,
-		None:                         la.stripNone,
-	}
-}
-
-func libraryBp2Build(ctx android.TopDownMutatorContext, m *Module) {
-	sharedAttrs := bp2BuildParseSharedProps(ctx, m)
-	staticAttrs := bp2BuildParseStaticProps(ctx, m)
-	baseAttributes := bp2BuildParseBaseProps(ctx, m)
-	compilerAttrs := baseAttributes.compilerAttributes
-	linkerAttrs := baseAttributes.linkerAttributes
-	exportedIncludes := bp2BuildParseExportedIncludes(ctx, m, &compilerAttrs.includes)
-
-	srcs := compilerAttrs.srcs
-
-	sharedAttrs.Dynamic_deps.Add(baseAttributes.protoDependency)
-	staticAttrs.Deps.Add(baseAttributes.protoDependency)
-
-	asFlags := compilerAttrs.asFlags
-	if compilerAttrs.asSrcs.IsEmpty() && sharedAttrs.Srcs_as.IsEmpty() && staticAttrs.Srcs_as.IsEmpty() {
-		// Skip asflags for BUILD file simplicity if there are no assembly sources.
-		asFlags = bazel.MakeStringListAttribute(nil)
-	}
-
-	sharedFeatures := baseAttributes.features.Clone().Append(sharedAttrs.Features)
-	sharedFeatures.DeduplicateAxesFromBase()
-	staticFeatures := baseAttributes.features.Clone().Append(staticAttrs.Features)
-	staticFeatures.DeduplicateAxesFromBase()
-
-	staticCommonAttrs := staticOrSharedAttributes{
-		Srcs:    *srcs.Clone().Append(staticAttrs.Srcs),
-		Srcs_c:  *compilerAttrs.cSrcs.Clone().Append(staticAttrs.Srcs_c),
-		Srcs_as: *compilerAttrs.asSrcs.Clone().Append(staticAttrs.Srcs_as),
-		Copts:   *compilerAttrs.copts.Clone().Append(staticAttrs.Copts),
-		Hdrs:    *compilerAttrs.hdrs.Clone().Append(staticAttrs.Hdrs),
-
-		Deps:                              *linkerAttrs.deps.Clone().Append(staticAttrs.Deps),
-		Implementation_deps:               *linkerAttrs.implementationDeps.Clone().Append(staticAttrs.Implementation_deps),
-		Dynamic_deps:                      *linkerAttrs.dynamicDeps.Clone().Append(staticAttrs.Dynamic_deps),
-		Implementation_dynamic_deps:       *linkerAttrs.implementationDynamicDeps.Clone().Append(staticAttrs.Implementation_dynamic_deps),
-		Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps,
-		Whole_archive_deps:                *linkerAttrs.wholeArchiveDeps.Clone().Append(staticAttrs.Whole_archive_deps),
-		System_dynamic_deps:               *linkerAttrs.systemDynamicDeps.Clone().Append(staticAttrs.System_dynamic_deps),
-		Runtime_deps:                      linkerAttrs.runtimeDeps,
-		sdkAttributes:                     bp2BuildParseSdkAttributes(m),
-		Native_coverage:                   baseAttributes.Native_coverage,
-	}
-
-	includeAttrs := includesAttributes{
-		Export_includes:          exportedIncludes.Includes,
-		Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
-		Export_system_includes:   exportedIncludes.SystemIncludes,
-		Local_includes:           compilerAttrs.localIncludes,
-		Absolute_includes:        compilerAttrs.absoluteIncludes,
-	}
-
-	sharedCommonAttrs := staticOrSharedAttributes{
-		Srcs:    *srcs.Clone().Append(sharedAttrs.Srcs),
-		Srcs_c:  *compilerAttrs.cSrcs.Clone().Append(sharedAttrs.Srcs_c),
-		Srcs_as: *compilerAttrs.asSrcs.Clone().Append(sharedAttrs.Srcs_as),
-		Copts:   *compilerAttrs.copts.Clone().Append(sharedAttrs.Copts),
-		Hdrs:    *compilerAttrs.hdrs.Clone().Append(sharedAttrs.Hdrs),
-
-		Deps:                              *linkerAttrs.deps.Clone().Append(sharedAttrs.Deps),
-		Implementation_deps:               *linkerAttrs.implementationDeps.Clone().Append(sharedAttrs.Implementation_deps),
-		Dynamic_deps:                      *linkerAttrs.dynamicDeps.Clone().Append(sharedAttrs.Dynamic_deps),
-		Implementation_dynamic_deps:       *linkerAttrs.implementationDynamicDeps.Clone().Append(sharedAttrs.Implementation_dynamic_deps),
-		Whole_archive_deps:                *linkerAttrs.wholeArchiveDeps.Clone().Append(sharedAttrs.Whole_archive_deps),
-		Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps,
-		System_dynamic_deps:               *linkerAttrs.systemDynamicDeps.Clone().Append(sharedAttrs.System_dynamic_deps),
-		Runtime_deps:                      linkerAttrs.runtimeDeps,
-		sdkAttributes:                     bp2BuildParseSdkAttributes(m),
-		Native_coverage:                   baseAttributes.Native_coverage,
-	}
-
-	staticTargetAttrs := &bazelCcLibraryStaticAttributes{
-		staticOrSharedAttributes: staticCommonAttrs,
-		includesAttributes:       includeAttrs,
-
-		Cppflags:   compilerAttrs.cppFlags,
-		Conlyflags: compilerAttrs.conlyFlags,
-		Asflags:    asFlags,
-
-		Rtti:    compilerAttrs.rtti,
-		Stl:     compilerAttrs.stl,
-		Cpp_std: compilerAttrs.cppStd,
-		C_std:   compilerAttrs.cStd,
-
-		Features: *staticFeatures,
-	}
-
-	sharedTargetAttrs := &bazelCcLibrarySharedAttributes{
-		staticOrSharedAttributes: sharedCommonAttrs,
-		includesAttributes:       includeAttrs,
-
-		Cppflags:   compilerAttrs.cppFlags,
-		Conlyflags: compilerAttrs.conlyFlags,
-		Asflags:    asFlags,
-
-		Linkopts:        linkerAttrs.linkopts,
-		Rtti:            compilerAttrs.rtti,
-		Stl:             compilerAttrs.stl,
-		Cpp_std:         compilerAttrs.cppStd,
-		C_std:           compilerAttrs.cStd,
-		Use_version_lib: linkerAttrs.useVersionLib,
-
-		Additional_linker_inputs: linkerAttrs.additionalLinkerInputs,
-
-		Strip:                             stripAttrsFromLinkerAttrs(&linkerAttrs),
-		Features:                          *sharedFeatures,
-		bazelCcHeaderAbiCheckerAttributes: bp2buildParseAbiCheckerProps(ctx, m),
-
-		Fdo_profile: compilerAttrs.fdoProfile,
-	}
-
-	if compilerAttrs.stubsSymbolFile != nil && len(compilerAttrs.stubsVersions.Value) > 0 {
-		sharedTargetAttrs.Stubs_symbol_file = compilerAttrs.stubsSymbolFile
-	}
-
-	sharedTargetAttrs.Stem = compilerAttrs.stem
-	sharedTargetAttrs.Suffix = compilerAttrs.suffix
-
-	for axis, configToProps := range m.GetArchVariantProperties(ctx, &LibraryProperties{}) {
-		for cfg, props := range configToProps {
-			if props, ok := props.(*LibraryProperties); ok {
-				if props.Inject_bssl_hash != nil {
-					// This is an edge case applies only to libcrypto
-					if m.Name() == "libcrypto" || m.Name() == "libcrypto_for_testing" {
-						sharedTargetAttrs.Inject_bssl_hash.SetSelectValue(axis, cfg, props.Inject_bssl_hash)
-					} else {
-						ctx.PropertyErrorf("inject_bssl_hash", "only applies to libcrypto")
-					}
-				}
-			}
-		}
-	}
-
-	staticProps := bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_library_static",
-		Bzl_load_location: "//build/bazel/rules/cc:cc_library_static.bzl",
-	}
-	sharedProps := bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_library_shared",
-		Bzl_load_location: "//build/bazel/rules/cc:cc_library_shared.bzl",
-	}
-
-	if _, ok := alwaysLinkLibraries[m.Name()]; ok {
-		staticTargetAttrs.Alwayslink = proptools.BoolPtr(true)
-	}
-
-	var tagsForStaticVariant bazel.StringListAttribute
-	if compilerAttrs.stubsSymbolFile == nil && len(compilerAttrs.stubsVersions.Value) == 0 {
-		tagsForStaticVariant = android.ApexAvailableTagsWithoutTestApexes(ctx, m)
-	}
-	tagsForStaticVariant.Append(bazel.StringListAttribute{Value: staticAttrs.Apex_available})
-
-	tagsForSharedVariant := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
-	tagsForSharedVariant.Append(bazel.StringListAttribute{Value: sharedAttrs.Apex_available})
-
-	ctx.CreateBazelTargetModuleWithRestrictions(staticProps,
-		android.CommonAttributes{
-			Name: m.Name() + "_bp2build_cc_library_static",
-			Tags: tagsForStaticVariant,
-		},
-		staticTargetAttrs, staticAttrs.Enabled)
-	ctx.CreateBazelTargetModuleWithRestrictions(sharedProps,
-		android.CommonAttributes{
-			Name: m.Name(),
-			Tags: tagsForSharedVariant,
-		},
-		sharedTargetAttrs, sharedAttrs.Enabled)
-
-	createStubsBazelTargetIfNeeded(ctx, m, compilerAttrs, exportedIncludes, baseAttributes)
-}
-
-func createStubsBazelTargetIfNeeded(ctx android.TopDownMutatorContext, m *Module, compilerAttrs compilerAttributes, exportedIncludes BazelIncludes, baseAttributes baseAttributes) {
-	if compilerAttrs.stubsSymbolFile != nil && len(compilerAttrs.stubsVersions.Value) > 0 {
-		stubSuitesProps := bazel.BazelTargetModuleProperties{
-			Rule_class:        "cc_stub_suite",
-			Bzl_load_location: "//build/bazel/rules/cc:cc_stub_library.bzl",
-		}
-		soname := m.Name() + ".so"
-		stubSuitesAttrs := &bazelCcStubSuiteAttributes{
-			Symbol_file:          compilerAttrs.stubsSymbolFile,
-			Versions:             compilerAttrs.stubsVersions,
-			Export_includes:      exportedIncludes.Includes,
-			Soname:               &soname,
-			Source_library_label: proptools.StringPtr(m.GetBazelLabel(ctx, m)),
-			Deps:                 baseAttributes.deps,
-		}
-		ctx.CreateBazelTargetModule(stubSuitesProps,
-			android.CommonAttributes{Name: m.Name() + "_stub_libs"},
-			stubSuitesAttrs)
-
-		// Add alias for the stub shared_library in @api_surfaces repository
-		currentModuleLibApiDir := ctx.Config().ApiSurfacesDir(android.ModuleLibApi, "current")
-		actualLabelInMainWorkspace := bazel.Label{
-			Label: fmt.Sprintf("@//%s:%s%s", ctx.ModuleDir(), m.Name(), stubsSuffix),
-		}
-		ctx.CreateBazelTargetAliasInDir(currentModuleLibApiDir, m.Name(), actualLabelInMainWorkspace)
-
-		// Add alias for headers exported by the stub library
-		headerLabelInMainWorkspace := bazel.Label{
-			// This label is generated from cc_stub_suite macro
-			Label: fmt.Sprintf("@//%s:%s_stub_libs_%s_headers", ctx.ModuleDir(), m.Name(), android.ModuleLibApi.String()),
-		}
-		headerAlias := m.Name() + "_headers"
-		ctx.CreateBazelTargetAliasInDir(currentModuleLibApiDir, headerAlias, headerLabelInMainWorkspace)
-	}
-}
-
-func apiContributionBp2Build(ctx android.TopDownMutatorContext, module *Module) {
-	apiSurfaces := make([]string, 0)
-	apiHeaders := make([]string, 0)
-	// module-libapi for apexes (non-null `stubs` property)
-	if module.HasStubsVariants() {
-		apiSurfaces = append(apiSurfaces, android.ModuleLibApi.String())
-		apiIncludes := getModuleLibApiIncludes(ctx, module)
-		if !apiIncludes.isEmpty() {
-			createApiHeaderTarget(ctx, apiIncludes)
-			apiHeaders = append(apiHeaders, apiIncludes.name)
-		}
-	}
-	// vendorapi (non-null `llndk` property)
-	if module.HasLlndkStubs() {
-		apiSurfaces = append(apiSurfaces, android.VendorApi.String())
-		apiIncludes := getVendorApiIncludes(ctx, module)
-		if !apiIncludes.isEmpty() {
-			createApiHeaderTarget(ctx, apiIncludes)
-			apiHeaders = append(apiHeaders, apiIncludes.name)
-		}
-	}
-	// create a target only if this module contributes to an api surface
-	// TODO: Currently this does not distinguish modulelibapi-only headers and vendrorapi-only headers
-	// TODO: Update so that modulelibapi-only headers do not get exported to vendorapi (and vice-versa)
-	if len(apiSurfaces) > 0 {
-		props := bazel.BazelTargetModuleProperties{
-			Rule_class:        "cc_api_contribution",
-			Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl",
-		}
-		attrs := &bazelCcApiContributionAttributes{
-			Library_name: module.Name(),
-			Api_surfaces: bazel.MakeStringListAttribute(apiSurfaces),
-			Api:          apiLabelAttribute(ctx, module),
-			Hdrs: bazel.MakeLabelListAttribute(
-				bazel.MakeLabelListFromTargetNames(apiHeaders),
-			),
-		}
-		ctx.CreateBazelTargetModule(
-			props,
-			android.CommonAttributes{
-				Name:     android.ApiContributionTargetName(module.Name()),
-				SkipData: proptools.BoolPtr(true),
-			},
-			attrs,
-		)
-	}
-}
-
-// Native apis are versioned in a single .map.txt for all api surfaces
-// Pick any one of the .map.txt files
-func apiLabelAttribute(ctx android.TopDownMutatorContext, module *Module) bazel.LabelAttribute {
-	var apiFile *string
-	linker := module.linker.(*libraryDecorator)
-	if llndkApi := linker.Properties.Llndk.Symbol_file; llndkApi != nil {
-		apiFile = llndkApi
-	} else if moduleLibApi := linker.Properties.Stubs.Symbol_file; moduleLibApi != nil {
-		apiFile = moduleLibApi
-	} else {
-		ctx.ModuleErrorf("API surface library does not have any API file")
-	}
-	apiLabel := android.BazelLabelForModuleSrcSingle(ctx, proptools.String(apiFile)).Label
-	return *bazel.MakeLabelAttribute(apiLabel)
-}
-
-// wrapper struct to flatten the arch and os specific export_include_dirs
-// flattening is necessary since we want to export apis of all arches even when we build for x86 (e.g.)
-type bazelCcApiLibraryHeadersAttributes struct {
-	bazelCcLibraryHeadersAttributes
-
-	Arch *string
-}
-
-func (a *bazelCcApiLibraryHeadersAttributes) isEmpty() bool {
-	return a.Export_includes.IsEmpty() &&
-		a.Export_system_includes.IsEmpty() &&
-		a.Deps.IsEmpty()
-}
-
-type apiIncludes struct {
-	name  string // name of the Bazel target in the generated bp2build workspace
-	attrs bazelCcApiLibraryHeadersAttributes
-}
-
-func (includes *apiIncludes) isEmpty() bool {
-	return includes.attrs.isEmpty()
-}
-
-func (includes *apiIncludes) addDep(name string) {
-	l := bazel.Label{Label: ":" + name}
-	ll := bazel.MakeLabelList([]bazel.Label{l})
-	lla := bazel.MakeLabelListAttribute(ll)
-	includes.attrs.Deps.Append(lla)
-}
-
-// includes provided to the module-lib API surface. This API surface is used by apexes.
-func getModuleLibApiIncludes(ctx android.TopDownMutatorContext, c *Module) apiIncludes {
-	flagProps := c.library.(*libraryDecorator).flagExporter.Properties
-	linkProps := c.library.(*libraryDecorator).baseLinker.Properties
-	includes := android.FirstUniqueStrings(flagProps.Export_include_dirs)
-	systemIncludes := android.FirstUniqueStrings(flagProps.Export_system_include_dirs)
-	headerLibs := android.FirstUniqueStrings(linkProps.Export_header_lib_headers)
-	attrs := bazelCcLibraryHeadersAttributes{
-		Export_includes:        bazel.MakeStringListAttribute(includes),
-		Export_system_includes: bazel.MakeStringListAttribute(systemIncludes),
-		Deps:                   bazel.MakeLabelListAttribute(apiHeaderLabels(ctx, headerLibs)),
-	}
-
-	return apiIncludes{
-		name: c.Name() + ".module-libapi.headers",
-		attrs: bazelCcApiLibraryHeadersAttributes{
-			bazelCcLibraryHeadersAttributes: attrs,
-		},
-	}
-}
-
-func getVendorApiIncludes(ctx android.TopDownMutatorContext, c *Module) apiIncludes {
-	baseProps := c.library.(*libraryDecorator).flagExporter.Properties
-	llndkProps := c.library.(*libraryDecorator).Properties.Llndk
-	includes := baseProps.Export_include_dirs
-	systemIncludes := baseProps.Export_system_include_dirs
-	// LLNDK can override the base includes
-	if llndkIncludes := llndkProps.Override_export_include_dirs; llndkIncludes != nil {
-		includes = llndkIncludes
-	}
-	if proptools.Bool(llndkProps.Export_headers_as_system) {
-		systemIncludes = append(systemIncludes, includes...)
-		includes = nil
-	}
-
-	attrs := bazelCcLibraryHeadersAttributes{
-		Export_includes:        bazel.MakeStringListAttribute(includes),
-		Export_system_includes: bazel.MakeStringListAttribute(systemIncludes),
-		Deps:                   bazel.MakeLabelListAttribute(apiHeaderLabels(ctx, llndkProps.Export_llndk_headers)),
-	}
-	return apiIncludes{
-		name: c.Name() + ".vendorapi.headers",
-		attrs: bazelCcApiLibraryHeadersAttributes{
-			bazelCcLibraryHeadersAttributes: attrs,
-		},
-	}
-}
-
 // cc_library creates both static and/or shared libraries for a device and/or
 // host. By default, a cc_library has a single variant that targets the device.
 // Specifying `host_supported: true` also creates a library that targets the
@@ -668,8 +231,6 @@
 		staticLibrarySdkMemberType,
 		staticAndSharedLibrarySdkMemberType,
 	}
-	module.bazelable = true
-	module.bazelHandler = &ccLibraryBazelHandler{module: module}
 	return module.Init()
 }
 
@@ -678,8 +239,6 @@
 	module, library := NewLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyStatic()
 	module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType}
-	module.bazelable = true
-	module.bazelHandler = &ccLibraryBazelHandler{module: module}
 	return module.Init()
 }
 
@@ -688,8 +247,6 @@
 	module, library := NewLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyShared()
 	module.sdkMemberTypes = []android.SdkMemberType{sharedLibrarySdkMemberType}
-	module.bazelable = true
-	module.bazelHandler = &ccLibraryBazelHandler{module: module}
 	return module.Init()
 }
 
@@ -699,8 +256,6 @@
 	module, library := NewLibrary(android.HostSupported)
 	library.BuildOnlyStatic()
 	module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType}
-	module.bazelable = true
-	module.bazelHandler = &ccLibraryBazelHandler{module: module}
 	return module.Init()
 }
 
@@ -709,8 +264,6 @@
 	module, library := NewLibrary(android.HostSupported)
 	library.BuildOnlyShared()
 	module.sdkMemberTypes = []android.SdkMemberType{sharedLibrarySdkMemberType}
-	module.bazelable = true
-	module.bazelHandler = &ccLibraryBazelHandler{module: module}
 	return module.Init()
 }
 
@@ -741,6 +294,10 @@
 	return android.PathsForModuleSrc(ctx, f.Properties.Export_include_dirs)
 }
 
+func (f *flagExporter) exportedSystemIncludes(ctx ModuleContext) android.Paths {
+	return android.PathsForModuleSrc(ctx, f.Properties.Export_system_include_dirs)
+}
+
 // exportIncludes registers the include directories and system include directories to be exported
 // transitively to modules depending on this module.
 func (f *flagExporter) exportIncludes(ctx ModuleContext) {
@@ -789,7 +346,7 @@
 }
 
 func (f *flagExporter) setProvider(ctx android.ModuleContext) {
-	ctx.SetProvider(FlagExporterInfoProvider, FlagExporterInfo{
+	android.SetProvider(ctx, FlagExporterInfoProvider, FlagExporterInfo{
 		// 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
@@ -836,9 +393,6 @@
 	// Output archive of gcno coverage information files
 	coverageOutputFile android.OptionalPath
 
-	// linked Source Abi Dump
-	sAbiOutputFile android.OptionalPath
-
 	// Source Abi Diff
 	sAbiDiff android.Paths
 
@@ -848,6 +402,8 @@
 
 	// Location of the linked, unstripped library for shared libraries
 	unstrippedOutputFile android.Path
+	// Location of the linked, stripped library for shared libraries, strip: "all"
+	strippedAllOutputFile android.Path
 
 	// Location of the file that should be copied to dist dir when requested
 	distFile android.Path
@@ -868,270 +424,9 @@
 	*baseLinker
 	*baseInstaller
 
-	collectedSnapshotHeaders android.Paths
-
 	apiListCoverageXmlPath android.ModuleOutPath
 }
 
-type ccLibraryBazelHandler struct {
-	module *Module
-}
-
-var _ BazelHandler = (*ccLibraryBazelHandler)(nil)
-
-// generateStaticBazelBuildActions constructs the StaticLibraryInfo Soong
-// provider from a Bazel shared library's CcInfo provider.
-func (handler *ccLibraryBazelHandler) generateStaticBazelBuildActions(ctx android.ModuleContext, label string, ccInfo cquery.CcInfo) {
-	rootStaticArchives := ccInfo.RootStaticArchives
-	if len(rootStaticArchives) != 1 {
-		ctx.ModuleErrorf("expected exactly one root archive file for '%s', but got %s", label, rootStaticArchives)
-		return
-	}
-	var outputFilePath android.Path = android.PathForBazelOut(ctx, rootStaticArchives[0])
-	if len(ccInfo.TidyFiles) > 0 {
-		handler.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles)
-		outputFilePath = android.AttachValidationActions(ctx, outputFilePath, handler.module.tidyFiles)
-	}
-	handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
-
-	objPaths := ccInfo.CcObjectFiles
-	objFiles := make(android.Paths, len(objPaths))
-	for i, objPath := range objPaths {
-		objFiles[i] = android.PathForBazelOut(ctx, objPath)
-	}
-	objects := Objects{
-		objFiles: objFiles,
-	}
-
-	ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
-		StaticLibrary: outputFilePath,
-		ReuseObjects:  objects,
-		Objects:       objects,
-
-		// TODO(b/190524881): Include transitive static libraries in this provider to support
-		// static libraries with deps.
-		TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).
-			Direct(outputFilePath).
-			Build(),
-	})
-
-	return
-}
-
-// generateSharedBazelBuildActions constructs the SharedLibraryInfo Soong
-// provider from a Bazel shared library's CcInfo provider.
-func (handler *ccLibraryBazelHandler) generateSharedBazelBuildActions(ctx android.ModuleContext, label string, ccInfo cquery.CcInfo) {
-	rootDynamicLibraries := ccInfo.RootDynamicLibraries
-
-	if len(rootDynamicLibraries) != 1 {
-		ctx.ModuleErrorf("expected exactly one root dynamic library file for '%s', but got %s", label, rootDynamicLibraries)
-		return
-	}
-	var outputFilePath android.Path = android.PathForBazelOut(ctx, rootDynamicLibraries[0])
-	if len(ccInfo.TidyFiles) > 0 {
-		handler.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles)
-		outputFilePath = android.AttachValidationActions(ctx, outputFilePath, handler.module.tidyFiles)
-	}
-
-	handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
-	handler.module.linker.(*libraryDecorator).unstrippedOutputFile = android.PathForBazelOut(ctx, ccInfo.UnstrippedOutput)
-
-	var tocFile android.OptionalPath
-	if len(ccInfo.TocFile) > 0 {
-		tocFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, ccInfo.TocFile))
-	}
-	handler.module.linker.(*libraryDecorator).tocFile = tocFile
-
-	if len(ccInfo.AbiDiffFiles) > 0 {
-		handler.module.linker.(*libraryDecorator).sAbiDiff = android.PathsForBazelOut(ctx, ccInfo.AbiDiffFiles)
-	}
-
-	ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
-		TableOfContents: tocFile,
-		SharedLibrary:   outputFilePath,
-		Target:          ctx.Target(),
-		// TODO(b/190524881): Include transitive static libraries in this provider to support
-		// static libraries with deps. The provider key for this is TransitiveStaticLibrariesForOrdering.
-	})
-}
-
-func (handler *ccLibraryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
-	if v := handler.module.library.stubsVersion(); v != "" {
-		stubsLabel := label + "_stub_libs-" + v
-		bazelCtx.QueueBazelRequest(stubsLabel, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
-	}
-}
-
-func (handler *ccLibraryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
-	if v := handler.module.library.stubsVersion(); v != "" {
-		// if we are a stubs variant, just use the Bazel stubs target
-		label = label + "_stub_libs-" + v
-	}
-	bazelCtx := ctx.Config().BazelContext
-	ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
-	if err != nil {
-		ctx.ModuleErrorf("Error getting Bazel CcInfo: %s", err)
-		return
-	}
-
-	if handler.module.static() {
-		handler.generateStaticBazelBuildActions(ctx, label, ccInfo)
-	} else if handler.module.Shared() {
-		handler.generateSharedBazelBuildActions(ctx, label, ccInfo)
-	} else {
-		ctx.ModuleErrorf("Unhandled bazel case for %s (neither shared nor static!)", ctx.ModuleName())
-	}
-
-	handler.module.linker.(*libraryDecorator).setFlagExporterInfoFromCcInfo(ctx, ccInfo)
-	handler.module.maybeUnhideFromMake()
-
-	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
-		// list.
-		// TODO(b/190533363): More closely mirror the collectHeadersForSnapshot
-		// implementation.
-		i.(*libraryDecorator).collectedSnapshotHeaders = android.Paths{}
-	}
-
-	handler.module.setAndroidMkVariablesFromCquery(ccInfo.CcAndroidMkInfo)
-
-	cctx := moduleContextFromAndroidModuleContext(ctx, handler.module)
-	addStubDependencyProviders(cctx)
-}
-
-func (library *libraryDecorator) setFlagExporterInfoFromCcInfo(ctx android.ModuleContext, ccInfo cquery.CcInfo) {
-	flagExporterInfo := flagExporterInfoFromCcInfo(ctx, ccInfo)
-	// flag exporters consolidates properties like includes, flags, dependencies that should be
-	// exported from this module to other modules
-	ctx.SetProvider(FlagExporterInfoProvider, flagExporterInfo)
-	// Store flag info to be passed along to androidmk
-	// TODO(b/184387147): Androidmk should be done in Bazel, not Soong.
-	library.flagExporterInfo = &flagExporterInfo
-}
-
-func GlobHeadersForSnapshot(ctx android.ModuleContext, paths android.Paths) android.Paths {
-	ret := android.Paths{}
-
-	// Headers in the source tree should be globbed. On the contrast, generated headers
-	// can't be globbed, and they should be manually collected.
-	// So, we first filter out intermediate directories (which contains generated headers)
-	// from exported directories, and then glob headers under remaining directories.
-	for _, path := range paths {
-		dir := path.String()
-		// Skip if dir is for generated headers
-		if strings.HasPrefix(dir, ctx.Config().OutDir()) {
-			continue
-		}
-
-		// Filter out the generated headers from bazel.
-		if strings.HasPrefix(dir, android.PathForBazelOut(ctx, "bazel-out").String()) {
-			continue
-		}
-
-		// libeigen wrongly exports the root directory "external/eigen". But only two
-		// subdirectories "Eigen" and "unsupported" contain exported header files. Even worse
-		// some of them have no extension. So we need special treatment for libeigen in order
-		// to glob correctly.
-		if dir == "external/eigen" {
-			// Only these two directories contains exported headers.
-			for _, subdir := range []string{"Eigen", "unsupported/Eigen"} {
-				globDir := "external/eigen/" + subdir + "/**/*"
-				glob, err := ctx.GlobWithDeps(globDir, nil)
-				if err != nil {
-					ctx.ModuleErrorf("glob of %q failed: %s", globDir, err)
-					return nil
-				}
-				for _, header := range glob {
-					if strings.HasSuffix(header, "/") {
-						continue
-					}
-					ext := filepath.Ext(header)
-					if ext != "" && ext != ".h" {
-						continue
-					}
-					ret = append(ret, android.PathForSource(ctx, header))
-				}
-			}
-			continue
-		}
-		globDir := dir + "/**/*"
-		glob, err := ctx.GlobWithDeps(globDir, nil)
-		if err != nil {
-			ctx.ModuleErrorf("glob of %q failed: %s", globDir, err)
-			return nil
-		}
-		isLibcxx := strings.HasPrefix(dir, "external/libcxx/include")
-		for _, header := range glob {
-			if isLibcxx {
-				// Glob all files under this special directory, because of C++ headers with no
-				// extension.
-				if strings.HasSuffix(header, "/") {
-					continue
-				}
-			} else {
-				// Filter out only the files with extensions that are headers.
-				found := false
-				for _, ext := range HeaderExts {
-					if strings.HasSuffix(header, ext) {
-						found = true
-						break
-					}
-				}
-				if !found {
-					continue
-				}
-			}
-			ret = append(ret, android.PathForSource(ctx, header))
-		}
-	}
-	return ret
-}
-
-func GlobGeneratedHeadersForSnapshot(_ android.ModuleContext, paths android.Paths) android.Paths {
-	ret := android.Paths{}
-	for _, header := range paths {
-		// TODO(b/148123511): remove exportedDeps after cleaning up genrule
-		if strings.HasSuffix(header.Base(), "-phony") {
-			continue
-		}
-		ret = append(ret, header)
-	}
-	return ret
-}
-
-// collectHeadersForSnapshot collects all exported headers from library.
-// It globs header files in the source tree for exported include directories,
-// and tracks generated header files separately.
-//
-// This is to be called from GenerateAndroidBuildActions, and then collected
-// header files can be retrieved by snapshotHeaders().
-func (l *libraryDecorator) collectHeadersForSnapshot(ctx android.ModuleContext) {
-	ret := android.Paths{}
-
-	// Headers in the source tree should be globbed. On the contrast, generated headers
-	// can't be globbed, and they should be manually collected.
-	// So, we first filter out intermediate directories (which contains generated headers)
-	// from exported directories, and then glob headers under remaining directories.
-	ret = append(ret, GlobHeadersForSnapshot(ctx, append(android.CopyOfPaths(l.flagExporter.dirs), l.flagExporter.systemDirs...))...)
-
-	// Collect generated headers
-	ret = append(ret, GlobGeneratedHeadersForSnapshot(ctx, append(android.CopyOfPaths(l.flagExporter.headers), l.flagExporter.deps...))...)
-
-	l.collectedSnapshotHeaders = ret
-}
-
-// This returns all exported header files, both generated ones and headers from source tree.
-// collectHeadersForSnapshot() must be called before calling this.
-func (l *libraryDecorator) snapshotHeaders() android.Paths {
-	if l.collectedSnapshotHeaders == nil {
-		panic("snapshotHeaders() must be called after collectHeadersForSnapshot()")
-	}
-	return l.collectedSnapshotHeaders
-}
-
 // linkerProps returns the list of properties structs relevant for this library. (For example, if
 // the library is cc_shared_library, then static-library properties are omitted.)
 func (library *libraryDecorator) linkerProps() []interface{} {
@@ -1265,18 +560,16 @@
 
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
 	if ctx.IsLlndk() {
+		vendorApiLevel := ctx.Config().VendorApiLevel()
+		if vendorApiLevel == "" {
+			// TODO(b/321892570): Some tests relying on old fixtures which
+			// doesn't set vendorApiLevel. Needs to fix them.
+			vendorApiLevel = ctx.Config().PlatformSdkVersion().String()
+		}
 		// This is the vendor variant of an LLNDK library, build the LLNDK stubs.
-		vndkVer := ctx.Module().(*Module).VndkVersion()
-		if !inList(vndkVer, ctx.Config().PlatformVersionActiveCodenames()) || vndkVer == "" {
-			// For non-enforcing devices, vndkVer is empty. Use "current" in that case, too.
-			vndkVer = "current"
-		}
-		if library.stubsVersion() != "" {
-			vndkVer = library.stubsVersion()
-		}
 		nativeAbiResult := parseNativeAbiDefinition(ctx,
 			String(library.Properties.Llndk.Symbol_file),
-			android.ApiLevelOrPanic(ctx, vndkVer), "--llndk")
+			android.ApiLevelOrPanic(ctx, vendorApiLevel), "--llndk")
 		objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
 		if !Bool(library.Properties.Llndk.Unversioned) {
 			library.versionScriptPath = android.OptionalPathForPath(
@@ -1346,15 +639,11 @@
 		return Objects{}
 	}
 	if library.sabi.shouldCreateSourceAbiDump() {
-		exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
-		var SourceAbiFlags []string
-		for _, dir := range exportIncludeDirs.Strings() {
-			SourceAbiFlags = append(SourceAbiFlags, "-I"+dir)
+		dirs := library.exportedIncludeDirsForAbiCheck(ctx)
+		flags.SAbiFlags = make([]string, 0, len(dirs))
+		for _, dir := range dirs {
+			flags.SAbiFlags = append(flags.SAbiFlags, "-I"+dir)
 		}
-		for _, reexportedInclude := range library.sabi.Properties.ReexportedIncludes {
-			SourceAbiFlags = append(SourceAbiFlags, "-I"+reexportedInclude)
-		}
-		flags.SAbiFlags = SourceAbiFlags
 		totalLength := len(library.baseCompiler.Properties.Srcs) + len(deps.GeneratedSources) +
 			len(library.SharedProperties.Shared.Srcs) + len(library.StaticProperties.Static.Srcs)
 		if totalLength > 0 {
@@ -1460,14 +749,6 @@
 func (library *libraryDecorator) getLibName(ctx BaseModuleContext) string {
 	name := library.getLibNameHelper(ctx.baseModuleName(), ctx.inVendor(), ctx.inProduct())
 
-	if ctx.IsVndkExt() {
-		// vndk-ext lib should have the same name with original lib
-		ctx.VisitDirectDepsWithTag(vndkExtDepTag, func(module android.Module) {
-			originalName := module.(*Module).outputFile.Path()
-			name = strings.TrimSuffix(originalName.Base(), originalName.Ext())
-		})
-	}
-
 	if ctx.Host() && Bool(library.Properties.Unique_host_soname) {
 		if !strings.HasSuffix(name, "-host") {
 			name = name + "-host"
@@ -1556,6 +837,10 @@
 		if library.baseLinker.Properties.crt() {
 			deps.CrtBegin = append(deps.CrtBegin, ctx.toolchain().CrtBeginSharedLibrary()...)
 			deps.CrtEnd = append(deps.CrtEnd, ctx.toolchain().CrtEndSharedLibrary()...)
+
+		}
+		if library.baseLinker.Properties.crtPadSegment() {
+			deps.CrtEnd = append(deps.CrtEnd, ctx.toolchain().CrtPadSegmentSharedLibrary()...)
 		}
 		deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.SharedProperties.Shared.Whole_static_libs...)
 		deps.StaticLibs = append(deps.StaticLibs, library.SharedProperties.Shared.Static_libs...)
@@ -1563,6 +848,8 @@
 
 		deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, library.SharedProperties.Shared.Export_shared_lib_headers...)
 		deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.SharedProperties.Shared.Export_static_lib_headers...)
+
+		deps.LlndkHeaderLibs = append(deps.LlndkHeaderLibs, library.Properties.Llndk.Export_llndk_headers...)
 	}
 	if ctx.inVendor() {
 		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Vendor.Exclude_static_libs)
@@ -1631,6 +918,40 @@
 	return specifiedDeps
 }
 
+func (library *libraryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+	if library.static() {
+		moduleInfoJSON.Class = []string{"STATIC_LIBRARIES"}
+		moduleInfoJSON.Uninstallable = true
+	} else if library.shared() {
+		moduleInfoJSON.Class = []string{"SHARED_LIBRARIES"}
+	} else if library.header() {
+		moduleInfoJSON.Class = []string{"HEADER_LIBRARIES"}
+		moduleInfoJSON.Uninstallable = true
+	}
+
+	if library.buildStubs() && library.stubsVersion() != "" {
+		moduleInfoJSON.SubName += "." + library.stubsVersion()
+	}
+
+	// If a library providing a stub is included in an APEX, the private APIs of the library
+	// is accessible only inside the APEX. From outside of the APEX, clients can only use the
+	// public APIs via the stub. To enforce this, the (latest version of the) stub gets the
+	// name of the library. The impl library instead gets the `.bootstrap` suffix to so that
+	// they can be exceptionally used directly when APEXes are not available (e.g. during the
+	// very early stage in the boot process).
+	if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.notInPlatform() &&
+		!ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && !ctx.useVndk() && !ctx.static() {
+		if library.buildStubs() && library.isLatestStubVersion() {
+			moduleInfoJSON.SubName = ""
+		}
+		if !library.buildStubs() {
+			moduleInfoJSON.SubName = ".bootstrap"
+		}
+	}
+
+	library.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON)
+}
+
 func (library *libraryDecorator) linkStatic(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
 
@@ -1661,7 +982,7 @@
 	ctx.CheckbuildFile(outputFile)
 
 	if library.static() {
-		ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+		android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{
 			StaticLibrary:                outputFile,
 			ReuseObjects:                 library.reuseObjects,
 			Objects:                      library.objects,
@@ -1675,7 +996,7 @@
 	}
 
 	if library.header() {
-		ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{})
+		android.SetProvider(ctx, HeaderLibraryInfoProvider, HeaderLibraryInfo{})
 	}
 
 	return outputFile
@@ -1793,6 +1114,17 @@
 		}
 	}
 
+	// Generate an output file for dist as if strip: "all" is set on the module.
+	// Currently this is for layoutlib release process only.
+	for _, dist := range ctx.Module().(*Module).Dists() {
+		if dist.Tag != nil && *dist.Tag == "stripped_all" {
+			strippedAllOutputFile := android.PathForModuleOut(ctx, "stripped_all", fileName)
+			transformStrip(ctx, outputFile, strippedAllOutputFile, StripFlags{Toolchain: flags.Toolchain})
+			library.strippedAllOutputFile = strippedAllOutputFile
+			break
+		}
+	}
+
 	sharedLibs := deps.EarlySharedLibs
 	sharedLibs = append(sharedLibs, deps.SharedLibs...)
 	sharedLibs = append(sharedLibs, deps.LateSharedLibs...)
@@ -1810,15 +1142,15 @@
 	objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.WholeStaticLibObjs.sAbiDumpFiles...)
 
 	library.coverageOutputFile = transformCoverageFilesToZip(ctx, objs, library.getLibName(ctx))
-	library.linkSAbiDumpFiles(ctx, objs, fileName, unstrippedOutputFile)
+	library.linkSAbiDumpFiles(ctx, deps, objs, fileName, unstrippedOutputFile)
 
 	var transitiveStaticLibrariesForOrdering *android.DepSet[android.Path]
 	if static := ctx.GetDirectDepsWithTag(staticVariantTag); len(static) > 0 {
-		s := ctx.OtherModuleProvider(static[0], StaticLibraryInfoProvider).(StaticLibraryInfo)
+		s, _ := android.OtherModuleProvider(ctx, static[0], StaticLibraryInfoProvider)
 		transitiveStaticLibrariesForOrdering = s.TransitiveStaticLibrariesForOrdering
 	}
 
-	ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+	android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
 		TableOfContents:                      android.OptionalPathForPath(tocFile),
 		SharedLibrary:                        unstrippedOutputFile,
 		TransitiveStaticLibrariesForOrdering: transitiveStaticLibrariesForOrdering,
@@ -1835,15 +1167,15 @@
 	if len(stubs) > 0 {
 		var stubsInfo []SharedStubLibrary
 		for _, stub := range stubs {
-			stubInfo := ctx.OtherModuleProvider(stub, SharedLibraryInfoProvider).(SharedLibraryInfo)
-			flagInfo := ctx.OtherModuleProvider(stub, FlagExporterInfoProvider).(FlagExporterInfo)
+			stubInfo, _ := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider)
+			flagInfo, _ := android.OtherModuleProvider(ctx, stub, FlagExporterInfoProvider)
 			stubsInfo = append(stubsInfo, SharedStubLibrary{
 				Version:           moduleLibraryInterface(stub).stubsVersion(),
 				SharedLibraryInfo: stubInfo,
 				FlagExporterInfo:  flagInfo,
 			})
 		}
-		ctx.SetProvider(SharedLibraryStubsProvider, SharedLibraryStubsInfo{
+		android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{
 			SharedStubLibraries: stubsInfo,
 			IsLLNDK:             ctx.IsLlndk(),
 		})
@@ -1854,6 +1186,10 @@
 	return library.unstrippedOutputFile
 }
 
+func (library *libraryDecorator) strippedAllOutputFilePath() android.Path {
+	return library.strippedAllOutputFile
+}
+
 func (library *libraryDecorator) disableStripping() {
 	library.stripper.StripProperties.Strip.None = BoolPtr(true)
 }
@@ -1869,6 +1205,75 @@
 	return library.coverageOutputFile
 }
 
+func (library *libraryDecorator) exportedIncludeDirsForAbiCheck(ctx ModuleContext) []string {
+	exportIncludeDirs := library.flagExporter.exportedIncludes(ctx).Strings()
+	exportIncludeDirs = append(exportIncludeDirs, library.sabi.Properties.ReexportedIncludes...)
+	exportSystemIncludeDirs := library.flagExporter.exportedSystemIncludes(ctx).Strings()
+	exportSystemIncludeDirs = append(exportSystemIncludeDirs, library.sabi.Properties.ReexportedSystemIncludes...)
+	// The ABI checker does not distinguish normal and system headers.
+	return append(exportIncludeDirs, exportSystemIncludeDirs...)
+}
+
+func (library *libraryDecorator) llndkIncludeDirsForAbiCheck(ctx ModuleContext, deps PathDeps) []string {
+	var includeDirs, systemIncludeDirs []string
+
+	// The ABI checker does not need the preprocess which adds macro guards to function declarations.
+	preprocessedDirs := android.PathsForModuleSrc(ctx, library.Properties.Llndk.Export_preprocessed_headers).Strings()
+	if Bool(library.Properties.Llndk.Export_headers_as_system) {
+		systemIncludeDirs = append(systemIncludeDirs, preprocessedDirs...)
+	} else {
+		includeDirs = append(includeDirs, preprocessedDirs...)
+	}
+
+	if library.Properties.Llndk.Override_export_include_dirs != nil {
+		includeDirs = append(includeDirs, android.PathsForModuleSrc(
+			ctx, library.Properties.Llndk.Override_export_include_dirs).Strings()...)
+	} else {
+		includeDirs = append(includeDirs, library.flagExporter.exportedIncludes(ctx).Strings()...)
+		// Ignore library.sabi.Properties.ReexportedIncludes because
+		// LLNDK does not reexport the implementation's dependencies, such as export_header_libs.
+	}
+
+	systemIncludeDirs = append(systemIncludeDirs,
+		library.flagExporter.exportedSystemIncludes(ctx).Strings()...)
+	if Bool(library.Properties.Llndk.Export_headers_as_system) {
+		systemIncludeDirs = append(systemIncludeDirs, includeDirs...)
+		includeDirs = nil
+	}
+	// Header libs.
+	includeDirs = append(includeDirs, deps.LlndkIncludeDirs.Strings()...)
+	systemIncludeDirs = append(systemIncludeDirs, deps.LlndkSystemIncludeDirs.Strings()...)
+	// The ABI checker does not distinguish normal and system headers.
+	return append(includeDirs, systemIncludeDirs...)
+}
+
+func (library *libraryDecorator) linkLlndkSAbiDumpFiles(ctx ModuleContext,
+	deps PathDeps, sAbiDumpFiles android.Paths, soFile android.Path, libFileName string,
+	excludeSymbolVersions, excludeSymbolTags []string,
+	vendorApiLevel string) android.Path {
+	// NDK symbols in version 34 are LLNDK symbols. Those in version 35 are not.
+	return transformDumpToLinkedDump(ctx,
+		sAbiDumpFiles, soFile, libFileName+".llndk",
+		library.llndkIncludeDirsForAbiCheck(ctx, deps),
+		android.OptionalPathForModuleSrc(ctx, library.Properties.Llndk.Symbol_file),
+		append([]string{"*_PLATFORM", "*_PRIVATE"}, excludeSymbolVersions...),
+		append([]string{"platform-only"}, excludeSymbolTags...),
+		[]string{"llndk=" + vendorApiLevel}, "34", true /* isLlndk */)
+}
+
+func (library *libraryDecorator) linkApexSAbiDumpFiles(ctx ModuleContext,
+	deps PathDeps, sAbiDumpFiles android.Paths, soFile android.Path, libFileName string,
+	excludeSymbolVersions, excludeSymbolTags []string,
+	sdkVersion string) android.Path {
+	return transformDumpToLinkedDump(ctx,
+		sAbiDumpFiles, soFile, libFileName+".apex",
+		library.exportedIncludeDirsForAbiCheck(ctx),
+		android.OptionalPathForModuleSrc(ctx, library.Properties.Stubs.Symbol_file),
+		append([]string{"*_PLATFORM", "*_PRIVATE"}, excludeSymbolVersions...),
+		append([]string{"platform-only"}, excludeSymbolTags...),
+		[]string{"apex", "systemapi"}, sdkVersion, false /* isLlndk */)
+}
+
 func getRefAbiDumpFile(ctx android.ModuleInstallPathContext,
 	versionedDumpDir, fileName string) android.OptionalPath {
 
@@ -1883,42 +1288,29 @@
 		fileName+".lsdump")
 }
 
-func getRefAbiDumpDir(isNdk, isVndk bool) string {
-	var dirName string
-	if isNdk {
-		dirName = "ndk"
-	} else if isVndk {
-		dirName = "vndk"
-	} else {
-		dirName = "platform"
-	}
-	return filepath.Join("prebuilts", "abi-dumps", dirName)
-}
-
-func prevRefAbiDumpVersion(ctx ModuleContext, dumpDir string) int {
+// Return the previous and current SDK versions for cross-version ABI diff.
+func crossVersionAbiDiffSdkVersions(ctx ModuleContext, dumpDir string) (int, int) {
 	sdkVersionInt := ctx.Config().PlatformSdkVersion().FinalInt()
-	sdkVersionStr := ctx.Config().PlatformSdkVersion().String()
 
 	if ctx.Config().PlatformSdkFinal() {
-		return sdkVersionInt - 1
+		return sdkVersionInt - 1, sdkVersionInt
 	} else {
 		// The platform SDK version can be upgraded before finalization while the corresponding abi dumps hasn't
 		// been generated. Thus the Cross-Version Check chooses PLATFORM_SDK_VERION - 1 as previous version.
 		// This situation could be identified by checking the existence of the PLATFORM_SDK_VERION dump directory.
-		versionedDumpDir := android.ExistentPathForSource(ctx, dumpDir, sdkVersionStr)
+		versionedDumpDir := android.ExistentPathForSource(ctx,
+			dumpDir, ctx.Config().PlatformSdkVersion().String())
 		if versionedDumpDir.Valid() {
-			return sdkVersionInt
+			return sdkVersionInt, sdkVersionInt + 1
 		} else {
-			return sdkVersionInt - 1
+			return sdkVersionInt - 1, sdkVersionInt
 		}
 	}
 }
 
-func currRefAbiDumpVersion(ctx ModuleContext, isVndk bool) string {
-	if isVndk {
-		// Each version of VNDK is independent, so follow the VNDK version which is the codename or PLATFORM_SDK_VERSION.
-		return ctx.Module().(*Module).VndkVersion()
-	} else if ctx.Config().PlatformSdkFinal() {
+// Return the SDK version for same-version ABI diff.
+func currRefAbiDumpSdkVersion(ctx ModuleContext) string {
+	if ctx.Config().PlatformSdkFinal() {
 		// After sdk finalization, the ABI of the latest API level must be consistent with the source code,
 		// so choose PLATFORM_SDK_VERSION as the current version.
 		return ctx.Config().PlatformSdkVersion().String()
@@ -1928,12 +1320,11 @@
 }
 
 // sourceAbiDiff registers a build statement to compare linked sAbi dump files (.lsdump).
-func (library *libraryDecorator) sourceAbiDiff(ctx android.ModuleContext, referenceDump android.Path,
+func (library *libraryDecorator) sourceAbiDiff(ctx android.ModuleContext,
+	sourceDump, referenceDump android.Path,
 	baseName, nameExt string, isLlndkOrNdk, allowExtensions bool,
 	sourceVersion, errorMessage string) {
 
-	sourceDump := library.sAbiOutputFile.Path()
-
 	extraFlags := []string{"-target-version", sourceVersion}
 	headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx)
 	if Bool(headerAbiChecker.Check_all_apis) {
@@ -1957,27 +1348,30 @@
 			baseName, nameExt, extraFlags, errorMessage))
 }
 
-func (library *libraryDecorator) crossVersionAbiDiff(ctx android.ModuleContext, referenceDump android.Path,
+func (library *libraryDecorator) crossVersionAbiDiff(ctx android.ModuleContext,
+	sourceDump, referenceDump android.Path,
 	baseName string, isLlndkOrNdk bool, sourceVersion, prevVersion string) {
 
-	errorMessage := "error: Please follow https://android.googlesource.com/platform/development/+/master/vndk/tools/header-checker/README.md#configure-cross_version-abi-check to resolve the ABI difference between your source code and version " + prevVersion + "."
+	errorMessage := "error: Please follow https://android.googlesource.com/platform/development/+/main/vndk/tools/header-checker/README.md#configure-cross_version-abi-check to resolve the ABI difference between your source code and version " + prevVersion + "."
 
-	library.sourceAbiDiff(ctx, referenceDump, baseName, prevVersion,
+	library.sourceAbiDiff(ctx, sourceDump, referenceDump, baseName, prevVersion,
 		isLlndkOrNdk, true /* allowExtensions */, sourceVersion, errorMessage)
 }
 
-func (library *libraryDecorator) sameVersionAbiDiff(ctx android.ModuleContext, referenceDump android.Path,
-	baseName string, isLlndkOrNdk, allowExtensions bool) {
+func (library *libraryDecorator) sameVersionAbiDiff(ctx android.ModuleContext,
+	sourceDump, referenceDump android.Path,
+	baseName, nameExt string, isLlndkOrNdk bool) {
 
 	libName := strings.TrimSuffix(baseName, filepath.Ext(baseName))
 	errorMessage := "error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l " + libName
 
-	library.sourceAbiDiff(ctx, referenceDump, baseName, "",
-		isLlndkOrNdk, allowExtensions, "current", errorMessage)
+	library.sourceAbiDiff(ctx, sourceDump, referenceDump, baseName, nameExt,
+		isLlndkOrNdk, false /* allowExtensions */, "current", errorMessage)
 }
 
-func (library *libraryDecorator) optInAbiDiff(ctx android.ModuleContext, referenceDump android.Path,
-	baseName, nameExt string, isLlndkOrNdk bool, refDumpDir string) {
+func (library *libraryDecorator) optInAbiDiff(ctx android.ModuleContext,
+	sourceDump, referenceDump android.Path,
+	baseName, nameExt string, refDumpDir string) {
 
 	libName := strings.TrimSuffix(baseName, filepath.Ext(baseName))
 	errorMessage := "error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py -l " + libName + " -ref-dump-dir $$ANDROID_BUILD_TOP/" + refDumpDir
@@ -1986,54 +1380,116 @@
 		errorMessage += " -products " + ctx.Config().DeviceProduct()
 	}
 
-	library.sourceAbiDiff(ctx, referenceDump, baseName, nameExt,
-		isLlndkOrNdk, false /* allowExtensions */, "current", errorMessage)
+	library.sourceAbiDiff(ctx, sourceDump, referenceDump, baseName, nameExt,
+		false /* isLlndkOrNdk */, false /* allowExtensions */, "current", errorMessage)
 }
 
-func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
+func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathDeps, objs Objects, fileName string, soFile android.Path) {
 	if library.sabi.shouldCreateSourceAbiDump() {
-		exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
-		var SourceAbiFlags []string
-		for _, dir := range exportIncludeDirs.Strings() {
-			SourceAbiFlags = append(SourceAbiFlags, "-I"+dir)
-		}
-		for _, reexportedInclude := range library.sabi.Properties.ReexportedIncludes {
-			SourceAbiFlags = append(SourceAbiFlags, "-I"+reexportedInclude)
-		}
-		exportedHeaderFlags := strings.Join(SourceAbiFlags, " ")
+		exportedIncludeDirs := library.exportedIncludeDirsForAbiCheck(ctx)
 		headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx)
-		library.sAbiOutputFile = transformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedHeaderFlags,
+		currSdkVersion := currRefAbiDumpSdkVersion(ctx)
+		currVendorVersion := ctx.Config().VendorApiLevel()
+
+		// Generate source dumps.
+		implDump := transformDumpToLinkedDump(ctx,
+			objs.sAbiDumpFiles, soFile, fileName,
+			exportedIncludeDirs,
 			android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)),
 			headerAbiChecker.Exclude_symbol_versions,
-			headerAbiChecker.Exclude_symbol_tags)
+			headerAbiChecker.Exclude_symbol_tags,
+			[]string{} /* includeSymbolTags */, currSdkVersion, false /* isLlndk */)
 
-		addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())
+		var llndkDump, apexVariantDump android.Path
+		tags := classifySourceAbiDump(ctx)
+		for _, tag := range tags {
+			if tag == llndkLsdumpTag && currVendorVersion != "" {
+				if llndkDump == nil {
+					// TODO(b/323447559): Evaluate if replacing sAbiDumpFiles with implDump is faster
+					llndkDump = library.linkLlndkSAbiDumpFiles(ctx,
+						deps, objs.sAbiDumpFiles, soFile, fileName,
+						headerAbiChecker.Exclude_symbol_versions,
+						headerAbiChecker.Exclude_symbol_tags,
+						currVendorVersion)
+				}
+				addLsdumpPath(string(tag) + ":" + llndkDump.String())
+			} else if tag == apexLsdumpTag {
+				if apexVariantDump == nil {
+					apexVariantDump = library.linkApexSAbiDumpFiles(ctx,
+						deps, objs.sAbiDumpFiles, soFile, fileName,
+						headerAbiChecker.Exclude_symbol_versions,
+						headerAbiChecker.Exclude_symbol_tags,
+						currSdkVersion)
+				}
+				addLsdumpPath(string(tag) + ":" + apexVariantDump.String())
+			} else {
+				addLsdumpPath(string(tag) + ":" + implDump.String())
+			}
+		}
 
-		// The logic must be consistent with classifySourceAbiDump.
-		isVndk := ctx.useVndk() && ctx.isVndk()
-		isNdk := ctx.isNdk(ctx.Config())
-		isLlndk := ctx.isImplementationForLLNDKPublic()
-		dumpDir := getRefAbiDumpDir(isNdk, isVndk)
-		binderBitness := ctx.DeviceConfig().BinderBitness()
-		// If NDK or PLATFORM library, check against previous version ABI.
-		if !isVndk {
-			prevVersionInt := prevRefAbiDumpVersion(ctx, dumpDir)
-			prevVersion := strconv.Itoa(prevVersionInt)
+		// Diff source dumps and reference dumps.
+		for _, tag := range tags {
+			dumpDirName := tag.dirName()
+			if dumpDirName == "" {
+				continue
+			}
+			dumpDir := filepath.Join("prebuilts", "abi-dumps", dumpDirName)
+			isLlndk := (tag == llndkLsdumpTag)
+			isApex := (tag == apexLsdumpTag)
+			isNdk := (tag == ndkLsdumpTag)
+			binderBitness := ctx.DeviceConfig().BinderBitness()
+			nameExt := ""
+			if isLlndk {
+				nameExt = "llndk"
+			} else if isApex {
+				nameExt = "apex"
+			}
+			// Check against the previous version.
+			var prevVersion, currVersion string
+			sourceDump := implDump
+			// If this release config does not define VendorApiLevel, fall back to the old policy.
+			if isLlndk && currVendorVersion != "" {
+				prevVersion = ctx.Config().PrevVendorApiLevel()
+				currVersion = currVendorVersion
+				// LLNDK dumps are generated by different rules after trunk stable.
+				if android.IsTrunkStableVendorApiLevel(prevVersion) {
+					sourceDump = llndkDump
+				}
+			} else {
+				prevVersionInt, currVersionInt := crossVersionAbiDiffSdkVersions(ctx, dumpDir)
+				prevVersion = strconv.Itoa(prevVersionInt)
+				currVersion = strconv.Itoa(currVersionInt)
+				// APEX dumps are generated by different rules after trunk stable.
+				if isApex && prevVersionInt > 34 {
+					sourceDump = apexVariantDump
+				}
+			}
 			prevDumpDir := filepath.Join(dumpDir, prevVersion, binderBitness)
 			prevDumpFile := getRefAbiDumpFile(ctx, prevDumpDir, fileName)
 			if prevDumpFile.Valid() {
-				library.crossVersionAbiDiff(ctx, prevDumpFile.Path(),
-					fileName, isLlndk || isNdk,
-					strconv.Itoa(prevVersionInt+1), prevVersion)
+				library.crossVersionAbiDiff(ctx, sourceDump, prevDumpFile.Path(),
+					fileName, isLlndk || isNdk, currVersion, nameExt+prevVersion)
 			}
-		}
-		// Check against the current version.
-		currVersion := currRefAbiDumpVersion(ctx, isVndk)
-		currDumpDir := filepath.Join(dumpDir, currVersion, binderBitness)
-		currDumpFile := getRefAbiDumpFile(ctx, currDumpDir, fileName)
-		if currDumpFile.Valid() {
-			library.sameVersionAbiDiff(ctx, currDumpFile.Path(),
-				fileName, isLlndk || isNdk, ctx.IsVndkExt())
+			// Check against the current version.
+			sourceDump = implDump
+			if isLlndk && currVendorVersion != "" {
+				currVersion = currVendorVersion
+				if android.IsTrunkStableVendorApiLevel(currVersion) {
+					sourceDump = llndkDump
+				}
+			} else {
+				currVersion = currSdkVersion
+				if isApex && (!ctx.Config().PlatformSdkFinal() ||
+					ctx.Config().PlatformSdkVersion().FinalInt() > 34) {
+					sourceDump = apexVariantDump
+				}
+			}
+			currDumpDir := filepath.Join(dumpDir, currVersion, binderBitness)
+			currDumpFile := getRefAbiDumpFile(ctx, currDumpDir, fileName)
+			if currDumpFile.Valid() {
+				library.sameVersionAbiDiff(ctx, sourceDump, currDumpFile.Path(),
+					fileName, nameExt, isLlndk || isNdk)
+			}
 		}
 		// Check against the opt-in reference dumps.
 		for i, optInDumpDir := range headerAbiChecker.Ref_dump_dirs {
@@ -2044,9 +1500,9 @@
 			if !optInDumpFile.Valid() {
 				continue
 			}
-			library.optInAbiDiff(ctx, optInDumpFile.Path(),
-				fileName, "opt"+strconv.Itoa(i), isLlndk || isNdk,
-				optInDumpDirPath.String())
+			library.optInAbiDiff(ctx,
+				implDump, optInDumpFile.Path(),
+				fileName, "opt"+strconv.Itoa(i), optInDumpDirPath.String())
 		}
 	}
 }
@@ -2293,7 +1749,7 @@
 
 			// do not install vndk libs
 			// vndk libs are packaged into VNDK APEX
-			if ctx.isVndk() && !ctx.IsVndkExt() && !ctx.Config().IsVndkDeprecated() {
+			if ctx.isVndk() && !ctx.IsVndkExt() && !ctx.Config().IsVndkDeprecated() && !ctx.inProduct() {
 				return
 			}
 		} else if library.hasStubsVariants() && !ctx.Host() && ctx.directlyInAnyApex() {
@@ -2317,7 +1773,7 @@
 	}
 
 	if Bool(library.Properties.Static_ndk_lib) && library.static() &&
-		!ctx.useVndk() && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && ctx.Device() &&
+		!ctx.InVendorOrProduct() && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && ctx.Device() &&
 		library.baseLinker.sanitize.isUnsanitizedVariant() &&
 		ctx.isForPlatform() && !ctx.isPreventInstall() {
 		installPath := getUnversionedLibraryInstallPath(ctx).Join(ctx, file.Base())
@@ -2412,12 +1868,13 @@
 	if props := library.getHeaderAbiCheckerProperties(ctx); props.Symbol_file != nil {
 		return props.Symbol_file
 	}
-	if ctx.Module().(*Module).IsLlndk() {
-		return library.Properties.Llndk.Symbol_file
-	}
 	if library.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil {
 		return library.Properties.Stubs.Symbol_file
 	}
+	// TODO(b/309880485): Distinguish platform, NDK, LLNDK, and APEX version scripts.
+	if library.baseLinker.Properties.Version_script != nil {
+		return library.baseLinker.Properties.Version_script
+	}
 	return nil
 }
 
@@ -2437,13 +1894,16 @@
 		return nil
 	}
 
-	if library.hasLLNDKStubs() && ctx.Module().(*Module).UseVndk() {
-		// LLNDK libraries only need a single stubs variant.
-		return []string{android.FutureApiLevel.String()}
+	if library.hasLLNDKStubs() && ctx.Module().(*Module).InVendorOrProduct() {
+		// LLNDK libraries only need a single stubs variant (""), which is
+		// added automatically in createVersionVariations().
+		return nil
 	}
 
 	// Future API level is implicitly added if there isn't
-	return addCurrentVersionIfNotPresent(library.Properties.Stubs.Versions)
+	versions := addCurrentVersionIfNotPresent(library.Properties.Stubs.Versions)
+	normalizeVersions(ctx, versions)
+	return versions
 }
 
 func addCurrentVersionIfNotPresent(vers []string) []string {
@@ -2711,7 +2171,7 @@
 // normalizeVersions modifies `versions` in place, so that each raw version
 // string becomes its normalized canonical form.
 // Validates that the versions in `versions` are specified in least to greatest order.
-func normalizeVersions(ctx android.BazelConversionPathContext, versions []string) {
+func normalizeVersions(ctx android.BaseModuleContext, versions []string) {
 	var previous android.ApiLevel
 	for i, v := range versions {
 		ver, err := android.ApiLevelFromUser(ctx, v)
@@ -2815,10 +2275,6 @@
 		return
 	}
 	versions := library.stubsVersions(mctx)
-	if len(versions) <= 0 {
-		return
-	}
-	normalizeVersions(mctx, versions)
 	if mctx.Failed() {
 		return
 	}
@@ -2882,249 +2338,3 @@
 
 	return outputFile
 }
-
-func bp2buildParseAbiCheckerProps(ctx android.TopDownMutatorContext, module *Module) bazelCcHeaderAbiCheckerAttributes {
-	lib, ok := module.linker.(*libraryDecorator)
-	if !ok {
-		return bazelCcHeaderAbiCheckerAttributes{}
-	}
-
-	abiChecker := lib.getHeaderAbiCheckerProperties(ctx)
-
-	abiCheckerAttrs := bazelCcHeaderAbiCheckerAttributes{
-		Abi_checker_enabled:                 abiChecker.Enabled,
-		Abi_checker_exclude_symbol_versions: abiChecker.Exclude_symbol_versions,
-		Abi_checker_exclude_symbol_tags:     abiChecker.Exclude_symbol_tags,
-		Abi_checker_check_all_apis:          abiChecker.Check_all_apis,
-		Abi_checker_diff_flags:              abiChecker.Diff_flags,
-	}
-	if abiChecker.Symbol_file != nil {
-		symbolFile := android.BazelLabelForModuleSrcSingle(ctx, *abiChecker.Symbol_file)
-		abiCheckerAttrs.Abi_checker_symbol_file = &symbolFile
-	}
-
-	return abiCheckerAttrs
-}
-
-func sharedOrStaticLibraryBp2Build(ctx android.TopDownMutatorContext, module *Module, isStatic bool) {
-	baseAttributes := bp2BuildParseBaseProps(ctx, module)
-	compilerAttrs := baseAttributes.compilerAttributes
-	linkerAttrs := baseAttributes.linkerAttributes
-
-	exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, &compilerAttrs.includes)
-	includeAttrs := includesAttributes{
-		Export_includes:          exportedIncludes.Includes,
-		Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
-		Export_system_includes:   exportedIncludes.SystemIncludes,
-		Local_includes:           compilerAttrs.localIncludes,
-		Absolute_includes:        compilerAttrs.absoluteIncludes,
-	}
-
-	// Append shared/static{} stanza properties. These won't be specified on
-	// cc_library_* itself, but may be specified in cc_defaults that this module
-	// depends on.
-	libSharedOrStaticAttrs := bp2BuildParseLibProps(ctx, module, isStatic)
-
-	compilerAttrs.srcs.Append(libSharedOrStaticAttrs.Srcs)
-	compilerAttrs.cSrcs.Append(libSharedOrStaticAttrs.Srcs_c)
-	compilerAttrs.asSrcs.Append(libSharedOrStaticAttrs.Srcs_as)
-	compilerAttrs.copts.Append(libSharedOrStaticAttrs.Copts)
-
-	linkerAttrs.deps.Append(libSharedOrStaticAttrs.Deps)
-	linkerAttrs.implementationDeps.Append(libSharedOrStaticAttrs.Implementation_deps)
-	linkerAttrs.dynamicDeps.Append(libSharedOrStaticAttrs.Dynamic_deps)
-	linkerAttrs.implementationDynamicDeps.Append(libSharedOrStaticAttrs.Implementation_dynamic_deps)
-	linkerAttrs.systemDynamicDeps.Append(libSharedOrStaticAttrs.System_dynamic_deps)
-
-	asFlags := compilerAttrs.asFlags
-	if compilerAttrs.asSrcs.IsEmpty() {
-		// Skip asflags for BUILD file simplicity if there are no assembly sources.
-		asFlags = bazel.MakeStringListAttribute(nil)
-	}
-
-	features := baseAttributes.features.Clone().Append(libSharedOrStaticAttrs.Features)
-	features.DeduplicateAxesFromBase()
-
-	commonAttrs := staticOrSharedAttributes{
-		Srcs:    compilerAttrs.srcs,
-		Srcs_c:  compilerAttrs.cSrcs,
-		Srcs_as: compilerAttrs.asSrcs,
-		Copts:   compilerAttrs.copts,
-		Hdrs:    compilerAttrs.hdrs,
-
-		Deps:                              linkerAttrs.deps,
-		Implementation_deps:               linkerAttrs.implementationDeps,
-		Dynamic_deps:                      linkerAttrs.dynamicDeps,
-		Implementation_dynamic_deps:       linkerAttrs.implementationDynamicDeps,
-		Whole_archive_deps:                linkerAttrs.wholeArchiveDeps,
-		Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps,
-		System_dynamic_deps:               linkerAttrs.systemDynamicDeps,
-		sdkAttributes:                     bp2BuildParseSdkAttributes(module),
-		Runtime_deps:                      linkerAttrs.runtimeDeps,
-		Native_coverage:                   baseAttributes.Native_coverage,
-	}
-
-	module.convertTidyAttributes(ctx, &commonAttrs.tidyAttributes)
-
-	var attrs interface{}
-	if isStatic {
-		commonAttrs.Deps.Add(baseAttributes.protoDependency)
-		var alwayslink *bool
-		if _, ok := alwaysLinkLibraries[module.Name()]; ok && isStatic {
-			alwayslink = proptools.BoolPtr(true)
-		}
-		attrs = &bazelCcLibraryStaticAttributes{
-			staticOrSharedAttributes: commonAttrs,
-			Rtti:                     compilerAttrs.rtti,
-			Stl:                      compilerAttrs.stl,
-			Cpp_std:                  compilerAttrs.cppStd,
-			C_std:                    compilerAttrs.cStd,
-
-			includesAttributes: includeAttrs,
-
-			Cppflags:   compilerAttrs.cppFlags,
-			Conlyflags: compilerAttrs.conlyFlags,
-			Asflags:    asFlags,
-
-			Alwayslink: alwayslink,
-			Features:   *features,
-		}
-
-	} else {
-		commonAttrs.Dynamic_deps.Add(baseAttributes.protoDependency)
-
-		sharedLibAttrs := &bazelCcLibrarySharedAttributes{
-			staticOrSharedAttributes: commonAttrs,
-
-			Cppflags:   compilerAttrs.cppFlags,
-			Conlyflags: compilerAttrs.conlyFlags,
-			Asflags:    asFlags,
-
-			Linkopts:        linkerAttrs.linkopts,
-			Use_version_lib: linkerAttrs.useVersionLib,
-
-			Rtti:    compilerAttrs.rtti,
-			Stl:     compilerAttrs.stl,
-			Cpp_std: compilerAttrs.cppStd,
-			C_std:   compilerAttrs.cStd,
-
-			includesAttributes: includeAttrs,
-
-			Additional_linker_inputs: linkerAttrs.additionalLinkerInputs,
-
-			Strip: stripAttrsFromLinkerAttrs(&linkerAttrs),
-
-			Features: *features,
-
-			Stem:   compilerAttrs.stem,
-			Suffix: compilerAttrs.suffix,
-
-			bazelCcHeaderAbiCheckerAttributes: bp2buildParseAbiCheckerProps(ctx, module),
-
-			Fdo_profile: compilerAttrs.fdoProfile,
-		}
-		if compilerAttrs.stubsSymbolFile != nil && len(compilerAttrs.stubsVersions.Value) > 0 {
-			sharedLibAttrs.Stubs_symbol_file = compilerAttrs.stubsSymbolFile
-		}
-		attrs = sharedLibAttrs
-	}
-
-	var modType string
-	if isStatic {
-		modType = "cc_library_static"
-	} else {
-		modType = "cc_library_shared"
-		createStubsBazelTargetIfNeeded(ctx, module, compilerAttrs, exportedIncludes, baseAttributes)
-	}
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        modType,
-		Bzl_load_location: fmt.Sprintf("//build/bazel/rules/cc:%s.bzl", modType),
-	}
-
-	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name(), Tags: tags}, attrs)
-}
-
-type includesAttributes struct {
-	Export_includes          bazel.StringListAttribute
-	Export_absolute_includes bazel.StringListAttribute
-	Export_system_includes   bazel.StringListAttribute
-	Local_includes           bazel.StringListAttribute
-	Absolute_includes        bazel.StringListAttribute
-}
-
-// TODO(b/199902614): Can this be factored to share with the other Attributes?
-type bazelCcLibraryStaticAttributes struct {
-	staticOrSharedAttributes
-	includesAttributes
-
-	Use_version_lib bazel.BoolAttribute
-	Rtti            bazel.BoolAttribute
-	Stl             *string
-	Cpp_std         *string
-	C_std           *string
-
-	Hdrs bazel.LabelListAttribute
-
-	Cppflags   bazel.StringListAttribute
-	Conlyflags bazel.StringListAttribute
-	Asflags    bazel.StringListAttribute
-
-	Alwayslink *bool
-	Features   bazel.StringListAttribute
-}
-
-// TODO(b/199902614): Can this be factored to share with the other Attributes?
-type bazelCcLibrarySharedAttributes struct {
-	staticOrSharedAttributes
-	includesAttributes
-
-	Linkopts        bazel.StringListAttribute
-	Use_version_lib bazel.BoolAttribute
-
-	Rtti    bazel.BoolAttribute
-	Stl     *string
-	Cpp_std *string
-	C_std   *string
-
-	Hdrs bazel.LabelListAttribute
-
-	Strip                    stripAttributes
-	Additional_linker_inputs bazel.LabelListAttribute
-
-	Cppflags   bazel.StringListAttribute
-	Conlyflags bazel.StringListAttribute
-	Asflags    bazel.StringListAttribute
-
-	Features bazel.StringListAttribute
-
-	Stubs_symbol_file *string
-
-	Inject_bssl_hash bazel.BoolAttribute
-
-	Stem   bazel.StringAttribute
-	Suffix bazel.StringAttribute
-
-	bazelCcHeaderAbiCheckerAttributes
-
-	Fdo_profile bazel.LabelAttribute
-}
-
-type bazelCcStubSuiteAttributes struct {
-	Symbol_file          *string
-	Versions             bazel.StringListAttribute
-	Export_includes      bazel.StringListAttribute
-	Source_library_label *string
-	Soname               *string
-	Deps                 bazel.LabelListAttribute
-}
-
-type bazelCcHeaderAbiCheckerAttributes struct {
-	Abi_checker_enabled                 *bool
-	Abi_checker_symbol_file             *bazel.Label
-	Abi_checker_exclude_symbol_versions []string
-	Abi_checker_exclude_symbol_tags     []string
-	Abi_checker_check_all_apis          *bool
-	Abi_checker_diff_flags              []string
-}
diff --git a/cc/library_headers.go b/cc/library_headers.go
index ce9c4aa..98533b2 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -15,11 +15,7 @@
 package cc
 
 import (
-	"github.com/google/blueprint/proptools"
-
 	"android/soong/android"
-	"android/soong/bazel"
-	"android/soong/bazel/cquery"
 )
 
 func init() {
@@ -50,52 +46,6 @@
 	ctx.RegisterModuleType("cc_prebuilt_library_headers", prebuiltLibraryHeaderFactory)
 }
 
-type libraryHeaderBazelHandler struct {
-	module  *Module
-	library *libraryDecorator
-}
-
-var _ BazelHandler = (*libraryHeaderBazelHandler)(nil)
-
-func (handler *libraryHeaderBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
-}
-
-func (h *libraryHeaderBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-		return
-	}
-
-	outputPaths := ccInfo.OutputFiles
-	if len(outputPaths) != 1 {
-		ctx.ModuleErrorf("expected exactly one output file for %q, but got %q", label, outputPaths)
-		return
-	}
-
-	var outputPath android.Path = android.PathForBazelOut(ctx, outputPaths[0])
-	if len(ccInfo.TidyFiles) > 0 {
-		h.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles)
-		outputPath = android.AttachValidationActions(ctx, outputPath, h.module.tidyFiles)
-	}
-	h.module.outputFile = android.OptionalPathForPath(outputPath)
-
-	// HeaderLibraryInfo is an empty struct to indicate to dependencies that this is a header library
-	ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{})
-
-	h.library.setFlagExporterInfoFromCcInfo(ctx, ccInfo)
-
-	// Dependencies on this library will expect collectedSnapshotHeaders to be set, otherwise
-	// validation will fail. For now, set this to an empty list.
-	// TODO(cparsons): More closely mirror the collectHeadersForSnapshot implementation.
-	h.library.collectedSnapshotHeaders = android.Paths{}
-
-	h.module.setAndroidMkVariablesFromCquery(ccInfo.CcAndroidMkInfo)
-}
-
 // cc_library_headers contains a set of c/c++ headers which are imported by
 // other soong cc modules using the header_libs property. For best practices,
 // use export_include_dirs property or LOCAL_EXPORT_C_INCLUDE_DIRS for
@@ -104,8 +54,6 @@
 	module, library := NewLibrary(android.HostAndDeviceSupported)
 	library.HeaderOnly()
 	module.sdkMemberTypes = []android.SdkMemberType{headersLibrarySdkMemberType}
-	module.bazelable = true
-	module.bazelHandler = &libraryHeaderBazelHandler{module: module, library: library}
 	return module.Init()
 }
 
@@ -113,163 +61,5 @@
 func prebuiltLibraryHeaderFactory() android.Module {
 	module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported, "")
 	library.HeaderOnly()
-	module.bazelable = true
-	module.bazelHandler = &ccLibraryBazelHandler{module: module}
 	return module.Init()
 }
-
-type bazelCcLibraryHeadersAttributes struct {
-	Hdrs                     bazel.LabelListAttribute
-	Export_includes          bazel.StringListAttribute
-	Export_absolute_includes bazel.StringListAttribute
-	Export_system_includes   bazel.StringListAttribute
-	Deps                     bazel.LabelListAttribute
-	Implementation_deps      bazel.LabelListAttribute
-	System_dynamic_deps      bazel.LabelListAttribute
-	sdkAttributes
-}
-
-func libraryHeadersBp2Build(ctx android.TopDownMutatorContext, module *Module) {
-	baseAttributes := bp2BuildParseBaseProps(ctx, module)
-	exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, &baseAttributes.includes)
-	linkerAttrs := baseAttributes.linkerAttributes
-	(&linkerAttrs.deps).Append(linkerAttrs.dynamicDeps)
-	(&linkerAttrs.deps).Append(linkerAttrs.wholeArchiveDeps)
-
-	attrs := &bazelCcLibraryHeadersAttributes{
-		Export_includes:          exportedIncludes.Includes,
-		Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
-		Export_system_includes:   exportedIncludes.SystemIncludes,
-		Deps:                     linkerAttrs.deps,
-		System_dynamic_deps:      linkerAttrs.systemDynamicDeps,
-		Hdrs:                     baseAttributes.hdrs,
-		sdkAttributes:            bp2BuildParseSdkAttributes(module),
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_library_headers",
-		Bzl_load_location: "//build/bazel/rules/cc:cc_library_headers.bzl",
-	}
-
-	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-		Name: module.Name(),
-		Tags: tags,
-	}, attrs)
-}
-
-// Append .contribution suffix to input labels
-func apiBazelTargets(ll bazel.LabelList) bazel.LabelList {
-	labels := make([]bazel.Label, 0)
-	for _, l := range ll.Includes {
-		labels = append(labels, bazel.Label{
-			Label: android.ApiContributionTargetName(l.Label),
-		})
-	}
-	return bazel.MakeLabelList(labels)
-}
-
-func apiLibraryHeadersBp2Build(ctx android.TopDownMutatorContext, module *Module) {
-	// cc_api_library_headers have a 1:1 mapping to arch/no-arch
-	// For API export, create a top-level arch-agnostic target and list the arch-specific targets as its deps
-
-	// arch-agnostic includes
-	apiIncludes := getModuleLibApiIncludes(ctx, module)
-	// arch and os specific includes
-	archApiIncludes, androidOsIncludes := archOsSpecificApiIncludes(ctx, module)
-	for _, arch := range allArches { // sorted iteration
-		archApiInclude := archApiIncludes[arch]
-		if !archApiInclude.isEmpty() {
-			createApiHeaderTarget(ctx, archApiInclude)
-			apiIncludes.addDep(archApiInclude.name)
-		}
-	}
-	// os==android includes
-	if !androidOsIncludes.isEmpty() {
-		createApiHeaderTarget(ctx, androidOsIncludes)
-		apiIncludes.addDep(androidOsIncludes.name)
-	}
-
-	if !apiIncludes.isEmpty() {
-		// override the name from <mod>.module-libapi.headers --> <mod>.contribution
-		apiIncludes.name = android.ApiContributionTargetName(module.Name())
-		createApiHeaderTarget(ctx, apiIncludes)
-	}
-}
-
-func createApiHeaderTarget(ctx android.TopDownMutatorContext, includes apiIncludes) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_api_library_headers",
-		Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl",
-	}
-	ctx.CreateBazelTargetModule(
-		props,
-		android.CommonAttributes{
-			Name:     includes.name,
-			SkipData: proptools.BoolPtr(true),
-		},
-		&includes.attrs,
-	)
-}
-
-var (
-	allArches = []string{"arm", "arm64", "x86", "x86_64"}
-)
-
-type archApiIncludes map[string]apiIncludes
-
-func archOsSpecificApiIncludes(ctx android.TopDownMutatorContext, module *Module) (archApiIncludes, apiIncludes) {
-	baseProps := bp2BuildParseBaseProps(ctx, module)
-	i := bp2BuildParseExportedIncludes(ctx, module, &baseProps.includes)
-	archRet := archApiIncludes{}
-	for _, arch := range allArches {
-		includes := i.Includes.SelectValue(
-			bazel.ArchConfigurationAxis,
-			arch)
-		systemIncludes := i.SystemIncludes.SelectValue(
-			bazel.ArchConfigurationAxis,
-			arch)
-		deps := baseProps.deps.SelectValue(
-			bazel.ArchConfigurationAxis,
-			arch)
-		attrs := bazelCcLibraryHeadersAttributes{
-			Export_includes:        bazel.MakeStringListAttribute(includes),
-			Export_system_includes: bazel.MakeStringListAttribute(systemIncludes),
-		}
-		apiDeps := apiBazelTargets(deps)
-		if !apiDeps.IsEmpty() {
-			attrs.Deps = bazel.MakeLabelListAttribute(apiDeps)
-		}
-		apiIncludes := apiIncludes{
-			name: android.ApiContributionTargetName(module.Name()) + "." + arch,
-			attrs: bazelCcApiLibraryHeadersAttributes{
-				bazelCcLibraryHeadersAttributes: attrs,
-				Arch:                            proptools.StringPtr(arch),
-			},
-		}
-		archRet[arch] = apiIncludes
-	}
-
-	// apiIncludes for os == Android
-	androidOsDeps := baseProps.deps.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid)
-	androidOsAttrs := bazelCcLibraryHeadersAttributes{
-		Export_includes: bazel.MakeStringListAttribute(
-			i.Includes.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid),
-		),
-		Export_system_includes: bazel.MakeStringListAttribute(
-			i.SystemIncludes.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid),
-		),
-	}
-	androidOsApiDeps := apiBazelTargets(androidOsDeps)
-	if !androidOsApiDeps.IsEmpty() {
-		androidOsAttrs.Deps = bazel.MakeLabelListAttribute(androidOsApiDeps)
-	}
-	osRet := apiIncludes{
-		name: android.ApiContributionTargetName(module.Name()) + ".androidos",
-		attrs: bazelCcApiLibraryHeadersAttributes{
-			bazelCcLibraryHeadersAttributes: androidOsAttrs,
-		},
-	}
-	return archRet, osRet
-}
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index e743bb6..a65b1ba 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -251,16 +251,9 @@
 	return &nativeLibInfoProperties{memberType: mt}
 }
 
-func isBazelOutDirectory(p android.Path) bool {
-	_, bazel := p.(android.BazelOutPath)
-	return bazel
-}
-
 func isGeneratedHeaderDirectory(p android.Path) bool {
 	_, gen := p.(android.WritablePath)
-	// TODO(b/183213331): Here we assume that bazel-based headers are not generated; we need
-	// to support generated headers in mixed builds.
-	return gen && !isBazelOutDirectory(p)
+	return gen
 }
 
 type includeDirsProperty struct {
@@ -518,7 +511,7 @@
 		}
 	}
 
-	exportedInfo := ctx.SdkModuleContext().OtherModuleProvider(variant, FlagExporterInfoProvider).(FlagExporterInfo)
+	exportedInfo, _ := android.OtherModuleProvider(ctx.SdkModuleContext(), variant, FlagExporterInfoProvider)
 
 	// Separate out the generated include dirs (which are arch specific) from the
 	// include dirs (which may not be).
diff --git a/cc/library_stub.go b/cc/library_stub.go
index 18d3f21..cddb1b5 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -48,7 +48,7 @@
 		return
 	}
 
-	if m.UseVndk() && apiLibrary.hasLLNDKStubs() {
+	if m.InVendorOrProduct() && apiLibrary.hasLLNDKStubs() {
 		// Add LLNDK variant dependency
 		if inList("llndk", apiLibrary.properties.Variants) {
 			variantName := BuildApiVariantName(m.BaseModuleName(), "llndk", "")
@@ -193,7 +193,7 @@
 		}
 	}
 
-	if m.UseVndk() && d.hasLLNDKStubs() {
+	if m.InVendorOrProduct() && d.hasLLNDKStubs() {
 		// LLNDK variant
 		load_cc_variant(BuildApiVariantName(m.BaseModuleName(), "llndk", ""))
 	} else if m.IsSdkVariant() {
@@ -244,7 +244,7 @@
 		},
 	})
 
-	ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+	android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
 		SharedLibrary: outputFile,
 		Target:        ctx.Target(),
 
@@ -262,15 +262,15 @@
 	if len(stubs) > 0 {
 		var stubsInfo []SharedStubLibrary
 		for _, stub := range stubs {
-			stubInfo := ctx.OtherModuleProvider(stub, SharedLibraryInfoProvider).(SharedLibraryInfo)
-			flagInfo := ctx.OtherModuleProvider(stub, FlagExporterInfoProvider).(FlagExporterInfo)
+			stubInfo, _ := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider)
+			flagInfo, _ := android.OtherModuleProvider(ctx, stub, FlagExporterInfoProvider)
 			stubsInfo = append(stubsInfo, SharedStubLibrary{
 				Version:           moduleLibraryInterface(stub).stubsVersion(),
 				SharedLibraryInfo: stubInfo,
 				FlagExporterInfo:  flagInfo,
 			})
 		}
-		ctx.SetProvider(SharedLibraryStubsProvider, SharedLibraryStubsInfo{
+		android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{
 			SharedStubLibraries: stubsInfo,
 
 			IsLLNDK: ctx.IsLlndk(),
@@ -312,7 +312,7 @@
 		}
 	}
 
-	if d.hasLLNDKStubs() && m.UseVndk() {
+	if d.hasLLNDKStubs() && m.InVendorOrProduct() {
 		// LLNDK libraries only need a single stubs variant.
 		return []string{android.FutureApiLevel.String()}
 	}
@@ -496,11 +496,10 @@
 func (v *CcApiVariant) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool      { return false }
 func (v *CcApiVariant) ExtraImageVariations(ctx android.BaseModuleContext) []string {
 	var variations []string
-	platformVndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
 
 	if String(v.properties.Variant) == "llndk" {
-		variations = append(variations, VendorVariationPrefix+platformVndkVersion)
-		variations = append(variations, ProductVariationPrefix+platformVndkVersion)
+		variations = append(variations, VendorVariation)
+		variations = append(variations, ProductVariation)
 	}
 
 	return variations
diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go
deleted file mode 100644
index 528577a..0000000
--- a/cc/library_stub_test.go
+++ /dev/null
@@ -1,459 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cc
-
-import (
-	_ "fmt"
-	_ "sort"
-
-	"testing"
-
-	"android/soong/android"
-
-	"github.com/google/blueprint"
-)
-
-func hasDirectDependency(t *testing.T, ctx *android.TestResult, from android.Module, to android.Module) bool {
-	t.Helper()
-	var found bool
-	ctx.VisitDirectDeps(from, func(dep blueprint.Module) {
-		if dep == to {
-			found = true
-		}
-	})
-	return found
-}
-
-func TestApiLibraryReplacesExistingModule(t *testing.T) {
-	bp := `
-		cc_library {
-			name: "libfoo",
-			shared_libs: ["libbar"],
-			vendor_available: true,
-		}
-
-		cc_library {
-			name: "libbar",
-		}
-
-		cc_api_library {
-			name: "libbar",
-			vendor_available: true,
-			src: "libbar.so",
-		}
-
-		api_imports {
-			name: "api_imports",
-			shared_libs: [
-				"libbar",
-			],
-		}
-	`
-
-	ctx := prepareForCcTest.RunTestWithBp(t, bp)
-
-	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
-	libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module()
-	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_shared").Module()
-
-	android.AssertBoolEquals(t, "original library should be linked with non-stub variant", true, hasDirectDependency(t, ctx, libfoo, libbar))
-	android.AssertBoolEquals(t, "Stub library from API surface should be not linked with non-stub variant", false, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
-
-	libfooVendor := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_shared").Module()
-	libbarApiImportVendor := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
-
-	android.AssertBoolEquals(t, "original library should not be linked", false, hasDirectDependency(t, ctx, libfooVendor, libbar))
-	android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfooVendor, libbarApiImportVendor))
-}
-
-func TestApiLibraryDoNotRequireOriginalModule(t *testing.T) {
-	bp := `
-		cc_library {
-			name: "libfoo",
-			shared_libs: ["libbar"],
-			vendor: true,
-		}
-
-		cc_api_library {
-			name: "libbar",
-			src: "libbar.so",
-			vendor_available: true,
-		}
-
-		api_imports {
-			name: "api_imports",
-			shared_libs: [
-				"libbar",
-			],
-		}
-	`
-
-	ctx := prepareForCcTest.RunTestWithBp(t, bp)
-
-	libfoo := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_shared").Module()
-	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
-
-	android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
-}
-
-func TestApiLibraryShouldNotReplaceWithoutApiImport(t *testing.T) {
-	bp := `
-		cc_library {
-			name: "libfoo",
-			shared_libs: ["libbar"],
-			vendor_available: true,
-		}
-
-		cc_library {
-			name: "libbar",
-			vendor_available: true,
-		}
-
-		cc_api_library {
-			name: "libbar",
-			src: "libbar.so",
-			vendor_available: true,
-		}
-
-		api_imports {
-			name: "api_imports",
-			shared_libs: [],
-		}
-	`
-
-	ctx := prepareForCcTest.RunTestWithBp(t, bp)
-
-	libfoo := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_shared").Module()
-	libbar := ctx.ModuleForTests("libbar", "android_vendor.29_arm64_armv8-a_shared").Module()
-	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
-
-	android.AssertBoolEquals(t, "original library should be linked", true, hasDirectDependency(t, ctx, libfoo, libbar))
-	android.AssertBoolEquals(t, "Stub library from API surface should not be linked", false, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
-}
-
-func TestExportDirFromStubLibrary(t *testing.T) {
-	bp := `
-		cc_library {
-			name: "libfoo",
-			export_include_dirs: ["source_include_dir"],
-			export_system_include_dirs: ["source_system_include_dir"],
-			vendor_available: true,
-		}
-		cc_api_library {
-			name: "libfoo",
-			export_include_dirs: ["stub_include_dir"],
-			export_system_include_dirs: ["stub_system_include_dir"],
-			vendor_available: true,
-			src: "libfoo.so",
-		}
-		api_imports {
-			name: "api_imports",
-			shared_libs: [
-				"libfoo",
-			],
-			header_libs: [],
-		}
-		// vendor binary
-		cc_binary {
-			name: "vendorbin",
-			vendor: true,
-			srcs: ["vendor.cc"],
-			shared_libs: ["libfoo"],
-		}
-	`
-	ctx := prepareForCcTest.RunTestWithBp(t, bp)
-	vendorCFlags := ctx.ModuleForTests("vendorbin", "android_vendor.29_arm64_armv8-a").Rule("cc").Args["cFlags"]
-	android.AssertStringDoesContain(t, "Vendor binary should compile using headers provided by stub", vendorCFlags, "-Istub_include_dir")
-	android.AssertStringDoesNotContain(t, "Vendor binary should not compile using headers of source", vendorCFlags, "-Isource_include_dir")
-	android.AssertStringDoesContain(t, "Vendor binary should compile using system headers provided by stub", vendorCFlags, "-isystem stub_system_include_dir")
-	android.AssertStringDoesNotContain(t, "Vendor binary should not compile using system headers of source", vendorCFlags, "-isystem source_system_include_dir")
-
-	vendorImplicits := ctx.ModuleForTests("vendorbin", "android_vendor.29_arm64_armv8-a").Rule("cc").OrderOnly.Strings()
-	// Building the stub.so file first assembles its .h files in multi-tree out.
-	// These header files are required for compiling the other API domain (vendor in this case)
-	android.AssertStringListContains(t, "Vendor binary compilation should have an implicit dep on the stub .so file", vendorImplicits, "libfoo.so")
-}
-
-func TestApiLibraryWithLlndkVariant(t *testing.T) {
-	bp := `
-		cc_binary {
-			name: "binfoo",
-			vendor: true,
-			srcs: ["binfoo.cc"],
-			shared_libs: ["libbar"],
-		}
-
-		cc_api_library {
-			name: "libbar",
-			// TODO(b/244244438) Remove src property once all variants are implemented.
-			src: "libbar.so",
-			vendor_available: true,
-			variants: [
-				"llndk",
-			],
-		}
-
-		cc_api_variant {
-			name: "libbar",
-			variant: "llndk",
-			src: "libbar_llndk.so",
-			export_include_dirs: ["libbar_llndk_include"]
-		}
-
-		api_imports {
-			name: "api_imports",
-			shared_libs: [
-				"libbar",
-			],
-			header_libs: [],
-		}
-	`
-
-	ctx := prepareForCcTest.RunTestWithBp(t, bp)
-
-	binfoo := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Module()
-	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
-	libbarApiVariant := ctx.ModuleForTests("libbar.llndk.apiimport", "android_vendor.29_arm64_armv8-a").Module()
-
-	android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, binfoo, libbarApiImport))
-	android.AssertBoolEquals(t, "Stub library variant from API surface should be linked", true, hasDirectDependency(t, ctx, libbarApiImport, libbarApiVariant))
-
-	binFooLibFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("ld").Args["libFlags"]
-	android.AssertStringDoesContain(t, "Vendor binary should be linked with LLNDK variant source", binFooLibFlags, "libbar.llndk.apiimport.so")
-
-	binFooCFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("cc").Args["cFlags"]
-	android.AssertStringDoesContain(t, "Vendor binary should include headers from the LLNDK variant source", binFooCFlags, "-Ilibbar_llndk_include")
-}
-
-func TestApiLibraryWithNdkVariant(t *testing.T) {
-	bp := `
-		cc_binary {
-			name: "binfoo",
-			sdk_version: "29",
-			srcs: ["binfoo.cc"],
-			shared_libs: ["libbar"],
-			stl: "c++_shared",
-		}
-
-		cc_binary {
-			name: "binbaz",
-			sdk_version: "30",
-			srcs: ["binbaz.cc"],
-			shared_libs: ["libbar"],
-			stl: "c++_shared",
-		}
-
-		cc_binary {
-			name: "binqux",
-			srcs: ["binfoo.cc"],
-			shared_libs: ["libbar"],
-		}
-
-		cc_library {
-			name: "libbar",
-			srcs: ["libbar.cc"],
-		}
-
-		cc_api_library {
-			name: "libbar",
-			// TODO(b/244244438) Remove src property once all variants are implemented.
-			src: "libbar.so",
-			variants: [
-				"ndk.29",
-				"ndk.30",
-				"ndk.current",
-			],
-		}
-
-		cc_api_variant {
-			name: "libbar",
-			variant: "ndk",
-			version: "29",
-			src: "libbar_ndk_29.so",
-			export_include_dirs: ["libbar_ndk_29_include"]
-		}
-
-		cc_api_variant {
-			name: "libbar",
-			variant: "ndk",
-			version: "30",
-			src: "libbar_ndk_30.so",
-			export_include_dirs: ["libbar_ndk_30_include"]
-		}
-
-		cc_api_variant {
-			name: "libbar",
-			variant: "ndk",
-			version: "current",
-			src: "libbar_ndk_current.so",
-			export_include_dirs: ["libbar_ndk_current_include"]
-		}
-
-		api_imports {
-			name: "api_imports",
-			shared_libs: [
-				"libbar",
-			],
-			header_libs: [],
-		}
-	`
-
-	ctx := prepareForCcTest.RunTestWithBp(t, bp)
-
-	binfoo := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Module()
-	libbarApiImportv29 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_29").Module()
-	libbarApiVariantv29 := ctx.ModuleForTests("libbar.ndk.29.apiimport", "android_arm64_armv8-a_sdk").Module()
-	libbarApiImportv30 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_30").Module()
-	libbarApiVariantv30 := ctx.ModuleForTests("libbar.ndk.30.apiimport", "android_arm64_armv8-a_sdk").Module()
-
-	android.AssertBoolEquals(t, "Stub library from API surface should be linked with target version", true, hasDirectDependency(t, ctx, binfoo, libbarApiImportv29))
-	android.AssertBoolEquals(t, "Stub library variant from API surface should be linked with target version", true, hasDirectDependency(t, ctx, libbarApiImportv29, libbarApiVariantv29))
-	android.AssertBoolEquals(t, "Stub library from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, binfoo, libbarApiImportv30))
-	android.AssertBoolEquals(t, "Stub library variant from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, libbarApiImportv29, libbarApiVariantv30))
-
-	binbaz := ctx.ModuleForTests("binbaz", "android_arm64_armv8-a_sdk").Module()
-
-	android.AssertBoolEquals(t, "Stub library from API surface should be linked with target version", true, hasDirectDependency(t, ctx, binbaz, libbarApiImportv30))
-	android.AssertBoolEquals(t, "Stub library from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, binbaz, libbarApiImportv29))
-
-	binFooLibFlags := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Rule("ld").Args["libFlags"]
-	android.AssertStringDoesContain(t, "Binary using sdk should be linked with NDK variant source", binFooLibFlags, "libbar.ndk.29.apiimport.so")
-
-	binFooCFlags := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Rule("cc").Args["cFlags"]
-	android.AssertStringDoesContain(t, "Binary using sdk should include headers from the NDK variant source", binFooCFlags, "-Ilibbar_ndk_29_include")
-
-	binQux := ctx.ModuleForTests("binqux", "android_arm64_armv8-a").Module()
-	android.AssertBoolEquals(t, "NDK Stub library from API surface should not be linked with nonSdk binary", false,
-		(hasDirectDependency(t, ctx, binQux, libbarApiImportv30) || hasDirectDependency(t, ctx, binQux, libbarApiImportv29)))
-}
-
-func TestApiLibraryWithMultipleVariants(t *testing.T) {
-	bp := `
-		cc_binary {
-			name: "binfoo",
-			sdk_version: "29",
-			srcs: ["binfoo.cc"],
-			shared_libs: ["libbar"],
-			stl: "c++_shared",
-		}
-
-		cc_binary {
-			name: "binbaz",
-			vendor: true,
-			srcs: ["binbaz.cc"],
-			shared_libs: ["libbar"],
-		}
-
-		cc_library {
-			name: "libbar",
-			srcs: ["libbar.cc"],
-		}
-
-		cc_api_library {
-			name: "libbar",
-			// TODO(b/244244438) Remove src property once all variants are implemented.
-			src: "libbar.so",
-			vendor_available: true,
-			variants: [
-				"llndk",
-				"ndk.29",
-				"ndk.30",
-				"ndk.current",
-				"apex.29",
-				"apex.30",
-				"apex.current",
-			],
-		}
-
-		cc_api_variant {
-			name: "libbar",
-			variant: "ndk",
-			version: "29",
-			src: "libbar_ndk_29.so",
-			export_include_dirs: ["libbar_ndk_29_include"]
-		}
-
-		cc_api_variant {
-			name: "libbar",
-			variant: "ndk",
-			version: "30",
-			src: "libbar_ndk_30.so",
-			export_include_dirs: ["libbar_ndk_30_include"]
-		}
-
-		cc_api_variant {
-			name: "libbar",
-			variant: "ndk",
-			version: "current",
-			src: "libbar_ndk_current.so",
-			export_include_dirs: ["libbar_ndk_current_include"]
-		}
-
-		cc_api_variant {
-			name: "libbar",
-			variant: "apex",
-			version: "29",
-			src: "libbar_apex_29.so",
-			export_include_dirs: ["libbar_apex_29_include"]
-		}
-
-		cc_api_variant {
-			name: "libbar",
-			variant: "apex",
-			version: "30",
-			src: "libbar_apex_30.so",
-			export_include_dirs: ["libbar_apex_30_include"]
-		}
-
-		cc_api_variant {
-			name: "libbar",
-			variant: "apex",
-			version: "current",
-			src: "libbar_apex_current.so",
-			export_include_dirs: ["libbar_apex_current_include"]
-		}
-
-		cc_api_variant {
-			name: "libbar",
-			variant: "llndk",
-			src: "libbar_llndk.so",
-			export_include_dirs: ["libbar_llndk_include"]
-		}
-
-		api_imports {
-			name: "api_imports",
-			shared_libs: [
-				"libbar",
-			],
-			apex_shared_libs: [
-				"libbar",
-			],
-		}
-	`
-	ctx := prepareForCcTest.RunTestWithBp(t, bp)
-
-	binfoo := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Module()
-	libbarApiImportv29 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_29").Module()
-	libbarApiImportLlndk := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
-
-	android.AssertBoolEquals(t, "Binary using SDK should be linked with API library from NDK variant", true, hasDirectDependency(t, ctx, binfoo, libbarApiImportv29))
-	android.AssertBoolEquals(t, "Binary using SDK should not be linked with API library from LLNDK variant", false, hasDirectDependency(t, ctx, binfoo, libbarApiImportLlndk))
-
-	binbaz := ctx.ModuleForTests("binbaz", "android_vendor.29_arm64_armv8-a").Module()
-
-	android.AssertBoolEquals(t, "Vendor binary should be linked with API library from LLNDK variant", true, hasDirectDependency(t, ctx, binbaz, libbarApiImportLlndk))
-	android.AssertBoolEquals(t, "Vendor binary should not be linked with API library from NDK variant", false, hasDirectDependency(t, ctx, binbaz, libbarApiImportv29))
-
-}
diff --git a/cc/library_test.go b/cc/library_test.go
index dbe2be8..2ed2d76 100644
--- a/cc/library_test.go
+++ b/cc/library_test.go
@@ -19,7 +19,6 @@
 	"testing"
 
 	"android/soong/android"
-	"android/soong/bazel/cquery"
 )
 
 func TestLibraryReuse(t *testing.T) {
@@ -246,137 +245,6 @@
 	testCcError(t, `"libfoo" .*: versions: "X" could not be parsed as an integer and is not a recognized codename`, bp)
 }
 
-func TestCcLibraryWithBazel(t *testing.T) {
-	t.Parallel()
-	bp := `
-cc_library {
-	name: "foo",
-	srcs: ["foo.cc"],
-	bazel_module: { label: "//foo/bar:bar" },
-}`
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.BazelContext = android.MockBazelContext{
-		OutputBaseDir: "outputbase",
-		LabelToCcInfo: map[string]cquery.CcInfo{
-			"//foo/bar:bar": cquery.CcInfo{
-				CcObjectFiles:        []string{"foo.o"},
-				Includes:             []string{"include"},
-				SystemIncludes:       []string{"system_include"},
-				Headers:              []string{"foo.h"},
-				RootDynamicLibraries: []string{"foo.so"},
-				UnstrippedOutput:     "foo_unstripped.so",
-			},
-			"//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{
-				CcObjectFiles:      []string{"foo.o"},
-				Includes:           []string{"include"},
-				SystemIncludes:     []string{"system_include"},
-				Headers:            []string{"foo.h"},
-				RootStaticArchives: []string{"foo.a"},
-			},
-		},
-	}
-	ctx := testCcWithConfig(t, config)
-
-	staticFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module()
-	outputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
-	}
-
-	expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.a"}
-	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
-
-	flagExporter := ctx.ModuleProvider(staticFoo, FlagExporterInfoProvider).(FlagExporterInfo)
-	android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
-	android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
-	android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders)
-	android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
-
-	sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
-	outputFiles, err = sharedFoo.(android.OutputFileProducer).OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_library outputfiles %s", err)
-	}
-	expectedOutputFiles = []string{"outputbase/execroot/__main__/foo.so"}
-	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
-
-	android.AssertStringEquals(t, "unstripped shared library", "outputbase/execroot/__main__/foo_unstripped.so", sharedFoo.(*Module).linker.unstrippedOutputFilePath().String())
-	flagExporter = ctx.ModuleProvider(sharedFoo, FlagExporterInfoProvider).(FlagExporterInfo)
-	android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
-	android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
-	android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders)
-	android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
-}
-
-func TestCcLibraryWithBazelValidations(t *testing.T) {
-	t.Parallel()
-	bp := `
-cc_library {
-	name: "foo",
-	srcs: ["foo.cc"],
-	bazel_module: { label: "//foo/bar:bar" },
-	tidy: true,
-}`
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.BazelContext = android.MockBazelContext{
-		OutputBaseDir: "outputbase",
-		LabelToCcInfo: map[string]cquery.CcInfo{
-			"//foo/bar:bar": cquery.CcInfo{
-				CcObjectFiles:        []string{"foo.o"},
-				Includes:             []string{"include"},
-				SystemIncludes:       []string{"system_include"},
-				Headers:              []string{"foo.h"},
-				RootDynamicLibraries: []string{"foo.so"},
-				UnstrippedOutput:     "foo_unstripped.so",
-			},
-			"//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{
-				CcObjectFiles:      []string{"foo.o"},
-				Includes:           []string{"include"},
-				SystemIncludes:     []string{"system_include"},
-				Headers:            []string{"foo.h"},
-				RootStaticArchives: []string{"foo.a"},
-				TidyFiles:          []string{"foo.c.tidy"},
-			},
-		},
-	}
-	ctx := android.GroupFixturePreparers(
-		prepareForCcTest,
-		android.FixtureMergeEnv(map[string]string{
-			"ALLOW_LOCAL_TIDY_TRUE": "1",
-		}),
-	).RunTestWithConfig(t, config).TestContext
-
-	staticFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module()
-	outputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
-	}
-
-	expectedOutputFiles := []string{"out/soong/.intermediates/foo/android_arm_armv7-a-neon_static/validated/foo.a"}
-	android.AssertPathsRelativeToTopEquals(t, "output files", expectedOutputFiles, outputFiles)
-
-	flagExporter := ctx.ModuleProvider(staticFoo, FlagExporterInfoProvider).(FlagExporterInfo)
-	android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
-	android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
-	android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders)
-	android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
-
-	sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
-	outputFiles, err = sharedFoo.(android.OutputFileProducer).OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_library outputfiles %s", err)
-	}
-	expectedOutputFiles = []string{"outputbase/execroot/__main__/foo.so"}
-	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
-
-	android.AssertStringEquals(t, "unstripped shared library", "outputbase/execroot/__main__/foo_unstripped.so", sharedFoo.(*Module).linker.unstrippedOutputFilePath().String())
-	flagExporter = ctx.ModuleProvider(sharedFoo, FlagExporterInfoProvider).(FlagExporterInfo)
-	android.AssertPathsRelativeToTopEquals(t, "exported include dirs", []string{"outputbase/execroot/__main__/include"}, flagExporter.IncludeDirs)
-	android.AssertPathsRelativeToTopEquals(t, "exported system include dirs", []string{"outputbase/execroot/__main__/system_include"}, flagExporter.SystemIncludeDirs)
-	android.AssertPathsRelativeToTopEquals(t, "exported headers", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.GeneratedHeaders)
-	android.AssertPathsRelativeToTopEquals(t, "deps", []string{"outputbase/execroot/__main__/foo.h"}, flagExporter.Deps)
-}
-
 func TestLibraryVersionScript(t *testing.T) {
 	t.Parallel()
 	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, `
@@ -413,107 +281,6 @@
 
 }
 
-func TestCcLibrarySharedWithBazelValidations(t *testing.T) {
-	t.Parallel()
-	bp := `
-cc_library_shared {
-	name: "foo",
-	srcs: ["foo.cc"],
-	bazel_module: { label: "//foo/bar:bar" },
-	tidy: true,
-}`
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.BazelContext = android.MockBazelContext{
-		OutputBaseDir: "outputbase",
-		LabelToCcInfo: map[string]cquery.CcInfo{
-			"//foo/bar:bar": cquery.CcInfo{
-				CcObjectFiles:        []string{"foo.o"},
-				Includes:             []string{"include"},
-				SystemIncludes:       []string{"system_include"},
-				RootDynamicLibraries: []string{"foo.so"},
-				TocFile:              "foo.so.toc",
-				TidyFiles:            []string{"foo.c.tidy"},
-			},
-		},
-	}
-	ctx := android.GroupFixturePreparers(
-		prepareForCcTest,
-		android.FixtureMergeEnv(map[string]string{
-			"ALLOW_LOCAL_TIDY_TRUE": "1",
-		}),
-	).RunTestWithConfig(t, config).TestContext
-
-	sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
-	producer := sharedFoo.(android.OutputFileProducer)
-	outputFiles, err := producer.OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
-	}
-	expectedOutputFiles := []string{"out/soong/.intermediates/foo/android_arm_armv7-a-neon_shared/validated/foo.so"}
-	android.AssertPathsRelativeToTopEquals(t, "output files", expectedOutputFiles, outputFiles)
-
-	tocFilePath := sharedFoo.(*Module).Toc()
-	if !tocFilePath.Valid() {
-		t.Errorf("Invalid tocFilePath: %s", tocFilePath)
-	}
-	tocFile := tocFilePath.Path()
-	expectedToc := "outputbase/execroot/__main__/foo.so.toc"
-	android.AssertStringEquals(t, "toc file", expectedToc, tocFile.String())
-
-	entries := android.AndroidMkEntriesForTest(t, ctx, sharedFoo)[0]
-	expectedFlags := []string{"-Ioutputbase/execroot/__main__/include", "-isystem outputbase/execroot/__main__/system_include"}
-	gotFlags := entries.EntryMap["LOCAL_EXPORT_CFLAGS"]
-	android.AssertDeepEquals(t, "androidmk exported cflags", expectedFlags, gotFlags)
-	android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_library_shared", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
-}
-
-func TestCcLibrarySharedWithBazel(t *testing.T) {
-	t.Parallel()
-	bp := `
-cc_library_shared {
-	name: "foo",
-	srcs: ["foo.cc"],
-	bazel_module: { label: "//foo/bar:bar" },
-}`
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.BazelContext = android.MockBazelContext{
-		OutputBaseDir: "outputbase",
-		LabelToCcInfo: map[string]cquery.CcInfo{
-			"//foo/bar:bar": cquery.CcInfo{
-				CcObjectFiles:        []string{"foo.o"},
-				Includes:             []string{"include"},
-				SystemIncludes:       []string{"system_include"},
-				RootDynamicLibraries: []string{"foo.so"},
-				TocFile:              "foo.so.toc",
-			},
-		},
-	}
-	ctx := testCcWithConfig(t, config)
-
-	sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
-	producer := sharedFoo.(android.OutputFileProducer)
-	outputFiles, err := producer.OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
-	}
-	expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.so"}
-	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
-
-	tocFilePath := sharedFoo.(*Module).Toc()
-	if !tocFilePath.Valid() {
-		t.Errorf("Invalid tocFilePath: %s", tocFilePath)
-	}
-	tocFile := tocFilePath.Path()
-	expectedToc := "outputbase/execroot/__main__/foo.so.toc"
-	android.AssertStringEquals(t, "toc file", expectedToc, tocFile.String())
-
-	entries := android.AndroidMkEntriesForTest(t, ctx, sharedFoo)[0]
-	expectedFlags := []string{"-Ioutputbase/execroot/__main__/include", "-isystem outputbase/execroot/__main__/system_include"}
-	gotFlags := entries.EntryMap["LOCAL_EXPORT_CFLAGS"]
-	android.AssertDeepEquals(t, "androidmk exported cflags", expectedFlags, gotFlags)
-	android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_library_shared", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
-}
-
 func TestWholeStaticLibPrebuilts(t *testing.T) {
 	t.Parallel()
 	result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, `
diff --git a/cc/linkable.go b/cc/linkable.go
index 2099399..10cc38f 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -2,9 +2,7 @@
 
 import (
 	"android/soong/android"
-	"android/soong/bazel/cquery"
 	"android/soong/fuzz"
-	"android/soong/snapshot"
 
 	"github.com/google/blueprint"
 )
@@ -64,43 +62,9 @@
 // implementation should handle tags from both.
 type SantizableDependencyTagChecker func(tag blueprint.DependencyTag) bool
 
-// Snapshottable defines those functions necessary for handling module snapshots.
-type Snapshottable interface {
-	snapshot.VendorSnapshotModuleInterface
-	snapshot.RecoverySnapshotModuleInterface
-
-	// SnapshotHeaders returns a list of header paths provided by this module.
-	SnapshotHeaders() android.Paths
-
-	// SnapshotLibrary returns true if this module is a snapshot library.
-	IsSnapshotLibrary() bool
-
-	// EffectiveLicenseFiles returns the list of License files for this module.
-	EffectiveLicenseFiles() android.Paths
-
-	// SnapshotRuntimeLibs returns a list of libraries needed by this module at runtime but which aren't build dependencies.
-	SnapshotRuntimeLibs() []string
-
-	// SnapshotSharedLibs returns the list of shared library dependencies for this module.
-	SnapshotSharedLibs() []string
-
-	// SnapshotStaticLibs returns the list of static library dependencies for this module.
-	SnapshotStaticLibs() []string
-
-	// SnapshotDylibs returns the list of dylib library dependencies for this module.
-	SnapshotDylibs() []string
-
-	// SnapshotRlibs returns the list of rlib library dependencies for this module.
-	SnapshotRlibs() []string
-
-	// IsSnapshotPrebuilt returns true if this module is a snapshot prebuilt.
-	IsSnapshotPrebuilt() bool
-}
-
 // LinkableInterface is an interface for a type of module that is linkable in a C++ library.
 type LinkableInterface interface {
 	android.Module
-	Snapshottable
 
 	Module() android.Module
 	CcLibrary() bool
@@ -207,6 +171,7 @@
 	ProductSpecific() bool
 	InProduct() bool
 	SdkAndPlatformVariantVisibleToMake() bool
+	InVendorOrProduct() bool
 
 	// SubName returns the modules SubName, used for image and NDK/SDK variations.
 	SubName() string
@@ -357,7 +322,7 @@
 	TransitiveStaticLibrariesForOrdering *android.DepSet[android.Path]
 }
 
-var SharedLibraryInfoProvider = blueprint.NewProvider(SharedLibraryInfo{})
+var SharedLibraryInfoProvider = blueprint.NewProvider[SharedLibraryInfo]()
 
 // SharedStubLibrary is a struct containing information about a stub shared library.
 // Stub libraries are used for cross-APEX dependencies; when a library is to depend on a shared
@@ -380,7 +345,7 @@
 	IsLLNDK bool
 }
 
-var SharedLibraryStubsProvider = blueprint.NewProvider(SharedLibraryStubsInfo{})
+var SharedLibraryStubsProvider = blueprint.NewProvider[SharedLibraryStubsInfo]()
 
 // StaticLibraryInfo is a provider to propagate information about a static C++ library.
 type StaticLibraryInfo struct {
@@ -399,14 +364,14 @@
 	TransitiveStaticLibrariesForOrdering *android.DepSet[android.Path]
 }
 
-var StaticLibraryInfoProvider = blueprint.NewProvider(StaticLibraryInfo{})
+var StaticLibraryInfoProvider = blueprint.NewProvider[StaticLibraryInfo]()
 
 // HeaderLibraryInfo is a marker provider that identifies a module as a header library.
 type HeaderLibraryInfo struct {
 }
 
 // HeaderLibraryInfoProvider is a marker provider that identifies a module as a header library.
-var HeaderLibraryInfoProvider = blueprint.NewProvider(HeaderLibraryInfo{})
+var HeaderLibraryInfoProvider = blueprint.NewProvider[HeaderLibraryInfo]()
 
 // FlagExporterInfo is a provider to propagate transitive library information
 // pertaining to exported include paths and flags.
@@ -418,20 +383,4 @@
 	GeneratedHeaders  android.Paths
 }
 
-var FlagExporterInfoProvider = blueprint.NewProvider(FlagExporterInfo{})
-
-// flagExporterInfoFromCcInfo populates FlagExporterInfo provider with information from Bazel.
-func flagExporterInfoFromCcInfo(ctx android.ModuleContext, ccInfo cquery.CcInfo) FlagExporterInfo {
-
-	includes := android.PathsForBazelOut(ctx, ccInfo.Includes)
-	systemIncludes := android.PathsForBazelOut(ctx, ccInfo.SystemIncludes)
-	headers := android.PathsForBazelOut(ctx, ccInfo.Headers)
-
-	return FlagExporterInfo{
-		IncludeDirs:       android.FirstUniquePaths(includes),
-		SystemIncludeDirs: android.FirstUniquePaths(systemIncludes),
-		GeneratedHeaders:  headers,
-		// necessary to ensure generated headers are considered implicit deps of dependent actions
-		Deps: headers,
-	}
-}
+var FlagExporterInfoProvider = blueprint.NewProvider[FlagExporterInfo]()
diff --git a/cc/linker.go b/cc/linker.go
index 257fe86..9686697 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -91,6 +91,10 @@
 	// compiling crt or libc.
 	Nocrt *bool `android:"arch_variant"`
 
+	// don't link in crt_pad_segment. This flag is currently only used internal to
+	// soong for testing and for vndk prebuilt shared libraries.
+	No_crt_pad_segment *bool `android:"arch_variant"`
+
 	// deprecated and ignored because lld makes it unnecessary. See b/189475744.
 	Group_static_libs *bool `android:"arch_variant"`
 
@@ -214,6 +218,11 @@
 			// variant of the C/C++ module.
 			Exclude_static_libs []string
 		}
+		Non_apex struct {
+			// list of shared libs that should not be used to build the non-apex
+			// variant of the C/C++ module.
+			Exclude_shared_libs []string
+		}
 	} `android:"arch_variant"`
 
 	// make android::build:GetBuildNumber() available containing the build ID.
@@ -248,6 +257,10 @@
 	return blp.No_libcrt == nil || !*blp.No_libcrt
 }
 
+func (blp *BaseLinkerProperties) crtPadSegment() bool {
+	return blp.No_crt_pad_segment == nil || !*blp.No_crt_pad_segment
+}
+
 func NewBaseLinker(sanitize *sanitize) *baseLinker {
 	return &baseLinker{sanitize: sanitize}
 }
@@ -300,6 +313,10 @@
 	// variants.
 	deps.ExcludeLibsForApex = append(deps.ExcludeLibsForApex, linker.Properties.Target.Apex.Exclude_shared_libs...)
 	deps.ExcludeLibsForApex = append(deps.ExcludeLibsForApex, linker.Properties.Target.Apex.Exclude_static_libs...)
+	// Record the libraries that need to be excluded when building for non-APEX variants
+	// for the same reason above. This is used for marking deps and marked deps are
+	// ignored for non-apex variants.
+	deps.ExcludeLibsForNonApex = append(deps.ExcludeLibsForNonApex, linker.Properties.Target.Non_apex.Exclude_shared_libs...)
 
 	if Bool(linker.Properties.Use_version_lib) {
 		deps.WholeStaticLibs = append(deps.WholeStaticLibs, "libbuildversion")
@@ -513,13 +530,6 @@
 		flags.Global.LdFlags = append(flags.Global.LdFlags, RpathFlags(ctx)...)
 	}
 
-	if ctx.useSdk() {
-		// The bionic linker now has support gnu style hashes (which are much faster!), but shipping
-		// to older devices requires the old style hash. Fortunately, we can build with both and
-		// it'll work anywhere.
-		flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--hash-style=both")
-	}
-
 	flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.ToolchainLdflags())
 
 	// Version_script is not needed when linking stubs lib where the version
@@ -639,6 +649,9 @@
 	return specifiedDeps
 }
 
+func (linker *baseLinker) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+}
+
 // Injecting version symbols
 // Some host modules want a version number, but we don't want to rebuild it every time.  Optionally add a step
 // after linking that injects a constant placeholder with the current version number.
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index c307410..9e727a1 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -14,6 +14,11 @@
 
 package cc
 
+import (
+	"android/soong/android"
+	"strings"
+)
+
 var (
 	llndkLibrarySuffix = ".llndk"
 	llndkHeadersSuffix = ".llndk"
@@ -55,3 +60,21 @@
 	// llndk.symbol_file.
 	Llndk_headers *bool
 }
+
+func makeLlndkVars(ctx android.MakeVarsContext) {
+	// Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if
+	// they been moved to an apex.
+	movedToApexLlndkLibraries := make(map[string]bool)
+	ctx.VisitAllModules(func(module android.Module) {
+		if library := moduleLibraryInterface(module); library != nil && library.hasLLNDKStubs() {
+			// Skip bionic libs, they are handled in different manner
+			name := library.implementationModuleName(module.(*Module).BaseModuleName())
+			if module.(android.ApexModule).DirectlyInAnyApex() && !isBionic(name) {
+				movedToApexLlndkLibraries[name] = true
+			}
+		}
+	})
+
+	ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES",
+		strings.Join(android.SortedKeys(movedToApexLlndkLibraries), " "))
+}
diff --git a/cc/lto.go b/cc/lto.go
index df9ca0a..a084db7 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -15,9 +15,12 @@
 package cc
 
 import (
-	"android/soong/android"
+	"fmt"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
+
+	"android/soong/android"
 )
 
 // LTO (link-time optimization) allows the compiler to optimize and generate
@@ -35,11 +38,11 @@
 // optimized at link time and may not be compatible with features that require
 // LTO, such as CFI.
 //
-// This file adds support to soong to automatically propogate LTO options to a
+// This file adds support to soong to automatically propagate LTO options to a
 // new variant of all static dependencies for each module with LTO enabled.
 
 type LTOProperties struct {
-	// Lto must violate capitialization style for acronyms so that it can be
+	// Lto must violate capitalization style for acronyms so that it can be
 	// referred to in blueprint files as "lto"
 	Lto struct {
 		Never *bool `android:"arch_variant"`
@@ -49,11 +52,6 @@
 	LtoEnabled bool `blueprint:"mutated"`
 	LtoDefault bool `blueprint:"mutated"`
 
-	// Dep properties indicate that this module needs to be built with LTO
-	// since it is an object dependency of an LTO module.
-	LtoDep   bool `blueprint:"mutated"`
-	NoLtoDep bool `blueprint:"mutated"`
-
 	// Use -fwhole-program-vtables cflag.
 	Whole_program_vtables *bool
 }
@@ -67,10 +65,12 @@
 }
 
 func (lto *lto) begin(ctx BaseModuleContext) {
-	// First, determine the module indepedent default LTO mode.
-	ltoDefault := GlobalThinLTO(ctx)
+	// First, determine the module independent default LTO mode.
+	ltoDefault := true
 	if ctx.Config().IsEnvTrue("DISABLE_LTO") {
 		ltoDefault = false
+	} else if lto.Never() {
+		ltoDefault = false
 	} else if ctx.Host() {
 		// Performance and binary size are less important for host binaries.
 		ltoDefault = false
@@ -90,17 +90,13 @@
 	} else if ctx.testBinary() || ctx.testLibrary() {
 		// Do not enable LTO for tests for better debugging.
 		ltoEnabled = false
-	} else if ctx.isVndk() {
-		// FIXME: ThinLTO for VNDK produces different output.
-		// b/169217596
-		ltoEnabled = false
 	}
 
 	lto.Properties.LtoDefault = ltoDefault
 	lto.Properties.LtoEnabled = ltoEnabled
 }
 
-func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
+func (lto *lto) flags(ctx ModuleContext, flags Flags) Flags {
 	// TODO(b/131771163): CFI and Fuzzer controls LTO flags by themselves.
 	// This has be checked late because these properties can be mutated.
 	if ctx.isCfi() || ctx.isFuzzer() {
@@ -114,7 +110,8 @@
 		// better dead code elimination and CFG simplification, but do
 		// not perform costly optimizations for a balance between compile
 		// time, binary size and performance.
-		if !lto.ThinLTO() {
+		// Apply the same for Eng builds as well.
+		if !lto.ThinLTO() || ctx.Config().Eng() {
 			ltoLdFlags = append(ltoLdFlags, "-Wl,--lto-O0")
 		}
 
@@ -138,13 +135,25 @@
 		// Reduce the inlining threshold for a better balance of binary size and
 		// performance.
 		if !ctx.Darwin() {
-			if ctx.isPgoCompile() || ctx.isAfdoCompile() {
+			if ctx.isAfdoCompile(ctx) {
 				ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=40")
 			} else {
 				ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5")
 			}
 		}
 
+		if !ctx.Config().IsEnvFalse("THINLTO_USE_MLGO") {
+			// Register allocation MLGO flags for ARM64.
+			if ctx.Arch().ArchType == android.Arm64 {
+				ltoLdFlags = append(ltoLdFlags, "-Wl,-mllvm,-regalloc-enable-advisor=release")
+			}
+			// Flags for training MLGO model.
+			if ctx.Config().IsEnvTrue("THINLTO_EMIT_INDEXES_AND_IMPORTS") {
+				ltoLdFlags = append(ltoLdFlags, "-Wl,--save-temps=import")
+				ltoLdFlags = append(ltoLdFlags, "-Wl,--thinlto-emit-index-files")
+			}
+		}
+
 		flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlags...)
 		flags.Local.AsFlags = append(flags.Local.AsFlags, ltoCFlags...)
 		flags.Local.LdFlags = append(flags.Local.LdFlags, ltoCFlags...)
@@ -161,92 +170,83 @@
 	return lto != nil && proptools.Bool(lto.Properties.Lto.Never)
 }
 
-func GlobalThinLTO(ctx android.BaseModuleContext) bool {
-	return !ctx.Config().IsEnvFalse("GLOBAL_THINLTO")
-}
-
-// Propagate lto requirements down from binaries
-func ltoDepsMutator(mctx android.TopDownMutatorContext) {
-	if m, ok := mctx.Module().(*Module); ok {
-		if m.lto == nil || m.lto.Properties.LtoEnabled == m.lto.Properties.LtoDefault {
-			return
-		}
-
-		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
-			tag := mctx.OtherModuleDependencyTag(dep)
-			libTag, isLibTag := tag.(libraryDependencyTag)
-
-			// Do not recurse down non-static dependencies
-			if isLibTag {
-				if !libTag.static() {
-					return false
-				}
-			} else {
-				if tag != objDepTag && tag != reuseObjTag {
-					return false
-				}
-			}
-
-			if dep, ok := dep.(*Module); ok {
-				if m.lto.Properties.LtoEnabled {
-					dep.lto.Properties.LtoDep = true
-				} else {
-					dep.lto.Properties.NoLtoDep = true
-				}
-			}
-
-			// Recursively walk static dependencies
-			return true
-		})
+func ltoPropagateViaDepTag(tag blueprint.DependencyTag) bool {
+	libTag, isLibTag := tag.(libraryDependencyTag)
+	// Do not recurse down non-static dependencies
+	if isLibTag {
+		return libTag.static()
+	} else {
+		return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag
 	}
 }
 
-// Create lto variants for modules that need them
-func ltoMutator(mctx android.BottomUpMutatorContext) {
-	globalThinLTO := GlobalThinLTO(mctx)
+// ltoTransitionMutator creates LTO variants of cc modules.  Variant "" is the default variant, which may
+// or may not have LTO enabled depending on the config and the module's type and properties.  "lto-thin" or
+// "lto-none" variants are created when a module needs to compile in the non-default state for that module.
+type ltoTransitionMutator struct{}
 
-	if m, ok := mctx.Module().(*Module); ok && m.lto != nil {
-		// Create variations for LTO types required as static
-		// dependencies
-		variationNames := []string{""}
-		if m.lto.Properties.LtoDep {
-			variationNames = append(variationNames, "lto-thin")
-		}
-		if m.lto.Properties.NoLtoDep {
-			variationNames = append(variationNames, "lto-none")
+const LTO_NONE_VARIATION = "lto-none"
+const LTO_THIN_VARIATION = "lto-thin"
+
+func (l *ltoTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+	return []string{""}
+}
+
+func (l *ltoTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+	if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
+		if !ltoPropagateViaDepTag(ctx.DepTag()) {
+			return ""
 		}
 
-		if globalThinLTO && !m.lto.Properties.LtoEnabled {
-			mctx.SetDependencyVariation("lto-none")
-		}
-		if !globalThinLTO && m.lto.Properties.LtoEnabled {
-			mctx.SetDependencyVariation("lto-thin")
+		if sourceVariation != "" {
+			return sourceVariation
 		}
 
-		if len(variationNames) > 1 {
-			modules := mctx.CreateVariations(variationNames...)
-			for i, name := range variationNames {
-				variation := modules[i].(*Module)
-				// Default module which will be
-				// installed. Variation set above according to
-				// explicit LTO properties
-				if name == "" {
-					continue
-				}
-
-				// LTO properties for dependencies
-				if name == "lto-thin" {
-					variation.lto.Properties.LtoEnabled = true
-				}
-				if name == "lto-none" {
-					variation.lto.Properties.LtoEnabled = false
-				}
-				variation.Properties.PreventInstall = true
-				variation.Properties.HideFromMake = true
-				variation.lto.Properties.LtoDefault = m.lto.Properties.LtoDefault
-				variation.lto.Properties.LtoDep = false
-				variation.lto.Properties.NoLtoDep = false
-			}
+		// Always request an explicit variation, IncomingTransition will rewrite it back to the default variation
+		// if necessary.
+		if m.lto.Properties.LtoEnabled {
+			return LTO_THIN_VARIATION
+		} else {
+			return LTO_NONE_VARIATION
 		}
 	}
+	return ""
+}
+
+func (l *ltoTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+	if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
+		if m.lto.Never() {
+			return ""
+		}
+		// Rewrite explicit variations back to the default variation if the default variation matches.
+		if incomingVariation == LTO_THIN_VARIATION && m.lto.Properties.LtoDefault {
+			return ""
+		} else if incomingVariation == LTO_NONE_VARIATION && !m.lto.Properties.LtoDefault {
+			return ""
+		}
+		return incomingVariation
+	}
+	return ""
+}
+
+func (l *ltoTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+	// Default module which will be installed. Variation set above according to explicit LTO properties.
+	if variation == "" {
+		return
+	}
+
+	if m, ok := ctx.Module().(*Module); ok && m.lto != nil {
+		// Non-default variation, set the LTO properties to match the variation.
+		switch variation {
+		case LTO_THIN_VARIATION:
+			m.lto.Properties.LtoEnabled = true
+		case LTO_NONE_VARIATION:
+			m.lto.Properties.LtoEnabled = false
+		default:
+			panic(fmt.Errorf("unknown variation %s", variation))
+		}
+		// Non-default variations are never installed.
+		m.Properties.PreventInstall = true
+		m.Properties.HideFromMake = true
+	}
 }
diff --git a/cc/lto_test.go b/cc/lto_test.go
index e0afd4a..e4b5a3a 100644
--- a/cc/lto_test.go
+++ b/cc/lto_test.go
@@ -23,11 +23,19 @@
 	"github.com/google/blueprint"
 )
 
-var NoGlobalThinLTOPreparer = android.GroupFixturePreparers(
+var LTOPreparer = android.GroupFixturePreparers(
 	prepareForCcTest,
-	android.FixtureModifyEnv(func(env map[string]string) {
-		env["GLOBAL_THINLTO"] = "false"
-	}))
+)
+
+func hasDep(result *android.TestResult, m android.Module, wantDep android.Module) bool {
+	var found bool
+	result.VisitDirectDeps(m, func(dep blueprint.Module) {
+		if dep == wantDep {
+			found = true
+		}
+	})
+	return found
+}
 
 func TestThinLtoDeps(t *testing.T) {
 	t.Parallel()
@@ -37,9 +45,6 @@
 		srcs: ["src.c"],
 		static_libs: ["foo", "lib_never_lto"],
 		shared_libs: ["bar"],
-		lto: {
-			thin: true,
-		}
 	}
 	cc_library_static {
 		name: "foo",
@@ -63,50 +68,40 @@
 	}
 `
 
-	result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
+	result := LTOPreparer.RunTestWithBp(t, bp)
 
 	libLto := result.ModuleForTests("lto_enabled", "android_arm64_armv8-a_shared").Module()
 
-	hasDep := func(m android.Module, wantDep android.Module) bool {
-		var found bool
-		result.VisitDirectDeps(m, func(dep blueprint.Module) {
-			if dep == wantDep {
-				found = true
-			}
-		})
-		return found
+	libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static").Module()
+	if !hasDep(result, libLto, libFoo) {
+		t.Errorf("'lto_enabled' missing dependency on the default variant of 'foo'")
 	}
 
-	libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static_lto-thin").Module()
-	if !hasDep(libLto, libFoo) {
-		t.Errorf("'lto_enabled' missing dependency on thin lto variant of 'foo'")
+	libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static").Module()
+	if !hasDep(result, libFoo, libBaz) {
+		t.Errorf("'foo' missing dependency on the default variant of transitive dep 'baz'")
 	}
 
-	libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static_lto-thin").Module()
-	if !hasDep(libFoo, libBaz) {
-		t.Errorf("'foo' missing dependency on thin lto variant of transitive dep 'baz'")
-	}
-
-	libNeverLto := result.ModuleForTests("lib_never_lto", "android_arm64_armv8-a_static_lto-thin").Module()
-	if !hasDep(libLto, libNeverLto) {
-		t.Errorf("'lto_enabled' missing dependency on NO-thin lto variant of 'lib_never_lto'")
+	libNeverLto := result.ModuleForTests("lib_never_lto", "android_arm64_armv8-a_static").Module()
+	if !hasDep(result, libLto, libNeverLto) {
+		t.Errorf("'lto_enabled' missing dependency on the default variant of 'lib_never_lto'")
 	}
 
 	libBar := result.ModuleForTests("bar", "android_arm64_armv8-a_shared").Module()
-	if !hasDep(libLto, libBar) {
-		t.Errorf("'lto_enabled' missing dependency on non-thin lto variant of 'bar'")
+	if !hasDep(result, libLto, libBar) {
+		t.Errorf("'lto_enabled' missing dependency on the default variant of 'bar'")
 	}
 
 	barVariants := result.ModuleVariantsForTests("bar")
 	for _, v := range barVariants {
-		if strings.Contains(v, "lto-thin") {
-			t.Errorf("Expected variants for 'bar' to not contain 'lto-thin', but found %q", v)
+		if strings.Contains(v, "lto-none") {
+			t.Errorf("Expected variants for 'bar' to not contain 'lto-none', but found %q", v)
 		}
 	}
 	quxVariants := result.ModuleVariantsForTests("qux")
 	for _, v := range quxVariants {
-		if strings.Contains(v, "lto-thin") {
-			t.Errorf("Expected variants for 'qux' to not contain 'lto-thin', but found %q", v)
+		if strings.Contains(v, "lto-none") {
+			t.Errorf("Expected variants for 'qux' to not contain 'lto-none', but found %q", v)
 		}
 	}
 }
@@ -141,28 +136,19 @@
 	}
 `
 
-	result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
+	result := LTOPreparer.RunTestWithBp(t, bp)
 
 	libRoot := result.ModuleForTests("root", "android_arm64_armv8-a_shared").Module()
 	libRootLtoNever := result.ModuleForTests("root_no_lto", "android_arm64_armv8-a_shared").Module()
 
-	hasDep := func(m android.Module, wantDep android.Module) bool {
-		var found bool
-		result.VisitDirectDeps(m, func(dep blueprint.Module) {
-			if dep == wantDep {
-				found = true
-			}
-		})
-		return found
-	}
-
 	libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static")
-	if !hasDep(libRoot, libFoo.Module()) {
-		t.Errorf("'root' missing dependency on thin lto variant of 'foo'")
+	if !hasDep(result, libRoot, libFoo.Module()) {
+		t.Errorf("'root' missing dependency on the default variant of 'foo'")
 	}
 
-	if !hasDep(libRootLtoNever, libFoo.Module()) {
-		t.Errorf("'root_no_lto' missing dependency on thin lto variant of 'foo'")
+	libFooNoLto := result.ModuleForTests("foo", "android_arm64_armv8-a_static_lto-none")
+	if !hasDep(result, libRootLtoNever, libFooNoLto.Module()) {
+		t.Errorf("'root_no_lto' missing dependency on the lto_none variant of 'foo'")
 	}
 
 	libFooCFlags := libFoo.Rule("cc").Args["cFlags"]
@@ -170,9 +156,9 @@
 		t.Errorf("'foo' expected to have flags %q, but got %q", w, libFooCFlags)
 	}
 
-	libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static_lto-thin")
-	if !hasDep(libFoo.Module(), libBaz.Module()) {
-		t.Errorf("'foo' missing dependency on thin lto variant of transitive dep 'baz'")
+	libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static")
+	if !hasDep(result, libFoo.Module(), libBaz.Module()) {
+		t.Errorf("'foo' missing dependency on the default variant of transitive dep 'baz'")
 	}
 
 	libBazCFlags := libFoo.Rule("cc").Args["cFlags"]
@@ -199,7 +185,7 @@
 			},
 		},
 	}`
-	result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
+	result := LTOPreparer.RunTestWithBp(t, bp)
 
 	libFooWithLto := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
 	libFooWithoutLto := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld")
@@ -227,7 +213,7 @@
 		},
 	}`
 
-	result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
+	result := LTOPreparer.RunTestWithBp(t, bp)
 
 	libFoo := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
 	libBar := result.ModuleForTests("runtime_libbar", "android_arm_armv7-a-neon_shared").Rule("ld")
diff --git a/cc/makevars.go b/cc/makevars.go
index 6c3f551..9251d6a 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -97,9 +97,6 @@
 	ctx.Strict("GLOBAL_CLANG_CPPFLAGS_NO_OVERRIDE", "")
 	ctx.Strict("GLOBAL_CLANG_EXTERNAL_CFLAGS_NO_OVERRIDE", "${config.NoOverrideExternalGlobalCflags}")
 
-	ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion())
-	ctx.Strict("RECOVERY_SNAPSHOT_VERSION", ctx.DeviceConfig().RecoverySnapshotVersion())
-
 	// Filter vendor_public_library that are exported to make
 	exportedVendorPublicLibraries := []string{}
 	ctx.VisitAllModules(func(module android.Module) {
@@ -123,6 +120,13 @@
 	ctx.Strict("SOONG_MODULES_USING_WNO_ERROR", makeStringOfKeys(ctx, modulesUsingWnoErrorKey))
 	ctx.Strict("SOONG_MODULES_MISSING_PGO_PROFILE_FILE", makeStringOfKeys(ctx, modulesMissingProfileFileKey))
 
+	ctx.Strict("CLANG_COVERAGE_CONFIG_CFLAGS", strings.Join(clangCoverageCFlags, " "))
+	ctx.Strict("CLANG_COVERAGE_CONFIG_COMMFLAGS", strings.Join(clangCoverageCommonFlags, " "))
+	ctx.Strict("CLANG_COVERAGE_HOST_LDFLAGS", strings.Join(clangCoverageHostLdFlags, " "))
+	ctx.Strict("CLANG_COVERAGE_INSTR_PROFILE", profileInstrFlag)
+	ctx.Strict("CLANG_COVERAGE_CONTINUOUS_FLAGS", strings.Join(clangContinuousCoverageFlags, " "))
+	ctx.Strict("CLANG_COVERAGE_HWASAN_FLAGS", strings.Join(clangCoverageHWASanFlags, " "))
+
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " "))
 	ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", strings.Join(asanLdflags, " "))
 
@@ -177,6 +181,8 @@
 	if len(deviceTargets) > 1 {
 		makeVarsToolchain(ctx, "2ND_", deviceTargets[1])
 	}
+
+	makeLlndkVars(ctx)
 }
 
 func makeVarsToolchain(ctx android.MakeVarsContext, secondPrefix string,
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index d0ae4a5..57a3b3a 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -15,12 +15,10 @@
 package cc
 
 import (
-	"fmt"
 	"path/filepath"
 
-	"github.com/google/blueprint"
-
 	"android/soong/android"
+	"github.com/google/blueprint"
 )
 
 var (
@@ -46,7 +44,7 @@
 }
 
 // Returns the NDK base include path for use with sdk_version current. Usable with -I.
-func getCurrentIncludePath(ctx android.ModuleContext) android.InstallPath {
+func getCurrentIncludePath(ctx android.ModuleContext) android.OutputPath {
 	return getNdkSysrootBase(ctx).Join(ctx, "usr/include")
 }
 
@@ -82,12 +80,13 @@
 
 	properties headerProperties
 
+	srcPaths     android.Paths
 	installPaths android.Paths
 	licensePath  android.Path
 }
 
 func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string,
-	to string) android.InstallPath {
+	to string) android.OutputPath {
 	// Output path is the sysroot base + "usr/include" + to directory + directory component
 	// of the file without the leading from directory stripped.
 	//
@@ -125,17 +124,16 @@
 
 	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
 
-	srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
-	for _, header := range srcFiles {
+	m.srcPaths = android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
+	for _, header := range m.srcPaths {
 		installDir := getHeaderInstallDir(ctx, header, String(m.properties.From),
 			String(m.properties.To))
-		installedPath := ctx.InstallFile(installDir, header.Base(), header)
 		installPath := installDir.Join(ctx, header.Base())
-		if installPath != installedPath {
-			panic(fmt.Sprintf(
-				"expected header install path (%q) not equal to actual install path %q",
-				installPath, installedPath))
-		}
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   android.Cp,
+			Input:  header,
+			Output: installPath,
+		})
 		m.installPaths = append(m.installPaths, installPath)
 	}
 
@@ -154,7 +152,7 @@
 //	to = "bar"
 //	header = "include/foo/woodly/doodly.h"
 //	output path = "ndk/sysroot/usr/include/bar/woodly/doodly.h"
-func ndkHeadersFactory() android.Module {
+func NdkHeadersFactory() android.Module {
 	module := &headerModule{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidModule(module)
@@ -182,7 +180,7 @@
 }
 
 // Like ndk_headers, but preprocesses the headers with the bionic versioner:
-// https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
+// https://android.googlesource.com/platform/bionic/+/main/tools/versioner/README.md.
 //
 // Unlike ndk_headers, we don't operate on a list of sources but rather a whole directory, the
 // module does not have the srcs property, and operates on a full directory (the `from` property).
@@ -193,6 +191,7 @@
 
 	properties versionedHeaderProperties
 
+	srcPaths     android.Paths
 	installPaths android.Paths
 	licensePath  android.Path
 }
@@ -211,9 +210,9 @@
 
 	fromSrcPath := android.PathForModuleSrc(ctx, String(m.properties.From))
 	toOutputPath := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
-	srcFiles := ctx.GlobFiles(headerGlobPattern(fromSrcPath.String()), nil)
+	m.srcPaths = ctx.GlobFiles(headerGlobPattern(fromSrcPath.String()), nil)
 	var installPaths []android.WritablePath
-	for _, header := range srcFiles {
+	for _, header := range m.srcPaths {
 		installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To))
 		installPath := installDir.Join(ctx, header.Base())
 		installPaths = append(installPaths, installPath)
@@ -224,11 +223,11 @@
 		ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From))
 	}
 
-	processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, srcFiles, installPaths)
+	processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, m.srcPaths, installPaths)
 }
 
 func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path,
-	srcFiles android.Paths, installPaths []android.WritablePath) android.Path {
+	srcPaths android.Paths, installPaths []android.WritablePath) android.Path {
 	// The versioner depends on a dependencies directory to simplify determining include paths
 	// when parsing headers. This directory contains architecture specific directories as well
 	// as a common directory, each of which contains symlinks to the actually directories to
@@ -253,7 +252,7 @@
 		Rule:            versionBionicHeaders,
 		Description:     "versioner preprocess " + srcDir.Rel(),
 		Output:          timestampFile,
-		Implicits:       append(srcFiles, depsGlob...),
+		Implicits:       append(srcPaths, depsGlob...),
 		ImplicitOutputs: installPaths,
 		Args: map[string]string{
 			"depsPath": depsPath.String(),
@@ -266,11 +265,11 @@
 }
 
 // versioned_ndk_headers preprocesses the headers with the bionic versioner:
-// https://android.googlesource.com/platform/bionic/+/master/tools/versioner/README.md.
+// https://android.googlesource.com/platform/bionic/+/main/tools/versioner/README.md.
 // Unlike the ndk_headers soong module, versioned_ndk_headers operates on a
 // directory level specified in `from` property. This is only used to process
 // the bionic/libc/include directory.
-func versionedNdkHeadersFactory() android.Module {
+func VersionedNdkHeadersFactory() android.Module {
 	module := &versionedHeaderModule{}
 
 	module.AddProperties(&module.properties)
@@ -317,6 +316,7 @@
 
 	properties preprocessedHeadersProperties
 
+	srcPaths     android.Paths
 	installPaths android.Paths
 	licensePath  android.Path
 }
@@ -329,9 +329,9 @@
 	preprocessor := android.PathForModuleSrc(ctx, String(m.properties.Preprocessor))
 	m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
 
-	srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
+	m.srcPaths = android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
 	installDir := getCurrentIncludePath(ctx).Join(ctx, String(m.properties.To))
-	for _, src := range srcFiles {
+	for _, src := range m.srcPaths {
 		installPath := installDir.Join(ctx, src.Base())
 		m.installPaths = append(m.installPaths, installPath)
 
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 9281aeb..25231fd 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -25,7 +25,6 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/cc/config"
 )
 
@@ -43,11 +42,17 @@
 			CommandDeps: []string{"$ndkStubGenerator"},
 		}, "arch", "apiLevel", "apiMap", "flags")
 
+	// $headersList should include paths to public headers. All types
+	// that are defined outside of public headers will be excluded from
+	// ABI monitoring.
+	//
+	// STG tool doesn't access content of files listed in $headersList,
+	// so there is no need to add them to dependencies.
 	stg = pctx.AndroidStaticRule("stg",
 		blueprint.RuleParams{
-			Command:     "$stg -S :$symbolList --elf $in -o $out",
+			Command:     "$stg -S :$symbolList --file-filter :$headersList --elf $in -o $out",
 			CommandDeps: []string{"$stg"},
-		}, "symbolList")
+		}, "symbolList", "headersList")
 
 	stgdiff = pctx.AndroidStaticRule("stgdiff",
 		blueprint.RuleParams{
@@ -55,7 +60,7 @@
 			// because we don't want to spam the build output with "nothing
 			// changed" messages, so redirect output message to $out, and if
 			// changes were detected print the output and fail.
-			Command:     "$stgdiff $args --stg $in -o $out || (cat $out && false)",
+			Command:     "$stgdiff $args --stg $in -o $out || (cat $out && echo 'Run $$ANDROID_BUILD_TOP/development/tools/ndk/update_ndk_abi.sh to update the ABI dumps.' && false)",
 			CommandDeps: []string{"$stgdiff"},
 		}, "args")
 
@@ -220,7 +225,7 @@
 }
 
 func init() {
-	config.ExportStringList("StubLibraryCompilerFlags", stubLibraryCompilerFlags)
+	pctx.StaticVariable("StubLibraryCompilerFlags", strings.Join(stubLibraryCompilerFlags, " "))
 }
 
 func addStubLibraryCompilerFlags(flags Flags) Flags {
@@ -320,26 +325,13 @@
 	if runtime.GOOS == "darwin" {
 		return false
 	}
-	// abidw doesn't currently handle top-byte-ignore correctly. Disable ABI
-	// dumping for those configs while we wait for a fix. We'll still have ABI
-	// checking coverage from non-hwasan builds.
-	// http://b/190554910
-	if android.InList("hwaddress", config.SanitizeDevice()) {
-		return false
-	}
 	// http://b/156513478
-	// http://b/277624006
-	// This step is expensive. We're not able to do anything with the outputs of
-	// this step yet (canDiffAbi is flagged off because libabigail isn't able to
-	// handle all our libraries), disable it. There's no sense in protecting
-	// against checking in code that breaks abidw since by the time any of this
-	// can be turned on we'll need to migrate to STG anyway.
-	return false
+	return config.ReleaseNdkAbiMonitored()
 }
 
 // Feature flag to disable diffing against prebuilts.
-func canDiffAbi() bool {
-	return false
+func canDiffAbi(config android.Config) bool {
+	return config.ReleaseNdkAbiMonitored()
 }
 
 func (this *stubDecorator) dumpAbi(ctx ModuleContext, symbolList android.Path) {
@@ -347,14 +339,19 @@
 	this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx,
 		this.apiLevel.String(), ctx.Arch().ArchType.String(),
 		this.libraryName(ctx), "abi.stg")
+	headersList := getNdkABIHeadersFile(ctx)
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        stg,
 		Description: fmt.Sprintf("stg %s", implementationLibrary),
 		Input:       implementationLibrary,
-		Implicit:    symbolList,
-		Output:      this.abiDumpPath,
+		Implicits: []android.Path{
+			symbolList,
+			headersList,
+		},
+		Output: this.abiDumpPath,
 		Args: map[string]string{
-			"symbolList": symbolList.String(),
+			"symbolList":  symbolList.String(),
+			"headersList": headersList.String(),
 		},
 	})
 }
@@ -375,9 +372,11 @@
 	// level.
 	abiDiffPath := android.PathForModuleOut(ctx, "stgdiff.timestamp")
 	prebuiltAbiDump := this.findPrebuiltAbiDump(ctx, this.apiLevel)
+	missingPrebuiltErrorTemplate :=
+		"Did not find prebuilt ABI dump for %q (%q). Generate with " +
+			"//development/tools/ndk/update_ndk_abi.sh."
 	missingPrebuiltError := fmt.Sprintf(
-		"Did not find prebuilt ABI dump for %q (%q). Generate with "+
-			"//development/tools/ndk/update_ndk_abi.sh.", this.libraryName(ctx),
+		missingPrebuiltErrorTemplate, this.libraryName(ctx),
 		prebuiltAbiDump.InvalidReason())
 	if !prebuiltAbiDump.Valid() {
 		ctx.Build(pctx, android.BuildParams{
@@ -404,7 +403,7 @@
 	// Also ensure that the ABI of the next API level (if there is one) matches
 	// this API level. *New* ABI is allowed, but any changes to APIs that exist
 	// in this API level are disallowed.
-	if !this.apiLevel.IsCurrent() {
+	if !this.apiLevel.IsCurrent() && prebuiltAbiDump.Valid() {
 		nextApiLevel := findNextApiLevel(ctx, this.apiLevel)
 		if nextApiLevel == nil {
 			panic(fmt.Errorf("could not determine which API level follows "+
@@ -413,21 +412,26 @@
 		nextAbiDiffPath := android.PathForModuleOut(ctx,
 			"abidiff_next.timestamp")
 		nextAbiDump := this.findPrebuiltAbiDump(ctx, *nextApiLevel)
+		missingNextPrebuiltError := fmt.Sprintf(
+			missingPrebuiltErrorTemplate, this.libraryName(ctx),
+			nextAbiDump.InvalidReason())
 		if !nextAbiDump.Valid() {
 			ctx.Build(pctx, android.BuildParams{
 				Rule:   android.ErrorRule,
 				Output: nextAbiDiffPath,
 				Args: map[string]string{
-					"error": missingPrebuiltError,
+					"error": missingNextPrebuiltError,
 				},
 			})
 		} else {
 			ctx.Build(pctx, android.BuildParams{
 				Rule: stgdiff,
-				Description: fmt.Sprintf("abidiff %s %s", this.abiDumpPath,
-					nextAbiDump),
+				Description: fmt.Sprintf(
+					"Comparing ABI to the next API level %s %s",
+					prebuiltAbiDump, nextAbiDump),
 				Output: nextAbiDiffPath,
-				Inputs: android.Paths{this.abiDumpPath, nextAbiDump.Path()},
+				Inputs: android.Paths{
+					prebuiltAbiDump.Path(), nextAbiDump.Path()},
 				Args: map[string]string{
 					"args": "--format=small --ignore=interface_addition",
 				},
@@ -458,7 +462,7 @@
 	c.versionScriptPath = nativeAbiResult.versionScript
 	if canDumpAbi(ctx.Config()) {
 		c.dumpAbi(ctx, nativeAbiResult.symbolList)
-		if canDiffAbi() {
+		if canDiffAbi(ctx.Config()) {
 			c.diffAbi(ctx)
 		}
 	}
@@ -475,6 +479,12 @@
 	}
 }
 
+func (linker *stubDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+	linker.libraryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+	// Overwrites the SubName computed by libraryDecorator
+	moduleInfoJSON.SubName = ndkLibrarySuffix + "." + linker.apiLevel.String()
+}
+
 func (linker *stubDecorator) Name(name string) string {
 	return name + ndkLibrarySuffix
 }
@@ -508,19 +518,25 @@
 
 // Returns the install path for unversioned NDK libraries (currently only static
 // libraries).
-func getUnversionedLibraryInstallPath(ctx ModuleContext) android.InstallPath {
+func getUnversionedLibraryInstallPath(ctx ModuleContext) android.OutputPath {
 	return getNdkSysrootBase(ctx).Join(ctx, "usr/lib", config.NDKTriple(ctx.toolchain()))
 }
 
 // Returns the install path for versioned NDK libraries. These are most often
 // stubs, but the same paths are used for CRT objects.
-func getVersionedLibraryInstallPath(ctx ModuleContext, apiLevel android.ApiLevel) android.InstallPath {
+func getVersionedLibraryInstallPath(ctx ModuleContext, apiLevel android.ApiLevel) android.OutputPath {
 	return getUnversionedLibraryInstallPath(ctx).Join(ctx, apiLevel.String())
 }
 
 func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) {
 	installDir := getVersionedLibraryInstallPath(ctx, stub.apiLevel)
-	stub.installPath = ctx.InstallFile(installDir, path.Base(), path)
+	out := installDir.Join(ctx, path.Base())
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   android.Cp,
+		Input:  path,
+		Output: out,
+	})
+	stub.installPath = out
 }
 
 func newStubLibrary() *Module {
@@ -551,22 +567,5 @@
 func NdkLibraryFactory() android.Module {
 	module := newStubLibrary()
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
-	android.InitBazelModule(module)
 	return module
 }
-
-type bazelCcApiContributionAttributes struct {
-	Api          bazel.LabelAttribute
-	Api_surfaces bazel.StringListAttribute
-	Hdrs         bazel.LabelListAttribute
-	Library_name string
-}
-
-// Names of the cc_api_header targets in the bp2build workspace
-func apiHeaderLabels(ctx android.TopDownMutatorContext, hdrLibs []string) bazel.LabelList {
-	addSuffix := func(ctx android.BazelConversionPathContext, module blueprint.Module) string {
-		label := android.BazelModuleLabel(ctx, module)
-		return android.ApiContributionTargetName(label)
-	}
-	return android.BazelLabelForModuleDepsWithFn(ctx, hdrLibs, addSuffix)
-}
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index d3a0a00..f503982 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -87,9 +87,12 @@
 	return module.Init()
 }
 
+const (
+	libDir = "current/sources/cxx-stl/llvm-libc++/libs"
+)
+
 func getNdkStlLibDir(ctx android.ModuleContext) android.SourcePath {
-	libDir := "prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs"
-	return android.PathForSource(ctx, libDir).Join(ctx, ctx.Arch().Abi[0])
+	return android.PathForSource(ctx, ctx.ModuleDir(), libDir).Join(ctx, ctx.Arch().Abi[0])
 }
 
 func (ndk *ndkPrebuiltStlLinker) link(ctx ModuleContext, flags Flags,
@@ -114,13 +117,13 @@
 
 	if ndk.static() {
 		depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(lib).Build()
-		ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+		android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{
 			StaticLibrary: lib,
 
 			TransitiveStaticLibrariesForOrdering: depSet,
 		})
 	} else {
-		ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+		android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
 			SharedLibrary: lib,
 			Target:        ctx.Target(),
 		})
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index feb3880..e815172 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -54,6 +54,7 @@
 
 import (
 	"android/soong/android"
+	"strings"
 )
 
 func init() {
@@ -61,19 +62,19 @@
 }
 
 func RegisterNdkModuleTypes(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("ndk_headers", ndkHeadersFactory)
+	ctx.RegisterModuleType("ndk_headers", NdkHeadersFactory)
 	ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
-	ctx.RegisterModuleType("versioned_ndk_headers", versionedNdkHeadersFactory)
+	ctx.RegisterModuleType("versioned_ndk_headers", VersionedNdkHeadersFactory)
 	ctx.RegisterModuleType("preprocessed_ndk_headers", preprocessedNdkHeadersFactory)
 	ctx.RegisterParallelSingletonType("ndk", NdkSingleton)
 }
 
-func getNdkInstallBase(ctx android.PathContext) android.InstallPath {
+func getNdkInstallBase(ctx android.PathContext) android.OutputPath {
 	return android.PathForNdkInstall(ctx)
 }
 
 // Returns the main install directory for the NDK sysroot. Usable with --sysroot.
-func getNdkSysrootBase(ctx android.PathContext) android.InstallPath {
+func getNdkSysrootBase(ctx android.PathContext) android.OutputPath {
 	return getNdkInstallBase(ctx).Join(ctx, "sysroot")
 }
 
@@ -96,15 +97,56 @@
 	return android.PathForOutput(ctx, "ndk.timestamp")
 }
 
+// The list of all NDK headers as they are located in the repo.
+// Used for ABI monitoring to track only structures defined in NDK headers.
+func getNdkABIHeadersFile(ctx android.PathContext) android.WritablePath {
+	return android.PathForOutput(ctx, "ndk_abi_headers.txt")
+}
+
 func NdkSingleton() android.Singleton {
 	return &ndkSingleton{}
 }
 
+// Collect all NDK exported headers paths into a file that is used to
+// detect public types that should be ABI monitored.
+//
+// Assume that we have the following code in exported header:
+//
+//	typedef struct Context Context;
+//	typedef struct Output {
+//	    ...
+//	} Output;
+//	void DoSomething(Context* ctx, Output* output);
+//
+// If none of public headers exported to end-users contain definition of
+// "struct Context", then "struct Context" layout and members shouldn't be
+// monitored. However we use DWARF information from a real library, which
+// may have access to the definition of "string Context" from
+// implementation headers, and it will leak to ABI.
+//
+// STG tool doesn't access source and header files, only DWARF information
+// from compiled library. And the DWARF contains file name where a type is
+// defined. So we need a rule to build a list of paths to public headers,
+// so STG can distinguish private types from public and do not monitor
+// private types that are not accessible to library users.
+func writeNdkAbiSrcFilter(ctx android.BuilderContext,
+	headerSrcPaths android.Paths, outputFile android.WritablePath) {
+	var filterBuilder strings.Builder
+	filterBuilder.WriteString("[decl_file_allowlist]\n")
+	for _, headerSrcPath := range headerSrcPaths {
+		filterBuilder.WriteString(headerSrcPath.String())
+		filterBuilder.WriteString("\n")
+	}
+
+	android.WriteFileRule(ctx, outputFile, filterBuilder.String())
+}
+
 type ndkSingleton struct{}
 
 func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	var staticLibInstallPaths android.Paths
-	var headerPaths android.Paths
+	var headerSrcPaths android.Paths
+	var headerInstallPaths android.Paths
 	var installPaths android.Paths
 	var licensePaths android.Paths
 	ctx.VisitAllModules(func(module android.Module) {
@@ -113,19 +155,22 @@
 		}
 
 		if m, ok := module.(*headerModule); ok {
-			headerPaths = append(headerPaths, m.installPaths...)
+			headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
+			headerInstallPaths = append(headerInstallPaths, m.installPaths...)
 			installPaths = append(installPaths, m.installPaths...)
 			licensePaths = append(licensePaths, m.licensePath)
 		}
 
 		if m, ok := module.(*versionedHeaderModule); ok {
-			headerPaths = append(headerPaths, m.installPaths...)
+			headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
+			headerInstallPaths = append(headerInstallPaths, m.installPaths...)
 			installPaths = append(installPaths, m.installPaths...)
 			licensePaths = append(licensePaths, m.licensePath)
 		}
 
 		if m, ok := module.(*preprocessedHeadersModule); ok {
-			headerPaths = append(headerPaths, m.installPaths...)
+			headerSrcPaths = append(headerSrcPaths, m.srcPaths...)
+			headerInstallPaths = append(headerInstallPaths, m.installPaths...)
 			installPaths = append(installPaths, m.installPaths...)
 			licensePaths = append(licensePaths, m.licensePath)
 		}
@@ -175,9 +220,11 @@
 	ctx.Build(pctx, android.BuildParams{
 		Rule:      android.Touch,
 		Output:    getNdkHeadersTimestampFile(ctx),
-		Implicits: headerPaths,
+		Implicits: headerInstallPaths,
 	})
 
+	writeNdkAbiSrcFilter(ctx, headerSrcPaths, getNdkABIHeadersFile(ctx))
+
 	fullDepPaths := append(staticLibInstallPaths, getNdkBaseTimestampFile(ctx))
 
 	// There's a phony "ndk" rule defined in core/main.mk that depends on this.
diff --git a/cc/ndkstubgen/test_ndkstubgen.py b/cc/ndkstubgen/test_ndkstubgen.py
index 1e0bdf3..22f31d9 100755
--- a/cc/ndkstubgen/test_ndkstubgen.py
+++ b/cc/ndkstubgen/test_ndkstubgen.py
@@ -463,6 +463,98 @@
         """)
         self.assertEqual(expected_version, version_file.getvalue())
 
+    def test_integration_with_llndk(self) -> None:
+        input_file = io.StringIO(textwrap.dedent("""\
+            VERSION_34 { # introduced=34
+                global:
+                    foo;
+                    bar; # llndk
+            };
+            VERSION_35 { # introduced=35
+                global:
+                    wiggle;
+                    waggle;
+                    waggle; # llndk=202404
+                    bubble; # llndk=202404
+                    duddle;
+                    duddle; # llndk=202504
+            } VERSION_34;
+        """))
+        f = copy(self.filter)
+        f.llndk = True
+        f.api = 202404
+        parser = symbolfile.SymbolFileParser(input_file, {}, f)
+        versions = parser.parse()
+
+        src_file = io.StringIO()
+        version_file = io.StringIO()
+        symbol_list_file = io.StringIO()
+
+        generator = ndkstubgen.Generator(src_file,
+                                         version_file, symbol_list_file, f)
+        generator.write(versions)
+
+        expected_src = textwrap.dedent("""\
+            void foo() {}
+            void bar() {}
+            void waggle() {}
+            void bubble() {}
+        """)
+        self.assertEqual(expected_src, src_file.getvalue())
+
+        expected_version = textwrap.dedent("""\
+            VERSION_34 {
+                global:
+                    foo;
+                    bar;
+            };
+            VERSION_35 {
+                global:
+                    waggle;
+                    bubble;
+            } VERSION_34;
+        """)
+        self.assertEqual(expected_version, version_file.getvalue())
+
+    def test_integration_with_llndk_with_single_version_block(self) -> None:
+        input_file = io.StringIO(textwrap.dedent("""\
+            LIBANDROID {
+                global:
+                    foo; # introduced=34
+                    bar; # introduced=35
+                    bar; # llndk=202404
+                    baz; # introduced=35
+            };
+        """))
+        f = copy(self.filter)
+        f.llndk = True
+        f.api = 202404
+        parser = symbolfile.SymbolFileParser(input_file, {}, f)
+        versions = parser.parse()
+
+        src_file = io.StringIO()
+        version_file = io.StringIO()
+        symbol_list_file = io.StringIO()
+
+        generator = ndkstubgen.Generator(src_file,
+                                         version_file, symbol_list_file, f)
+        generator.write(versions)
+
+        expected_src = textwrap.dedent("""\
+            void foo() {}
+            void bar() {}
+        """)
+        self.assertEqual(expected_src, src_file.getvalue())
+
+        expected_version = textwrap.dedent("""\
+            LIBANDROID {
+                global:
+                    foo;
+                    bar;
+            };
+        """)
+        self.assertEqual(expected_version, version_file.getvalue())
+
     def test_empty_stub(self) -> None:
         """Tests that empty stubs can be generated.
 
diff --git a/cc/object.go b/cc/object.go
index ca14845..6c0391f 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -19,8 +19,6 @@
 	"strings"
 
 	"android/soong/android"
-	"android/soong/bazel"
-	"android/soong/bazel/cquery"
 )
 
 //
@@ -50,33 +48,6 @@
 	ndkSysrootPath android.Path
 }
 
-type objectBazelHandler struct {
-	module *Module
-}
-
-var _ BazelHandler = (*objectBazelHandler)(nil)
-
-func (handler *objectBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
-}
-
-func (handler *objectBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	objPaths, err := bazelCtx.GetOutputFiles(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-		return
-	}
-
-	if len(objPaths) != 1 {
-		ctx.ModuleErrorf("expected exactly one object file for '%s', but got %s", label, objPaths)
-		return
-	}
-
-	handler.module.outputFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, objPaths[0]))
-}
-
 type ObjectLinkerProperties struct {
 	// list of static library modules that should only provide headers for this module.
 	Static_libs []string `android:"arch_variant,variant_prepend"`
@@ -125,115 +96,15 @@
 		baseLinker: NewBaseLinker(module.sanitize),
 	}
 	module.compiler = NewBaseCompiler()
-	module.bazelHandler = &objectBazelHandler{module: module}
 
 	// Clang's address-significance tables are incompatible with ld -r.
 	module.compiler.appendCflags([]string{"-fno-addrsig"})
 
 	module.sdkMemberTypes = []android.SdkMemberType{ccObjectSdkMemberType}
 
-	module.bazelable = true
 	return module.Init()
 }
 
-// For bp2build conversion.
-type bazelObjectAttributes struct {
-	Srcs                bazel.LabelListAttribute
-	Srcs_as             bazel.LabelListAttribute
-	Hdrs                bazel.LabelListAttribute
-	Objs                bazel.LabelListAttribute
-	Deps                bazel.LabelListAttribute
-	System_dynamic_deps bazel.LabelListAttribute
-	Copts               bazel.StringListAttribute
-	Asflags             bazel.StringListAttribute
-	Local_includes      bazel.StringListAttribute
-	Absolute_includes   bazel.StringListAttribute
-	Stl                 *string
-	Linker_script       bazel.LabelAttribute
-	Crt                 *bool
-	sdkAttributes
-}
-
-// objectBp2Build is the bp2build converter from cc_object modules to the
-// Bazel equivalent target, plus any necessary include deps for the cc_object.
-func objectBp2Build(ctx android.TopDownMutatorContext, m *Module) {
-	if m.compiler == nil {
-		// a cc_object must have access to the compiler decorator for its props.
-		ctx.ModuleErrorf("compiler must not be nil for a cc_object module")
-	}
-
-	// Set arch-specific configurable attributes
-	baseAttributes := bp2BuildParseBaseProps(ctx, m)
-	compilerAttrs := baseAttributes.compilerAttributes
-	var objs bazel.LabelListAttribute
-	var deps bazel.LabelListAttribute
-	systemDynamicDeps := bazel.LabelListAttribute{ForceSpecifyEmptyList: true}
-
-	var linkerScript bazel.LabelAttribute
-
-	for axis, configToProps := range m.GetArchVariantProperties(ctx, &ObjectLinkerProperties{}) {
-		for config, props := range configToProps {
-			if objectLinkerProps, ok := props.(*ObjectLinkerProperties); ok {
-				if objectLinkerProps.Linker_script != nil {
-					label := android.BazelLabelForModuleSrcSingle(ctx, *objectLinkerProps.Linker_script)
-					linkerScript.SetSelectValue(axis, config, label)
-				}
-				objs.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, objectLinkerProps.Objs))
-				systemSharedLibs := objectLinkerProps.System_shared_libs
-				if len(systemSharedLibs) > 0 {
-					systemSharedLibs = android.FirstUniqueStrings(systemSharedLibs)
-				}
-				systemDynamicDeps.SetSelectValue(axis, config, bazelLabelForSharedDeps(ctx, systemSharedLibs))
-				deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, objectLinkerProps.Static_libs))
-				deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, objectLinkerProps.Shared_libs))
-				deps.SetSelectValue(axis, config, android.BazelLabelForModuleDeps(ctx, objectLinkerProps.Header_libs))
-				// static_libs, shared_libs, and header_libs have variant_prepend tag
-				deps.Prepend = true
-			}
-		}
-	}
-	objs.ResolveExcludes()
-
-	// Don't split cc_object srcs across languages. Doing so would add complexity,
-	// and this isn't typically done for cc_object.
-	srcs := compilerAttrs.srcs
-	srcs.Append(compilerAttrs.cSrcs)
-
-	asFlags := compilerAttrs.asFlags
-	if compilerAttrs.asSrcs.IsEmpty() {
-		// Skip asflags for BUILD file simplicity if there are no assembly sources.
-		asFlags = bazel.MakeStringListAttribute(nil)
-	}
-
-	attrs := &bazelObjectAttributes{
-		Srcs:                srcs,
-		Srcs_as:             compilerAttrs.asSrcs,
-		Objs:                objs,
-		Deps:                deps,
-		System_dynamic_deps: systemDynamicDeps,
-		Copts:               compilerAttrs.copts,
-		Asflags:             asFlags,
-		Local_includes:      compilerAttrs.localIncludes,
-		Absolute_includes:   compilerAttrs.absoluteIncludes,
-		Stl:                 compilerAttrs.stl,
-		Linker_script:       linkerScript,
-		Crt:                 m.linker.(*objectLinker).Properties.Crt,
-		sdkAttributes:       bp2BuildParseSdkAttributes(m),
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_object",
-		Bzl_load_location: "//build/bazel/rules/cc:cc_object.bzl",
-	}
-
-	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-		Name: m.Name(),
-		Tags: tags,
-	}, attrs)
-}
-
 func (object *objectLinker) appendLdflags(flags []string) {
 	panic(fmt.Errorf("appendLdflags on objectLinker not supported"))
 }
@@ -348,6 +219,10 @@
 	return nil
 }
 
+func (object *objectLinker) strippedAllOutputFilePath() android.Path {
+	panic("Not implemented.")
+}
+
 func (object *objectLinker) nativeCoverage() bool {
 	return true
 }
@@ -363,3 +238,8 @@
 func (object *objectLinker) isCrt() bool {
 	return Bool(object.Properties.Crt)
 }
+
+func (object *objectLinker) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+	object.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON)
+	moduleInfoJSON.Class = []string{"STATIC_LIBRARIES"}
+}
diff --git a/cc/object_test.go b/cc/object_test.go
index b1e2a0f..004dfd3 100644
--- a/cc/object_test.go
+++ b/cc/object_test.go
@@ -22,7 +22,7 @@
 )
 
 func TestMinSdkVersionsOfCrtObjects(t *testing.T) {
-	ctx := testCc(t, `
+	bp := `
 		cc_object {
 			name: "crt_foo",
 			srcs: ["foo.c"],
@@ -30,8 +30,8 @@
 			stl: "none",
 			min_sdk_version: "28",
 			vendor_available: true,
-		}`)
-
+		}
+	`
 	variants := []struct {
 		variant string
 		num     string
@@ -41,13 +41,19 @@
 		{"android_arm64_armv8-a_sdk_29", "29"},
 		{"android_arm64_armv8-a_sdk_30", "30"},
 		{"android_arm64_armv8-a_sdk_current", "10000"},
-		{"android_vendor.29_arm64_armv8-a", "29"},
+		{"android_vendor_arm64_armv8-a", "10000"},
 	}
+
+	ctx := prepareForCcTest.RunTestWithBp(t, bp)
 	for _, v := range variants {
 		cflags := ctx.ModuleForTests("crt_foo", v.variant).Rule("cc").Args["cFlags"]
 		expected := "-target aarch64-linux-android" + v.num + " "
 		android.AssertStringDoesContain(t, "cflag", cflags, expected)
 	}
+	ctx = prepareForCcTest.RunTestWithBp(t, bp)
+	android.AssertStringDoesContain(t, "cflag",
+		ctx.ModuleForTests("crt_foo", "android_vendor_arm64_armv8-a").Rule("cc").Args["cFlags"],
+		"-target aarch64-linux-android10000 ")
 }
 
 func TestUseCrtObjectOfCorrectVersion(t *testing.T) {
@@ -85,30 +91,6 @@
 	})
 }
 
-func TestCcObjectWithBazel(t *testing.T) {
-	bp := `
-cc_object {
-	name: "foo",
-	srcs: ["baz.o"],
-	bazel_module: { label: "//foo/bar:bar" },
-}`
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.BazelContext = android.MockBazelContext{
-		OutputBaseDir: "outputbase",
-		LabelToOutputFiles: map[string][]string{
-			"//foo/bar:bar": []string{"bazel_out.o"}}}
-	ctx := testCcWithConfig(t, config)
-
-	module := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon").Module()
-	outputFiles, err := module.(android.OutputFileProducer).OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
-	}
-
-	expectedOutputFiles := []string{"outputbase/execroot/__main__/bazel_out.o"}
-	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
-}
-
 func TestCcObjectOutputFile(t *testing.T) {
 	testcases := []struct {
 		name       string
diff --git a/cc/orderfile.go b/cc/orderfile.go
index cc1ab29..38b8905 100644
--- a/cc/orderfile.go
+++ b/cc/orderfile.go
@@ -20,6 +20,8 @@
 import (
 	"fmt"
 
+	"github.com/google/blueprint"
+
 	"android/soong/android"
 )
 
@@ -58,17 +60,17 @@
 
 type OrderfileProperties struct {
 	Orderfile struct {
-		Instrumentation    *bool
-		Order_file_path    *string `android:"arch_variant"`
-		Load_order_file    *bool `android:"arch_variant"`
+		Instrumentation *bool
+		Order_file_path *string `android:"arch_variant"`
+		Load_order_file *bool   `android:"arch_variant"`
 		// Additional compiler flags to use when building this module
 		// for orderfile profiling.
 		Cflags []string `android:"arch_variant"`
 	} `android:"arch_variant"`
 
-	ShouldProfileModule 	  bool `blueprint:"mutated"`
-	OrderfileLoad             bool `blueprint:"mutated"`
-	OrderfileInstrLink        bool `blueprint:"mutated"`
+	ShouldProfileModule bool `blueprint:"mutated"`
+	OrderfileLoad       bool `blueprint:"mutated"`
+	OrderfileInstrLink  bool `blueprint:"mutated"`
 }
 
 type orderfile struct {
@@ -121,14 +123,13 @@
 }
 
 func (props *OrderfileProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
-	flags.Local.CFlags = append(flags.Local.CFlags, props.Orderfile.Cflags...)
 	flags.Local.CFlags = append(flags.Local.CFlags, orderfileProfileFlag)
 	flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm -enable-order-file-instrumentation")
+	flags.Local.CFlags = append(flags.Local.CFlags, props.Orderfile.Cflags...)
 	flags.Local.LdFlags = append(flags.Local.LdFlags, orderfileProfileFlag)
 	return flags
 }
 
-
 func (props *OrderfileProperties) loadOrderfileFlags(ctx ModuleContext, file string) []string {
 	flags := []string{fmt.Sprintf(orderfileUseFormat, file)}
 	flags = append(flags, orderfileOtherFlags...)
@@ -140,7 +141,6 @@
 	orderFilePath := orderFile.Path()
 	loadFlags := props.loadOrderfileFlags(ctx, orderFilePath.String())
 
-	flags.Local.CFlags = append(flags.Local.CFlags, loadFlags...)
 	flags.Local.LdFlags = append(flags.Local.LdFlags, loadFlags...)
 
 	// Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
@@ -192,66 +192,61 @@
 	return flags
 }
 
-// Propagate profile orderfile flags down from binaries and shared libraries
-// We do not allow propagation for load flags because the orderfile is specific
-// to the module (binary / shared library)
-func orderfileDepsMutator(mctx android.TopDownMutatorContext) {
-	if m, ok := mctx.Module().(*Module); ok {
-		if !m.orderfile.orderfileLinkEnabled() {
-			return
-		}
-		mctx.WalkDeps(func(dep android.
-			Module, parent android.Module) bool {
-			tag := mctx.OtherModuleDependencyTag(dep)
-			libTag, isLibTag := tag.(libraryDependencyTag)
-
-			// Do not recurse down non-static dependencies
-			if isLibTag {
-				if !libTag.static() {
-					return false
-				}
-			} else {
-				if tag != objDepTag && tag != reuseObjTag {
-					return false
-				}
-			}
-
-			if dep, ok := dep.(*Module); ok {
-				if m.orderfile.Properties.OrderfileInstrLink {
-					dep.orderfile.Properties.OrderfileInstrLink = true;
-				}
-			}
-
-			return true
-		})
+func orderfilePropagateViaDepTag(tag blueprint.DependencyTag) bool {
+	libTag, isLibTag := tag.(libraryDependencyTag)
+	// Do not recurse down non-static dependencies
+	if isLibTag {
+		return libTag.static()
+	} else {
+		return tag == objDepTag || tag == reuseObjTag || tag == staticVariantTag
 	}
 }
 
-// Create orderfile variants for modules that need them
-func orderfileMutator(mctx android.BottomUpMutatorContext) {
-	if m, ok := mctx.Module().(*Module); ok && m.orderfile != nil {
-		if !m.static() && m.orderfile.orderfileEnabled() {
-			mctx.SetDependencyVariation("orderfile")
-			return
+// orderfileTransitionMutator creates orderfile variants of cc modules.
+type orderfileTransitionMutator struct{}
+
+const ORDERFILE_VARIATION = "orderfile"
+
+func (o *orderfileTransitionMutator) Split(ctx android.BaseModuleContext) []string {
+	return []string{""}
+}
+
+func (o *orderfileTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+	if m, ok := ctx.Module().(*Module); ok && m.orderfile != nil {
+		if !orderfilePropagateViaDepTag(ctx.DepTag()) {
+			return ""
 		}
 
-		variationNames := []string{""}
-		if m.orderfile.Properties.OrderfileInstrLink {
-			variationNames = append(variationNames, "orderfile")
+		if sourceVariation != "" {
+			return sourceVariation
 		}
 
-		if len(variationNames) > 1 {
-			modules := mctx.CreateVariations(variationNames...)
-			for i, name := range variationNames {
-				if name == "" {
-					continue
-				}
-				variation := modules[i].(*Module)
-				variation.Properties.PreventInstall = true
-				variation.Properties.HideFromMake = true
-				variation.orderfile.Properties.ShouldProfileModule = true
-				variation.orderfile.Properties.OrderfileLoad = false
-			}
+		// Propagate profile orderfile flags down from binaries and shared libraries
+		if m.orderfile.orderfileLinkEnabled() {
+			return ORDERFILE_VARIATION
 		}
 	}
+	return ""
+}
+
+func (o *orderfileTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+	if m, ok := ctx.Module().(*Module); ok && m.orderfile != nil {
+		return incomingVariation
+	}
+	return ""
+}
+
+func (o *orderfileTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+	if variation == "" {
+		return
+	}
+
+	if m, ok := ctx.Module().(*Module); ok && m.orderfile != nil {
+		m.Properties.PreventInstall = true
+		m.Properties.HideFromMake = true
+		m.orderfile.Properties.ShouldProfileModule = true
+		// We do not allow propagation for load flags because the orderfile is specific
+		// to the module (binary / shared library)
+		m.orderfile.Properties.OrderfileLoad = false
+	}
 }
diff --git a/cc/orderfile_test.go b/cc/orderfile_test.go
index 9e30bd2..3486f96 100644
--- a/cc/orderfile_test.go
+++ b/cc/orderfile_test.go
@@ -15,8 +15,8 @@
 package cc
 
 import (
-	"testing"
 	"strings"
+	"testing"
 
 	"android/soong/android"
 )
@@ -79,12 +79,6 @@
 
 	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
 
-	// Check cFlags of orderfile-enabled module
-	cFlags := libTest.Rule("cc").Args["cFlags"]
-	if !strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
-	}
-
 	// Check ldFlags of orderfile-enabled module
 	ldFlags := libTest.Rule("ld").Args["ldFlags"]
 	if !strings.Contains(ldFlags, expectedCFlag) {
@@ -150,12 +144,6 @@
 
 	test := result.ModuleForTests("test", "android_arm64_armv8-a")
 
-	// Check cFlags of orderfile-enabled module
-	cFlags := test.Rule("cc").Args["cFlags"]
-	if !strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'test' to load orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
-	}
-
 	// Check ldFlags of orderfile-enabled module
 	ldFlags := test.Rule("ld").Args["ldFlags"]
 	if !strings.Contains(ldFlags, expectedCFlag) {
@@ -205,8 +193,8 @@
 	}
 
 	// Check cFlags of orderfile variant static libraries
-	libFooOfVariant  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_orderfile")
-	libBarOfVariant  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_orderfile")
+	libFooOfVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_orderfile")
+	libBarOfVariant := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_orderfile")
 
 	cFlags = libFooOfVariant.Rule("cc").Args["cFlags"]
 	if !strings.Contains(cFlags, expectedCFlag) {
@@ -228,8 +216,8 @@
 	}
 
 	// Check cFlags of the non-orderfile variant static libraries
-	libFoo  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
-	libBar  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+	libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
 
 	cFlags = libFoo.Rule("cc").Args["cFlags"]
 	if strings.Contains(cFlags, expectedCFlag) {
@@ -285,27 +273,16 @@
 
 	expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/test.orderfile"
 
-	// Check cFlags of orderfile-enabled module
+	// Check ldFlags of orderfile-enabled module
 	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
 
-	cFlags := libTest.Rule("cc").Args["cFlags"]
-	if !strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	ldFlags := libTest.Rule("ld").Args["ldFlags"]
+	if !strings.Contains(ldFlags, expectedCFlag) {
+		t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in ldFlags %q", expectedCFlag, ldFlags)
 	}
 
-	// Check cFlags of the non-orderfile variant static libraries
-	libFoo  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
-	libBar  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
-
-	cFlags = libFoo.Rule("cc").Args["cFlags"]
-	if strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libFoo' not load orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
-	}
-
-	cFlags = libBar.Rule("cc").Args["cFlags"]
-	if strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libBar' not load orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
-	}
+	libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
 
 	// Check dependency edge from orderfile-enabled module to non-orderfile variant static libraries
 	if !hasDirectDep(result, libTest.Module(), libFoo.Module()) {
@@ -374,8 +351,8 @@
 	}
 
 	// Check cFlags of the static and shared libraries
-	libFoo  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_shared")
-	libBar  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+	libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_shared")
+	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
 
 	cFlags = libFoo.Rule("cc").Args["cFlags"]
 	if strings.Contains(cFlags, expectedCFlag) {
@@ -454,8 +431,8 @@
 	}
 
 	// Check cFlags of the static libraries
-	libFoo  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
-	libBar  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+	libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
 
 	cFlags = libFoo.Rule("cc").Args["cFlags"]
 	if strings.Contains(cFlags, expectedCFlag) {
@@ -490,4 +467,4 @@
 			t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v)
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/cc/pgo.go b/cc/pgo.go
deleted file mode 100644
index 463e2e6..0000000
--- a/cc/pgo.go
+++ /dev/null
@@ -1,294 +0,0 @@
-// Copyright 2017 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cc
-
-import (
-	"fmt"
-	"path/filepath"
-	"strings"
-
-	"github.com/google/blueprint/proptools"
-
-	"android/soong/android"
-)
-
-var (
-	// Add flags to ignore warnings that profiles are old or missing for
-	// some functions.
-	profileUseOtherFlags = []string{
-		"-Wno-backend-plugin",
-	}
-
-	globalPgoProfileProjects = []string{
-		"toolchain/pgo-profiles/pgo",
-		"vendor/google_data/pgo_profile/pgo",
-	}
-)
-
-var pgoProfileProjectsConfigKey = android.NewOnceKey("PgoProfileProjects")
-
-const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
-const profileUseInstrumentFormat = "-fprofile-use=%s"
-
-func getPgoProfileProjects(config android.DeviceConfig) []string {
-	return config.OnceStringSlice(pgoProfileProjectsConfigKey, func() []string {
-		return append(globalPgoProfileProjects, config.PgoAdditionalProfileDirs()...)
-	})
-}
-
-func recordMissingProfileFile(ctx BaseModuleContext, missing string) {
-	getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
-}
-
-type PgoProperties struct {
-	Pgo struct {
-		Instrumentation    *bool
-		Profile_file       *string `android:"arch_variant"`
-		Benchmarks         []string
-		Enable_profile_use *bool `android:"arch_variant"`
-		// Additional compiler flags to use when building this module
-		// for profiling.
-		Cflags []string `android:"arch_variant"`
-	} `android:"arch_variant"`
-
-	PgoPresent          bool `blueprint:"mutated"`
-	ShouldProfileModule bool `blueprint:"mutated"`
-	PgoCompile          bool `blueprint:"mutated"`
-	PgoInstrLink        bool `blueprint:"mutated"`
-}
-
-type pgo struct {
-	Properties PgoProperties
-}
-
-func (props *PgoProperties) isInstrumentation() bool {
-	return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true
-}
-
-func (pgo *pgo) props() []interface{} {
-	return []interface{}{&pgo.Properties}
-}
-
-func (props *PgoProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
-	// Add to C flags iff PGO is explicitly enabled for this module.
-	if props.ShouldProfileModule {
-		flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...)
-		flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag)
-	}
-	flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrumentFlag)
-	return flags
-}
-
-func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath {
-	profileFile := *props.Pgo.Profile_file
-
-	// Test if the profile_file is present in any of the PGO profile projects
-	for _, profileProject := range getPgoProfileProjects(ctx.DeviceConfig()) {
-		// Bug: http://b/74395273 If the profile_file is unavailable,
-		// use a versioned file named
-		// <profile_file>.<arbitrary-version> when available.  This
-		// works around an issue where ccache serves stale cache
-		// entries when the profile file has changed.
-		globPattern := filepath.Join(profileProject, profileFile+".*")
-		versionedProfiles, err := ctx.GlobWithDeps(globPattern, nil)
-		if err != nil {
-			ctx.ModuleErrorf("glob: %s", err.Error())
-		}
-
-		path := android.ExistentPathForSource(ctx, profileProject, profileFile)
-		if path.Valid() {
-			if len(versionedProfiles) != 0 {
-				ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+filepath.Join(profileProject, profileFile)+", "+strings.Join(versionedProfiles, ", "))
-			}
-			return path
-		}
-
-		if len(versionedProfiles) > 1 {
-			ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+strings.Join(versionedProfiles, ", "))
-		} else if len(versionedProfiles) == 1 {
-			return android.OptionalPathForPath(android.PathForSource(ctx, versionedProfiles[0]))
-		}
-	}
-
-	// Record that this module's profile file is absent
-	missing := *props.Pgo.Profile_file + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
-	recordMissingProfileFile(ctx, missing)
-
-	return android.OptionalPathForPath(nil)
-}
-
-func (props *PgoProperties) profileUseFlags(ctx ModuleContext, file string) []string {
-	flags := []string{fmt.Sprintf(profileUseInstrumentFormat, file)}
-	flags = append(flags, profileUseOtherFlags...)
-	return flags
-}
-
-func (props *PgoProperties) addProfileUseFlags(ctx ModuleContext, flags Flags) Flags {
-	// Return if 'pgo' property is not present in this module.
-	if !props.PgoPresent {
-		return flags
-	}
-
-	if props.PgoCompile {
-		profileFile := props.getPgoProfileFile(ctx)
-		profileFilePath := profileFile.Path()
-		profileUseFlags := props.profileUseFlags(ctx, profileFilePath.String())
-
-		flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlags...)
-		flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlags...)
-
-		// Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
-		// if profileFile gets updated
-		flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath)
-		flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath)
-	}
-	return flags
-}
-
-func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool {
-	isInstrumentation := props.isInstrumentation()
-
-	profileKindPresent := isInstrumentation
-	filePresent := props.Pgo.Profile_file != nil
-	benchmarksPresent := len(props.Pgo.Benchmarks) > 0
-
-	// If all three properties are absent, PGO is OFF for this module
-	if !profileKindPresent && !filePresent && !benchmarksPresent {
-		return false
-	}
-
-	// profileKindPresent and filePresent are mandatory properties.
-	if !profileKindPresent || !filePresent {
-		var missing []string
-		if !profileKindPresent {
-			missing = append(missing, "profile kind")
-		}
-		if !filePresent {
-			missing = append(missing, "profile_file property")
-		}
-		missingProps := strings.Join(missing, ", ")
-		ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps)
-	}
-
-	// Benchmark property is mandatory for instrumentation PGO.
-	if isInstrumentation && !benchmarksPresent {
-		ctx.ModuleErrorf("Instrumentation PGO specification is missing benchmark property")
-	}
-
-	return true
-}
-
-func (pgo *pgo) begin(ctx BaseModuleContext) {
-	// TODO Evaluate if we need to support PGO for host modules
-	if ctx.Host() {
-		return
-	}
-
-	// Check if PGO is needed for this module
-	pgo.Properties.PgoPresent = pgo.Properties.isPGO(ctx)
-
-	if !pgo.Properties.PgoPresent {
-		return
-	}
-
-	// This module should be instrumented if ANDROID_PGO_INSTRUMENT is set
-	// and includes 'all', 'ALL' or a benchmark listed for this module.
-	//
-	// TODO Validate that each benchmark instruments at least one module
-	pgo.Properties.ShouldProfileModule = false
-	pgoBenchmarks := ctx.Config().Getenv("ANDROID_PGO_INSTRUMENT")
-	pgoBenchmarksMap := make(map[string]bool)
-	for _, b := range strings.Split(pgoBenchmarks, ",") {
-		pgoBenchmarksMap[b] = true
-	}
-
-	if pgoBenchmarksMap["all"] == true || pgoBenchmarksMap["ALL"] == true {
-		pgo.Properties.ShouldProfileModule = true
-		pgo.Properties.PgoInstrLink = pgo.Properties.isInstrumentation()
-	} else {
-		for _, b := range pgo.Properties.Pgo.Benchmarks {
-			if pgoBenchmarksMap[b] == true {
-				pgo.Properties.ShouldProfileModule = true
-				pgo.Properties.PgoInstrLink = pgo.Properties.isInstrumentation()
-				break
-			}
-		}
-	}
-
-	// PGO profile use is not feasible for a Clang coverage build because
-	// -fprofile-use and -fprofile-instr-generate are incompatible.
-	if ctx.DeviceConfig().ClangCoverageEnabled() {
-		return
-	}
-
-	if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") &&
-		proptools.BoolDefault(pgo.Properties.Pgo.Enable_profile_use, true) {
-		if profileFile := pgo.Properties.getPgoProfileFile(ctx); profileFile.Valid() {
-			pgo.Properties.PgoCompile = true
-		}
-	}
-}
-
-func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags {
-	if ctx.Host() {
-		return flags
-	}
-
-	// Deduce PgoInstrLink property i.e. whether this module needs to be
-	// linked with profile-generation flags.  Here, we're setting it if any
-	// dependency needs PGO instrumentation.  It is initially set in
-	// begin() if PGO is directly enabled for this module.
-	if ctx.static() && !ctx.staticBinary() {
-		// For static libraries, check if any whole_static_libs are
-		// linked with profile generation
-		ctx.VisitDirectDeps(func(m android.Module) {
-			if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok {
-				if depTag.static() && depTag.wholeStatic {
-					if cc, ok := m.(*Module); ok {
-						if cc.pgo.Properties.PgoInstrLink {
-							pgo.Properties.PgoInstrLink = true
-						}
-					}
-				}
-			}
-		})
-	} else {
-		// For executables and shared libraries, check all static dependencies.
-		ctx.VisitDirectDeps(func(m android.Module) {
-			if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok {
-				if depTag.static() {
-					if cc, ok := m.(*Module); ok {
-						if cc.pgo.Properties.PgoInstrLink {
-							pgo.Properties.PgoInstrLink = true
-						}
-					}
-				}
-			}
-		})
-	}
-
-	props := pgo.Properties
-	// Add flags to profile this module based on its profile_kind
-	if (props.ShouldProfileModule && props.isInstrumentation()) || props.PgoInstrLink {
-		// Instrumentation PGO use and gather flags cannot coexist.
-		return props.addInstrumentationProfileGatherFlags(ctx, flags)
-	}
-
-	if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
-		flags = props.addProfileUseFlags(ctx, flags)
-	}
-
-	return flags
-}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index e2cd3ad..e9f790f 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -17,9 +17,9 @@
 import (
 	"path/filepath"
 
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
-	"android/soong/bazel"
-	"android/soong/bazel/cquery"
 )
 
 func init() {
@@ -38,9 +38,15 @@
 type prebuiltLinkerInterface interface {
 	Name(string) string
 	prebuilt() *android.Prebuilt
+	sourceModuleName() string
 }
 
 type prebuiltLinkerProperties struct {
+	// Name of the source soong module that gets shadowed by this prebuilt
+	// If unspecified, follows the naming convention that the source module of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_module_name *string
+
 	// a prebuilt library or binary. Can reference a genrule module that generates an executable file.
 	Srcs []string `android:"path,arch_variant"`
 
@@ -57,13 +63,6 @@
 	// This is needed only if this library is linked by other modules in build time.
 	// Only makes sense for the Windows target.
 	Windows_import_lib *string `android:"path,arch_variant"`
-
-	// MixedBuildsDisabled is true if and only if building this prebuilt is explicitly disabled in mixed builds for either
-	// its static or shared version on the current build variant. This is to prevent Bazel targets for build variants with
-	// which either the static or shared version is incompatible from participating in mixed buiods. Please note that this
-	// is an override and does not fully determine whether Bazel or Soong will be used. For the full determination, see
-	// cc.ProcessBazelQueryResponse, cc.QueueBazelCall, and cc.MixedBuildsDisabled.
-	MixedBuildsDisabled bool `blueprint:"mutated"`
 }
 
 type prebuiltLinker struct {
@@ -141,7 +140,7 @@
 
 		if p.static() {
 			depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(in).Build()
-			ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+			android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{
 				StaticLibrary: in,
 
 				TransitiveStaticLibrariesForOrdering: depSet,
@@ -199,7 +198,7 @@
 				},
 			})
 
-			ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+			android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
 				SharedLibrary: outputFile,
 				Target:        ctx.Target(),
 
@@ -222,7 +221,7 @@
 	}
 
 	if p.header() {
-		ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{})
+		android.SetProvider(ctx, HeaderLibraryInfoProvider, HeaderLibraryInfo{})
 
 		// Need to return an output path so that the AndroidMk logic doesn't skip
 		// the prebuilt header. For compatibility, in case Android.mk files use a
@@ -261,7 +260,9 @@
 
 func (p *prebuiltLibraryLinker) disablePrebuilt() {
 	p.properties.Srcs = nil
-	p.properties.MixedBuildsDisabled = true
+	p.properties.Sanitized.None.Srcs = nil
+	p.properties.Sanitized.Address.Srcs = nil
+	p.properties.Sanitized.Hwaddress.Srcs = nil
 }
 
 // Implements versionedInterface
@@ -272,8 +273,6 @@
 func NewPrebuiltLibrary(hod android.HostOrDeviceSupported, srcsProperty string) (*Module, *libraryDecorator) {
 	module, library := NewLibrary(hod)
 	module.compiler = nil
-	module.bazelable = true
-	module.bazelHandler = &prebuiltLibraryBazelHandler{module: module, library: library}
 
 	prebuilt := &prebuiltLibraryLinker{
 		libraryDecorator: library,
@@ -348,84 +347,12 @@
 	return module, library
 }
 
-type bazelPrebuiltLibraryStaticAttributes struct {
-	Static_library         bazel.LabelAttribute
-	Export_includes        bazel.StringListAttribute
-	Export_system_includes bazel.StringListAttribute
-	Alwayslink             bazel.BoolAttribute
-}
-
-// TODO(b/228623543): The below is not entirely true until the bug is fixed. For now, both targets are always generated
-// Implements bp2build for cc_prebuilt_library modules. This will generate:
-//   - Only a cc_prebuilt_library_static if the shared.enabled property is set to false across all variants.
-//   - Only a cc_prebuilt_library_shared if the static.enabled property is set to false across all variants
-//   - Both a cc_prebuilt_library_static and cc_prebuilt_library_shared if the aforementioned properties are not false across
-//     all variants
-//
-// In all cases, cc_prebuilt_library_static target names will be appended with "_bp2build_cc_library_static".
-func prebuiltLibraryBp2Build(ctx android.TopDownMutatorContext, module *Module) {
-	prebuiltLibraryStaticBp2Build(ctx, module, true)
-	prebuiltLibrarySharedBp2Build(ctx, module)
-}
-
-func prebuiltLibraryStaticBp2Build(ctx android.TopDownMutatorContext, module *Module, fullBuild bool) {
-	prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module, true)
-	exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, nil)
-
-	attrs := &bazelPrebuiltLibraryStaticAttributes{
-		Static_library:         prebuiltAttrs.Src,
-		Export_includes:        exportedIncludes.Includes,
-		Export_system_includes: exportedIncludes.SystemIncludes,
-		// TODO: ¿Alwayslink?
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_prebuilt_library_static",
-		Bzl_load_location: "//build/bazel/rules/cc:cc_prebuilt_library_static.bzl",
-	}
-
-	name := android.RemoveOptionalPrebuiltPrefix(module.Name())
-	if fullBuild {
-		name += "_bp2build_cc_library_static"
-	}
-
-	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
-	ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name, Tags: tags}, attrs, prebuiltAttrs.Enabled)
-
-	_true := true
-	alwayslinkAttrs := *attrs
-	alwayslinkAttrs.Alwayslink.SetValue(&_true)
-	ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name + "_alwayslink", Tags: tags}, &alwayslinkAttrs, prebuiltAttrs.Enabled)
-}
-
-type bazelPrebuiltLibrarySharedAttributes struct {
-	Shared_library         bazel.LabelAttribute
-	Export_includes        bazel.StringListAttribute
-	Export_system_includes bazel.StringListAttribute
-}
-
-func prebuiltLibrarySharedBp2Build(ctx android.TopDownMutatorContext, module *Module) {
-	prebuiltAttrs := Bp2BuildParsePrebuiltLibraryProps(ctx, module, false)
-	exportedIncludes := bp2BuildParseExportedIncludes(ctx, module, nil)
-
-	attrs := &bazelPrebuiltLibrarySharedAttributes{
-		Shared_library:         prebuiltAttrs.Src,
-		Export_includes:        exportedIncludes.Includes,
-		Export_system_includes: exportedIncludes.SystemIncludes,
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_prebuilt_library_shared",
-		Bzl_load_location: "//build/bazel/rules/cc:cc_prebuilt_library_shared.bzl",
-	}
-
-	name := android.RemoveOptionalPrebuiltPrefix(module.Name())
-	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
-	ctx.CreateBazelTargetModuleWithRestrictions(props, android.CommonAttributes{Name: name, Tags: tags}, attrs, prebuiltAttrs.Enabled)
-}
-
 type prebuiltObjectProperties struct {
-	Srcs []string `android:"path,arch_variant"`
+	// Name of the source soong module that gets shadowed by this prebuilt
+	// If unspecified, follows the naming convention that the source module of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_module_name *string
+	Srcs               []string `android:"path,arch_variant"`
 }
 
 type prebuiltObjectLinker struct {
@@ -435,139 +362,14 @@
 	properties prebuiltObjectProperties
 }
 
-type prebuiltLibraryBazelHandler struct {
-	module  *Module
-	library *libraryDecorator
-}
-
-var _ BazelHandler = (*prebuiltLibraryBazelHandler)(nil)
-
-func (h *prebuiltLibraryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
-	if h.module.linker.(*prebuiltLibraryLinker).properties.MixedBuildsDisabled {
-		return
-	}
-	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(label, cquery.GetCcInfo, android.GetConfigKey(ctx))
-}
-
-func (h *prebuiltLibraryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
-	if h.module.linker.(*prebuiltLibraryLinker).properties.MixedBuildsDisabled {
-		return
-	}
-	bazelCtx := ctx.Config().BazelContext
-	ccInfo, err := bazelCtx.GetCcInfo(label, android.GetConfigKey(ctx))
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-		return
-	}
-
-	if h.module.static() {
-		if ok := h.processStaticBazelQueryResponse(ctx, label, ccInfo); !ok {
-			return
-		}
-	} else if h.module.Shared() {
-		if ok := h.processSharedBazelQueryResponse(ctx, label, ccInfo); !ok {
-			return
-		}
-	} else {
-		return
-	}
-
-	h.module.maybeUnhideFromMake()
-
-	h.module.setAndroidMkVariablesFromCquery(ccInfo.CcAndroidMkInfo)
-}
-
-func (h *prebuiltLibraryBazelHandler) processStaticBazelQueryResponse(ctx android.ModuleContext, label string, ccInfo cquery.CcInfo) bool {
-	staticLibs := ccInfo.CcStaticLibraryFiles
-	if len(staticLibs) > 1 {
-		ctx.ModuleErrorf("expected 1 static library from bazel target %q, got %s", label, staticLibs)
-		return false
-	}
-
-	// TODO(b/184543518): cc_prebuilt_library_static may have properties for re-exporting flags
-
-	// TODO(eakammer):Add stub-related flags if this library is a stub library.
-	// h.library.exportVersioningMacroIfNeeded(ctx)
-
-	// Dependencies on this library will expect collectedSnapshotHeaders to be set, otherwise
-	// validation will fail. For now, set this to an empty list.
-	// TODO(cparsons): More closely mirror the collectHeadersForSnapshot implementation.
-	h.library.collectedSnapshotHeaders = android.Paths{}
-
-	if len(staticLibs) == 0 {
-		h.module.outputFile = android.OptionalPath{}
-		return true
-	}
-
-	var outputPath android.Path = android.PathForBazelOut(ctx, staticLibs[0])
-	if len(ccInfo.TidyFiles) > 0 {
-		h.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles)
-		outputPath = android.AttachValidationActions(ctx, outputPath, h.module.tidyFiles)
-	}
-
-	h.module.outputFile = android.OptionalPathForPath(outputPath)
-
-	depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(outputPath).Build()
-	ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
-		StaticLibrary:                        outputPath,
-		TransitiveStaticLibrariesForOrdering: depSet,
-	})
-
-	return true
-}
-
-func (h *prebuiltLibraryBazelHandler) processSharedBazelQueryResponse(ctx android.ModuleContext, label string, ccInfo cquery.CcInfo) bool {
-	sharedLibs := ccInfo.CcSharedLibraryFiles
-	if len(sharedLibs) > 1 {
-		ctx.ModuleErrorf("expected 1 shared library from bazel target %s, got %q", label, sharedLibs)
-		return false
-	}
-
-	// TODO(b/184543518): cc_prebuilt_library_shared may have properties for re-exporting flags
-
-	// TODO(eakammer):Add stub-related flags if this library is a stub library.
-	// h.library.exportVersioningMacroIfNeeded(ctx)
-
-	if len(sharedLibs) == 0 {
-		h.module.outputFile = android.OptionalPath{}
-		return true
-	}
-
-	var outputPath android.Path = android.PathForBazelOut(ctx, sharedLibs[0])
-	if len(ccInfo.TidyFiles) > 0 {
-		h.module.tidyFiles = android.PathsForBazelOut(ctx, ccInfo.TidyFiles)
-		outputPath = android.AttachValidationActions(ctx, outputPath, h.module.tidyFiles)
-	}
-
-	h.module.outputFile = android.OptionalPathForPath(outputPath)
-
-	// FIXME(b/214600441): We don't yet strip prebuilt shared libraries
-	h.library.unstrippedOutputFile = outputPath
-
-	var toc android.Path
-	if len(ccInfo.TocFile) > 0 {
-		toc = android.PathForBazelOut(ctx, ccInfo.TocFile)
-	} else {
-		toc = outputPath // Just reuse `out` so ninja still gets an input but won't matter
-	}
-
-	info := SharedLibraryInfo{
-		SharedLibrary:   outputPath,
-		TableOfContents: android.OptionalPathForPath(toc),
-		Target:          ctx.Target(),
-	}
-	ctx.SetProvider(SharedLibraryInfoProvider, info)
-
-	h.library.setFlagExporterInfoFromCcInfo(ctx, ccInfo)
-	h.module.maybeUnhideFromMake()
-	return true
-}
-
 func (p *prebuiltObjectLinker) prebuilt() *android.Prebuilt {
 	return &p.Prebuilt
 }
 
+func (p *prebuiltObjectLinker) sourceModuleName() string {
+	return proptools.String(p.properties.Source_module_name)
+}
+
 var _ prebuiltLinkerInterface = (*prebuiltObjectLinker)(nil)
 
 func (p *prebuiltObjectLinker) link(ctx ModuleContext,
@@ -593,8 +395,6 @@
 
 func NewPrebuiltObject(hod android.HostOrDeviceSupported) *Module {
 	module := newObject(hod)
-	module.bazelHandler = &prebuiltObjectBazelHandler{module: module}
-	module.bazelable = true
 	prebuilt := &prebuiltObjectLinker{
 		objectLinker: objectLinker{
 			baseLinker: NewBaseLinker(nil),
@@ -606,54 +406,6 @@
 	return module
 }
 
-type prebuiltObjectBazelHandler struct {
-	module *Module
-}
-
-var _ BazelHandler = (*prebuiltObjectBazelHandler)(nil)
-
-func (h *prebuiltObjectBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKey(ctx))
-}
-
-func (h *prebuiltObjectBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	outputs, err := bazelCtx.GetOutputFiles(label, android.GetConfigKey(ctx))
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-		return
-	}
-	if len(outputs) != 1 {
-		ctx.ModuleErrorf("Expected a single output for `%s`, but got:\n%v", label, outputs)
-		return
-	}
-	out := android.PathForBazelOut(ctx, outputs[0])
-	h.module.outputFile = android.OptionalPathForPath(out)
-	h.module.maybeUnhideFromMake()
-}
-
-type bazelPrebuiltObjectAttributes struct {
-	Src bazel.LabelAttribute
-}
-
-func prebuiltObjectBp2Build(ctx android.TopDownMutatorContext, module *Module) {
-	prebuiltAttrs := bp2BuildParsePrebuiltObjectProps(ctx, module)
-
-	attrs := &bazelPrebuiltObjectAttributes{
-		Src: prebuiltAttrs.Src,
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_prebuilt_object",
-		Bzl_load_location: "//build/bazel/rules/cc:cc_prebuilt_object.bzl",
-	}
-
-	name := android.RemoveOptionalPrebuiltPrefix(module.Name())
-	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name, Tags: tags}, attrs)
-}
-
 func PrebuiltObjectFactory() android.Module {
 	module := NewPrebuiltObject(android.HostAndDeviceSupported)
 	return module.Init()
@@ -747,15 +499,9 @@
 	return module.Init()
 }
 
-type prebuiltBinaryBazelHandler struct {
-	module    *Module
-	decorator *binaryDecorator
-}
-
 func NewPrebuiltBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
-	module, binary := newBinary(hod, true)
+	module, binary := newBinary(hod)
 	module.compiler = nil
-	module.bazelHandler = &prebuiltBinaryBazelHandler{module, binary}
 
 	prebuilt := &prebuiltBinaryLinker{
 		binaryDecorator: binary,
@@ -769,54 +515,6 @@
 	return module, binary
 }
 
-var _ BazelHandler = (*prebuiltBinaryBazelHandler)(nil)
-
-func (h *prebuiltBinaryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
-}
-
-func (h *prebuiltBinaryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	outputs, err := bazelCtx.GetOutputFiles(label, android.GetConfigKeyApexVariant(ctx, GetApexConfigKey(ctx)))
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-		return
-	}
-	if len(outputs) != 1 {
-		ctx.ModuleErrorf("Expected a single output for `%s`, but got:\n%v", label, outputs)
-		return
-	}
-	out := android.PathForBazelOut(ctx, outputs[0])
-	h.module.outputFile = android.OptionalPathForPath(out)
-	h.module.maybeUnhideFromMake()
-}
-
-type bazelPrebuiltBinaryAttributes struct {
-	Src   bazel.LabelAttribute
-	Strip stripAttributes
-}
-
-func prebuiltBinaryBp2Build(ctx android.TopDownMutatorContext, module *Module) {
-	prebuiltAttrs := bp2BuildParsePrebuiltBinaryProps(ctx, module)
-
-	var la linkerAttributes
-	la.convertStripProps(ctx, module)
-	attrs := &bazelPrebuiltBinaryAttributes{
-		Src:   prebuiltAttrs.Src,
-		Strip: stripAttrsFromLinkerAttrs(&la),
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_prebuilt_binary",
-		Bzl_load_location: "//build/bazel/rules/cc:cc_prebuilt_binary.bzl",
-	}
-
-	name := android.RemoveOptionalPrebuiltPrefix(module.Name())
-	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name, Tags: tags}, attrs)
-}
-
 type Sanitized struct {
 	None struct {
 		Srcs []string `android:"path,arch_variant"`
@@ -841,3 +539,7 @@
 	}
 	return sanitized.None.Srcs
 }
+
+func (p *prebuiltLinker) sourceModuleName() string {
+	return proptools.String(p.properties.Source_module_name)
+}
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 0c79e55..71b7e43 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -15,12 +15,11 @@
 package cc
 
 import (
+	"fmt"
 	"runtime"
 	"testing"
 
 	"android/soong/android"
-	"android/soong/bazel/cquery"
-
 	"github.com/google/blueprint"
 )
 
@@ -386,289 +385,6 @@
 	assertString(t, static2.OutputFile().Path().Base(), "libf.hwasan.a")
 }
 
-func TestPrebuiltLibraryWithBazel(t *testing.T) {
-	const bp = `
-cc_prebuilt_library {
-	name: "foo",
-	shared: {
-		srcs: ["foo.so"],
-	},
-	static: {
-		srcs: ["foo.a"],
-	},
-	bazel_module: { label: "//foo/bar:bar" },
-}`
-	outBaseDir := "outputbase"
-	result := android.GroupFixturePreparers(
-		prepareForPrebuiltTest,
-		android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: outBaseDir,
-				LabelToCcInfo: map[string]cquery.CcInfo{
-					"//foo/bar:bar": cquery.CcInfo{
-						CcSharedLibraryFiles: []string{"foo.so"},
-					},
-					"//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{
-						CcStaticLibraryFiles: []string{"foo.a"},
-					},
-				},
-			}
-		}),
-	).RunTestWithBp(t, bp)
-	sharedFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
-	pathPrefix := outBaseDir + "/execroot/__main__/"
-
-	sharedInfo := result.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo)
-	android.AssertPathRelativeToTopEquals(t,
-		"prebuilt library shared target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.",
-		pathPrefix+"foo.so", sharedInfo.SharedLibrary)
-
-	outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
-	}
-	expectedOutputFiles := []string{pathPrefix + "foo.so"}
-	android.AssertDeepEquals(t,
-		"prebuilt library shared target output files did not match expected.",
-		expectedOutputFiles, outputFiles.Strings())
-
-	staticFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module()
-	staticInfo := result.ModuleProvider(staticFoo, StaticLibraryInfoProvider).(StaticLibraryInfo)
-	android.AssertPathRelativeToTopEquals(t,
-		"prebuilt library static target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.",
-		pathPrefix+"foo.a", staticInfo.StaticLibrary)
-
-	staticOutputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_object staticOutputFiles %s", err)
-	}
-	expectedStaticOutputFiles := []string{pathPrefix + "foo.a"}
-	android.AssertDeepEquals(t,
-		"prebuilt library static target output files did not match expected.",
-		expectedStaticOutputFiles, staticOutputFiles.Strings())
-}
-
-func TestPrebuiltLibraryWithBazelValidations(t *testing.T) {
-	const bp = `
-cc_prebuilt_library {
-	name: "foo",
-	shared: {
-		srcs: ["foo.so"],
-	},
-	static: {
-		srcs: ["foo.a"],
-	},
-	bazel_module: { label: "//foo/bar:bar" },
-	tidy: true,
-}`
-	outBaseDir := "outputbase"
-	result := android.GroupFixturePreparers(
-		prepareForPrebuiltTest,
-		android.FixtureMergeEnv(map[string]string{
-			"ALLOW_LOCAL_TIDY_TRUE": "1",
-		}),
-		android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: outBaseDir,
-				LabelToCcInfo: map[string]cquery.CcInfo{
-					"//foo/bar:bar": cquery.CcInfo{
-						CcSharedLibraryFiles: []string{"foo.so"},
-						TidyFiles:            []string{"foo.c.tidy"},
-					},
-					"//foo/bar:bar_bp2build_cc_library_static": cquery.CcInfo{
-						CcStaticLibraryFiles: []string{"foo.a"},
-						TidyFiles:            []string{"foo.c.tidy"},
-					},
-				},
-			}
-		}),
-	).RunTestWithBp(t, bp)
-	sharedFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
-
-	expectedOutputFile := "out/soong/.intermediates/foo/android_arm_armv7-a-neon_shared/validated/foo.so"
-	sharedInfo := result.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo)
-	android.AssertPathRelativeToTopEquals(t,
-		"prebuilt library shared target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.",
-		expectedOutputFile, sharedInfo.SharedLibrary)
-
-	outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
-	}
-	expectedOutputFiles := []string{expectedOutputFile}
-	android.AssertPathsRelativeToTopEquals(t,
-		"prebuilt library shared target output files did not match expected.",
-		expectedOutputFiles, outputFiles)
-
-	staticFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module()
-	staticInfo := result.ModuleProvider(staticFoo, StaticLibraryInfoProvider).(StaticLibraryInfo)
-	expectedStaticOutputFile := "out/soong/.intermediates/foo/android_arm_armv7-a-neon_static/validated/foo.a"
-	android.AssertPathRelativeToTopEquals(t,
-		"prebuilt library static target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.",
-		expectedStaticOutputFile, staticInfo.StaticLibrary)
-
-	staticOutputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_object staticOutputFiles %s", err)
-	}
-	expectedStaticOutputFiles := []string{expectedStaticOutputFile}
-	android.AssertPathsRelativeToTopEquals(t,
-		"prebuilt library static target output files did not match expected.",
-		expectedStaticOutputFiles, staticOutputFiles)
-}
-
-func TestPrebuiltLibraryWithBazelStaticDisabled(t *testing.T) {
-	const bp = `
-cc_prebuilt_library {
-	name: "foo",
-	shared: {
-		srcs: ["foo.so"],
-	},
-	static: {
-		enabled: false
-	},
-	bazel_module: { label: "//foo/bar:bar" },
-}`
-	outBaseDir := "outputbase"
-	result := android.GroupFixturePreparers(
-		prepareForPrebuiltTest,
-		android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: outBaseDir,
-				LabelToCcInfo: map[string]cquery.CcInfo{
-					"//foo/bar:bar": cquery.CcInfo{
-						CcSharedLibraryFiles: []string{"foo.so"},
-					},
-				},
-			}
-		}),
-	).RunTestWithBp(t, bp)
-	sharedFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
-	pathPrefix := outBaseDir + "/execroot/__main__/"
-
-	sharedInfo := result.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo)
-	android.AssertPathRelativeToTopEquals(t,
-		"prebuilt library shared target path did not exist or did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.",
-		pathPrefix+"foo.so", sharedInfo.SharedLibrary)
-
-	outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
-	}
-	expectedOutputFiles := []string{pathPrefix + "foo.so"}
-	android.AssertDeepEquals(t,
-		"prebuilt library shared target output files did not match expected.",
-		expectedOutputFiles, outputFiles.Strings())
-}
-
-func TestPrebuiltLibraryStaticWithBazel(t *testing.T) {
-	const bp = `
-cc_prebuilt_library_static {
-	name: "foo",
-	srcs: ["foo.so"],
-	bazel_module: { label: "//foo/bar:bar" },
-}`
-	outBaseDir := "outputbase"
-	result := android.GroupFixturePreparers(
-		prepareForPrebuiltTest,
-		android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: outBaseDir,
-				LabelToCcInfo: map[string]cquery.CcInfo{
-					"//foo/bar:bar": cquery.CcInfo{
-						CcStaticLibraryFiles: []string{"foo.so"},
-					},
-				},
-			}
-		}),
-	).RunTestWithBp(t, bp)
-	staticFoo := result.ModuleForTests("foo", "android_arm_armv7-a-neon_static").Module()
-	pathPrefix := outBaseDir + "/execroot/__main__/"
-
-	info := result.ModuleProvider(staticFoo, StaticLibraryInfoProvider).(StaticLibraryInfo)
-	android.AssertPathRelativeToTopEquals(t,
-		"prebuilt library static path did not match expected. If the base path is what does not match, it is likely that Soong built this module instead of Bazel.",
-		pathPrefix+"foo.so", info.StaticLibrary)
-
-	outputFiles, err := staticFoo.(android.OutputFileProducer).OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
-	}
-	expectedOutputFiles := []string{pathPrefix + "foo.so"}
-	android.AssertDeepEquals(t, "prebuilt library static output files did not match expected.", expectedOutputFiles, outputFiles.Strings())
-}
-
-func TestPrebuiltLibrarySharedWithBazelWithoutToc(t *testing.T) {
-	const bp = `
-cc_prebuilt_library_shared {
-	name: "foo",
-	srcs: ["foo.so"],
-	bazel_module: { label: "//foo/bar:bar" },
-}`
-	outBaseDir := "outputbase"
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.BazelContext = android.MockBazelContext{
-		OutputBaseDir: outBaseDir,
-		LabelToCcInfo: map[string]cquery.CcInfo{
-			"//foo/bar:bar": cquery.CcInfo{
-				CcSharedLibraryFiles: []string{"foo.so"},
-			},
-		},
-	}
-	ctx := testCcWithConfig(t, config)
-	sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
-	pathPrefix := outBaseDir + "/execroot/__main__/"
-
-	info := ctx.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo)
-	android.AssertPathRelativeToTopEquals(t, "prebuilt shared library",
-		pathPrefix+"foo.so", info.SharedLibrary)
-	android.AssertPathRelativeToTopEquals(t, "prebuilt's 'nullary' ToC",
-		pathPrefix+"foo.so", info.TableOfContents.Path())
-
-	outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
-	}
-	expectedOutputFiles := []string{pathPrefix + "foo.so"}
-	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
-}
-
-func TestPrebuiltLibrarySharedWithBazelWithToc(t *testing.T) {
-	const bp = `
-cc_prebuilt_library_shared {
-	name: "foo",
-	srcs: ["foo.so"],
-	bazel_module: { label: "//foo/bar:bar" },
-}`
-	outBaseDir := "outputbase"
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.BazelContext = android.MockBazelContext{
-		OutputBaseDir: outBaseDir,
-		LabelToCcInfo: map[string]cquery.CcInfo{
-			"//foo/bar:bar": cquery.CcInfo{
-				CcSharedLibraryFiles: []string{"foo.so"},
-				TocFile:              "toc",
-			},
-		},
-	}
-	ctx := testCcWithConfig(t, config)
-	sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
-	pathPrefix := outBaseDir + "/execroot/__main__/"
-
-	info := ctx.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo)
-	android.AssertPathRelativeToTopEquals(t, "prebuilt shared library's ToC",
-		pathPrefix+"toc", info.TableOfContents.Path())
-	android.AssertPathRelativeToTopEquals(t, "prebuilt shared library",
-		pathPrefix+"foo.so", info.SharedLibrary)
-
-	outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
-	}
-	expectedOutputFiles := []string{pathPrefix + "foo.so"}
-	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
-}
-
 func TestPrebuiltStubNoinstall(t *testing.T) {
 	testFunc := func(t *testing.T, expectLibfooOnSystemLib bool, fs android.MockFS) {
 		result := android.GroupFixturePreparers(
@@ -795,26 +511,252 @@
 	testCcError(t, `Android.bp:4:6: module "bintest" variant "android_arm64_armv8-a": srcs: multiple prebuilt source files`, bp)
 }
 
-func TestPrebuiltBinaryWithBazel(t *testing.T) {
-	const bp = `
-cc_prebuilt_binary {
-	name: "bintest",
-	srcs: ["bin"],
-	bazel_module: { label: "//bin/foo:foo" },
-}`
-	const outBaseDir = "outputbase"
-	const expectedOut = outBaseDir + "/execroot/__main__/bin"
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.BazelContext = android.MockBazelContext{
-		OutputBaseDir:      outBaseDir,
-		LabelToOutputFiles: map[string][]string{"//bin/foo:foo": []string{"bin"}},
+func TestMultiplePrebuilts(t *testing.T) {
+	bp := `
+		// an rdep
+		cc_library {
+			name: "libfoo",
+			shared_libs: ["libbar"],
+		}
+
+		// multiple variations of dep
+		// source
+		cc_library {
+			name: "libbar",
+		}
+		// prebuilt "v1"
+		cc_prebuilt_library_shared {
+			name: "libbar",
+			srcs: ["libbar.so"],
+		}
+		// prebuilt "v2"
+		cc_prebuilt_library_shared {
+			name: "libbar.v2",
+			stem: "libbar",
+			source_module_name: "libbar",
+			srcs: ["libbar.so"],
+		}
+
+		// selectors
+		apex_contributions {
+			name: "myapex_contributions",
+			contents: ["%v"],
+		}
+		all_apex_contributions {name: "all_apex_contributions"}
+	`
+	hasDep := func(ctx *android.TestContext, m android.Module, wantDep android.Module) bool {
+		t.Helper()
+		var found bool
+		ctx.VisitDirectDeps(m, func(dep blueprint.Module) {
+			if dep == wantDep {
+				found = true
+			}
+		})
+		return found
 	}
-	ctx := testCcWithConfig(t, config)
-	bin := ctx.ModuleForTests("bintest", "android_arm64_armv8-a").Module().(*Module)
-	out := bin.OutputFile()
-	if !out.Valid() {
-		t.Error("Invalid output file")
-		return
+
+	testCases := []struct {
+		desc                   string
+		selectedDependencyName string
+		expectedDependencyName string
+	}{
+		{
+			desc:                   "Source library is selected using apex_contributions",
+			selectedDependencyName: "libbar",
+			expectedDependencyName: "libbar",
+		},
+		{
+			desc:                   "Prebuilt library v1 is selected using apex_contributions",
+			selectedDependencyName: "prebuilt_libbar",
+			expectedDependencyName: "prebuilt_libbar",
+		},
+		{
+			desc:                   "Prebuilt library v2 is selected using apex_contributions",
+			selectedDependencyName: "prebuilt_libbar.v2",
+			expectedDependencyName: "prebuilt_libbar.v2",
+		},
 	}
-	android.AssertStringEquals(t, "output file", expectedOut, out.String())
+
+	for _, tc := range testCases {
+		preparer := android.GroupFixturePreparers(
+			android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+				android.RegisterApexContributionsBuildComponents(ctx)
+			}),
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "myapex_contributions",
+				}
+			}),
+		)
+		ctx := testPrebuilt(t, fmt.Sprintf(bp, tc.selectedDependencyName), map[string][]byte{
+			"libbar.so": nil,
+			"crtx.o":    nil,
+		}, preparer)
+		libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+		expectedDependency := ctx.ModuleForTests(tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module()
+		android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", libfoo.Name(), tc.expectedDependencyName), true, hasDep(ctx, libfoo, expectedDependency))
+		// check that LOCAL_SHARED_LIBRARIES contains libbar and not libbar.v<N>
+		entries := android.AndroidMkEntriesForTest(t, ctx, libfoo)[0]
+		android.AssertStringListContains(t, "Version should not be present in LOCAL_SHARED_LIBRARIES", entries.EntryMap["LOCAL_SHARED_LIBRARIES"], "libbar")
+
+		// check installation rules
+		// the selected soong module should be exported to make
+		libbar := ctx.ModuleForTests(tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module()
+		android.AssertBoolEquals(t, fmt.Sprintf("dependency %s should be exported to make\n", expectedDependency), true, !libbar.IsHideFromMake())
+
+		// check LOCAL_MODULE of the selected module name
+		// the prebuilt should have the same LOCAL_MODULE when exported to make
+		entries = android.AndroidMkEntriesForTest(t, ctx, libbar)[0]
+		android.AssertStringEquals(t, "unexpected LOCAL_MODULE", "libbar", entries.EntryMap["LOCAL_MODULE"][0])
+	}
+}
+
+// Setting prefer on multiple prebuilts is an error, unless one of them is also listed in apex_contributions
+func TestMultiplePrebuiltsPreferredUsingLegacyFlags(t *testing.T) {
+	bp := `
+		// an rdep
+		cc_library {
+			name: "libfoo",
+			shared_libs: ["libbar"],
+		}
+
+		// multiple variations of dep
+		// source
+		cc_library {
+			name: "libbar",
+		}
+		// prebuilt "v1"
+		cc_prebuilt_library_shared {
+			name: "libbar",
+			srcs: ["libbar.so"],
+			prefer: true,
+		}
+		// prebuilt "v2"
+		cc_prebuilt_library_shared {
+			name: "libbar.v2",
+			stem: "libbar",
+			source_module_name: "libbar",
+			srcs: ["libbar.so"],
+			prefer: true,
+		}
+
+		// selectors
+		apex_contributions {
+			name: "myapex_contributions",
+			contents: [%v],
+		}
+		all_apex_contributions {name: "all_apex_contributions"}
+	`
+	hasDep := func(ctx *android.TestContext, m android.Module, wantDep android.Module) bool {
+		t.Helper()
+		var found bool
+		ctx.VisitDirectDeps(m, func(dep blueprint.Module) {
+			if dep == wantDep {
+				found = true
+			}
+		})
+		return found
+	}
+
+	testCases := []struct {
+		desc                   string
+		selectedDependencyName string
+		expectedDependencyName string
+		expectedErr            string
+	}{
+		{
+			desc:        "Multiple prebuilts have prefer: true",
+			expectedErr: "Multiple prebuilt modules prebuilt_libbar and prebuilt_libbar.v2 have been marked as preferred for this source module",
+		},
+		{
+			desc:                   "Multiple prebuilts have prefer: true. The prebuilt listed in apex_contributions wins.",
+			selectedDependencyName: `"prebuilt_libbar"`,
+			expectedDependencyName: "prebuilt_libbar",
+		},
+	}
+
+	for _, tc := range testCases {
+		preparer := android.GroupFixturePreparers(
+			android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+				android.RegisterApexContributionsBuildComponents(ctx)
+			}),
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "myapex_contributions",
+				}
+			}),
+		)
+		if tc.expectedErr != "" {
+			preparer = preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(tc.expectedErr))
+		}
+
+		ctx := testPrebuilt(t, fmt.Sprintf(bp, tc.selectedDependencyName), map[string][]byte{
+			"libbar.so": nil,
+			"crtx.o":    nil,
+		}, preparer)
+		if tc.expectedErr != "" {
+			return // the fixture will assert that the excepted err has been raised
+		}
+		libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+		expectedDependency := ctx.ModuleForTests(tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module()
+		android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", libfoo.Name(), tc.expectedDependencyName), true, hasDep(ctx, libfoo, expectedDependency))
+	}
+}
+
+// If module sdk cannot provide a cc module variant (e.g. static), then the module variant from source should be used
+func TestMissingVariantInModuleSdk(t *testing.T) {
+	bp := `
+		// an rdep
+		cc_library {
+			name: "libfoo",
+			static_libs: ["libbar"],
+		}
+
+		// source
+		cc_library {
+			name: "libbar",
+		}
+		// prebuilt
+		// libbar only exists as a shared library
+		cc_prebuilt_library_shared {
+			name: "libbar",
+			srcs: ["libbar.so"],
+		}
+		// selectors
+		apex_contributions {
+			name: "myapex_contributions",
+			contents: ["prebuilt_libbar"],
+		}
+		all_apex_contributions {name: "all_apex_contributions"}
+	`
+	hasDep := func(ctx *android.TestContext, m android.Module, wantDep android.Module) bool {
+		t.Helper()
+		var found bool
+		ctx.VisitDirectDeps(m, func(dep blueprint.Module) {
+			if dep == wantDep {
+				found = true
+			}
+		})
+		return found
+	}
+
+	preparer := android.GroupFixturePreparers(
+		android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+			android.RegisterApexContributionsBuildComponents(ctx)
+		}),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "myapex_contributions",
+			}
+		}),
+	)
+	ctx := testPrebuilt(t, bp, map[string][]byte{
+		"libbar.so": nil,
+		"crtx.o":    nil,
+	}, preparer)
+	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module()
+	sourceLibBar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Module()
+	// Even though the prebuilt is listed in apex_contributions, the prebuilt does not have a static variant.
+	// Therefore source of libbar should be used.
+	android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from libfoo to source libbar"), true, hasDep(ctx, libfoo, sourceLibBar))
 }
diff --git a/cc/proto.go b/cc/proto.go
index 5d9aef6..4d72f26 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -19,7 +19,6 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 )
 
 const (
@@ -163,70 +162,3 @@
 
 	return flags
 }
-
-type protoAttributes struct {
-	Deps            bazel.LabelListAttribute
-	Min_sdk_version *string
-}
-
-type bp2buildProtoDeps struct {
-	wholeStaticLib               *bazel.LabelAttribute
-	implementationWholeStaticLib *bazel.LabelAttribute
-	protoDep                     *bazel.LabelAttribute
-}
-
-func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) bp2buildProtoDeps {
-	var ret bp2buildProtoDeps
-
-	protoInfo, ok := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, protoSrcs)
-	if !ok || protoInfo.Proto_libs.IsEmpty() {
-		return ret
-	}
-
-	var depName string
-	typ := proptools.StringDefault(protoInfo.Type, protoTypeDefault)
-	var rule_class string
-	suffix := "_cc_proto"
-	switch typ {
-	case "lite":
-		suffix += "_lite"
-		rule_class = "cc_lite_proto_library"
-		depName = "libprotobuf-cpp-lite"
-	case "full":
-		rule_class = "cc_proto_library"
-		depName = "libprotobuf-cpp-full"
-	default:
-		ctx.PropertyErrorf("proto.type", "cannot handle conversion at this time: %q", typ)
-	}
-
-	dep := android.BazelLabelForModuleDepSingle(ctx, depName)
-	ret.protoDep = &bazel.LabelAttribute{Value: &dep}
-
-	var protoAttrs protoAttributes
-	protoAttrs.Deps.SetValue(protoInfo.Proto_libs)
-	protoAttrs.Min_sdk_version = m.Properties.Min_sdk_version
-
-	name := m.Name() + suffix
-	tags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), m)
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        rule_class,
-			Bzl_load_location: "//build/bazel/rules/cc:cc_proto.bzl",
-		},
-		android.CommonAttributes{Name: name, Tags: tags},
-		&protoAttrs)
-
-	var privateHdrs bool
-	if lib, ok := m.linker.(*libraryDecorator); ok {
-		privateHdrs = !proptools.Bool(lib.Properties.Proto.Export_proto_headers)
-	}
-
-	labelAttr := &bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + name}}
-	if privateHdrs {
-		ret.implementationWholeStaticLib = labelAttr
-	} else {
-		ret.wholeStaticLib = labelAttr
-	}
-
-	return ret
-}
diff --git a/cc/rs.go b/cc/rs.go
index 93acdc7..b0d759b 100644
--- a/cc/rs.go
+++ b/cc/rs.go
@@ -20,7 +20,6 @@
 	"strings"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"github.com/google/blueprint"
 )
 
@@ -134,35 +133,3 @@
 
 	return flags
 }
-
-type rscriptAttributes struct {
-	// Renderscript source files
-	Srcs bazel.LabelListAttribute
-}
-
-func bp2buildRScript(ctx android.Bp2buildMutatorContext, m *Module, ca compilerAttributes) (bazel.LabelAttribute, bazel.StringListAttribute, bazel.StringListAttribute) {
-	var rscriptAttrs rscriptAttributes
-	var rsAbsIncludes bazel.StringListAttribute
-	var localIncludes bazel.StringListAttribute
-	var rsModuleName string
-	var convertedRsSrcsLabel bazel.LabelAttribute
-
-	if !ca.rscriptSrcs.IsEmpty() {
-		rscriptAttrs.Srcs = ca.rscriptSrcs
-		rsModuleName = m.Name() + "_renderscript"
-
-		localIncludes.Value = []string{"."}
-		rsAbsIncludes.Value = []string{"frameworks/rs", "frameworks/rs/cpp"}
-		convertedRsSrcsLabel = bazel.LabelAttribute{Value: &bazel.Label{Label: rsModuleName}}
-
-		ctx.CreateBazelTargetModule(
-			bazel.BazelTargetModuleProperties{
-				Rule_class:        "rscript_to_cpp",
-				Bzl_load_location: "//build/bazel/rules/cc:rscript_to_cpp.bzl",
-			},
-			android.CommonAttributes{Name: rsModuleName},
-			&rscriptAttrs)
-	}
-
-	return convertedRsSrcsLabel, rsAbsIncludes, localIncludes
-}
diff --git a/cc/sabi.go b/cc/sabi.go
index 4cd776a..cd9bf63 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -26,6 +26,33 @@
 	lsdumpPathsLock sync.Mutex
 )
 
+type lsdumpTag string
+
+const (
+	apexLsdumpTag     lsdumpTag = "APEX"
+	llndkLsdumpTag    lsdumpTag = "LLNDK"
+	ndkLsdumpTag      lsdumpTag = "NDK"
+	platformLsdumpTag lsdumpTag = "PLATFORM"
+	productLsdumpTag  lsdumpTag = "PRODUCT"
+	vendorLsdumpTag   lsdumpTag = "VENDOR"
+)
+
+// Return the prebuilt ABI dump directory for a tag; an empty string for an opt-in dump.
+func (tag *lsdumpTag) dirName() string {
+	switch *tag {
+	case apexLsdumpTag:
+		return "platform"
+	case ndkLsdumpTag:
+		return "ndk"
+	case llndkLsdumpTag:
+		return "vndk"
+	case platformLsdumpTag:
+		return "platform"
+	default:
+		return ""
+	}
+}
+
 // Properties for ABI compatibility checker in Android.bp.
 type headerAbiCheckerProperties struct {
 	// Enable ABI checks (even if this is not an LLNDK/VNDK lib)
@@ -68,7 +95,8 @@
 
 	// Include directories that may contain ABI information exported by a library.
 	// These directories are passed to the header-abi-dumper.
-	ReexportedIncludes []string `blueprint:"mutated"`
+	ReexportedIncludes       []string `blueprint:"mutated"`
+	ReexportedSystemIncludes []string `blueprint:"mutated"`
 }
 
 type sabi struct {
@@ -97,49 +125,36 @@
 	return sabi != nil && sabi.Properties.ShouldCreateSourceAbiDump
 }
 
-// Returns a string that represents the class of the ABI dump.
-// Returns an empty string if ABI check is disabled for this library.
-func classifySourceAbiDump(ctx android.BaseModuleContext) string {
+// Returns a slice of strings that represent the ABI dumps generated for this module.
+func classifySourceAbiDump(ctx android.BaseModuleContext) []lsdumpTag {
+	result := []lsdumpTag{}
 	m := ctx.Module().(*Module)
 	headerAbiChecker := m.library.getHeaderAbiCheckerProperties(ctx)
 	if headerAbiChecker.explicitlyDisabled() {
-		return ""
+		return result
 	}
-	// Return NDK if the library is both NDK and LLNDK.
-	if m.IsNdk(ctx.Config()) {
-		return "NDK"
-	}
-	if m.isImplementationForLLNDKPublic() {
-		return "LLNDK"
-	}
-	if m.UseVndk() && m.IsVndk() && !m.IsVndkPrivate() {
-		if m.IsVndkSp() {
-			if m.IsVndkExt() {
-				return "VNDK-SP-ext"
-			} else {
-				return "VNDK-SP"
-			}
-		} else {
-			if m.IsVndkExt() {
-				return "VNDK-ext"
-			} else {
-				return "VNDK-core"
-			}
+	if !m.InProduct() && !m.InVendor() {
+		if m.isImplementationForLLNDKPublic() {
+			result = append(result, llndkLsdumpTag)
 		}
-	}
-	if m.library.hasStubsVariants() && !m.InProduct() && !m.InVendor() {
-		return "PLATFORM"
-	}
-	if headerAbiChecker.enabled() {
+		if m.IsNdk(ctx.Config()) {
+			result = append(result, ndkLsdumpTag)
+		}
+		// APEX and opt-in platform dumps are placed in the same directory.
+		if m.library.hasStubsVariants() {
+			result = append(result, apexLsdumpTag)
+		} else if headerAbiChecker.enabled() {
+			result = append(result, platformLsdumpTag)
+		}
+	} else if headerAbiChecker.enabled() {
 		if m.InProduct() {
-			return "PRODUCT"
+			result = append(result, productLsdumpTag)
 		}
 		if m.InVendor() {
-			return "VENDOR"
+			result = append(result, vendorLsdumpTag)
 		}
-		return "PLATFORM"
 	}
-	return ""
+	return result
 }
 
 // Called from sabiDepsMutator to check whether ABI dumps should be created for this module.
@@ -194,8 +209,8 @@
 		return false
 	}
 
-	isPlatformVariant := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
-	if isPlatformVariant {
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+	if apexInfo.IsForPlatform() {
 		// Bionic libraries that are installed to the bootstrap directory are not ABI checked.
 		// Only the runtime APEX variants, which are the implementation libraries of bionic NDK stubs,
 		// are checked.
@@ -208,7 +223,7 @@
 			return false
 		}
 	}
-	return classifySourceAbiDump(ctx) != ""
+	return len(classifySourceAbiDump(ctx)) > 0
 }
 
 // Mark the direct and transitive dependencies of libraries that need ABI check, so that ABI dumps
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 30bce9b..2a1ee3c 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -25,7 +25,6 @@
 
 	"android/soong/android"
 	"android/soong/cc/config"
-	"android/soong/snapshot"
 )
 
 var (
@@ -56,7 +55,6 @@
 		// higher number of "optimized out" stack variables.
 		// b/112437883.
 		"-instcombine-lower-dbg-declare=0",
-		"-hwasan-use-after-scope=1",
 		"-dom-tree-reachability-max-bbs-to-explore=128",
 	}
 
@@ -83,10 +81,11 @@
 		"-fno-sanitize-recover=integer,undefined"}
 	hwasanGlobalOptions = []string{"heap_history_size=1023", "stack_history_size=512",
 		"export_memory_stats=0", "max_malloc_fill_size=131072", "malloc_fill_byte=0"}
-	memtagStackCommonFlags = []string{"-march=armv8-a+memtag", "-mllvm", "-dom-tree-reachability-max-bbs-to-explore=128"}
+	memtagStackCommonFlags = []string{"-march=armv8-a+memtag"}
+	memtagStackLlvmFlags = []string{"-dom-tree-reachability-max-bbs-to-explore=128"}
 
 	hostOnlySanitizeFlags   = []string{"-fno-sanitize-recover=all"}
-	deviceOnlySanitizeFlags = []string{"-fsanitize-trap=all", "-ftrap-function=abort"}
+	deviceOnlySanitizeFlags = []string{"-fsanitize-trap=all"}
 
 	noSanitizeLinkRuntimeFlag = "-fno-sanitize-link-runtime"
 )
@@ -403,30 +402,8 @@
 
 var _ android.SkipApexAllowedDependenciesCheck = (*libraryDependencyTag)(nil)
 
-var exportedVars = android.NewExportedVariables(pctx)
-
 func init() {
-	exportedVars.ExportStringListStaticVariable("HostOnlySanitizeFlags", hostOnlySanitizeFlags)
-	exportedVars.ExportStringList("DeviceOnlySanitizeFlags", deviceOnlySanitizeFlags)
-
-	exportedVars.ExportStringList("MinimalRuntimeFlags", minimalRuntimeFlags)
-
-	// Leave out "-flto" from the slices exported to bazel, as we will use the
-	// dedicated LTO feature for this. For C Flags and Linker Flags, also leave
-	// out the cross DSO flag which will be added separately under the correct conditions.
-	exportedVars.ExportStringList("CfiCFlags", append(cfiCflags[2:], cfiEnableFlag))
-	exportedVars.ExportStringList("CfiLdFlags", cfiLdflags[2:])
-	exportedVars.ExportStringList("CfiAsFlags", cfiAsflags[1:])
-
-	exportedVars.ExportString("SanitizeIgnorelistPrefix", sanitizeIgnorelistPrefix)
-	exportedVars.ExportString("CfiCrossDsoFlag", cfiCrossDsoFlag)
-	exportedVars.ExportString("CfiBlocklistPath", cfiBlocklistPath)
-	exportedVars.ExportString("CfiBlocklistFilename", cfiBlocklistFilename)
-	exportedVars.ExportString("CfiExportsMapPath", cfiExportsMapPath)
-	exportedVars.ExportString("CfiExportsMapFilename", cfiExportsMapFilename)
-	exportedVars.ExportString("CfiAssemblySupportFlag", cfiAssemblySupportFlag)
-
-	exportedVars.ExportString("NoSanitizeLinkRuntimeFlag", noSanitizeLinkRuntimeFlag)
+	pctx.StaticVariable("HostOnlySanitizeFlags", strings.Join(hostOnlySanitizeFlags, " "))
 
 	android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider)
 	android.RegisterMakeVarsProvider(pctx, hwasanMakeVarsProvider)
@@ -553,7 +530,9 @@
 		}
 
 		if found, globalSanitizers = removeFromList("hwaddress", globalSanitizers); found && s.Hwaddress == nil {
-			s.Hwaddress = proptools.BoolPtr(true)
+			if !ctx.Config().HWASanDisabledForPath(ctx.ModuleDir()) {
+				s.Hwaddress = proptools.BoolPtr(true)
+			}
 		}
 
 		if found, globalSanitizers = removeFromList("writeonly", globalSanitizers); found && s.Writeonly == nil {
@@ -677,12 +656,6 @@
 		s.Integer_overflow = nil
 	}
 
-	// TODO(b/254713216): CFI doesn't work for riscv64 yet because LTO doesn't work.
-	if ctx.Arch().ArchType == android.Riscv64 {
-		s.Cfi = nil
-		s.Diag.Cfi = nil
-	}
-
 	// Disable CFI for musl
 	if ctx.toolchain().Musl() {
 		s.Cfi = nil
@@ -885,6 +858,7 @@
 
 		flags.Local.CFlags = append(flags.Local.CFlags, cfiCflags...)
 		flags.Local.AsFlags = append(flags.Local.AsFlags, cfiAsflags...)
+		flags.CFlagsDeps = append(flags.CFlagsDeps, android.PathForSource(ctx, cfiBlocklistPath + "/" + cfiBlocklistFilename))
 		if Bool(s.Properties.Sanitize.Config.Cfi_assembly_support) {
 			flags.Local.CFlags = append(flags.Local.CFlags, cfiAssemblySupportFlag)
 		}
@@ -905,6 +879,13 @@
 		flags.Local.CFlags = append(flags.Local.CFlags, memtagStackCommonFlags...)
 		flags.Local.AsFlags = append(flags.Local.AsFlags, memtagStackCommonFlags...)
 		flags.Local.LdFlags = append(flags.Local.LdFlags, memtagStackCommonFlags...)
+
+		for _, flag := range memtagStackLlvmFlags {
+			flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", flag)
+		}
+		for _, flag := range memtagStackLlvmFlags {
+			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm,"+flag)
+		}
 	}
 
 	if (Bool(sanProps.Memtag_heap) || Bool(sanProps.Memtag_stack) || Bool(sanProps.Memtag_globals)) && ctx.binary() {
@@ -1117,12 +1098,15 @@
 // indirectly (via a mutator) sets the bool ptr to true, and you can't
 // distinguish between the cases. It isn't needed though - both cases can be
 // treated identically.
-func (sanitize *sanitize) isSanitizerEnabled(t SanitizerType) bool {
-	if sanitize == nil {
+func (s *sanitize) isSanitizerEnabled(t SanitizerType) bool {
+	if s == nil {
+		return false
+	}
+	if proptools.Bool(s.Properties.SanitizeMutated.Never) {
 		return false
 	}
 
-	sanitizerVal := sanitize.getSanitizerBoolPtr(t)
+	sanitizerVal := s.getSanitizerBoolPtr(t)
 	return sanitizerVal != nil && *sanitizerVal == true
 }
 
@@ -1142,42 +1126,6 @@
 	return IsSanitizableDependencyTag
 }
 
-// Determines if the current module is a static library going to be captured
-// as vendor snapshot. Such modules must create both cfi and non-cfi variants,
-// except for ones which explicitly disable cfi.
-func needsCfiForVendorSnapshot(mctx android.BaseModuleContext) bool {
-	if inList("hwaddress", mctx.Config().SanitizeDevice()) {
-		// cfi will not be built if SANITIZE_TARGET=hwaddress is set
-		return false
-	}
-
-	if snapshot.IsVendorProprietaryModule(mctx) {
-		return false
-	}
-
-	c := mctx.Module().(PlatformSanitizeable)
-
-	if !c.InVendor() {
-		return false
-	}
-
-	if !c.StaticallyLinked() {
-		return false
-	}
-
-	if c.IsPrebuilt() {
-		return false
-	}
-
-	if !c.SanitizerSupported(cfi) {
-		return false
-	}
-
-	return c.SanitizePropDefined() &&
-		!c.SanitizeNever() &&
-		!c.IsSanitizerExplicitlyDisabled(cfi)
-}
-
 type sanitizerSplitMutator struct {
 	sanitizer SanitizerType
 }
@@ -1189,7 +1137,7 @@
 	if sanitizeable, ok := ctx.Module().(Sanitizeable); ok {
 		enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
 		ctx.VisitDirectDeps(func(dep android.Module) {
-			if c, ok := dep.(*Module); ok && c.sanitize.isSanitizerEnabled(s.sanitizer) {
+			if c, ok := dep.(PlatformSanitizeable); ok && c.IsSanitizerEnabled(s.sanitizer) {
 				enabled = true
 			}
 		})
@@ -1202,10 +1150,6 @@
 
 func (s *sanitizerSplitMutator) Split(ctx android.BaseModuleContext) []string {
 	if c, ok := ctx.Module().(PlatformSanitizeable); ok && c.SanitizePropDefined() {
-		if s.sanitizer == cfi && needsCfiForVendorSnapshot(ctx) {
-			return []string{"", s.sanitizer.variationName()}
-		}
-
 		// If the given sanitizer is not requested in the .bp file for a module, it
 		// won't automatically build the sanitized variation.
 		if !c.IsSanitizerEnabled(s.sanitizer) {
@@ -1243,19 +1187,6 @@
 		}
 	}
 
-	if c, ok := ctx.Module().(*Module); ok {
-		//TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable
-
-		// Check if it's a snapshot module supporting sanitizer
-		if ss, ok := c.linker.(snapshotSanitizer); ok {
-			if ss.isSanitizerAvailable(s.sanitizer) {
-				return []string{"", s.sanitizer.variationName()}
-			} else {
-				return []string{""}
-			}
-		}
-	}
-
 	return []string{""}
 }
 
@@ -1280,12 +1211,6 @@
 
 func (s *sanitizerSplitMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
 	if d, ok := ctx.Module().(PlatformSanitizeable); ok {
-		if dm, ok := ctx.Module().(*Module); ok {
-			if ss, ok := dm.linker.(snapshotSanitizer); ok && ss.isSanitizerAvailable(s.sanitizer) {
-				return incomingVariation
-			}
-		}
-
 		if !d.SanitizePropDefined() ||
 			d.SanitizeNever() ||
 			d.IsSanitizerExplicitlyDisabled(s.sanitizer) ||
@@ -1396,27 +1321,6 @@
 		if sanitizerVariation {
 			sanitizeable.AddSanitizerDependencies(mctx, s.sanitizer.name())
 		}
-	} else if c, ok := mctx.Module().(*Module); ok {
-		if ss, ok := c.linker.(snapshotSanitizer); ok && ss.isSanitizerAvailable(s.sanitizer) {
-			if !ss.isUnsanitizedVariant() {
-				// Snapshot sanitizer may have only one variantion.
-				// Skip exporting the module if it already has a sanitizer variation.
-				c.SetPreventInstall()
-				c.SetHideFromMake()
-				return
-			}
-			c.linker.(snapshotSanitizer).setSanitizerVariation(s.sanitizer, sanitizerVariation)
-
-			// Export the static lib name to make
-			if c.static() && c.ExportedToMake() {
-				// use BaseModuleName which is the name for Make.
-				if s.sanitizer == cfi {
-					cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName())
-				} else if s.sanitizer == Hwasan {
-					hwasanStaticLibs(mctx.Config()).add(c, c.BaseModuleName())
-				}
-			}
-		}
 	}
 }
 
@@ -1466,15 +1370,6 @@
 				return true
 			}
 
-			if p, ok := d.linker.(*snapshotLibraryDecorator); ok {
-				if Bool(p.properties.Sanitize_minimal_dep) {
-					c.sanitize.Properties.MinimalRuntimeDep = true
-				}
-				if Bool(p.properties.Sanitize_ubsan_dep) {
-					c.sanitize.Properties.UbsanRuntimeDep = true
-				}
-			}
-
 			return false
 		})
 	}
@@ -1600,12 +1495,6 @@
 		}
 
 		addStaticDeps := func(dep string, hideSymbols bool) {
-			// If we're using snapshots, redirect to snapshot whenever possible
-			snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo)
-			if lib, ok := snapshot.StaticLibs[dep]; ok {
-				dep = lib
-			}
-
 			// static executable gets static runtime libs
 			depTag := libraryDependencyTag{Kind: staticLibraryDependency, unexportedSymbols: hideSymbols}
 			variations := append(mctx.Target().Variations(),
@@ -1650,12 +1539,12 @@
 			Bool(sanProps.Fuzzer) ||
 			Bool(sanProps.Undefined) ||
 			Bool(sanProps.All_undefined) {
-			if toolchain.Musl() || (c.staticBinary() && toolchain.Bionic()) {
-				// Use a static runtime for static binaries.
-				// Also use a static runtime for musl to match
-				// what clang does for glibc.  Otherwise dlopening
-				// libraries that depend on libclang_rt.ubsan_standalone.so
-				// fails with:
+			if toolchain.Musl() || c.staticBinary() {
+				// Use a static runtime for static binaries.  For sanitized glibc binaries the runtime is
+				// added automatically by clang, but for static glibc binaries that are not sanitized but
+				// have a sanitized dependency the runtime needs to be added manually.
+				// Also manually add a static runtime for musl to match what clang does for glibc.
+				// Otherwise dlopening libraries that depend on libclang_rt.ubsan_standalone.so fails with:
 				// Error relocating ...: initial-exec TLS resolves to dynamic definition
 				addStaticDeps(config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain)+".static", true)
 			} else {
@@ -1687,12 +1576,6 @@
 				// the best.
 				addStaticDeps(runtimeSharedLibrary, true)
 			} else if !c.static() && !c.Header() {
-				// If we're using snapshots, redirect to snapshot whenever possible
-				snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo)
-				if lib, ok := snapshot.SharedLibs[runtimeSharedLibrary]; ok {
-					runtimeSharedLibrary = lib
-				}
-
 				// Skip apex dependency check for sharedLibraryDependency
 				// when sanitizer diags are enabled. Skipping the check will allow
 				// building with diag libraries without having to list the
@@ -1885,7 +1768,3 @@
 func hwasanMakeVarsProvider(ctx android.MakeVarsContext) {
 	hwasanStaticLibs(ctx.Config()).exportToMake(ctx)
 }
-
-func BazelCcSanitizerToolchainVars(config android.Config) string {
-	return android.BazelToolchainVars(config, exportedVars)
-}
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
index 29b17d4..44f38e1 100644
--- a/cc/sanitize_test.go
+++ b/cc/sanitize_test.go
@@ -16,13 +16,12 @@
 
 import (
 	"fmt"
+	"reflect"
 	"runtime"
 	"strings"
 	"testing"
 
 	"android/soong/android"
-
-	"github.com/google/blueprint"
 )
 
 var prepareForAsanTest = android.FixtureAddFile("asan/Android.bp", []byte(`
@@ -48,7 +47,7 @@
 `))
 
 type providerInterface interface {
-	ModuleProvider(blueprint.Module, blueprint.ProviderKey) interface{}
+	android.SingletonModuleProviderContext
 }
 
 // expectSharedLinkDep verifies that the from module links against the to module as a
@@ -56,7 +55,7 @@
 func expectSharedLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) {
 	t.Helper()
 	fromLink := from.Description("link")
-	toInfo := ctx.ModuleProvider(to.Module(), SharedLibraryInfoProvider).(SharedLibraryInfo)
+	toInfo, _ := android.SingletonModuleProvider(ctx, to.Module(), SharedLibraryInfoProvider)
 
 	if g, w := fromLink.OrderOnly.Strings(), toInfo.SharedLibrary.RelativeToTop().String(); !android.InList(w, g) {
 		t.Errorf("%s should link against %s, expected %q, got %q",
@@ -69,7 +68,7 @@
 func expectNoSharedLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) {
 	t.Helper()
 	fromLink := from.Description("link")
-	toInfo := ctx.ModuleProvider(to.Module(), SharedLibraryInfoProvider).(SharedLibraryInfo)
+	toInfo, _ := android.SingletonModuleProvider(ctx, to.Module(), SharedLibraryInfoProvider)
 
 	if g, w := fromLink.OrderOnly.Strings(), toInfo.SharedLibrary.RelativeToTop().String(); android.InList(w, g) {
 		t.Errorf("%s should not link against %s, expected %q, got %q",
@@ -82,7 +81,7 @@
 func expectStaticLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) {
 	t.Helper()
 	fromLink := from.Description("link")
-	toInfo := ctx.ModuleProvider(to.Module(), StaticLibraryInfoProvider).(StaticLibraryInfo)
+	toInfo, _ := android.SingletonModuleProvider(ctx, to.Module(), StaticLibraryInfoProvider)
 
 	if g, w := fromLink.Implicits.Strings(), toInfo.StaticLibrary.RelativeToTop().String(); !android.InList(w, g) {
 		t.Errorf("%s should link against %s, expected %q, got %q",
@@ -96,7 +95,7 @@
 func expectNoStaticLinkDep(t *testing.T, ctx providerInterface, from, to android.TestingModule) {
 	t.Helper()
 	fromLink := from.Description("link")
-	toInfo := ctx.ModuleProvider(to.Module(), StaticLibraryInfoProvider).(StaticLibraryInfo)
+	toInfo, _ := android.SingletonModuleProvider(ctx, to.Module(), StaticLibraryInfoProvider)
 
 	if g, w := fromLink.Implicits.Strings(), toInfo.StaticLibrary.RelativeToTop().String(); android.InList(w, g) {
 		t.Errorf("%s should not link against %s, expected %q, got %q",
@@ -714,6 +713,15 @@
 			],
 		}
 
+		cc_binary {
+			name: "static_bin_with_ubsan_dep",
+			static_executable: true,
+			host_supported: true,
+			static_libs: [
+				"libubsan_diag",
+			],
+		}
+
 		cc_library_shared {
 			name: "libshared",
 			host_supported: true,
@@ -742,6 +750,17 @@
 		}
 
 		cc_library_static {
+			name: "libubsan_diag",
+			host_supported: true,
+			sanitize: {
+				undefined: true,
+				diag: {
+					undefined: true,
+				},
+			},
+		}
+
+		cc_library_static {
 			name: "libstatic",
 			host_supported: true,
 		}
@@ -763,6 +782,7 @@
 		sharedVariant := variant + "_shared"
 
 		minimalRuntime := result.ModuleForTests("libclang_rt.ubsan_minimal", staticVariant)
+		standaloneRuntime := result.ModuleForTests("libclang_rt.ubsan_standalone.static", staticVariant)
 
 		// The binaries, one with ubsan and one without
 		binWithUbsan := result.ModuleForTests("bin_with_ubsan", variant)
@@ -770,6 +790,7 @@
 		libSharedUbsan := result.ModuleForTests("libsharedubsan", sharedVariant)
 		binDependsUbsanShared := result.ModuleForTests("bin_depends_ubsan_shared", variant)
 		binNoUbsan := result.ModuleForTests("bin_no_ubsan", variant)
+		staticBin := result.ModuleForTests("static_bin_with_ubsan_dep", variant)
 
 		android.AssertStringListContains(t, "missing libclang_rt.ubsan_minimal in bin_with_ubsan static libs",
 			strings.Split(binWithUbsan.Rule("ld").Args["libFlags"], " "),
@@ -810,6 +831,11 @@
 		android.AssertStringListDoesNotContain(t, "unexpected -Wl,--exclude-libs for minimal runtime in bin_no_ubsan static libs",
 			strings.Split(binNoUbsan.Rule("ld").Args["ldFlags"], " "),
 			"-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base())
+
+		android.AssertStringListContains(t, "missing libclang_rt.ubsan_standalone.static in static_bin_with_ubsan_dep static libs",
+			strings.Split(staticBin.Rule("ld").Args["libFlags"], " "),
+			standaloneRuntime.OutputFiles(t, "")[0].String())
+
 	}
 
 	t.Run("host", func(t *testing.T) { check(t, buildOS, preparer) })
@@ -1246,3 +1272,122 @@
 		t.Errorf("non-CFI variant of baz not expected to contain CFI flags ")
 	}
 }
+
+func TestHwasan(t *testing.T) {
+	t.Parallel()
+
+	bp := `
+	cc_library_shared {
+		name: "shared_with_hwaddress",
+		static_libs: [
+			"static_dep_with_hwaddress",
+			"static_dep_no_hwaddress",
+		],
+		sanitize: {
+			hwaddress: true,
+		},
+		sdk_version: "current",
+			stl: "c++_shared",
+	}
+
+	cc_library_static {
+		name: "static_dep_with_hwaddress",
+		sanitize: {
+			hwaddress: true,
+		},
+		sdk_version: "current",
+			stl: "c++_shared",
+	}
+
+	cc_library_static {
+		name: "static_dep_no_hwaddress",
+		sdk_version: "current",
+			stl: "c++_shared",
+	}
+`
+
+	androidArm := "android_arm_armv7-a-neon"
+	androidArm64 := "android_arm64_armv8-a"
+	androidX86 := "android_x86_silvermont"
+	sharedSuffix := "_shared"
+	hwasanSuffix := "_hwasan"
+	staticSuffix := "_static"
+	sdkSuffix := "_sdk"
+
+	sharedWithHwasanVariant := sharedSuffix + hwasanSuffix
+	sharedWithSdkVariant := sdkSuffix + sharedSuffix
+	staticWithHwasanVariant := staticSuffix + hwasanSuffix
+	staticWithSdkVariant := sdkSuffix + staticSuffix
+
+	testCases := []struct {
+		buildOs          string
+		extraPreparer    android.FixturePreparer
+		expectedVariants map[string][]string
+	}{
+		{
+			buildOs: androidArm64,
+			expectedVariants: map[string][]string{
+				"shared_with_hwaddress": []string{
+					androidArm64 + sharedWithHwasanVariant,
+					androidArm64 + sharedWithSdkVariant,
+					androidArm + sharedSuffix,
+					androidArm + sharedWithSdkVariant,
+				},
+				"static_dep_with_hwaddress": []string{
+					androidArm64 + staticSuffix,
+					androidArm64 + staticWithHwasanVariant,
+					androidArm64 + staticWithSdkVariant,
+					androidArm + staticSuffix,
+					androidArm + staticWithSdkVariant,
+				},
+				"static_dep_no_hwaddress": []string{
+					androidArm64 + staticSuffix,
+					androidArm64 + staticWithHwasanVariant,
+					androidArm64 + staticWithSdkVariant,
+					androidArm + staticSuffix,
+					androidArm + staticWithSdkVariant,
+				},
+			},
+		},
+		{
+			buildOs: androidX86,
+			extraPreparer: android.FixtureModifyConfig(func(config android.Config) {
+				config.Targets[android.Android] = []android.Target{
+					{
+						android.Android,
+						android.Arch{
+							ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, android.NativeBridgeDisabled, "", "", false},
+				}
+			}),
+			expectedVariants: map[string][]string{
+				"shared_with_hwaddress": []string{
+					androidX86 + sharedSuffix,
+					androidX86 + sharedWithSdkVariant,
+				},
+				"static_dep_with_hwaddress": []string{
+					androidX86 + staticSuffix,
+					androidX86 + staticWithSdkVariant,
+				},
+				"static_dep_no_hwaddress": []string{
+					androidX86 + staticSuffix,
+					androidX86 + staticWithSdkVariant,
+				},
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		preparer := android.GroupFixturePreparers(
+			prepareForCcTest,
+			android.OptionalFixturePreparer(tc.extraPreparer),
+		)
+		result := preparer.RunTestWithBp(t, bp)
+
+		for m, v := range tc.expectedVariants {
+			variants := result.ModuleVariantsForTests(m)
+			if !reflect.DeepEqual(variants, v) {
+				t.Errorf("Expected variants of %q to be %q, but got %q", m, v, variants)
+			}
+		}
+	}
+}
diff --git a/cc/sdk.go b/cc/sdk.go
index 6341926..ce0fdc2 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -59,35 +59,6 @@
 				modules[1].(*Module).Properties.PreventInstall = true
 			}
 			ctx.AliasVariation("")
-		} else if isCcModule && ccModule.isImportedApiLibrary() {
-			apiLibrary, _ := ccModule.linker.(*apiLibraryDecorator)
-			if apiLibrary.hasNDKStubs() && ccModule.canUseSdk() {
-				variations := []string{"sdk"}
-				if apiLibrary.hasApexStubs() {
-					variations = append(variations, "")
-				}
-				// Handle cc_api_library module with NDK stubs and variants only which can use SDK
-				modules := ctx.CreateVariations(variations...)
-				// Mark the SDK variant.
-				modules[0].(*Module).Properties.IsSdkVariant = true
-				if ctx.Config().UnbundledBuildApps() {
-					if apiLibrary.hasApexStubs() {
-						// For an unbundled apps build, hide the platform variant from Make.
-						modules[1].(*Module).Properties.HideFromMake = true
-					}
-					modules[1].(*Module).Properties.PreventInstall = true
-				} else {
-					// For a platform build, mark the SDK variant so that it gets a ".sdk" suffix when
-					// exposed to Make.
-					modules[0].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
-					// SDK variant is not supposed to be installed
-					modules[0].(*Module).Properties.PreventInstall = true
-				}
-			} else {
-				ccModule.Properties.Sdk_version = nil
-				ctx.CreateVariations("")
-				ctx.AliasVariation("")
-			}
 		} else {
 			if isCcModule {
 				// Clear the sdk_version property for modules that don't have an SDK variant so
@@ -106,8 +77,6 @@
 			}
 			ctx.AliasVariation("")
 		}
-	case *snapshotModule:
-		ctx.CreateVariations("")
 	case *CcApiVariant:
 		ccApiVariant, _ := ctx.Module().(*CcApiVariant)
 		if String(ccApiVariant.properties.Variant) == "ndk" {
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index bb13310..f4a3d88 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -18,818 +18,9 @@
 // snapshot mutators and snapshot information maps which are also defined in this file.
 
 import (
-	"fmt"
-	"strings"
-
 	"android/soong/android"
-	"android/soong/snapshot"
-
-	"github.com/google/blueprint"
 )
 
-// This interface overrides snapshot.SnapshotImage to implement cc module specific functions
-type SnapshotImage interface {
-	snapshot.SnapshotImage
-
-	// The image variant name for this snapshot image.
-	// For example, recovery snapshot image will return "recovery", and vendor snapshot image will
-	// return "vendor." + version.
-	imageVariantName(cfg android.DeviceConfig) string
-
-	// The variant suffix for snapshot modules. For example, vendor snapshot modules will have
-	// ".vendor" as their suffix.
-	moduleNameSuffix() string
-}
-
-type vendorSnapshotImage struct {
-	*snapshot.VendorSnapshotImage
-}
-
-type recoverySnapshotImage struct {
-	*snapshot.RecoverySnapshotImage
-}
-
-func (vendorSnapshotImage) imageVariantName(cfg android.DeviceConfig) string {
-	return VendorVariationPrefix + cfg.VndkVersion()
-}
-
-func (vendorSnapshotImage) moduleNameSuffix() string {
-	return VendorSuffix
-}
-
-func (recoverySnapshotImage) imageVariantName(cfg android.DeviceConfig) string {
-	return android.RecoveryVariation
-}
-
-func (recoverySnapshotImage) moduleNameSuffix() string {
-	return RecoverySuffix
-}
-
-// Override existing vendor and recovery snapshot for cc module specific extra functions
-var VendorSnapshotImageSingleton vendorSnapshotImage = vendorSnapshotImage{&snapshot.VendorSnapshotImageSingleton}
-var RecoverySnapshotImageSingleton recoverySnapshotImage = recoverySnapshotImage{&snapshot.RecoverySnapshotImageSingleton}
-
-func RegisterVendorSnapshotModules(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("vendor_snapshot", vendorSnapshotFactory)
-	ctx.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory)
-	ctx.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory)
-	ctx.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory)
-	ctx.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory)
-	ctx.RegisterModuleType("vendor_snapshot_object", VendorSnapshotObjectFactory)
-}
-
-func RegisterRecoverySnapshotModules(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("recovery_snapshot", recoverySnapshotFactory)
-	ctx.RegisterModuleType("recovery_snapshot_shared", RecoverySnapshotSharedFactory)
-	ctx.RegisterModuleType("recovery_snapshot_static", RecoverySnapshotStaticFactory)
-	ctx.RegisterModuleType("recovery_snapshot_header", RecoverySnapshotHeaderFactory)
-	ctx.RegisterModuleType("recovery_snapshot_binary", RecoverySnapshotBinaryFactory)
-	ctx.RegisterModuleType("recovery_snapshot_object", RecoverySnapshotObjectFactory)
-}
-
-func init() {
-	RegisterVendorSnapshotModules(android.InitRegistrationContext)
-	RegisterRecoverySnapshotModules(android.InitRegistrationContext)
-	android.RegisterMakeVarsProvider(pctx, snapshotMakeVarsProvider)
-}
-
-const (
-	snapshotHeaderSuffix = "_header."
-	SnapshotSharedSuffix = "_shared."
-	SnapshotStaticSuffix = "_static."
-	snapshotBinarySuffix = "_binary."
-	snapshotObjectSuffix = "_object."
-	SnapshotRlibSuffix   = "_rlib."
-	SnapshotDylibSuffix  = "_dylib."
-)
-
-type SnapshotProperties struct {
-	Header_libs []string `android:"arch_variant"`
-	Static_libs []string `android:"arch_variant"`
-	Shared_libs []string `android:"arch_variant"`
-	Rlibs       []string `android:"arch_variant"`
-	Dylibs      []string `android:"arch_variant"`
-	Vndk_libs   []string `android:"arch_variant"`
-	Binaries    []string `android:"arch_variant"`
-	Objects     []string `android:"arch_variant"`
-}
-type snapshotModule struct {
-	android.ModuleBase
-
-	properties SnapshotProperties
-
-	baseSnapshot BaseSnapshotDecorator
-
-	image SnapshotImage
-}
-
-func (s *snapshotModule) ImageMutatorBegin(ctx android.BaseModuleContext) {
-	cfg := ctx.DeviceConfig()
-	if !s.image.IsUsingSnapshot(cfg) || s.image.TargetSnapshotVersion(cfg) != s.baseSnapshot.Version() {
-		s.Disable()
-	}
-}
-
-func (s *snapshotModule) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
-	return false
-}
-
-func (s *snapshotModule) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
-	return false
-}
-
-func (s *snapshotModule) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
-	return false
-}
-
-func (s *snapshotModule) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
-	return false
-}
-
-func (s *snapshotModule) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
-	return false
-}
-
-func (s *snapshotModule) ExtraImageVariations(ctx android.BaseModuleContext) []string {
-	return []string{s.image.imageVariantName(ctx.DeviceConfig())}
-}
-
-func (s *snapshotModule) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
-}
-
-func (s *snapshotModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	// Nothing, the snapshot module is only used to forward dependency information in DepsMutator.
-}
-
-func getSnapshotNameSuffix(moduleSuffix, version, arch string) string {
-	versionSuffix := version
-	if arch != "" {
-		versionSuffix += "." + arch
-	}
-	return moduleSuffix + versionSuffix
-}
-
-func (s *snapshotModule) DepsMutator(ctx android.BottomUpMutatorContext) {
-	collectSnapshotMap := func(names []string, snapshotSuffix, moduleSuffix string) map[string]string {
-		snapshotMap := make(map[string]string)
-		for _, name := range names {
-			snapshotMap[name] = name +
-				getSnapshotNameSuffix(snapshotSuffix+moduleSuffix,
-					s.baseSnapshot.Version(),
-					ctx.DeviceConfig().Arches()[0].ArchType.String())
-		}
-		return snapshotMap
-	}
-
-	snapshotSuffix := s.image.moduleNameSuffix()
-	headers := collectSnapshotMap(s.properties.Header_libs, snapshotSuffix, snapshotHeaderSuffix)
-	binaries := collectSnapshotMap(s.properties.Binaries, snapshotSuffix, snapshotBinarySuffix)
-	objects := collectSnapshotMap(s.properties.Objects, snapshotSuffix, snapshotObjectSuffix)
-	staticLibs := collectSnapshotMap(s.properties.Static_libs, snapshotSuffix, SnapshotStaticSuffix)
-	sharedLibs := collectSnapshotMap(s.properties.Shared_libs, snapshotSuffix, SnapshotSharedSuffix)
-	rlibs := collectSnapshotMap(s.properties.Rlibs, snapshotSuffix, SnapshotRlibSuffix)
-	dylibs := collectSnapshotMap(s.properties.Dylibs, snapshotSuffix, SnapshotDylibSuffix)
-	vndkLibs := collectSnapshotMap(s.properties.Vndk_libs, "", vndkSuffix)
-	for k, v := range vndkLibs {
-		sharedLibs[k] = v
-	}
-
-	ctx.SetProvider(SnapshotInfoProvider, SnapshotInfo{
-		HeaderLibs: headers,
-		Binaries:   binaries,
-		Objects:    objects,
-		StaticLibs: staticLibs,
-		SharedLibs: sharedLibs,
-		Rlibs:      rlibs,
-		Dylibs:     dylibs,
-	})
-}
-
-type SnapshotInfo struct {
-	HeaderLibs, Binaries, Objects, StaticLibs, SharedLibs, Rlibs, Dylibs map[string]string
-}
-
-var SnapshotInfoProvider = blueprint.NewMutatorProvider(SnapshotInfo{}, "deps")
-
-var _ android.ImageInterface = (*snapshotModule)(nil)
-
-func snapshotMakeVarsProvider(ctx android.MakeVarsContext) {
-	snapshotSet := map[string]struct{}{}
-	ctx.VisitAllModules(func(m android.Module) {
-		if s, ok := m.(*snapshotModule); ok {
-			if _, ok := snapshotSet[s.Name()]; ok {
-				// arch variant generates duplicated modules
-				// skip this as we only need to know the path of the module.
-				return
-			}
-			snapshotSet[s.Name()] = struct{}{}
-			imageNameVersion := strings.Split(s.image.imageVariantName(ctx.DeviceConfig()), ".")
-			ctx.Strict(
-				strings.Join([]string{strings.ToUpper(imageNameVersion[0]), s.baseSnapshot.Version(), "SNAPSHOT_DIR"}, "_"),
-				ctx.ModuleDir(s))
-		}
-	})
-}
-
-func vendorSnapshotFactory() android.Module {
-	return snapshotFactory(VendorSnapshotImageSingleton)
-}
-
-func recoverySnapshotFactory() android.Module {
-	return snapshotFactory(RecoverySnapshotImageSingleton)
-}
-
-func snapshotFactory(image SnapshotImage) android.Module {
-	snapshotModule := &snapshotModule{}
-	snapshotModule.image = image
-	snapshotModule.AddProperties(
-		&snapshotModule.properties,
-		&snapshotModule.baseSnapshot.baseProperties)
-	android.InitAndroidArchModule(snapshotModule, android.DeviceSupported, android.MultilibBoth)
-	return snapshotModule
-}
-
-type BaseSnapshotDecoratorProperties struct {
-	// snapshot version.
-	Version string
-
-	// Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64')
-	Target_arch string
-
-	// Suffix to be added to the module name when exporting to Android.mk, e.g. ".vendor".
-	Androidmk_suffix string `blueprint:"mutated"`
-
-	// Suffix to be added to the module name, e.g., vendor_shared,
-	// recovery_shared, etc.
-	ModuleSuffix string `blueprint:"mutated"`
-}
-
-// BaseSnapshotDecorator provides common basic functions for all snapshot modules, such as snapshot
-// version, snapshot arch, etc. It also adds a special suffix to Soong module name, so it doesn't
-// collide with source modules. e.g. the following example module,
-//
-//	vendor_snapshot_static {
-//	    name: "libbase",
-//	    arch: "arm64",
-//	    version: 30,
-//	    ...
-//	}
-//
-// will be seen as "libbase.vendor_static.30.arm64" by Soong.
-type BaseSnapshotDecorator struct {
-	baseProperties BaseSnapshotDecoratorProperties
-	Image          SnapshotImage
-}
-
-func (p *BaseSnapshotDecorator) Name(name string) string {
-	return name + p.NameSuffix()
-}
-
-func (p *BaseSnapshotDecorator) NameSuffix() string {
-	return getSnapshotNameSuffix(p.moduleSuffix(), p.Version(), p.Arch())
-}
-
-func (p *BaseSnapshotDecorator) Version() string {
-	return p.baseProperties.Version
-}
-
-func (p *BaseSnapshotDecorator) Arch() string {
-	return p.baseProperties.Target_arch
-}
-
-func (p *BaseSnapshotDecorator) moduleSuffix() string {
-	return p.baseProperties.ModuleSuffix
-}
-
-func (p *BaseSnapshotDecorator) IsSnapshotPrebuilt() bool {
-	return true
-}
-
-func (p *BaseSnapshotDecorator) SnapshotAndroidMkSuffix() string {
-	return p.baseProperties.Androidmk_suffix
-}
-
-func (p *BaseSnapshotDecorator) SetSnapshotAndroidMkSuffix(ctx android.ModuleContext, variant string) {
-	// If there are any 2 or more variations among {core, product, vendor, recovery}
-	// we have to add the androidmk suffix to avoid duplicate modules with the same
-	// name.
-	variations := append(ctx.Target().Variations(), blueprint.Variation{
-		Mutator:   "image",
-		Variation: android.CoreVariation})
-
-	if ctx.OtherModuleFarDependencyVariantExists(variations, ctx.Module().(LinkableInterface).BaseModuleName()) {
-		p.baseProperties.Androidmk_suffix = p.Image.moduleNameSuffix()
-		return
-	}
-
-	variations = append(ctx.Target().Variations(), blueprint.Variation{
-		Mutator:   "image",
-		Variation: ProductVariationPrefix + ctx.DeviceConfig().PlatformVndkVersion()})
-
-	if ctx.OtherModuleFarDependencyVariantExists(variations, ctx.Module().(LinkableInterface).BaseModuleName()) {
-		p.baseProperties.Androidmk_suffix = p.Image.moduleNameSuffix()
-		return
-	}
-
-	images := []SnapshotImage{VendorSnapshotImageSingleton, RecoverySnapshotImageSingleton}
-
-	for _, image := range images {
-		if p.Image == image {
-			continue
-		}
-		variations = append(ctx.Target().Variations(), blueprint.Variation{
-			Mutator:   "image",
-			Variation: image.imageVariantName(ctx.DeviceConfig())})
-
-		if ctx.OtherModuleFarDependencyVariantExists(variations,
-			ctx.Module().(LinkableInterface).BaseModuleName()+
-				getSnapshotNameSuffix(
-					image.moduleNameSuffix()+variant,
-					p.Version(),
-					ctx.DeviceConfig().Arches()[0].ArchType.String())) {
-			p.baseProperties.Androidmk_suffix = p.Image.moduleNameSuffix()
-			return
-		}
-	}
-
-	p.baseProperties.Androidmk_suffix = ""
-}
-
-// Call this with a module suffix after creating a snapshot module, such as
-// vendorSnapshotSharedSuffix, recoverySnapshotBinarySuffix, etc.
-func (p *BaseSnapshotDecorator) Init(m LinkableInterface, image SnapshotImage, moduleSuffix string) {
-	p.Image = image
-	p.baseProperties.ModuleSuffix = image.moduleNameSuffix() + moduleSuffix
-	m.AddProperties(&p.baseProperties)
-	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
-		vendorSnapshotLoadHook(ctx, p)
-	})
-}
-
-// vendorSnapshotLoadHook disables snapshots if it's not BOARD_VNDK_VERSION.
-// As vendor snapshot is only for vendor, such modules won't be used at all.
-func vendorSnapshotLoadHook(ctx android.LoadHookContext, p *BaseSnapshotDecorator) {
-	if p.Version() != ctx.DeviceConfig().VndkVersion() {
-		ctx.Module().Disable()
-		return
-	}
-}
-
-// Module definitions for snapshots of libraries (shared, static, header).
-//
-// Modules (vendor|recovery)_snapshot_(shared|static|header) are defined here. Shared libraries and
-// static libraries have their prebuilt library files (.so for shared, .a for static) as their src,
-// which can be installed or linked against. Also they export flags needed when linked, such as
-// include directories, c flags, sanitize dependency information, etc.
-//
-// These modules are auto-generated by development/vendor_snapshot/update.py.
-type SnapshotLibraryProperties struct {
-	// Prebuilt file for each arch.
-	Src *string `android:"arch_variant"`
-
-	// list of directories that will be added to the include path (using -I).
-	Export_include_dirs []string `android:"arch_variant"`
-
-	// list of directories that will be added to the system path (using -isystem).
-	Export_system_include_dirs []string `android:"arch_variant"`
-
-	// list of flags that will be used for any module that links against this module.
-	Export_flags []string `android:"arch_variant"`
-
-	// Whether this prebuilt needs to depend on sanitize ubsan runtime or not.
-	Sanitize_ubsan_dep *bool `android:"arch_variant"`
-
-	// Whether this prebuilt needs to depend on sanitize minimal runtime or not.
-	Sanitize_minimal_dep *bool `android:"arch_variant"`
-}
-
-type snapshotSanitizer interface {
-	isSanitizerAvailable(t SanitizerType) bool
-	setSanitizerVariation(t SanitizerType, enabled bool)
-	isSanitizerEnabled(t SanitizerType) bool
-	isUnsanitizedVariant() bool
-}
-
-type snapshotLibraryDecorator struct {
-	BaseSnapshotDecorator
-	*libraryDecorator
-	properties          SnapshotLibraryProperties
-	sanitizerProperties struct {
-		SanitizerVariation SanitizerType `blueprint:"mutated"`
-
-		// Library flags for cfi variant.
-		Cfi SnapshotLibraryProperties `android:"arch_variant"`
-
-		// Library flags for hwasan variant.
-		Hwasan SnapshotLibraryProperties `android:"arch_variant"`
-	}
-}
-
-func (p *snapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
-	p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), p.NameSuffix())
-	return p.libraryDecorator.linkerFlags(ctx, flags)
-}
-
-func (p *snapshotLibraryDecorator) MatchesWithDevice(config android.DeviceConfig) bool {
-	arches := config.Arches()
-	if len(arches) == 0 || arches[0].ArchType.String() != p.Arch() {
-		return false
-	}
-	if !p.header() && p.properties.Src == nil {
-		return false
-	}
-	return true
-}
-
-// cc modules' link functions are to link compiled objects into final binaries.
-// As snapshots are prebuilts, this just returns the prebuilt binary after doing things which are
-// done by normal library decorator, e.g. exporting flags.
-func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
-	var variant string
-	if p.shared() {
-		variant = SnapshotSharedSuffix
-	} else if p.static() {
-		variant = SnapshotStaticSuffix
-	} else {
-		variant = snapshotHeaderSuffix
-	}
-
-	p.SetSnapshotAndroidMkSuffix(ctx, variant)
-
-	if p.header() {
-		return p.libraryDecorator.link(ctx, flags, deps, objs)
-	}
-
-	if p.isSanitizerEnabled(cfi) {
-		p.properties = p.sanitizerProperties.Cfi
-	} else if p.isSanitizerEnabled(Hwasan) {
-		p.properties = p.sanitizerProperties.Hwasan
-	}
-
-	if !p.MatchesWithDevice(ctx.DeviceConfig()) {
-		return nil
-	}
-
-	// Flags specified directly to this module.
-	p.libraryDecorator.reexportDirs(android.PathsForModuleSrc(ctx, p.properties.Export_include_dirs)...)
-	p.libraryDecorator.reexportSystemDirs(android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...)
-	p.libraryDecorator.reexportFlags(p.properties.Export_flags...)
-
-	// Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
-	p.libraryDecorator.reexportDirs(deps.ReexportedDirs...)
-	p.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
-	p.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
-	p.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
-	p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
-
-	in := android.PathForModuleSrc(ctx, *p.properties.Src)
-	p.unstrippedOutputFile = in
-
-	if p.shared() {
-		libName := in.Base()
-
-		// Optimize out relinking against shared libraries whose interface hasn't changed by
-		// depending on a table of contents file instead of the library itself.
-		tocFile := android.PathForModuleOut(ctx, libName+".toc")
-		p.tocFile = android.OptionalPathForPath(tocFile)
-		TransformSharedObjectToToc(ctx, in, tocFile)
-
-		ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
-			SharedLibrary: in,
-			Target:        ctx.Target(),
-
-			TableOfContents: p.tocFile,
-		})
-	}
-
-	if p.static() {
-		depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(in).Build()
-		ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
-			StaticLibrary: in,
-
-			TransitiveStaticLibrariesForOrdering: depSet,
-		})
-	}
-
-	p.libraryDecorator.flagExporter.setProvider(ctx)
-
-	return in
-}
-
-func (p *snapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) {
-	if p.MatchesWithDevice(ctx.DeviceConfig()) && p.shared() {
-		p.baseInstaller.install(ctx, file)
-	}
-}
-
-func (p *snapshotLibraryDecorator) nativeCoverage() bool {
-	return false
-}
-
-var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil)
-
-func (p *snapshotLibraryDecorator) isSanitizerAvailable(t SanitizerType) bool {
-	switch t {
-	case cfi:
-		return p.sanitizerProperties.Cfi.Src != nil
-	case Hwasan:
-		return p.sanitizerProperties.Hwasan.Src != nil
-	default:
-		return false
-	}
-}
-
-func (p *snapshotLibraryDecorator) setSanitizerVariation(t SanitizerType, enabled bool) {
-	if !enabled || p.isSanitizerEnabled(t) {
-		return
-	}
-	if !p.isUnsanitizedVariant() {
-		panic(fmt.Errorf("snapshot Sanitizer must be one of Cfi or Hwasan but not both"))
-	}
-	p.sanitizerProperties.SanitizerVariation = t
-}
-
-func (p *snapshotLibraryDecorator) isSanitizerEnabled(t SanitizerType) bool {
-	return p.sanitizerProperties.SanitizerVariation == t
-}
-
-func (p *snapshotLibraryDecorator) isUnsanitizedVariant() bool {
-	return !p.isSanitizerEnabled(Asan) &&
-		!p.isSanitizerEnabled(Hwasan)
-}
-
-func snapshotLibraryFactory(image SnapshotImage, moduleSuffix string) (*Module, *snapshotLibraryDecorator) {
-	module, library := NewLibrary(android.DeviceSupported)
-
-	module.stl = nil
-	module.sanitize = nil
-	library.disableStripping()
-
-	prebuilt := &snapshotLibraryDecorator{
-		libraryDecorator: library,
-	}
-
-	prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true)
-	prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true)
-
-	// Prevent default system libs (libc, libm, and libdl) from being linked
-	if prebuilt.baseLinker.Properties.System_shared_libs == nil {
-		prebuilt.baseLinker.Properties.System_shared_libs = []string{}
-	}
-
-	module.compiler = nil
-	module.linker = prebuilt
-	module.installer = prebuilt
-
-	prebuilt.Init(module, image, moduleSuffix)
-	module.AddProperties(
-		&prebuilt.properties,
-		&prebuilt.sanitizerProperties,
-	)
-
-	return module, prebuilt
-}
-
-// vendor_snapshot_shared is a special prebuilt shared library which is auto-generated by
-// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_shared
-// overrides the vendor variant of the cc shared library with the same name, if BOARD_VNDK_VERSION
-// is set.
-func VendorSnapshotSharedFactory() android.Module {
-	module, prebuilt := snapshotLibraryFactory(VendorSnapshotImageSingleton, SnapshotSharedSuffix)
-	prebuilt.libraryDecorator.BuildOnlyShared()
-	return module.Init()
-}
-
-// recovery_snapshot_shared is a special prebuilt shared library which is auto-generated by
-// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_shared
-// overrides the recovery variant of the cc shared library with the same name, if BOARD_VNDK_VERSION
-// is set.
-func RecoverySnapshotSharedFactory() android.Module {
-	module, prebuilt := snapshotLibraryFactory(RecoverySnapshotImageSingleton, SnapshotSharedSuffix)
-	prebuilt.libraryDecorator.BuildOnlyShared()
-	return module.Init()
-}
-
-// vendor_snapshot_static is a special prebuilt static library which is auto-generated by
-// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_static
-// overrides the vendor variant of the cc static library with the same name, if BOARD_VNDK_VERSION
-// is set.
-func VendorSnapshotStaticFactory() android.Module {
-	module, prebuilt := snapshotLibraryFactory(VendorSnapshotImageSingleton, SnapshotStaticSuffix)
-	prebuilt.libraryDecorator.BuildOnlyStatic()
-	return module.Init()
-}
-
-// recovery_snapshot_static is a special prebuilt static library which is auto-generated by
-// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_static
-// overrides the recovery variant of the cc static library with the same name, if BOARD_VNDK_VERSION
-// is set.
-func RecoverySnapshotStaticFactory() android.Module {
-	module, prebuilt := snapshotLibraryFactory(RecoverySnapshotImageSingleton, SnapshotStaticSuffix)
-	prebuilt.libraryDecorator.BuildOnlyStatic()
-	return module.Init()
-}
-
-// vendor_snapshot_header is a special header library which is auto-generated by
-// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_header
-// overrides the vendor variant of the cc header library with the same name, if BOARD_VNDK_VERSION
-// is set.
-func VendorSnapshotHeaderFactory() android.Module {
-	module, prebuilt := snapshotLibraryFactory(VendorSnapshotImageSingleton, snapshotHeaderSuffix)
-	prebuilt.libraryDecorator.HeaderOnly()
-	return module.Init()
-}
-
-// recovery_snapshot_header is a special header library which is auto-generated by
-// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_header
-// overrides the recovery variant of the cc header library with the same name, if BOARD_VNDK_VERSION
-// is set.
-func RecoverySnapshotHeaderFactory() android.Module {
-	module, prebuilt := snapshotLibraryFactory(RecoverySnapshotImageSingleton, snapshotHeaderSuffix)
-	prebuilt.libraryDecorator.HeaderOnly()
-	return module.Init()
-}
-
-// Module definitions for snapshots of executable binaries.
-//
-// Modules (vendor|recovery)_snapshot_binary are defined here. They have their prebuilt executable
-// binaries (e.g. toybox, sh) as their src, which can be installed.
-//
-// These modules are auto-generated by development/vendor_snapshot/update.py.
-type snapshotBinaryProperties struct {
-	// Prebuilt file for each arch.
-	Src *string `android:"arch_variant"`
-}
-
-type snapshotBinaryDecorator struct {
-	BaseSnapshotDecorator
-	*binaryDecorator
-	properties snapshotBinaryProperties
-}
-
-func (p *snapshotBinaryDecorator) MatchesWithDevice(config android.DeviceConfig) bool {
-	if config.DeviceArch() != p.Arch() {
-		return false
-	}
-	if p.properties.Src == nil {
-		return false
-	}
-	return true
-}
-
-// cc modules' link functions are to link compiled objects into final binaries.
-// As snapshots are prebuilts, this just returns the prebuilt binary
-func (p *snapshotBinaryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
-	p.SetSnapshotAndroidMkSuffix(ctx, snapshotBinarySuffix)
-
-	if !p.MatchesWithDevice(ctx.DeviceConfig()) {
-		return nil
-	}
-
-	in := android.PathForModuleSrc(ctx, *p.properties.Src)
-	p.unstrippedOutputFile = in
-	binName := in.Base()
-
-	// use cpExecutable to make it executable
-	outputFile := android.PathForModuleOut(ctx, binName)
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.CpExecutable,
-		Description: "prebuilt",
-		Output:      outputFile,
-		Input:       in,
-	})
-
-	// binary snapshots need symlinking
-	p.setSymlinkList(ctx)
-
-	return outputFile
-}
-
-func (p *snapshotBinaryDecorator) nativeCoverage() bool {
-	return false
-}
-
-// vendor_snapshot_binary is a special prebuilt executable binary which is auto-generated by
-// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_binary
-// overrides the vendor variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set.
-func VendorSnapshotBinaryFactory() android.Module {
-	return snapshotBinaryFactory(VendorSnapshotImageSingleton, snapshotBinarySuffix)
-}
-
-// recovery_snapshot_binary is a special prebuilt executable binary which is auto-generated by
-// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_binary
-// overrides the recovery variant of the cc binary with the same name, if BOARD_VNDK_VERSION is set.
-func RecoverySnapshotBinaryFactory() android.Module {
-	return snapshotBinaryFactory(RecoverySnapshotImageSingleton, snapshotBinarySuffix)
-}
-
-func snapshotBinaryFactory(image SnapshotImage, moduleSuffix string) android.Module {
-	module, binary := NewBinary(android.DeviceSupported)
-	binary.baseLinker.Properties.No_libcrt = BoolPtr(true)
-	binary.baseLinker.Properties.Nocrt = BoolPtr(true)
-
-	// Prevent default system libs (libc, libm, and libdl) from being linked
-	if binary.baseLinker.Properties.System_shared_libs == nil {
-		binary.baseLinker.Properties.System_shared_libs = []string{}
-	}
-
-	prebuilt := &snapshotBinaryDecorator{
-		binaryDecorator: binary,
-	}
-
-	module.compiler = nil
-	module.sanitize = nil
-	module.stl = nil
-	module.linker = prebuilt
-
-	prebuilt.Init(module, image, moduleSuffix)
-	module.AddProperties(&prebuilt.properties)
-	return module.Init()
-}
-
-// Module definitions for snapshots of object files (*.o).
-//
-// Modules (vendor|recovery)_snapshot_object are defined here. They have their prebuilt object
-// files (*.o) as their src.
-//
-// These modules are auto-generated by development/vendor_snapshot/update.py.
-type vendorSnapshotObjectProperties struct {
-	// Prebuilt file for each arch.
-	Src *string `android:"arch_variant"`
-}
-
-type snapshotObjectLinker struct {
-	BaseSnapshotDecorator
-	objectLinker
-	properties vendorSnapshotObjectProperties
-}
-
-func (p *snapshotObjectLinker) MatchesWithDevice(config android.DeviceConfig) bool {
-	if config.DeviceArch() != p.Arch() {
-		return false
-	}
-	if p.properties.Src == nil {
-		return false
-	}
-	return true
-}
-
-// cc modules' link functions are to link compiled objects into final binaries.
-// As snapshots are prebuilts, this just returns the prebuilt binary
-func (p *snapshotObjectLinker) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path {
-	p.SetSnapshotAndroidMkSuffix(ctx, snapshotObjectSuffix)
-
-	if !p.MatchesWithDevice(ctx.DeviceConfig()) {
-		return nil
-	}
-
-	return android.PathForModuleSrc(ctx, *p.properties.Src)
-}
-
-func (p *snapshotObjectLinker) nativeCoverage() bool {
-	return false
-}
-
-// vendor_snapshot_object is a special prebuilt compiled object file which is auto-generated by
-// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_object
-// overrides the vendor variant of the cc object with the same name, if BOARD_VNDK_VERSION is set.
-func VendorSnapshotObjectFactory() android.Module {
-	module := newObject(android.DeviceSupported)
-
-	prebuilt := &snapshotObjectLinker{
-		objectLinker: objectLinker{
-			baseLinker: NewBaseLinker(nil),
-		},
-	}
-	module.linker = prebuilt
-
-	prebuilt.Init(module, VendorSnapshotImageSingleton, snapshotObjectSuffix)
-	module.AddProperties(&prebuilt.properties)
-
-	// vendor_snapshot_object module does not provide sanitizer variants
-	module.sanitize.Properties.Sanitize.Never = BoolPtr(true)
-
-	return module.Init()
-}
-
-// recovery_snapshot_object is a special prebuilt compiled object file which is auto-generated by
-// development/vendor_snapshot/update.py. As a part of recovery snapshot, recovery_snapshot_object
-// overrides the recovery variant of the cc object with the same name, if BOARD_VNDK_VERSION is set.
-func RecoverySnapshotObjectFactory() android.Module {
-	module := newObject(android.DeviceSupported)
-
-	prebuilt := &snapshotObjectLinker{
-		objectLinker: objectLinker{
-			baseLinker: NewBaseLinker(nil),
-		},
-	}
-	module.linker = prebuilt
-
-	prebuilt.Init(module, RecoverySnapshotImageSingleton, snapshotObjectSuffix)
-	module.AddProperties(&prebuilt.properties)
-	return module.Init()
-}
-
 type SnapshotInterface interface {
 	MatchesWithDevice(config android.DeviceConfig) bool
 	IsSnapshotPrebuilt() bool
@@ -838,6 +29,3 @@
 }
 
 var _ SnapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil)
-var _ SnapshotInterface = (*snapshotLibraryDecorator)(nil)
-var _ SnapshotInterface = (*snapshotBinaryDecorator)(nil)
-var _ SnapshotInterface = (*snapshotObjectLinker)(nil)
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
deleted file mode 100644
index 1ee120e..0000000
--- a/cc/snapshot_utils.go
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package cc
-
-// This file contains utility types and functions for VNDK / vendor snapshot.
-
-import (
-	"android/soong/android"
-)
-
-var (
-	HeaderExts = []string{".h", ".hh", ".hpp", ".hxx", ".h++", ".inl", ".inc", ".ipp", ".h.generic"}
-)
-
-func (m *Module) IsSnapshotLibrary() bool {
-	if _, ok := m.linker.(snapshotLibraryInterface); ok {
-		return true
-	}
-	return false
-}
-
-func (m *Module) SnapshotHeaders() android.Paths {
-	if m.IsSnapshotLibrary() {
-		return m.linker.(snapshotLibraryInterface).snapshotHeaders()
-	}
-	return android.Paths{}
-}
-
-func (m *Module) Dylib() bool {
-	return false
-}
-
-func (m *Module) Rlib() bool {
-	return false
-}
-
-func (m *Module) SnapshotRuntimeLibs() []string {
-	return m.Properties.SnapshotRuntimeLibs
-}
-
-func (m *Module) SnapshotSharedLibs() []string {
-	return m.Properties.SnapshotSharedLibs
-}
-
-func (m *Module) SnapshotStaticLibs() []string {
-	return m.Properties.SnapshotStaticLibs
-}
-
-func (m *Module) SnapshotRlibs() []string {
-	return []string{}
-}
-
-func (m *Module) SnapshotDylibs() []string {
-	return []string{}
-}
-
-// snapshotLibraryInterface is an interface for libraries captured to VNDK / vendor snapshots.
-type snapshotLibraryInterface interface {
-	libraryInterface
-
-	// collectHeadersForSnapshot is called in GenerateAndroidBuildActions for snapshot aware
-	// modules (See isSnapshotAware below).
-	// This function should gather all headers needed for snapshot.
-	collectHeadersForSnapshot(ctx android.ModuleContext)
-
-	// snapshotHeaders should return collected headers by collectHeadersForSnapshot.
-	// Calling snapshotHeaders before collectHeadersForSnapshot is an error.
-	snapshotHeaders() android.Paths
-}
-
-var _ snapshotLibraryInterface = (*prebuiltLibraryLinker)(nil)
-var _ snapshotLibraryInterface = (*libraryDecorator)(nil)
-
-// snapshotMap is a helper wrapper to a map from base module name to snapshot module name.
-type snapshotMap struct {
-	snapshots map[string]string
-}
-
-func newSnapshotMap() *snapshotMap {
-	return &snapshotMap{
-		snapshots: make(map[string]string),
-	}
-}
-
-func snapshotMapKey(name string, arch android.ArchType) string {
-	return name + ":" + arch.String()
-}
-
-// Adds a snapshot name for given module name and architecture.
-// e.g. add("libbase", X86, "libbase.vndk.29.x86")
-func (s *snapshotMap) add(name string, arch android.ArchType, snapshot string) {
-	s.snapshots[snapshotMapKey(name, arch)] = snapshot
-}
-
-// Returns snapshot name for given module name and architecture, if found.
-// e.g. get("libcutils", X86) => "libcutils.vndk.29.x86", true
-func (s *snapshotMap) get(name string, arch android.ArchType) (snapshot string, found bool) {
-	snapshot, found = s.snapshots[snapshotMapKey(name, arch)]
-	return snapshot, found
-}
-
-// ShouldCollectHeadersForSnapshot determines if the module is a possible candidate for snapshot.
-// If it's true, collectHeadersForSnapshot will be called in GenerateAndroidBuildActions.
-func ShouldCollectHeadersForSnapshot(ctx android.ModuleContext, m LinkableInterface, apexInfo android.ApexInfo) bool {
-	if ctx.DeviceConfig().VndkVersion() != "current" &&
-		ctx.DeviceConfig().RecoverySnapshotVersion() != "current" {
-		return false
-	}
-	if _, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo); ok {
-		return ctx.Config().VndkSnapshotBuildArtifacts()
-	}
-
-	for _, image := range []SnapshotImage{VendorSnapshotImageSingleton, RecoverySnapshotImageSingleton} {
-		if isSnapshotAware(ctx.DeviceConfig(), m, image.IsProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()), apexInfo, image) {
-			return true
-		}
-	}
-	return false
-}
diff --git a/cc/stl.go b/cc/stl.go
index 8f92dcb..de2066f 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -134,8 +134,6 @@
 	return "libunwind"
 }
 
-// Should be kept up to date with
-// https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/cc/stl.bzl;l=46;drc=21771b671ae08565033768a6d3d151c54f887fa2
 func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps {
 	switch stl.Properties.SelectedStl {
 	case "libstdc++":
@@ -172,6 +170,7 @@
 		// The system STL doesn't have a prebuilt (it uses the system's libstdc++), but it does have
 		// its own includes. The includes are handled in CCBase.Flags().
 		deps.SharedLibs = append([]string{"libstdc++"}, deps.SharedLibs...)
+		deps.HeaderLibs = append([]string{"ndk_system"}, deps.HeaderLibs...)
 	case "ndk_libc++_shared", "ndk_libc++_static":
 		if stl.Properties.SelectedStl == "ndk_libc++_shared" {
 			deps.SharedLibs = append(deps.SharedLibs, stl.Properties.SelectedStl)
@@ -186,8 +185,6 @@
 	return deps
 }
 
-// Should be kept up to date with
-// https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/cc/stl.bzl;l=94;drc=5bc8e39d2637927dc57dd0850210d43d348a1341
 func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags {
 	switch stl.Properties.SelectedStl {
 	case "libc++", "libc++_static":
@@ -208,19 +205,20 @@
 			flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++")
 			if ctx.Windows() {
 				flags.Local.CppFlags = append(flags.Local.CppFlags,
-					// Disable visiblity annotations since we're using static
-					// libc++.
-					"-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS",
-					"-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS",
+					// These macros can also be defined by libc++'s __config
+					// or __config_site headers so define them the same way
+					// (i.e. to nothing). Disable visibility annotations since
+					// we're using static libc++.
+					"-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS=",
+					"-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS=",
 					// Use Win32 threads in libc++.
-					"-D_LIBCPP_HAS_THREAD_API_WIN32")
+					"-D_LIBCPP_HAS_THREAD_API_WIN32=")
 			}
 		}
 	case "libstdc++":
 		// Nothing
 	case "ndk_system":
-		ndkSrcRoot := android.PathForSource(ctx, "prebuilts/ndk/current/sources/cxx-stl/system/include")
-		flags.Local.CFlags = append(flags.Local.CFlags, "-isystem "+ndkSrcRoot.String())
+		// Nothing: The exports of ndk_system will be added automatically to the local cflags
 	case "ndk_libc++_shared", "ndk_libc++_static":
 		if ctx.Arch().ArchType == android.Arm {
 			// Make sure the _Unwind_XXX symbols are not re-exported.
diff --git a/cc/strip.go b/cc/strip.go
index c60e135..b1f34bb 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -59,7 +59,6 @@
 	return !forceDisable && (forceEnable || defaultEnable)
 }
 
-// Keep this consistent with //build/bazel/rules/stripped_shared_library.bzl.
 func (stripper *Stripper) strip(actx android.ModuleContext, in android.Path, out android.ModuleOutPath,
 	flags StripFlags, isStaticLib bool) {
 	if actx.Darwin() {
diff --git a/cc/stub_library.go b/cc/stub_library.go
index 3a6d0ae..47c6cb9 100644
--- a/cc/stub_library.go
+++ b/cc/stub_library.go
@@ -27,7 +27,8 @@
 }
 
 type stubLibraries struct {
-	stubLibraryMap map[string]bool
+	stubLibraryMap       map[string]bool
+	stubVendorLibraryMap map[string]bool
 
 	apiListCoverageXmlPaths []string
 }
@@ -54,6 +55,9 @@
 			if IsStubTarget(m) {
 				if name := getInstalledFileName(m); name != "" {
 					s.stubLibraryMap[name] = true
+					if m.InVendor() {
+						s.stubVendorLibraryMap[name] = true
+					}
 				}
 			}
 			if m.library != nil {
@@ -67,13 +71,15 @@
 
 func stubLibrariesSingleton() android.Singleton {
 	return &stubLibraries{
-		stubLibraryMap: make(map[string]bool),
+		stubLibraryMap:       make(map[string]bool),
+		stubVendorLibraryMap: make(map[string]bool),
 	}
 }
 
 func (s *stubLibraries) MakeVars(ctx android.MakeVarsContext) {
 	// Convert stub library file names into Makefile variable.
 	ctx.Strict("STUB_LIBRARIES", strings.Join(android.SortedKeys(s.stubLibraryMap), " "))
+	ctx.Strict("SOONG_STUB_VENDOR_LIBRARIES", strings.Join(android.SortedKeys(s.stubVendorLibraryMap), " "))
 
 	// Export the list of API XML files to Make.
 	sort.Strings(s.apiListCoverageXmlPaths)
diff --git a/cc/symbolfile/__init__.py b/cc/symbolfile/__init__.py
index 94c8567..4553616 100644
--- a/cc/symbolfile/__init__.py
+++ b/cc/symbolfile/__init__.py
@@ -46,6 +46,15 @@
     Arch('x86_64'),
 )
 
+# TODO: it would be nice to dedupe with 'has_*_tag' property methods
+SUPPORTED_TAGS = ALL_ARCHITECTURES + (
+    Tag('apex'),
+    Tag('llndk'),
+    Tag('platform-only'),
+    Tag('systemapi'),
+    Tag('var'),
+    Tag('weak'),
+)
 
 # Arbitrary magic number. We use the same one in api-level.h for this purpose.
 FUTURE_API_LEVEL = 10000
@@ -94,13 +103,24 @@
     @property
     def has_llndk_tags(self) -> bool:
         """Returns True if any LL-NDK tags are set."""
-        return 'llndk' in self.tags
+        for tag in self.tags:
+            if tag == 'llndk' or tag.startswith('llndk='):
+                return True
+        return False
 
     @property
     def has_platform_only_tags(self) -> bool:
         """Returns True if any platform-only tags are set."""
         return 'platform-only' in self.tags
 
+    def copy_introduced_from(self, tags: Tags) -> None:
+        """Copies introduced= or introduced-*= tags."""
+        for tag in tags:
+            if tag.startswith('introduced=') or tag.startswith('introduced-'):
+                name, _ = split_tag(tag)
+                if not any(self_tag.startswith(name + '=') for self_tag in self.tags):
+                    self.tags += (tag,)
+
 
 @dataclass
 class Symbol:
@@ -136,6 +156,10 @@
 
 def is_api_level_tag(tag: Tag) -> bool:
     """Returns true if this tag has an API level that may need decoding."""
+    if tag.startswith('llndk-deprecated='):
+        return True
+    if tag.startswith('llndk='):
+        return True
     if tag.startswith('introduced='):
         return True
     if tag.startswith('introduced-'):
@@ -170,6 +194,9 @@
         ParseError: An unknown version name was found in a tag.
     """
     if not is_api_level_tag(tag):
+        if tag not in SUPPORTED_TAGS:
+            raise ParseError(f'Unsupported tag: {tag}')
+
         return tag
 
     name, value = split_tag(tag)
@@ -223,15 +250,22 @@
 
         This defines the rules shared between version tagging and symbol tagging.
         """
-        # The apex and llndk tags will only exclude APIs from other modes. If in
+        # LLNDK mode/tags follow the similar filtering except that API level checking
+        # is based llndk= instead of introduced=.
+        if self.llndk:
+            if tags.has_mode_tags and not tags.has_llndk_tags:
+                return True
+            if not symbol_in_arch(tags, self.arch):
+                return True
+            if not symbol_in_llndk_api(tags, self.arch, self.api):
+                return True
+            return False
         # APEX or LLNDK mode and neither tag is provided, we fall back to the
         # default behavior because all NDK symbols are implicitly available to
         # APEX and LLNDK.
         if tags.has_mode_tags:
             if self.apex and tags.has_apex_tags:
                 return False
-            if self.llndk and tags.has_llndk_tags:
-                return False
             if self.systemapi and tags.has_systemapi_tags:
                 return False
             return True
@@ -252,6 +286,10 @@
             return True
         if version.tags.has_platform_only_tags:
             return True
+        # Include all versions when targeting LLNDK because LLNDK symbols are self-versioned.
+        # Empty version block will be handled separately.
+        if self.llndk:
+            return False
         return self._should_omit_tags(version.tags)
 
     def should_omit_symbol(self, symbol: Symbol) -> bool:
@@ -278,6 +316,14 @@
     # for the tagged architectures.
     return not has_arch_tags
 
+def symbol_in_llndk_api(tags: Iterable[Tag], arch: Arch, api: int) -> bool:
+    """Returns true if the symbol is present for the given LLNDK API level."""
+    # Check llndk= first.
+    for tag in tags:
+        if tag.startswith('llndk='):
+            return api >= int(get_tag_value(tag))
+    # If not, we keep old behavior: NDK symbols in <= 34 are LLNDK symbols.
+    return symbol_in_api(tags, arch, 34)
 
 def symbol_in_api(tags: Iterable[Tag], arch: Arch, api: int) -> bool:
     """Returns true if the symbol is present for the given API level."""
@@ -354,6 +400,7 @@
                     f'Unexpected contents at top level: {self.current_line}')
 
         self.check_no_duplicate_symbols(versions)
+        self.check_llndk_introduced(versions)
         return versions
 
     def check_no_duplicate_symbols(self, versions: Iterable[Version]) -> None:
@@ -382,6 +429,31 @@
             raise MultiplyDefinedSymbolError(
                 sorted(list(multiply_defined_symbols)))
 
+    def check_llndk_introduced(self, versions: Iterable[Version]) -> None:
+        """Raises errors when llndk= is missing for new llndk symbols."""
+        if not self.filter.llndk:
+            return
+
+        def assert_llndk_with_version(tags: Tags,  name: str) -> None:
+            has_llndk_introduced = False
+            for tag in tags:
+                if tag.startswith('llndk='):
+                    has_llndk_introduced = True
+                    break
+            if not has_llndk_introduced:
+                raise ParseError(f'{name}: missing version. `llndk=yyyymm`')
+
+        arch = self.filter.arch
+        for version in versions:
+            # llndk symbols >= introduced=35 should be tagged
+            # explicitly with llndk=yyyymm.
+            for symbol in version.symbols:
+                if not symbol.tags.has_llndk_tags:
+                    continue
+                if symbol_in_api(symbol.tags, arch, 34):
+                    continue
+                assert_llndk_with_version(symbol.tags, symbol.name)
+
     def parse_version(self) -> Version:
         """Parses a single version section and returns a Version object."""
         assert self.current_line is not None
@@ -415,7 +487,9 @@
                 else:
                     raise ParseError('Unknown visiblity label: ' + visibility)
             elif global_scope and not cpp_symbols:
-                symbols.append(self.parse_symbol())
+                symbol = self.parse_symbol()
+                symbol.tags.copy_introduced_from(tags)
+                symbols.append(symbol)
             else:
                 # We're in a hidden scope or in 'extern "C++"' block. Ignore
                 # everything.
diff --git a/cc/symbolfile/test_symbolfile.py b/cc/symbolfile/test_symbolfile.py
index 856b9d7..8b412b9 100644
--- a/cc/symbolfile/test_symbolfile.py
+++ b/cc/symbolfile/test_symbolfile.py
@@ -40,10 +40,20 @@
         self.assertEqual(Tags(), symbolfile.get_tags('foo bar baz', {}))
 
     def test_get_tags(self) -> None:
-        self.assertEqual(Tags.from_strs(['foo', 'bar']),
-                         symbolfile.get_tags('# foo bar', {}))
-        self.assertEqual(Tags.from_strs(['bar', 'baz']),
-                         symbolfile.get_tags('foo # bar baz', {}))
+        self.assertEqual(Tags.from_strs(['llndk', 'apex']),
+                         symbolfile.get_tags('# llndk apex', {}))
+        self.assertEqual(Tags.from_strs(['llndk', 'apex']),
+                         symbolfile.get_tags('foo # llndk apex', {}))
+
+    def test_get_unrecognized_tags(self) -> None:
+        with self.assertRaises(symbolfile.ParseError):
+            symbolfile.get_tags('# bar', {})
+        with self.assertRaises(symbolfile.ParseError):
+            symbolfile.get_tags('foo # bar', {})
+        with self.assertRaises(symbolfile.ParseError):
+            symbolfile.get_tags('# #', {})
+        with self.assertRaises(symbolfile.ParseError):
+            symbolfile.get_tags('# apex # llndk', {})
 
     def test_split_tag(self) -> None:
         self.assertTupleEqual(('foo', 'bar'),
@@ -334,6 +344,45 @@
         self.assertInclude(f_llndk, s_none)
         self.assertInclude(f_llndk, s_llndk)
 
+    def test_omit_llndk_versioned(self) -> None:
+        f_ndk = self.filter
+        f_ndk.api = 35
+
+        f_llndk = copy(f_ndk)
+        f_llndk.llndk = True
+        f_llndk.api = 202404
+
+        s = Symbol('foo', Tags())
+        s_llndk = Symbol('foo', Tags.from_strs(['llndk']))
+        s_llndk_202404 = Symbol('foo', Tags.from_strs(['llndk=202404']))
+        s_34 = Symbol('foo', Tags.from_strs(['introduced=34']))
+        s_34_llndk = Symbol('foo', Tags.from_strs(['introduced=34', 'llndk']))
+        s_35 = Symbol('foo', Tags.from_strs(['introduced=35']))
+        s_35_llndk_202404 = Symbol('foo', Tags.from_strs(['introduced=35', 'llndk=202404']))
+        s_35_llndk_202504 = Symbol('foo', Tags.from_strs(['introduced=35', 'llndk=202504']))
+
+        # When targeting NDK, omit LLNDK tags
+        self.assertInclude(f_ndk, s)
+        self.assertOmit(f_ndk, s_llndk)
+        self.assertOmit(f_ndk, s_llndk_202404)
+        self.assertInclude(f_ndk, s_34)
+        self.assertOmit(f_ndk, s_34_llndk)
+        self.assertInclude(f_ndk, s_35)
+        self.assertOmit(f_ndk, s_35_llndk_202404)
+        self.assertOmit(f_ndk, s_35_llndk_202504)
+
+        # When targeting LLNDK, old symbols without any mode tags are included as LLNDK
+        self.assertInclude(f_llndk, s)
+        # When targeting LLNDK, old symbols with #llndk are included as LLNDK
+        self.assertInclude(f_llndk, s_llndk)
+        self.assertInclude(f_llndk, s_llndk_202404)
+        self.assertInclude(f_llndk, s_34)
+        self.assertInclude(f_llndk, s_34_llndk)
+        # When targeting LLNDK, new symbols(>=35) should be tagged with llndk-introduced=.
+        self.assertOmit(f_llndk, s_35)
+        self.assertInclude(f_llndk, s_35_llndk_202404)
+        self.assertOmit(f_llndk, s_35_llndk_202504)
+
     def test_omit_apex(self) -> None:
         f_none = self.filter
         f_apex = copy(f_none)
@@ -425,13 +474,13 @@
 
     def test_parse_version(self) -> None:
         input_file = io.StringIO(textwrap.dedent("""\
-            VERSION_1 { # foo bar
+            VERSION_1 { # weak introduced=35
                 baz;
-                qux; # woodly doodly
+                qux; # apex llndk
             };
 
             VERSION_2 {
-            } VERSION_1; # asdf
+            } VERSION_1; # not-a-tag
         """))
         parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
 
@@ -439,11 +488,14 @@
         version = parser.parse_version()
         self.assertEqual('VERSION_1', version.name)
         self.assertIsNone(version.base)
-        self.assertEqual(Tags.from_strs(['foo', 'bar']), version.tags)
+        self.assertEqual(Tags.from_strs(['weak', 'introduced=35']), version.tags)
 
+        # Inherit introduced= tags from version block so that
+        # should_omit_tags() can differently based on introduced API level when treating
+        # LLNDK-available symbols.
         expected_symbols = [
-            Symbol('baz', Tags()),
-            Symbol('qux', Tags.from_strs(['woodly', 'doodly'])),
+            Symbol('baz', Tags.from_strs(['introduced=35'])),
+            Symbol('qux', Tags.from_strs(['apex', 'llndk', 'introduced=35'])),
         ]
         self.assertEqual(expected_symbols, version.symbols)
 
@@ -476,7 +528,7 @@
     def test_parse_symbol(self) -> None:
         input_file = io.StringIO(textwrap.dedent("""\
             foo;
-            bar; # baz qux
+            bar; # llndk apex
         """))
         parser = symbolfile.SymbolFileParser(input_file, {}, self.filter)
 
@@ -488,7 +540,7 @@
         parser.next_line()
         symbol = parser.parse_symbol()
         self.assertEqual('bar', symbol.name)
-        self.assertEqual(Tags.from_strs(['baz', 'qux']), symbol.tags)
+        self.assertEqual(Tags.from_strs(['llndk', 'apex']), symbol.tags)
 
     def test_wildcard_symbol_global(self) -> None:
         input_file = io.StringIO(textwrap.dedent("""\
@@ -537,13 +589,13 @@
                     hidden1;
                 global:
                     foo;
-                    bar; # baz
+                    bar; # llndk
             };
 
-            VERSION_2 { # wasd
+            VERSION_2 { # weak
                 # Implicit global scope.
                     woodly;
-                    doodly; # asdf
+                    doodly; # llndk
                 local:
                     qwerty;
             } VERSION_1;
@@ -554,12 +606,12 @@
         expected = [
             symbolfile.Version('VERSION_1', None, Tags(), [
                 Symbol('foo', Tags()),
-                Symbol('bar', Tags.from_strs(['baz'])),
+                Symbol('bar', Tags.from_strs(['llndk'])),
             ]),
             symbolfile.Version(
-                'VERSION_2', 'VERSION_1', Tags.from_strs(['wasd']), [
+                'VERSION_2', 'VERSION_1', Tags.from_strs(['weak']), [
                     Symbol('woodly', Tags()),
-                    Symbol('doodly', Tags.from_strs(['asdf'])),
+                    Symbol('doodly', Tags.from_strs(['llndk'])),
                 ]),
         ]
 
@@ -591,6 +643,19 @@
         ]
         self.assertEqual(expected_symbols, version.symbols)
 
+    def test_parse_llndk_version_is_missing(self) -> None:
+        input_file = io.StringIO(textwrap.dedent("""\
+            VERSION_1 { # introduced=35
+                foo;
+                bar; # llndk
+            };
+        """))
+        f = copy(self.filter)
+        f.llndk = True
+        parser = symbolfile.SymbolFileParser(input_file, {}, f)
+        with self.assertRaises(symbolfile.ParseError):
+            parser.parse()
+
 
 def main() -> None:
     suite = unittest.TestLoader().loadTestsFromName(__name__)
diff --git a/cc/sysprop.go b/cc/sysprop.go
deleted file mode 100644
index 7ddd476..0000000
--- a/cc/sysprop.go
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (C) 2019 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cc
-
-import (
-	"android/soong/android"
-	"android/soong/bazel"
-)
-
-// TODO(b/240463568): Additional properties will be added for API validation
-type bazelSyspropLibraryAttributes struct {
-	Srcs bazel.LabelListAttribute
-	Tags bazel.StringListAttribute
-}
-
-type bazelCcSyspropLibraryAttributes struct {
-	Dep             bazel.LabelAttribute
-	Min_sdk_version *string
-	Tags            bazel.StringListAttribute
-}
-
-type SyspropLibraryLabels struct {
-	SyspropLibraryLabel string
-	SharedLibraryLabel  string
-	StaticLibraryLabel  string
-}
-
-func Bp2buildSysprop(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, srcs bazel.LabelListAttribute, minSdkVersion *string) {
-	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), ctx.Module())
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "sysprop_library",
-			Bzl_load_location: "//build/bazel/rules/sysprop:sysprop_library.bzl",
-		},
-		android.CommonAttributes{Name: labels.SyspropLibraryLabel},
-		&bazelSyspropLibraryAttributes{
-			Srcs: srcs,
-			Tags: apexAvailableTags,
-		},
-	)
-
-	attrs := &bazelCcSyspropLibraryAttributes{
-		Dep:             *bazel.MakeLabelAttribute(":" + labels.SyspropLibraryLabel),
-		Min_sdk_version: minSdkVersion,
-		Tags:            apexAvailableTags,
-	}
-
-	if labels.SharedLibraryLabel != "" {
-		ctx.CreateBazelTargetModule(
-			bazel.BazelTargetModuleProperties{
-				Rule_class:        "cc_sysprop_library_shared",
-				Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl",
-			},
-			android.CommonAttributes{Name: labels.SharedLibraryLabel},
-			attrs)
-	}
-
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "cc_sysprop_library_static",
-			Bzl_load_location: "//build/bazel/rules/cc:cc_sysprop_library.bzl",
-		},
-		android.CommonAttributes{Name: labels.StaticLibraryLabel},
-		attrs)
-}
diff --git a/cc/test.go b/cc/test.go
index 0be2301..3a1a3af 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -22,8 +22,6 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
-	"android/soong/bazel/cquery"
 	"android/soong/tradefed"
 )
 
@@ -139,8 +137,7 @@
 // specific functionality on a device. The executable binary gets an implicit
 // static_libs dependency on libgtests unless the gtest flag is set to false.
 func TestFactory() android.Module {
-	module := NewTest(android.HostAndDeviceSupported, true)
-	module.bazelHandler = &ccTestBazelHandler{module: module}
+	module := NewTest(android.HostAndDeviceSupported)
 	return module.Init()
 }
 
@@ -158,12 +155,13 @@
 // binary.
 func BenchmarkFactory() android.Module {
 	module := NewBenchmark(android.HostAndDeviceSupported)
+	module.testModule = true
 	return module.Init()
 }
 
 // cc_test_host compiles a test host binary.
 func TestHostFactory() android.Module {
-	module := NewTest(android.HostSupported, true)
+	module := NewTest(android.HostSupported)
 	return module.Init()
 }
 
@@ -323,6 +321,13 @@
 	return []interface{}{&test.InstallerProperties}
 }
 
+func (test *testDecorator) moduleInfoJSON(ctx android.ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+	if android.PrefixInList(moduleInfoJSON.CompatibilitySuites, "mts-") &&
+		!android.InList("mts", moduleInfoJSON.CompatibilitySuites) {
+		moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "mts")
+	}
+}
+
 func NewTestInstaller() *baseInstaller {
 	return NewBaseInstaller("nativetest", "nativetest64", InstallInData)
 }
@@ -357,6 +362,38 @@
 	return flags
 }
 
+func (test *testBinary) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+	if ctx.Host() && Bool(test.Properties.Test_options.Unit_test) {
+		moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests")
+	}
+	moduleInfoJSON.TestOptionsTags = append(moduleInfoJSON.TestOptionsTags, test.Properties.Test_options.Tags...)
+	moduleInfoJSON.TestMainlineModules = append(moduleInfoJSON.TestMainlineModules, test.Properties.Test_mainline_modules...)
+	if test.testConfig != nil {
+		if _, ok := test.testConfig.(android.WritablePath); ok {
+			moduleInfoJSON.AutoTestConfig = []string{"true"}
+		}
+		moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, test.testConfig.String())
+	}
+	moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, test.extraTestConfigs.Strings()...)
+
+	if Bool(test.Properties.Test_per_src) {
+		moduleInfoJSON.SubName = "_" + String(test.binaryDecorator.Properties.Stem)
+	}
+
+	moduleInfoJSON.DataDependencies = append(moduleInfoJSON.DataDependencies, test.Properties.Data_bins...)
+
+	if len(test.InstallerProperties.Test_suites) > 0 {
+		moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, test.InstallerProperties.Test_suites...)
+	} else {
+		moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
+	}
+
+	test.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+	test.testDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+	moduleInfoJSON.Class = []string{"NATIVE_TESTS"}
+
+}
+
 func (test *testBinary) installerProps() []interface{} {
 	return append(test.baseInstaller.installerProps(), test.testDecorator.installerProps()...)
 }
@@ -393,9 +430,8 @@
 		}
 	})
 
-	useVendor := ctx.inVendor() || ctx.useVndk()
-	testInstallBase := getTestInstallBase(useVendor)
-	configs := getTradefedConfigOptions(ctx, &test.Properties, test.isolated(ctx))
+	testInstallBase := getTestInstallBase(ctx.InVendorOrProduct())
+	configs := getTradefedConfigOptions(ctx, &test.Properties, test.isolated(ctx), ctx.Device())
 
 	test.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
 		TestConfigProp:         test.Properties.Test_config,
@@ -423,6 +459,8 @@
 	if ctx.Host() && test.gtest() && test.Properties.Test_options.Unit_test == nil {
 		test.Properties.Test_options.Unit_test = proptools.BoolPtr(true)
 	}
+
+	test.binaryDecorator.baseInstaller.installTestData(ctx, test.data)
 	test.binaryDecorator.baseInstaller.install(ctx, file)
 }
 
@@ -435,22 +473,24 @@
 	return testInstallBase
 }
 
-func getTradefedConfigOptions(ctx android.EarlyModuleContext, properties *TestBinaryProperties, isolated bool) []tradefed.Config {
+func getTradefedConfigOptions(ctx android.EarlyModuleContext, properties *TestBinaryProperties, isolated bool, device bool) []tradefed.Config {
 	var configs []tradefed.Config
 
 	for _, module := range properties.Test_mainline_modules {
 		configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: "mainline-param", Value: module})
 	}
-	if Bool(properties.Require_root) {
-		configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil})
-	} else {
-		var options []tradefed.Option
-		options = append(options, tradefed.Option{Name: "force-root", Value: "false"})
-		configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options})
-	}
-	if Bool(properties.Disable_framework) {
-		var options []tradefed.Option
-		configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.StopServicesSetup", options})
+	if device {
+		if Bool(properties.Require_root) {
+			configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil})
+		} else {
+			var options []tradefed.Option
+			options = append(options, tradefed.Option{Name: "force-root", Value: "false"})
+			configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options})
+		}
+		if Bool(properties.Disable_framework) {
+			var options []tradefed.Option
+			configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.StopServicesSetup", options})
+		}
 	}
 	if isolated {
 		configs = append(configs, tradefed.Option{Name: "not-shardable", Value: "true"})
@@ -483,10 +523,10 @@
 	return configs
 }
 
-func NewTest(hod android.HostOrDeviceSupported, bazelable bool) *Module {
-	module, binary := newBinary(hod, bazelable)
-	module.bazelable = bazelable
+func NewTest(hod android.HostOrDeviceSupported) *Module {
+	module, binary := newBinary(hod)
 	module.multilib = android.MultilibBoth
+	module.testModule = true
 	binary.baseInstaller = NewTestInstaller()
 
 	test := &testBinary{
@@ -530,6 +570,15 @@
 	return flags
 }
 
+func (test *testLibrary) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+	if len(test.InstallerProperties.Test_suites) > 0 {
+		moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, test.InstallerProperties.Test_suites...)
+	}
+
+	test.libraryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+	test.testDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+}
+
 func (test *testLibrary) installerProps() []interface{} {
 	return append(test.baseInstaller.installerProps(), test.testDecorator.installerProps()...)
 }
@@ -546,7 +595,6 @@
 	}
 	module.linker = test
 	module.installer = test
-	module.bazelable = true
 	return module
 }
 
@@ -580,7 +628,7 @@
 type benchmarkDecorator struct {
 	*binaryDecorator
 	Properties BenchmarkProperties
-	data       android.Paths
+	data       []android.DataPath
 	testConfig android.Path
 }
 
@@ -601,7 +649,9 @@
 }
 
 func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Path) {
-	benchmark.data = android.PathsForModuleSrc(ctx, benchmark.Properties.Data)
+	for _, d := range android.PathsForModuleSrc(ctx, benchmark.Properties.Data) {
+		benchmark.data = append(benchmark.data, android.DataPath{SrcPath: d})
+	}
 
 	var configs []tradefed.Config
 	if Bool(benchmark.Properties.Require_root) {
@@ -619,11 +669,35 @@
 
 	benchmark.binaryDecorator.baseInstaller.dir = filepath.Join("benchmarktest", ctx.ModuleName())
 	benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("benchmarktest64", ctx.ModuleName())
+	benchmark.binaryDecorator.baseInstaller.installTestData(ctx, benchmark.data)
 	benchmark.binaryDecorator.baseInstaller.install(ctx, file)
 }
 
+func (benchmark *benchmarkDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+	benchmark.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+
+	moduleInfoJSON.Class = []string{"NATIVE_TESTS"}
+	if len(benchmark.Properties.Test_suites) > 0 {
+		moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, benchmark.Properties.Test_suites...)
+	} else {
+		moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
+	}
+
+	if android.PrefixInList(moduleInfoJSON.CompatibilitySuites, "mts-") &&
+		!android.InList("mts", moduleInfoJSON.CompatibilitySuites) {
+		moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "mts")
+	}
+
+	if benchmark.testConfig != nil {
+		if _, ok := benchmark.testConfig.(android.WritablePath); ok {
+			moduleInfoJSON.AutoTestConfig = []string{"true"}
+		}
+		moduleInfoJSON.TestConfig = []string{benchmark.testConfig.String()}
+	}
+}
+
 func NewBenchmark(hod android.HostOrDeviceSupported) *Module {
-	module, binary := newBinary(hod, false)
+	module, binary := newBinary(hod)
 	module.multilib = android.MultilibBoth
 	binary.baseInstaller = NewBaseInstaller("benchmarktest", "benchmarktest64", InstallInData)
 
@@ -634,155 +708,3 @@
 	module.installer = benchmark
 	return module
 }
-
-type ccTestBazelHandler struct {
-	module *Module
-}
-
-var _ BazelHandler = (*ccTestBazelHandler)(nil)
-
-// The top level target named $label is a test_suite target,
-// not the internal cc_test executable target.
-//
-// This is to ensure `b test //$label` runs the test_suite target directly,
-// which depends on tradefed_test targets, instead of the internal cc_test
-// target, which doesn't have tradefed integrations.
-//
-// However, for cquery, we want the internal cc_test executable target, which
-// has the suffix "__tf_internal".
-func mixedBuildsTestLabel(label string) string {
-	return label + "__tf_internal"
-}
-
-func (handler *ccTestBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(mixedBuildsTestLabel(label), cquery.GetCcUnstrippedInfo, android.GetConfigKey(ctx))
-}
-
-func (handler *ccTestBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	info, err := bazelCtx.GetCcUnstrippedInfo(mixedBuildsTestLabel(label), android.GetConfigKey(ctx))
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-		return
-	}
-
-	var outputFilePath android.Path = android.PathForBazelOut(ctx, info.OutputFile)
-	if len(info.TidyFiles) > 0 {
-		handler.module.tidyFiles = android.PathsForBazelOut(ctx, info.TidyFiles)
-		outputFilePath = android.AttachValidationActions(ctx, outputFilePath, handler.module.tidyFiles)
-	}
-	handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
-	handler.module.linker.(*testBinary).unstrippedOutputFile = android.PathForBazelOut(ctx, info.UnstrippedOutput)
-
-	handler.module.setAndroidMkVariablesFromCquery(info.CcAndroidMkInfo)
-}
-
-// binaryAttributes contains Bazel attributes corresponding to a cc test
-type testBinaryAttributes struct {
-	binaryAttributes
-
-	Gtest *bool
-
-	tidyAttributes
-	tradefed.TestConfigAttributes
-}
-
-// testBinaryBp2build is the bp2build converter for cc_test modules. A cc_test's
-// dependency graph and compilation/linking steps are functionally similar to a
-// cc_binary, but has additional dependencies on test deps like gtest, and
-// produces additional runfiles like XML plans for Tradefed orchestration
-//
-// TODO(b/244432609): handle `isolated` property.
-// TODO(b/244432134): handle custom runpaths for tests that assume runfile layouts not
-// default to bazel. (see linkerInit function)
-func testBinaryBp2build(ctx android.TopDownMutatorContext, m *Module) {
-	var testBinaryAttrs testBinaryAttributes
-	testBinaryAttrs.binaryAttributes = binaryBp2buildAttrs(ctx, m)
-
-	var data bazel.LabelListAttribute
-	var tags bazel.StringListAttribute
-
-	testBinaryProps := m.GetArchVariantProperties(ctx, &TestBinaryProperties{})
-	for axis, configToProps := range testBinaryProps {
-		for config, props := range configToProps {
-			if p, ok := props.(*TestBinaryProperties); ok {
-				// Combine data, data_bins and data_libs into a single 'data' attribute.
-				var combinedData bazel.LabelList
-				combinedData.Append(android.BazelLabelForModuleSrc(ctx, p.Data))
-				combinedData.Append(android.BazelLabelForModuleDeps(ctx, p.Data_bins))
-				combinedData.Append(android.BazelLabelForModuleDeps(ctx, p.Data_libs))
-				data.SetSelectValue(axis, config, combinedData)
-				tags.SetSelectValue(axis, config, p.Test_options.Tags)
-			}
-		}
-	}
-
-	m.convertTidyAttributes(ctx, &testBinaryAttrs.tidyAttributes)
-
-	testBinary := m.linker.(*testBinary)
-	gtest := testBinary.gtest()
-	gtestIsolated := testBinary.isolated(ctx)
-	// Use the underling bool pointer for Gtest in attrs
-	// This ensures that if this property is not set in Android.bp file, it will not be set in BUILD file either
-	// cc_test macro will default gtest to True
-	testBinaryAttrs.Gtest = testBinary.LinkerProperties.Gtest
-
-	addImplicitGtestDeps(ctx, &testBinaryAttrs, gtest, gtestIsolated)
-
-	for _, testProps := range m.GetProperties() {
-		if p, ok := testProps.(*TestBinaryProperties); ok {
-			useVendor := false // TODO Bug: 262914724
-			testInstallBase := getTestInstallBase(useVendor)
-			testConfigAttributes := tradefed.GetTestConfigAttributes(
-				ctx,
-				p.Test_config,
-				p.Test_options.Extra_test_configs,
-				p.Auto_gen_config,
-				p.Test_options.Test_suite_tag,
-				p.Test_config_template,
-				getTradefedConfigOptions(ctx, p, gtestIsolated),
-				&testInstallBase,
-			)
-			testBinaryAttrs.TestConfigAttributes = testConfigAttributes
-		}
-	}
-
-	// TODO (b/262914724): convert to tradefed_cc_test and tradefed_cc_test_host
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "cc_test",
-			Bzl_load_location: "//build/bazel/rules/cc:cc_test.bzl",
-		},
-		android.CommonAttributes{
-			Name: m.Name(),
-			Data: data,
-			Tags: tags,
-		},
-		&testBinaryAttrs)
-}
-
-// cc_test that builds using gtest needs some additional deps
-// addImplicitGtestDeps makes these deps explicit in the generated BUILD files
-func addImplicitGtestDeps(ctx android.BazelConversionPathContext, attrs *testBinaryAttributes, gtest, gtestIsolated bool) {
-	addDepsAndDedupe := func(lla *bazel.LabelListAttribute, modules []string) {
-		moduleLabels := android.BazelLabelForModuleDeps(ctx, modules)
-		lla.Value.Append(moduleLabels)
-		// Dedupe
-		lla.Value = bazel.FirstUniqueBazelLabelList(lla.Value)
-	}
-	// this must be kept in sync with Soong's implementation in:
-	// https://cs.android.com/android/_/android/platform/build/soong/+/460fb2d6d546b5ab493a7e5479998c4933a80f73:cc/test.go;l=300-313;drc=ec7314336a2b35ea30ce5438b83949c28e3ac429;bpv=1;bpt=0
-	if gtest {
-		// TODO - b/244433197: Handle canUseSdk
-		if gtestIsolated {
-			addDepsAndDedupe(&attrs.Deps, []string{"libgtest_isolated_main"})
-			addDepsAndDedupe(&attrs.Dynamic_deps, []string{"liblog"})
-		} else {
-			addDepsAndDedupe(&attrs.Deps, []string{
-				"libgtest_main",
-				"libgtest",
-			})
-		}
-	}
-}
diff --git a/cc/testing.go b/cc/testing.go
index d1632aa..20c435a 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -15,14 +15,12 @@
 package cc
 
 import (
-	"encoding/json"
 	"path/filepath"
 	"testing"
 
 	"android/soong/android"
 	"android/soong/genrule"
 	"android/soong/multitree"
-	"android/soong/snapshot"
 )
 
 func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
@@ -35,13 +33,14 @@
 
 	multitree.RegisterApiImportsModule(ctx)
 
+	ctx.RegisterModuleType("prebuilt_build_tool", android.NewPrebuiltBuildTool)
 	ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory)
 	ctx.RegisterModuleType("cc_object", ObjectFactory)
 	ctx.RegisterModuleType("cc_genrule", GenRuleFactory)
 	ctx.RegisterModuleType("ndk_prebuilt_shared_stl", NdkPrebuiltSharedStlFactory)
 	ctx.RegisterModuleType("ndk_prebuilt_static_stl", NdkPrebuiltStaticStlFactory)
 	ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
-	ctx.RegisterModuleType("ndk_headers", ndkHeadersFactory)
+	ctx.RegisterModuleType("ndk_headers", NdkHeadersFactory)
 }
 
 func GatherRequiredDepsForTest(oses ...android.OsType) string {
@@ -76,6 +75,7 @@
 			no_libcrt: true,
 			sdk_version: "minimum",
 			nocrt: true,
+			no_crt_pad_segment: true,
 			system_shared_libs: [],
 			stl: "none",
 			check_elf_files: false,
@@ -303,10 +303,7 @@
 			recovery_available: true,
 			host_supported: true,
 			min_sdk_version: "29",
-			vndk: {
-				enabled: true,
-				support_system_process: true,
-			},
+			double_loadable: true,
 			apex_available: [
 				"//apex_available:platform",
 				"//apex_available:anyapex",
@@ -384,6 +381,11 @@
 		}
 
 		cc_object {
+			name: "crt_pad_segment",
+			defaults: ["crt_defaults"],
+		}
+
+		cc_object {
 			name: "crtbrand",
 			defaults: ["crt_defaults"],
 			srcs: ["crtbrand.c"],
@@ -558,7 +560,7 @@
 	// This includes files that are needed by all, or at least most, instances of a cc module type.
 	android.MockFS{
 		// Needed for ndk_prebuilt_(shared|static)_stl.
-		"prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs": nil,
+		"defaults/cc/common/current/sources/cxx-stl/llvm-libc++/libs": nil,
 	}.AddToFixture(),
 )
 
@@ -570,6 +572,7 @@
 	android.MockFS{
 		"defaults/cc/common/libc.map.txt":      nil,
 		"defaults/cc/common/libdl.map.txt":     nil,
+		"defaults/cc/common/libft2.map.txt":    nil,
 		"defaults/cc/common/libm.map.txt":      nil,
 		"defaults/cc/common/ndk_libc++_shared": nil,
 		"defaults/cc/common/crtbegin_so.c":     nil,
@@ -577,6 +580,7 @@
 		"defaults/cc/common/crtend_so.c":       nil,
 		"defaults/cc/common/crtend.c":          nil,
 		"defaults/cc/common/crtbrand.c":        nil,
+		"external/compiler-rt/lib/cfi/cfi_blocklist.txt":   nil,
 
 		"defaults/cc/common/libclang_rt.ubsan_minimal.android_arm64.a": nil,
 		"defaults/cc/common/libclang_rt.ubsan_minimal.android_arm.a":   nil,
@@ -616,19 +620,6 @@
 	android.FixtureOverrideTextFile(linuxBionicDefaultsPath, withLinuxBionic()),
 )
 
-// This adds some additional modules and singletons which might negatively impact the performance
-// of tests so they are not included in the PrepareForIntegrationTestWithCc.
-var PrepareForTestWithCcIncludeVndk = android.GroupFixturePreparers(
-	PrepareForIntegrationTestWithCc,
-	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
-		snapshot.VendorSnapshotImageSingleton.Init(ctx)
-		snapshot.RecoverySnapshotImageSingleton.Init(ctx)
-		RegisterVendorSnapshotModules(ctx)
-		RegisterRecoverySnapshotModules(ctx)
-		ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
-	}),
-)
-
 // PrepareForTestWithHostMusl sets the host configuration to musl libc instead of glibc.  It also disables the test
 // on mac, which doesn't support musl libc, and adds musl modules.
 var PrepareForTestWithHostMusl = android.GroupFixturePreparers(
@@ -671,7 +662,7 @@
 // PrepareForTestWithFdoProfile registers module types to test with fdo_profile
 var PrepareForTestWithFdoProfile = android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("soong_namespace", android.NamespaceFactory)
-	ctx.RegisterModuleType("fdo_profile", fdoProfileFactory)
+	ctx.RegisterModuleType("fdo_profile", FdoProfileFactory)
 })
 
 // TestConfig is the legacy way of creating a test Config for testing cc modules.
@@ -710,11 +701,6 @@
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
 
-	snapshot.VendorSnapshotImageSingleton.Init(ctx)
-	snapshot.RecoverySnapshotImageSingleton.Init(ctx)
-	RegisterVendorSnapshotModules(ctx)
-	RegisterRecoverySnapshotModules(ctx)
-	ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
 	RegisterVndkLibraryTxtTypes(ctx)
 
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
@@ -768,14 +754,6 @@
 	checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true, true)
 }
 
-func AssertExcludeFromVendorSnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool, variant string) {
-	t.Helper()
-	m := ctx.ModuleForTests(name, variant).Module().(LinkableInterface)
-	if m.ExcludeFromVendorSnapshot() != expected {
-		t.Errorf("expected %q ExcludeFromVendorSnapshot to be %t", m.String(), expected)
-	}
-}
-
 func GetOutputPaths(ctx *android.TestContext, variant string, moduleNames []string) (paths android.Paths) {
 	for _, moduleName := range moduleNames {
 		module := ctx.ModuleForTests(moduleName, variant).Module().(*Module)
@@ -784,30 +762,3 @@
 	}
 	return paths
 }
-
-func AssertExcludeFromRecoverySnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool, variant string) {
-	t.Helper()
-	m := ctx.ModuleForTests(name, variant).Module().(LinkableInterface)
-	if m.ExcludeFromRecoverySnapshot() != expected {
-		t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", m.String(), expected)
-	}
-}
-
-func checkOverrides(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, jsonPath string, expected []string) {
-	t.Helper()
-	out := singleton.MaybeOutput(jsonPath)
-	content := android.ContentFromFileRuleForTests(t, out)
-
-	var flags snapshotJsonFlags
-	if err := json.Unmarshal([]byte(content), &flags); err != nil {
-		t.Errorf("Error while unmarshalling json %q: %s", jsonPath, err.Error())
-		return
-	}
-
-	for _, moduleName := range expected {
-		if !android.InList(moduleName, flags.Overrides) {
-			t.Errorf("expected %q to be in %q: %q", moduleName, flags.Overrides, content)
-			return
-		}
-	}
-}
diff --git a/cc/tidy.go b/cc/tidy.go
index 7b123cb..76ac7d5 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -68,7 +68,6 @@
 // Then, that old style usage will be obsolete and an error.
 const NoWarningsAsErrorsInTidyFlags = true
 
-// keep this up to date with https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/cc/clang_tidy.bzl
 func (tidy *tidyFeature) flags(ctx ModuleContext, flags Flags) Flags {
 	CheckBadTidyFlags(ctx, "tidy_flags", tidy.Properties.Tidy_flags)
 	CheckBadTidyChecks(ctx, "tidy_checks", tidy.Properties.Tidy_checks)
diff --git a/cc/tidy_test.go b/cc/tidy_test.go
index 7036ecb..9481778 100644
--- a/cc/tidy_test.go
+++ b/cc/tidy_test.go
@@ -244,3 +244,30 @@
 		})
 	}
 }
+
+func TestWithGeneratedCode(t *testing.T) {
+	bp := `
+		cc_library_shared {
+			name: "libfoo",
+			srcs: ["foo_1.y", "foo_2.yy", "foo_3.l", "foo_4.ll", "foo_5.proto",
+			       "foo_6.aidl", "foo_7.rscript", "foo_8.fs", "foo_9.sysprop",
+			       "foo_src.cpp"],
+			tidy: true,
+		}`
+	variant := "android_arm64_armv8-a_shared"
+
+	testEnv := map[string]string{}
+	testEnv["ALLOW_LOCAL_TIDY_TRUE"] = "1"
+
+	ctx := android.GroupFixturePreparers(prepareForCcTest, android.FixtureMergeEnv(testEnv)).RunTestWithBp(t, bp)
+
+	t.Run("tidy should be only run for source code, not for generated code", func(t *testing.T) {
+		depFiles := ctx.ModuleForTests("libfoo", variant).Rule("ld").Validations.Strings()
+
+		tidyFileForCpp := "out/soong/.intermediates/libfoo/" + variant + "/obj/foo_src.tidy"
+
+		android.AssertArrayString(t,
+			"only one .tidy file for source code should exist for libfoo",
+			[]string{tidyFileForCpp}, depFiles)
+	})
+}
diff --git a/cc/util.go b/cc/util.go
index c93646b..3ede8ff 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -19,7 +19,6 @@
 	"strings"
 
 	"android/soong/android"
-	"android/soong/snapshot"
 )
 
 // Efficiently converts a list of include directories to a single string
@@ -56,18 +55,19 @@
 		localCppFlags:        strings.Join(in.Local.CppFlags, " "),
 		localLdFlags:         strings.Join(in.Local.LdFlags, " "),
 
-		aidlFlags:     strings.Join(in.aidlFlags, " "),
-		rsFlags:       strings.Join(in.rsFlags, " "),
-		libFlags:      strings.Join(in.libFlags, " "),
-		extraLibFlags: strings.Join(in.extraLibFlags, " "),
-		tidyFlags:     strings.Join(in.TidyFlags, " "),
-		sAbiFlags:     strings.Join(in.SAbiFlags, " "),
-		toolchain:     in.Toolchain,
-		gcovCoverage:  in.GcovCoverage,
-		tidy:          in.Tidy,
-		needTidyFiles: in.NeedTidyFiles,
-		sAbiDump:      in.SAbiDump,
-		emitXrefs:     in.EmitXrefs,
+		noOverrideFlags: strings.Join(in.NoOverrideFlags, " "),
+		aidlFlags:       strings.Join(in.aidlFlags, " "),
+		rsFlags:         strings.Join(in.rsFlags, " "),
+		libFlags:        strings.Join(in.libFlags, " "),
+		extraLibFlags:   strings.Join(in.extraLibFlags, " "),
+		tidyFlags:       strings.Join(in.TidyFlags, " "),
+		sAbiFlags:       strings.Join(in.SAbiFlags, " "),
+		toolchain:       in.Toolchain,
+		gcovCoverage:    in.GcovCoverage,
+		tidy:            in.Tidy,
+		needTidyFiles:   in.NeedTidyFiles,
+		sAbiDump:        in.SAbiDump,
+		emitXrefs:       in.EmitXrefs,
 
 		systemIncludeFlags: strings.Join(in.SystemIncludeFlags, " "),
 
@@ -100,6 +100,12 @@
 		"ln -sf " + target + " " + filepath.Join(dir, linkName)
 }
 
+func WriteStringToFileRule(ctx android.SingletonContext, content, out string) android.OutputPath {
+	outPath := android.PathForOutput(ctx, out)
+	android.WriteFileRule(ctx, outPath, content)
+	return outPath
+}
+
 // Dump a map to a list file as:
 //
 // {key1} {value1}
@@ -115,5 +121,5 @@
 		txtBuilder.WriteString(" ")
 		txtBuilder.WriteString(m[k])
 	}
-	return snapshot.WriteStringToFileRule(ctx, txtBuilder.String(), path)
+	return WriteStringToFileRule(ctx, txtBuilder.String(), path)
 }
diff --git a/cc/vendor_public_library_test.go b/cc/vendor_public_library_test.go
index 769be09..7385f2b 100644
--- a/cc/vendor_public_library_test.go
+++ b/cc/vendor_public_library_test.go
@@ -65,8 +65,8 @@
 	`)
 
 	coreVariant := "android_arm64_armv8-a_shared"
-	vendorVariant := "android_vendor.29_arm64_armv8-a_shared"
-	productVariant := "android_product.29_arm64_armv8-a_shared"
+	vendorVariant := "android_vendor_arm64_armv8-a_shared"
+	productVariant := "android_product_arm64_armv8-a_shared"
 
 	// test if header search paths are correctly added
 	// _static variant is used since _shared reuses *.o from the static variant
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
deleted file mode 100644
index 9ea337b..0000000
--- a/cc/vendor_snapshot.go
+++ /dev/null
@@ -1,454 +0,0 @@
-// Copyright 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package cc
-
-import (
-	"encoding/json"
-	"path/filepath"
-	"strings"
-
-	"android/soong/android"
-	"android/soong/snapshot"
-)
-
-// This file defines how to capture cc modules into snapshot package.
-
-// Checks if the target image would contain VNDK
-func includeVndk(image snapshot.SnapshotImage) bool {
-	if image.ImageName() == snapshot.VendorSnapshotImageName {
-		return true
-	}
-
-	return false
-}
-
-// Check if the module is VNDK private
-func isPrivate(image snapshot.SnapshotImage, m LinkableInterface) bool {
-	if image.ImageName() == snapshot.VendorSnapshotImageName && m.IsVndkPrivate() {
-		return true
-	}
-
-	return false
-}
-
-// Checks if target image supports VNDK Ext
-func supportsVndkExt(image snapshot.SnapshotImage) bool {
-	if image.ImageName() == snapshot.VendorSnapshotImageName {
-		return true
-	}
-
-	return false
-}
-
-// Determines if the module is a candidate for snapshot.
-func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietaryPath bool, apexInfo android.ApexInfo, image snapshot.SnapshotImage) bool {
-	if !m.Enabled() || m.HiddenFromMake() {
-		return false
-	}
-	// When android/prebuilt.go selects between source and prebuilt, it sets
-	// HideFromMake on the other one to avoid duplicate install rules in make.
-	if m.IsHideFromMake() {
-		return false
-	}
-	// skip proprietary modules, but (for the vendor snapshot only)
-	// include all VNDK (static)
-	if inProprietaryPath && (!includeVndk(image) || !m.IsVndk()) {
-		return false
-	}
-	// If the module would be included based on its path, check to see if
-	// the module is marked to be excluded. If so, skip it.
-	if image.ExcludeFromSnapshot(m) {
-		return false
-	}
-	if m.Target().Os.Class != android.Device {
-		return false
-	}
-	if m.Target().NativeBridge == android.NativeBridgeEnabled {
-		return false
-	}
-	// the module must be installed in target image
-	if !apexInfo.IsForPlatform() || m.IsSnapshotPrebuilt() || !image.InImage(m)() {
-		return false
-	}
-	// skip kernel_headers which always depend on vendor
-	if m.KernelHeadersDecorator() {
-		return false
-	}
-
-	if m.IsLlndk() {
-		return false
-	}
-
-	// Libraries
-	if sanitizable, ok := m.(PlatformSanitizeable); ok && sanitizable.IsSnapshotLibrary() {
-		if sanitizable.SanitizePropDefined() {
-			// scs exports both sanitized and unsanitized variants for static and header
-			// Always use unsanitized variant of it.
-			if !sanitizable.Shared() && sanitizable.IsSanitizerEnabled(scs) {
-				return false
-			}
-			// cfi and hwasan also export both variants. But for static, we capture both.
-			// This is because cfi static libraries can't be linked from non-cfi modules,
-			// and vice versa.
-			// hwasan is captured as well to support hwasan build.
-			if !sanitizable.Static() &&
-				!sanitizable.Shared() &&
-				(sanitizable.IsSanitizerEnabled(cfi) || sanitizable.IsSanitizerEnabled(Hwasan)) {
-				return false
-			}
-		}
-		if sanitizable.Static() || sanitizable.Rlib() {
-			return sanitizable.OutputFile().Valid() && !isPrivate(image, m)
-		}
-		if sanitizable.Shared() || sanitizable.Dylib() {
-			if !sanitizable.OutputFile().Valid() {
-				return false
-			}
-			if includeVndk(image) {
-				if !sanitizable.IsVndk() {
-					return true
-				}
-				return sanitizable.IsVndkExt()
-			}
-		}
-		return true
-	}
-
-	// Binaries and Objects
-	if m.Binary() || m.Object() {
-		return m.OutputFile().Valid()
-	}
-
-	return false
-}
-
-// Extend the snapshot.SnapshotJsonFlags to include cc specific fields.
-type snapshotJsonFlags struct {
-	snapshot.SnapshotJsonFlags
-	// library flags
-	ExportedDirs       []string `json:",omitempty"`
-	ExportedSystemDirs []string `json:",omitempty"`
-	ExportedFlags      []string `json:",omitempty"`
-	Sanitize           string   `json:",omitempty"`
-	SanitizeMinimalDep bool     `json:",omitempty"`
-	SanitizeUbsanDep   bool     `json:",omitempty"`
-
-	// binary flags
-	Symlinks         []string `json:",omitempty"`
-	StaticExecutable bool     `json:",omitempty"`
-	InstallInRoot    bool     `json:",omitempty"`
-
-	// dependencies
-	SharedLibs  []string `json:",omitempty"`
-	StaticLibs  []string `json:",omitempty"`
-	RuntimeLibs []string `json:",omitempty"`
-	Dylibs      []string `json:",omitempty"`
-	Rlibs       []string `json:",omitempty"`
-
-	// extra config files
-	InitRc         []string `json:",omitempty"`
-	VintfFragments []string `json:",omitempty"`
-	MinSdkVersion  string   `json:",omitempty"`
-}
-
-var ccSnapshotAction snapshot.GenerateSnapshotAction = func(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) snapshot.SnapshotPaths {
-	/*
-		Vendor snapshot zipped artifacts directory structure for cc modules:
-		{SNAPSHOT_ARCH}/
-			arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
-				shared/
-					(.so shared libraries)
-				static/
-					(.a static libraries)
-				header/
-					(header only libraries)
-				binary/
-					(executable binaries)
-				object/
-					(.o object files)
-			arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
-				shared/
-					(.so shared libraries)
-				static/
-					(.a static libraries)
-				header/
-					(header only libraries)
-				binary/
-					(executable binaries)
-				object/
-					(.o object files)
-			NOTICE_FILES/
-				(notice files, e.g. libbase.txt)
-			configs/
-				(config files, e.g. init.rc files, vintf_fragments.xml files, etc.)
-			include/
-				(header files of same directory structure with source tree)
-	*/
-
-	var snapshotOutputs android.Paths
-	var snapshotNotices android.Paths
-
-	includeDir := filepath.Join(snapshotArchDir, "include")
-	configsDir := filepath.Join(snapshotArchDir, "configs")
-
-	installedNotices := make(map[string]bool)
-	installedConfigs := make(map[string]bool)
-
-	var headers android.Paths
-
-	copyFile := func(ctx android.SingletonContext, path android.Path, out string, fake bool) android.OutputPath {
-		if fake {
-			// All prebuilt binaries and headers are installed by copyFile function. This makes a fake
-			// snapshot just touch prebuilts and headers, rather than installing real files.
-			return snapshot.WriteStringToFileRule(ctx, "", out)
-		} else {
-			return snapshot.CopyFileRule(pctx, ctx, path, out)
-		}
-	}
-
-	// installSnapshot function copies prebuilt file (.so, .a, or executable) and json flag file.
-	// For executables, init_rc and vintf_fragments files are also copied.
-	installSnapshot := func(m LinkableInterface, fake bool) android.Paths {
-		targetArch := "arch-" + m.Target().Arch.ArchType.String()
-		if m.Target().Arch.ArchVariant != "" {
-			targetArch += "-" + m.Target().Arch.ArchVariant
-		}
-
-		var ret android.Paths
-
-		prop := snapshotJsonFlags{}
-
-		// Common properties among snapshots.
-		prop.InitBaseSnapshotPropsWithName(m, ctx.ModuleName(m))
-		if supportsVndkExt(s.Image) && m.IsVndkExt() {
-			// vndk exts are installed to /vendor/lib(64)?/vndk(-sp)?
-			if m.IsVndkSp() {
-				prop.RelativeInstallPath = "vndk-sp"
-			} else {
-				prop.RelativeInstallPath = "vndk"
-			}
-		} else {
-			prop.RelativeInstallPath = m.RelativeInstallPath()
-		}
-		prop.RuntimeLibs = m.SnapshotRuntimeLibs()
-		prop.Required = m.RequiredModuleNames()
-		if o, ok := m.(overridable); ok {
-			prop.Overrides = o.overriddenModules()
-		}
-		for _, path := range m.InitRc() {
-			prop.InitRc = append(prop.InitRc, filepath.Join("configs", path.Base()))
-		}
-		for _, path := range m.VintfFragments() {
-			prop.VintfFragments = append(prop.VintfFragments, filepath.Join("configs", path.Base()))
-		}
-		if m.IsPrebuilt() {
-			prop.MinSdkVersion = "apex_inherit"
-		} else {
-			prop.MinSdkVersion = m.MinSdkVersion()
-		}
-
-		// install config files. ignores any duplicates.
-		for _, path := range append(m.InitRc(), m.VintfFragments()...) {
-			out := filepath.Join(configsDir, path.Base())
-			if !installedConfigs[out] {
-				installedConfigs[out] = true
-				ret = append(ret, copyFile(ctx, path, out, fake))
-			}
-		}
-
-		var propOut string
-
-		if m.IsSnapshotLibrary() {
-			exporterInfo := ctx.ModuleProvider(m.Module(), FlagExporterInfoProvider).(FlagExporterInfo)
-
-			// library flags
-			prop.ExportedFlags = exporterInfo.Flags
-			for _, dir := range exporterInfo.IncludeDirs {
-				prop.ExportedDirs = append(prop.ExportedDirs, filepath.Join("include", dir.String()))
-			}
-			for _, dir := range exporterInfo.SystemIncludeDirs {
-				prop.ExportedSystemDirs = append(prop.ExportedSystemDirs, filepath.Join("include", dir.String()))
-			}
-
-			// shared libs dependencies aren't meaningful on static or header libs
-			if m.Shared() {
-				prop.SharedLibs = m.SnapshotSharedLibs()
-			}
-
-			// dylibs collect both shared and dylib dependencies.
-			if m.Dylib() {
-				prop.SharedLibs = m.SnapshotSharedLibs()
-				prop.Dylibs = m.SnapshotDylibs()
-			}
-
-			// static and rlib libs dependencies are required to collect the NOTICE files.
-			prop.StaticLibs = m.SnapshotStaticLibs()
-			prop.Rlibs = m.SnapshotRlibs()
-
-			if sanitizable, ok := m.(PlatformSanitizeable); ok {
-				if sanitizable.Static() && sanitizable.SanitizePropDefined() {
-					prop.SanitizeMinimalDep = sanitizable.MinimalRuntimeDep() || sanitizable.MinimalRuntimeNeeded()
-					prop.SanitizeUbsanDep = sanitizable.UbsanRuntimeDep() || sanitizable.UbsanRuntimeNeeded()
-				}
-			}
-
-			var libType string
-			if m.Static() {
-				libType = "static"
-			} else if m.Shared() {
-				libType = "shared"
-			} else if m.Rlib() {
-				libType = "rlib"
-			} else if m.Dylib() {
-				libType = "dylib"
-			} else {
-				libType = "header"
-			}
-
-			var stem string
-
-			// install .a, .rlib, .dylib.so, or .so
-			if libType != "header" {
-				libPath := m.OutputFile().Path()
-				stem = libPath.Base()
-				if sanitizable, ok := m.(PlatformSanitizeable); ok {
-					if (sanitizable.Static() || sanitizable.Rlib()) && sanitizable.SanitizePropDefined() {
-						if sanitizable.IsSanitizerEnabled(cfi) {
-							// both cfi and non-cfi variant for static libraries can exist.
-							// attach .cfi to distinguish between cfi and non-cfi.
-							// e.g. libbase.a -> libbase.cfi.a
-							ext := filepath.Ext(stem)
-							stem = strings.TrimSuffix(stem, ext) + ".cfi" + ext
-							prop.Sanitize = "cfi"
-							prop.ModuleName += ".cfi"
-						} else if sanitizable.IsSanitizerEnabled(Hwasan) {
-							// Same for the hwasan
-							ext := filepath.Ext(stem)
-							stem = strings.TrimSuffix(stem, ext) + ".hwasan" + ext
-							prop.Sanitize = "hwasan"
-							prop.ModuleName += ".hwasan"
-						}
-					}
-				}
-				if m.Rlib() && m.RlibStd() {
-					// rlibs produce both rlib-std and dylib-std variants
-					ext := filepath.Ext(stem)
-					stem = strings.TrimSuffix(stem, ext) + ".rlib-std" + ext
-					prop.ModuleName += ".rlib-std"
-				}
-				snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, m.RelativeInstallPath(), stem)
-				ret = append(ret, copyFile(ctx, libPath, snapshotLibOut, fake))
-			} else {
-				stem = ctx.ModuleName(m)
-			}
-
-			propOut = filepath.Join(snapshotArchDir, targetArch, libType, m.RelativeInstallPath(), stem+".json")
-		} else if m.Binary() {
-			// binary flags
-			prop.Symlinks = m.Symlinks()
-			prop.StaticExecutable = m.StaticExecutable()
-			prop.InstallInRoot = m.InstallInRoot()
-			prop.SharedLibs = m.SnapshotSharedLibs()
-			prop.Dylibs = m.SnapshotDylibs()
-
-			// static and rlib dependencies are required to collect the NOTICE files.
-			prop.StaticLibs = m.SnapshotStaticLibs()
-			prop.Rlibs = m.SnapshotRlibs()
-
-			// install bin
-			binPath := m.OutputFile().Path()
-			snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base())
-			ret = append(ret, copyFile(ctx, binPath, snapshotBinOut, fake))
-			propOut = snapshotBinOut + ".json"
-		} else if m.Object() {
-			// object files aren't installed to the device, so their names can conflict.
-			// Use module name as stem.
-			objPath := m.OutputFile().Path()
-			snapshotObjOut := filepath.Join(snapshotArchDir, targetArch, "object",
-				ctx.ModuleName(m)+filepath.Ext(objPath.Base()))
-			ret = append(ret, copyFile(ctx, objPath, snapshotObjOut, fake))
-			propOut = snapshotObjOut + ".json"
-		} else {
-			ctx.Errorf("unknown module %q in vendor snapshot", m.String())
-			return nil
-		}
-
-		j, err := json.Marshal(prop)
-		if err != nil {
-			ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
-			return nil
-		}
-		ret = append(ret, snapshot.WriteStringToFileRule(ctx, string(j), propOut))
-
-		return ret
-	}
-
-	ctx.VisitAllModules(func(module android.Module) {
-		m, ok := module.(LinkableInterface)
-		if !ok {
-			return
-		}
-
-		moduleDir := ctx.ModuleDir(module)
-		inProprietaryPath := s.Image.IsProprietaryPath(moduleDir, ctx.DeviceConfig())
-		apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
-
-		if s.Image.ExcludeFromSnapshot(m) {
-			if inProprietaryPath {
-				// Error: exclude_from_vendor_snapshot applies
-				// to framework-path modules only.
-				ctx.Errorf("module %q in vendor proprietary path %q may not use \"exclude_from_vendor_snapshot: true\"", m.String(), moduleDir)
-				return
-			}
-		}
-
-		if !isSnapshotAware(ctx.DeviceConfig(), m, inProprietaryPath, apexInfo, s.Image) {
-			return
-		}
-
-		// If we are using directed snapshot and a module is not included in the
-		// list, we will still include the module as if it was a fake module.
-		// The reason is that soong needs all the dependencies to be present, even
-		// if they are not using during the build.
-		installAsFake := s.Fake
-		if s.Image.ExcludeFromDirectedSnapshot(ctx.DeviceConfig(), m.BaseModuleName()) {
-			installAsFake = true
-		}
-
-		// installSnapshot installs prebuilts and json flag files
-		snapshotOutputs = append(snapshotOutputs, installSnapshot(m, installAsFake)...)
-		// just gather headers and notice files here, because they are to be deduplicated
-		if m.IsSnapshotLibrary() {
-			headers = append(headers, m.SnapshotHeaders()...)
-		}
-
-		for _, notice := range m.EffectiveLicenseFiles() {
-			if _, ok := installedNotices[notice.String()]; !ok {
-				installedNotices[notice.String()] = true
-				snapshotNotices = append(snapshotNotices, notice)
-			}
-		}
-	})
-
-	// install all headers after removing duplicates
-	for _, header := range android.FirstUniquePaths(headers) {
-		snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String()), s.Fake))
-	}
-
-	return snapshot.SnapshotPaths{OutputFiles: snapshotOutputs, NoticeFiles: snapshotNotices}
-}
-
-func init() {
-	snapshot.RegisterSnapshotAction(ccSnapshotAction)
-}
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
deleted file mode 100644
index c5431b3..0000000
--- a/cc/vendor_snapshot_test.go
+++ /dev/null
@@ -1,1740 +0,0 @@
-// Copyright 2021 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package cc
-
-import (
-	"android/soong/android"
-	"fmt"
-	"path/filepath"
-	"reflect"
-	"strings"
-	"testing"
-)
-
-func checkJsonContents(t *testing.T, ctx android.TestingSingleton, jsonPath string, key string, value string) {
-	jsonOut := ctx.MaybeOutput(jsonPath)
-	if jsonOut.Rule == nil {
-		t.Errorf("%q expected but not found", jsonPath)
-		return
-	}
-	if !strings.Contains(jsonOut.Args["content"], fmt.Sprintf("%q:%q", key, value)) {
-		t.Errorf("%q must include %q:%q but it only has %v", jsonPath, key, value, jsonOut.Args["content"])
-	}
-}
-
-func TestVendorSnapshotCapture(t *testing.T) {
-	bp := `
-	cc_library {
-		name: "libvndk",
-		vendor_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		nocrt: true,
-	}
-
-	cc_library {
-		name: "libvendor",
-		vendor: true,
-		nocrt: true,
-	}
-
-	cc_library {
-		name: "libvendor_override",
-		vendor: true,
-		nocrt: true,
-		overrides: ["libvendor"],
-	}
-
-	cc_library {
-		name: "libvendor_available",
-		vendor_available: true,
-		nocrt: true,
-		min_sdk_version: "29",
-	}
-
-	cc_library_headers {
-		name: "libvendor_headers",
-		vendor_available: true,
-		nocrt: true,
-	}
-
-	cc_binary {
-		name: "vendor_bin",
-		vendor: true,
-		nocrt: true,
-	}
-
-	cc_binary {
-		name: "vendor_available_bin",
-		vendor_available: true,
-		nocrt: true,
-	}
-
-	cc_binary {
-		name: "vendor_bin_override",
-		vendor: true,
-		nocrt: true,
-		overrides: ["vendor_bin"],
-	}
-
-	cc_prebuilt_library_static {
-		name: "libb",
-		vendor_available: true,
-		srcs: ["libb.a"],
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-	}
-
-	cc_object {
-		name: "obj",
-		vendor_available: true,
-	}
-
-	cc_library {
-		name: "libllndk",
-		llndk: {
-			symbol_file: "libllndk.map.txt",
-		},
-	}
-`
-
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	ctx := testCcWithConfig(t, config)
-
-	// Check Vendor snapshot output.
-
-	snapshotDir := "vendor-snapshot"
-	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
-
-	var jsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-		[]string{"arm", "armv7-a-neon"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		// For shared libraries, only non-VNDK vendor_available modules are captured
-		sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-		CheckSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
-		CheckSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(sharedDir, "libvendor.so.json"),
-			filepath.Join(sharedDir, "libvendor_available.so.json"))
-
-		// LLNDK modules are not captured
-		CheckSnapshotExclude(t, ctx, snapshotSingleton, "libllndk", "libllndk.so", sharedDir, sharedVariant)
-
-		// For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
-		// Also cfi variants are captured, except for prebuilts like toolchain_library
-		staticVariant := fmt.Sprintf("android_vendor.29_%s_%s_static", archType, archVariant)
-		staticCfiVariant := fmt.Sprintf("android_vendor.29_%s_%s_static_cfi", archType, archVariant)
-		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
-		CheckSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
-		CheckSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.a", staticDir, staticVariant)
-		CheckSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.cfi.a", staticDir, staticCfiVariant)
-		CheckSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.a", staticDir, staticVariant)
-		CheckSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.cfi.a", staticDir, staticCfiVariant)
-		CheckSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.a", staticDir, staticVariant)
-		CheckSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.cfi.a", staticDir, staticCfiVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(staticDir, "libb.a.json"),
-			filepath.Join(staticDir, "libvndk.a.json"),
-			filepath.Join(staticDir, "libvndk.cfi.a.json"),
-			filepath.Join(staticDir, "libvendor.a.json"),
-			filepath.Join(staticDir, "libvendor.cfi.a.json"),
-			filepath.Join(staticDir, "libvendor_available.a.json"),
-			filepath.Join(staticDir, "libvendor_available.cfi.a.json"))
-
-		checkJsonContents(t, snapshotSingleton, filepath.Join(staticDir, "libb.a.json"), "MinSdkVersion", "apex_inherit")
-		checkJsonContents(t, snapshotSingleton, filepath.Join(staticDir, "libvendor_available.a.json"), "MinSdkVersion", "29")
-
-		// For binary executables, all vendor:true and vendor_available modules are captured.
-		if archType == "arm64" {
-			binaryVariant := fmt.Sprintf("android_vendor.29_%s_%s", archType, archVariant)
-			binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
-			CheckSnapshot(t, ctx, snapshotSingleton, "vendor_bin", "vendor_bin", binaryDir, binaryVariant)
-			CheckSnapshot(t, ctx, snapshotSingleton, "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant)
-			jsonFiles = append(jsonFiles,
-				filepath.Join(binaryDir, "vendor_bin.json"),
-				filepath.Join(binaryDir, "vendor_available_bin.json"))
-
-			checkOverrides(t, ctx, snapshotSingleton, filepath.Join(binaryDir, "vendor_bin_override.json"), []string{"vendor_bin"})
-		}
-
-		// For header libraries, all vendor:true and vendor_available modules are captured.
-		headerDir := filepath.Join(snapshotVariantPath, archDir, "header")
-		jsonFiles = append(jsonFiles, filepath.Join(headerDir, "libvendor_headers.json"))
-
-		// For object modules, all vendor:true and vendor_available modules are captured.
-		objectVariant := fmt.Sprintf("android_vendor.29_%s_%s", archType, archVariant)
-		objectDir := filepath.Join(snapshotVariantPath, archDir, "object")
-		CheckSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant)
-		jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json"))
-
-		checkOverrides(t, ctx, snapshotSingleton, filepath.Join(sharedDir, "libvendor_override.so.json"), []string{"libvendor"})
-	}
-
-	for _, jsonFile := range jsonFiles {
-		// verify all json files exist
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("%q expected but not found", jsonFile)
-		}
-	}
-
-	// fake snapshot should have all outputs in the normal snapshot.
-	fakeSnapshotSingleton := ctx.SingletonForTests("vendor-fake-snapshot")
-	for _, output := range snapshotSingleton.AllOutputs() {
-		fakeOutput := strings.Replace(output, "/vendor-snapshot/", "/fake/vendor-snapshot/", 1)
-		if fakeSnapshotSingleton.MaybeOutput(fakeOutput).Rule == nil {
-			t.Errorf("%q expected but not found", fakeOutput)
-		}
-	}
-}
-
-func TestVendorSnapshotDirected(t *testing.T) {
-	bp := `
-	cc_library_shared {
-		name: "libvendor",
-		vendor: true,
-		nocrt: true,
-	}
-
-	cc_library_shared {
-		name: "libvendor_available",
-		vendor_available: true,
-		nocrt: true,
-	}
-
-	genrule {
-		name: "libfoo_gen",
-		cmd: "",
-		out: ["libfoo.so"],
-	}
-
-	cc_prebuilt_library_shared {
-		name: "libfoo",
-		vendor: true,
-		prefer: true,
-		srcs: [":libfoo_gen"],
-	}
-
-	cc_library_shared {
-		name: "libfoo",
-		vendor: true,
-		nocrt: true,
-	}
-`
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	config.TestProductVariables.DirectedVendorSnapshot = true
-	config.TestProductVariables.VendorSnapshotModules = make(map[string]bool)
-	config.TestProductVariables.VendorSnapshotModules["libvendor"] = true
-	config.TestProductVariables.VendorSnapshotModules["libfoo"] = true
-	ctx := testCcWithConfig(t, config)
-
-	// Check Vendor snapshot output.
-
-	snapshotDir := "vendor-snapshot"
-	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
-
-	var includeJsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-		[]string{"arm", "armv7-a-neon"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-
-		// Included modules
-		CheckSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json"))
-		// Check that snapshot captures "prefer: true" prebuilt
-		CheckSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json"))
-
-		// Excluded modules. Modules not included in the directed vendor snapshot
-		// are still include as fake modules.
-		CheckSnapshotRule(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libvendor_available.so.json"))
-	}
-
-	// Verify that each json file for an included module has a rule.
-	for _, jsonFile := range includeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("include json file %q not found", jsonFile)
-		}
-	}
-}
-
-func TestVendorSnapshotUse(t *testing.T) {
-	frameworkBp := `
-	cc_library {
-		name: "libvndk",
-		vendor_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		nocrt: true,
-	}
-
-	cc_library {
-		name: "libvendor",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-	}
-
-	cc_library {
-		name: "libvendor_available",
-		vendor_available: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-	}
-
-	cc_library {
-		name: "lib32",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-		compile_multilib: "32",
-	}
-
-	cc_library {
-		name: "lib64",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-		compile_multilib: "64",
-	}
-
-	cc_library {
-		name: "libllndk",
-		llndk: {
-			symbol_file: "libllndk.map.txt",
-		},
-	}
-
-	cc_binary {
-		name: "bin",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-	}
-
-	cc_binary {
-		name: "bin32",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-		compile_multilib: "32",
-	}
-`
-
-	vndkBp := `
-	vndk_prebuilt_shared {
-		name: "libvndk",
-		version: "31",
-		target_arch: "arm64",
-		vendor_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		arch: {
-			arm64: {
-				srcs: ["libvndk.so"],
-				export_include_dirs: ["include/libvndk"],
-			},
-			arm: {
-				srcs: ["libvndk.so"],
-				export_include_dirs: ["include/libvndk"],
-			},
-		},
-	}
-
-	// old snapshot module which has to be ignored
-	vndk_prebuilt_shared {
-		name: "libvndk",
-		version: "26",
-		target_arch: "arm64",
-		vendor_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		arch: {
-			arm64: {
-				srcs: ["libvndk.so"],
-				export_include_dirs: ["include/libvndk"],
-			},
-			arm: {
-				srcs: ["libvndk.so"],
-				export_include_dirs: ["include/libvndk"],
-			},
-		},
-	}
-
-	// different arch snapshot which has to be ignored
-	vndk_prebuilt_shared {
-		name: "libvndk",
-		version: "31",
-		target_arch: "arm",
-		vendor_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		arch: {
-			arm: {
-				srcs: ["libvndk.so"],
-				export_include_dirs: ["include/libvndk"],
-			},
-		},
-	}
-
-	vndk_prebuilt_shared {
-		name: "libllndk",
-		version: "31",
-		target_arch: "arm64",
-		vendor_available: true,
-		product_available: true,
-		arch: {
-			arm64: {
-				srcs: ["libllndk.so"],
-			},
-			arm: {
-				srcs: ["libllndk.so"],
-			},
-		},
-	}
-`
-
-	vendorProprietaryBp := `
-	cc_library {
-		name: "libvendor_without_snapshot",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-	}
-
-	cc_library_shared {
-		name: "libclient",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-		shared_libs: ["libvndk", "libvendor_available", "libllndk"],
-		static_libs: ["libvendor", "libvendor_without_snapshot"],
-		arch: {
-			arm64: {
-				shared_libs: ["lib64"],
-			},
-			arm: {
-				shared_libs: ["lib32"],
-			},
-		},
-		srcs: ["client.cpp"],
-	}
-
-	cc_library_shared {
-		name: "libclient_cfi",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-		static_libs: ["libvendor"],
-		sanitize: {
-			cfi: true,
-		},
-		srcs: ["client.cpp"],
-	}
-
-	cc_library_shared {
-		name: "libvndkext",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-		vndk: {
-			extends: "libvndk",
-			enabled: true,
-		}
-	}
-
-	cc_binary {
-		name: "bin_without_snapshot",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "libc++_static",
-		system_shared_libs: [],
-		static_libs: ["libvndk"],
-		srcs: ["bin.cpp"],
-	}
-
-	vendor_snapshot {
-		name: "vendor_snapshot",
-		version: "31",
-		arch: {
-			arm64: {
-				vndk_libs: [
-					"libvndk",
-					"libllndk",
-				],
-				static_libs: [
-					"libc++_static",
-					"libc++demangle",
-					"libunwind",
-					"libvendor",
-					"libvendor_available",
-					"libvndk",
-					"lib64",
-				],
-				shared_libs: [
-					"libvendor",
-					"libvendor_override",
-					"libvendor_available",
-					"lib64",
-				],
-				binaries: [
-					"bin",
-					"bin_override",
-				],
-			},
-			arm: {
-				vndk_libs: [
-					"libvndk",
-					"libllndk",
-				],
-				static_libs: [
-					"libvendor",
-					"libvendor_available",
-					"libvndk",
-					"lib32",
-				],
-				shared_libs: [
-					"libvendor",
-					"libvendor_override",
-					"libvendor_available",
-					"lib32",
-				],
-				binaries: [
-					"bin32",
-				],
-			},
-		}
-	}
-
-	vendor_snapshot_static {
-		name: "libvndk",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "both",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "libvndk.a",
-			},
-			arm: {
-				src: "libvndk.a",
-			},
-		},
-		shared_libs: ["libvndk"],
-		export_shared_lib_headers: ["libvndk"],
-	}
-
-	vendor_snapshot_shared {
-		name: "libvendor",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "both",
-		vendor: true,
-		shared_libs: [
-			"libvendor_without_snapshot",
-			"libvendor_available",
-			"libvndk",
-		],
-		arch: {
-			arm64: {
-				src: "libvendor.so",
-				export_include_dirs: ["include/libvendor"],
-			},
-			arm: {
-				src: "libvendor.so",
-				export_include_dirs: ["include/libvendor"],
-			},
-		},
-	}
-
-	vendor_snapshot_shared {
-		name: "libvendor_override",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "both",
-		vendor: true,
-		overrides: ["libvendor"],
-		shared_libs: [
-			"libvendor_without_snapshot",
-			"libvendor_available",
-			"libvndk",
-		],
-		arch: {
-			arm64: {
-				src: "override/libvendor.so",
-				export_include_dirs: ["include/libvendor"],
-			},
-			arm: {
-				src: "override/libvendor.so",
-				export_include_dirs: ["include/libvendor"],
-			},
-		},
-	}
-
-	vendor_snapshot_static {
-		name: "lib32",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "32",
-		vendor: true,
-		arch: {
-			arm: {
-				src: "lib32.a",
-			},
-		},
-	}
-
-	vendor_snapshot_shared {
-		name: "lib32",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "32",
-		vendor: true,
-		arch: {
-			arm: {
-				src: "lib32.so",
-			},
-		},
-	}
-
-	vendor_snapshot_static {
-		name: "lib64",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "lib64.a",
-			},
-		},
-	}
-
-	vendor_snapshot_shared {
-		name: "lib64",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "lib64.so",
-			},
-		},
-	}
-
-	vendor_snapshot_static {
-		name: "libvendor",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "both",
-		vendor: true,
-		arch: {
-			arm64: {
-				cfi: {
-					src: "libvendor.cfi.a",
-					export_include_dirs: ["include/libvendor_cfi"],
-				},
-				src: "libvendor.a",
-				export_include_dirs: ["include/libvendor"],
-			},
-			arm: {
-				cfi: {
-					src: "libvendor.cfi.a",
-					export_include_dirs: ["include/libvendor_cfi"],
-				},
-				src: "libvendor.a",
-				export_include_dirs: ["include/libvendor"],
-			},
-		},
-	}
-
-	vendor_snapshot_shared {
-		name: "libvendor_available",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "both",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "libvendor_available.so",
-				export_include_dirs: ["include/libvendor"],
-			},
-			arm: {
-				src: "libvendor_available.so",
-				export_include_dirs: ["include/libvendor"],
-			},
-		},
-	}
-
-	vendor_snapshot_static {
-		name: "libvendor_available",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "both",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "libvendor_available.a",
-				export_include_dirs: ["include/libvendor"],
-			},
-			arm: {
-				src: "libvendor_available.so",
-				export_include_dirs: ["include/libvendor"],
-			},
-		},
-	}
-
-	vendor_snapshot_static {
-		name: "libc++_static",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "libc++_static.a",
-			},
-		},
-	}
-
-	vendor_snapshot_static {
-		name: "libc++demangle",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "libc++demangle.a",
-			},
-		},
-	}
-
-	vendor_snapshot_static {
-		name: "libunwind",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "libunwind.a",
-			},
-		},
-	}
-
-	vendor_snapshot_binary {
-		name: "bin",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "bin",
-			},
-		},
-		symlinks: ["binfoo", "binbar"],
-	}
-
-	vendor_snapshot_binary {
-		name: "bin_override",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "64",
-		vendor: true,
-		overrides: ["bin"],
-		arch: {
-			arm64: {
-				src: "override/bin",
-			},
-		},
-		symlinks: ["binfoo", "binbar"],
-	}
-
-	vendor_snapshot_binary {
-		name: "bin32",
-		version: "31",
-		target_arch: "arm64",
-		compile_multilib: "32",
-		vendor: true,
-		arch: {
-			arm: {
-				src: "bin32",
-			},
-		},
-	}
-
-	// old snapshot module which has to be ignored
-	vendor_snapshot_binary {
-		name: "bin",
-		version: "26",
-		target_arch: "arm64",
-		compile_multilib: "first",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "bin",
-			},
-		},
-	}
-
-	// different arch snapshot which has to be ignored
-	vendor_snapshot_binary {
-		name: "bin",
-		version: "31",
-		target_arch: "arm",
-		compile_multilib: "first",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "bin",
-			},
-		},
-	}
-`
-	depsBp := GatherRequiredDepsForTest(android.Android)
-
-	mockFS := map[string][]byte{
-		"deps/Android.bp":                  []byte(depsBp),
-		"framework/Android.bp":             []byte(frameworkBp),
-		"framework/symbol.txt":             nil,
-		"vendor/Android.bp":                []byte(vendorProprietaryBp),
-		"vendor/bin":                       nil,
-		"vendor/override/bin":              nil,
-		"vendor/bin32":                     nil,
-		"vendor/bin.cpp":                   nil,
-		"vendor/client.cpp":                nil,
-		"vendor/include/libvndk/a.h":       nil,
-		"vendor/include/libvendor/b.h":     nil,
-		"vendor/include/libvendor_cfi/c.h": nil,
-		"vendor/libc++_static.a":           nil,
-		"vendor/libc++demangle.a":          nil,
-		"vendor/libunwind.a":               nil,
-		"vendor/libvndk.a":                 nil,
-		"vendor/libvendor.a":               nil,
-		"vendor/libvendor.cfi.a":           nil,
-		"vendor/libvendor.so":              nil,
-		"vendor/override/libvendor.so":     nil,
-		"vendor/lib32.a":                   nil,
-		"vendor/lib32.so":                  nil,
-		"vendor/lib64.a":                   nil,
-		"vendor/lib64.so":                  nil,
-		"vndk/Android.bp":                  []byte(vndkBp),
-		"vndk/include/libvndk/a.h":         nil,
-		"vndk/libvndk.so":                  nil,
-		"vndk/libllndk.so":                 nil,
-	}
-
-	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("31")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("32")
-	ctx := CreateTestContext(config)
-	ctx.Register()
-
-	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "vendor/Android.bp", "vndk/Android.bp"})
-	android.FailIfErrored(t, errs)
-	_, errs = ctx.PrepareBuildActions(config)
-	android.FailIfErrored(t, errs)
-
-	sharedVariant := "android_vendor.31_arm64_armv8-a_shared"
-	staticVariant := "android_vendor.31_arm64_armv8-a_static"
-	binaryVariant := "android_vendor.31_arm64_armv8-a"
-
-	sharedCfiVariant := "android_vendor.31_arm64_armv8-a_shared_cfi"
-	staticCfiVariant := "android_vendor.31_arm64_armv8-a_static_cfi"
-
-	shared32Variant := "android_vendor.31_arm_armv7-a-neon_shared"
-	binary32Variant := "android_vendor.31_arm_armv7-a-neon"
-
-	// libclient uses libvndk.vndk.31.arm64, libvendor.vendor_static.31.arm64, libvendor_without_snapshot
-	libclientCcFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("cc").Args["cFlags"]
-	for _, includeFlags := range []string{
-		"-Ivndk/include/libvndk",     // libvndk
-		"-Ivendor/include/libvendor", // libvendor
-	} {
-		if !strings.Contains(libclientCcFlags, includeFlags) {
-			t.Errorf("flags for libclient must contain %#v, but was %#v.",
-				includeFlags, libclientCcFlags)
-		}
-	}
-
-	libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld").Args["libFlags"]
-	for _, input := range [][]string{
-		[]string{sharedVariant, "libvndk.vndk.31.arm64"},
-		[]string{sharedVariant, "libllndk.vndk.31.arm64"},
-		[]string{staticVariant, "libvendor.vendor_static.31.arm64"},
-		[]string{staticVariant, "libvendor_without_snapshot"},
-	} {
-		outputPaths := GetOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */)
-		if !strings.Contains(libclientLdFlags, outputPaths[0].String()) {
-			t.Errorf("libflags for libclient must contain %#v, but was %#v", outputPaths[0], libclientLdFlags)
-		}
-
-	}
-
-	libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkSharedLibs
-	if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "libllndk.vendor", "lib64"}; !reflect.DeepEqual(g, w) {
-		t.Errorf("wanted libclient AndroidMkSharedLibs %q, got %q", w, g)
-	}
-
-	libclientAndroidMkStaticLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkStaticLibs
-	if g, w := libclientAndroidMkStaticLibs, []string{"libvendor", "libvendor_without_snapshot"}; !reflect.DeepEqual(g, w) {
-		t.Errorf("wanted libclient AndroidMkStaticLibs %q, got %q", w, g)
-	}
-
-	libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).Properties.AndroidMkSharedLibs
-	if g, w := libclient32AndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "libllndk.vendor", "lib32"}; !reflect.DeepEqual(g, w) {
-		t.Errorf("wanted libclient32 AndroidMkSharedLibs %q, got %q", w, g)
-	}
-
-	// libclient_cfi uses libvendor.vendor_static.31.arm64's cfi variant
-	libclientCfiCcFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("cc").Args["cFlags"]
-	if !strings.Contains(libclientCfiCcFlags, "-Ivendor/include/libvendor_cfi") {
-		t.Errorf("flags for libclient_cfi must contain %#v, but was %#v.",
-			"-Ivendor/include/libvendor_cfi", libclientCfiCcFlags)
-	}
-
-	libclientCfiLdFlags := ctx.ModuleForTests("libclient_cfi", sharedCfiVariant).Rule("ld").Args["libFlags"]
-	libvendorCfiOutputPaths := GetOutputPaths(ctx, staticCfiVariant, []string{"libvendor.vendor_static.31.arm64"})
-	if !strings.Contains(libclientCfiLdFlags, libvendorCfiOutputPaths[0].String()) {
-		t.Errorf("libflags for libclientCfi must contain %#v, but was %#v", libvendorCfiOutputPaths[0], libclientCfiLdFlags)
-	}
-
-	// bin_without_snapshot uses libvndk.vendor_static.31.arm64 (which reexports vndk's exported headers)
-	binWithoutSnapshotCcFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("cc").Args["cFlags"]
-	if !strings.Contains(binWithoutSnapshotCcFlags, "-Ivndk/include/libvndk") {
-		t.Errorf("flags for bin_without_snapshot must contain %#v, but was %#v.",
-			"-Ivendor/include/libvndk", binWithoutSnapshotCcFlags)
-	}
-
-	binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld").Args["libFlags"]
-	libVndkStaticOutputPaths := GetOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.31.arm64"})
-	if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) {
-		t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
-			libVndkStaticOutputPaths[0], binWithoutSnapshotLdFlags)
-	}
-
-	// libvendor.so is installed by libvendor.vendor_shared.31.arm64
-	ctx.ModuleForTests("libvendor.vendor_shared.31.arm64", sharedVariant).Output("libvendor.so")
-
-	// lib64.so is installed by lib64.vendor_shared.31.arm64
-	ctx.ModuleForTests("lib64.vendor_shared.31.arm64", sharedVariant).Output("lib64.so")
-
-	// lib32.so is installed by lib32.vendor_shared.31.arm64
-	ctx.ModuleForTests("lib32.vendor_shared.31.arm64", shared32Variant).Output("lib32.so")
-
-	// libvendor_available.so is installed by libvendor_available.vendor_shared.31.arm64
-	ctx.ModuleForTests("libvendor_available.vendor_shared.31.arm64", sharedVariant).Output("libvendor_available.so")
-
-	// libvendor_without_snapshot.so is installed by libvendor_without_snapshot
-	ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so")
-
-	// bin is installed by bin.vendor_binary.31.arm64
-	bin64Module := ctx.ModuleForTests("bin.vendor_binary.31.arm64", binaryVariant)
-	bin64Module.Output("bin")
-
-	// also test symlinks
-	bin64MkEntries := android.AndroidMkEntriesForTest(t, ctx, bin64Module.Module())
-	bin64KatiSymlinks := bin64MkEntries[0].EntryMap["LOCAL_SOONG_INSTALL_SYMLINKS"]
-
-	// Either AndroidMk entries contain symlinks, or symlinks should be installed by Soong
-	for _, symlink := range []string{"binfoo", "binbar"} {
-		if inList(symlink, bin64KatiSymlinks) {
-			continue
-		}
-
-		bin64Module.Output(symlink)
-	}
-
-	// bin32 is installed by bin32.vendor_binary.31.arm64
-	ctx.ModuleForTests("bin32.vendor_binary.31.arm64", binary32Variant).Output("bin32")
-
-	// bin_without_snapshot is installed by bin_without_snapshot
-	ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot")
-
-	// libvendor, libvendor_available and bin don't have vendor.31 variant
-	libvendorVariants := ctx.ModuleVariantsForTests("libvendor")
-	if inList(sharedVariant, libvendorVariants) {
-		t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant)
-	}
-
-	libvendorAvailableVariants := ctx.ModuleVariantsForTests("libvendor_available")
-	if inList(sharedVariant, libvendorAvailableVariants) {
-		t.Errorf("libvendor_available must not have variant %#v, but it does", sharedVariant)
-	}
-
-	binVariants := ctx.ModuleVariantsForTests("bin")
-	if inList(binaryVariant, binVariants) {
-		t.Errorf("bin must not have variant %#v, but it does", sharedVariant)
-	}
-
-	// test overrides property
-	binOverrideModule := ctx.ModuleForTests("bin_override.vendor_binary.31.arm64", binaryVariant)
-	binOverrideModule.Output("bin")
-	binOverrideMkEntries := android.AndroidMkEntriesForTest(t, ctx, binOverrideModule.Module())
-	binOverrideEntry := binOverrideMkEntries[0].EntryMap["LOCAL_OVERRIDES_MODULES"]
-	if !inList("bin", binOverrideEntry) {
-		t.Errorf("bin_override must override bin but was %q\n", binOverrideEntry)
-	}
-
-	libvendorOverrideModule := ctx.ModuleForTests("libvendor_override.vendor_shared.31.arm64", sharedVariant)
-	libvendorOverrideModule.Output("libvendor.so")
-	libvendorOverrideMkEntries := android.AndroidMkEntriesForTest(t, ctx, libvendorOverrideModule.Module())
-	libvendorOverrideEntry := libvendorOverrideMkEntries[0].EntryMap["LOCAL_OVERRIDES_MODULES"]
-	if !inList("libvendor", libvendorOverrideEntry) {
-		t.Errorf("libvendor_override must override libvendor but was %q\n", libvendorOverrideEntry)
-	}
-}
-
-func TestVendorSnapshotSanitizer(t *testing.T) {
-	bp := `
-	vendor_snapshot {
-		name: "vendor_snapshot",
-		version: "28",
-		arch: {
-			arm64: {
-				static_libs: [
-					"libsnapshot",
-					"note_memtag_heap_sync",
-				],
-				objects: [
-					"snapshot_object",
-				],
-				vndk_libs: [
-					"libclang_rt.hwasan",
-				],
-			},
-		},
-	}
-
-	vendor_snapshot_static {
-		name: "libsnapshot",
-		vendor: true,
-		target_arch: "arm64",
-		version: "28",
-		arch: {
-			arm64: {
-				src: "libsnapshot.a",
-				cfi: {
-					src: "libsnapshot.cfi.a",
-				},
-				hwasan: {
-					src: "libsnapshot.hwasan.a",
-				},
-			},
-		},
-	}
-
-	vendor_snapshot_static {
-		name: "note_memtag_heap_sync",
-		vendor: true,
-		target_arch: "arm64",
-		version: "28",
-		arch: {
-			arm64: {
-				src: "note_memtag_heap_sync.a",
-			},
-		},
-	}
-
-	vndk_prebuilt_shared {
-		name: "libclang_rt.hwasan",
-		version: "28",
-		target_arch: "arm64",
-		vendor_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		arch: {
-			arm64: {
-				srcs: ["libclang_rt.hwasan.so"],
-			},
-		},
-	}
-
-	vendor_snapshot_object {
-		name: "snapshot_object",
-		vendor: true,
-		target_arch: "arm64",
-		version: "28",
-		arch: {
-			arm64: {
-				src: "snapshot_object.o",
-			},
-		},
-		stl: "none",
-	}
-
-	cc_test {
-		name: "vstest",
-		gtest: false,
-		vendor: true,
-		compile_multilib: "64",
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		static_libs: ["libsnapshot"],
-		system_shared_libs: [],
-	}
-`
-
-	mockFS := map[string][]byte{
-		"vendor/Android.bp":              []byte(bp),
-		"vendor/libc++demangle.a":        nil,
-		"vendor/libclang_rt.hwasan.so":   nil,
-		"vendor/libsnapshot.a":           nil,
-		"vendor/libsnapshot.cfi.a":       nil,
-		"vendor/libsnapshot.hwasan.a":    nil,
-		"vendor/note_memtag_heap_sync.a": nil,
-		"vendor/snapshot_object.o":       nil,
-	}
-
-	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("28")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
-	ctx := testCcWithConfig(t, config)
-
-	// Check non-cfi, cfi and hwasan variant.
-	staticVariant := "android_vendor.28_arm64_armv8-a_static"
-	staticCfiVariant := "android_vendor.28_arm64_armv8-a_static_cfi"
-	staticHwasanVariant := "android_vendor.28_arm64_armv8-a_static_hwasan"
-	staticHwasanCfiVariant := "android_vendor.28_arm64_armv8-a_static_hwasan_cfi"
-
-	staticModule := ctx.ModuleForTests("libsnapshot.vendor_static.28.arm64", staticVariant).Module().(*Module)
-	assertString(t, staticModule.outputFile.Path().Base(), "libsnapshot.a")
-
-	staticCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.28.arm64", staticCfiVariant).Module().(*Module)
-	assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a")
-
-	staticHwasanModule := ctx.ModuleForTests("libsnapshot.vendor_static.28.arm64", staticHwasanVariant).Module().(*Module)
-	assertString(t, staticHwasanModule.outputFile.Path().Base(), "libsnapshot.hwasan.a")
-
-	staticHwasanCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.28.arm64", staticHwasanCfiVariant).Module().(*Module)
-	if !staticHwasanCfiModule.HiddenFromMake() || !staticHwasanCfiModule.PreventInstall() {
-		t.Errorf("Hwasan and Cfi cannot enabled at the same time.")
-	}
-
-	snapshotObjModule := ctx.ModuleForTests("snapshot_object.vendor_object.28.arm64", "android_vendor.28_arm64_armv8-a").Module()
-	snapshotObjMkEntries := android.AndroidMkEntriesForTest(t, ctx, snapshotObjModule)
-	// snapshot object must not add ".hwasan" suffix
-	assertString(t, snapshotObjMkEntries[0].EntryMap["LOCAL_MODULE"][0], "snapshot_object")
-}
-
-func TestVendorSnapshotExclude(t *testing.T) {
-
-	// This test verifies that the exclude_from_vendor_snapshot property
-	// makes its way from the Android.bp source file into the module data
-	// structure. It also verifies that modules are correctly included or
-	// excluded in the vendor snapshot based on their path (framework or
-	// vendor) and the exclude_from_vendor_snapshot property.
-
-	frameworkBp := `
-		cc_library_shared {
-			name: "libinclude",
-			srcs: ["src/include.cpp"],
-			vendor_available: true,
-		}
-		cc_library_shared {
-			name: "libexclude",
-			srcs: ["src/exclude.cpp"],
-			vendor: true,
-			exclude_from_vendor_snapshot: true,
-		}
-		cc_library_shared {
-			name: "libavailable_exclude",
-			srcs: ["src/exclude.cpp"],
-			vendor_available: true,
-			exclude_from_vendor_snapshot: true,
-		}
-	`
-
-	vendorProprietaryBp := `
-		cc_library_shared {
-			name: "libvendor",
-			srcs: ["vendor.cpp"],
-			vendor: true,
-		}
-	`
-
-	depsBp := GatherRequiredDepsForTest(android.Android)
-
-	mockFS := map[string][]byte{
-		"deps/Android.bp":       []byte(depsBp),
-		"framework/Android.bp":  []byte(frameworkBp),
-		"framework/include.cpp": nil,
-		"framework/exclude.cpp": nil,
-		"device/Android.bp":     []byte(vendorProprietaryBp),
-		"device/vendor.cpp":     nil,
-	}
-
-	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	ctx := CreateTestContext(config)
-	ctx.Register()
-
-	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"})
-	android.FailIfErrored(t, errs)
-	_, errs = ctx.PrepareBuildActions(config)
-	android.FailIfErrored(t, errs)
-
-	// Test an include and exclude framework module.
-	AssertExcludeFromVendorSnapshotIs(t, ctx, "libinclude", false, vendorVariant)
-	AssertExcludeFromVendorSnapshotIs(t, ctx, "libexclude", true, vendorVariant)
-	AssertExcludeFromVendorSnapshotIs(t, ctx, "libavailable_exclude", true, vendorVariant)
-
-	// A vendor module is excluded, but by its path, not the
-	// exclude_from_vendor_snapshot property.
-	AssertExcludeFromVendorSnapshotIs(t, ctx, "libvendor", false, vendorVariant)
-
-	// Verify the content of the vendor snapshot.
-
-	snapshotDir := "vendor-snapshot"
-	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
-
-	var includeJsonFiles []string
-	var excludeJsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-		[]string{"arm", "armv7-a-neon"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-
-		// Included modules
-		CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json"))
-
-		// Excluded modules
-		CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
-		CheckSnapshotExclude(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json"))
-		CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
-	}
-
-	// Verify that each json file for an included module has a rule.
-	for _, jsonFile := range includeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("include json file %q not found", jsonFile)
-		}
-	}
-
-	// Verify that each json file for an excluded module has no rule.
-	for _, jsonFile := range excludeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
-			t.Errorf("exclude json file %q found", jsonFile)
-		}
-	}
-}
-
-func TestVendorSnapshotExcludeInVendorProprietaryPathErrors(t *testing.T) {
-
-	// This test verifies that using the exclude_from_vendor_snapshot
-	// property on a module in a vendor proprietary path generates an
-	// error. These modules are already excluded, so we prohibit using the
-	// property in this way, which could add to confusion.
-
-	vendorProprietaryBp := `
-		cc_library_shared {
-			name: "libvendor",
-			srcs: ["vendor.cpp"],
-			vendor: true,
-			exclude_from_vendor_snapshot: true,
-		}
-	`
-
-	depsBp := GatherRequiredDepsForTest(android.Android)
-
-	mockFS := map[string][]byte{
-		"deps/Android.bp":   []byte(depsBp),
-		"device/Android.bp": []byte(vendorProprietaryBp),
-		"device/vendor.cpp": nil,
-	}
-
-	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	ctx := CreateTestContext(config)
-	ctx.Register()
-
-	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "device/Android.bp"})
-	android.FailIfErrored(t, errs)
-
-	_, errs = ctx.PrepareBuildActions(config)
-	android.CheckErrorsAgainstExpectations(t, errs, []string{
-		`module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
-		`module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
-		`module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
-		`module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
-		`module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
-		`module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
-	})
-}
-
-func TestRecoverySnapshotCapture(t *testing.T) {
-	bp := `
-	cc_library {
-		name: "libvndk",
-		vendor_available: true,
-		recovery_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		nocrt: true,
-	}
-
-	cc_library {
-		name: "librecovery",
-		recovery: true,
-		nocrt: true,
-	}
-
-	cc_library {
-		name: "librecovery_available",
-		recovery_available: true,
-		nocrt: true,
-	}
-
-	cc_library_headers {
-		name: "librecovery_headers",
-		recovery_available: true,
-		nocrt: true,
-	}
-
-	cc_binary {
-		name: "recovery_bin",
-		recovery: true,
-		nocrt: true,
-	}
-
-	cc_binary {
-		name: "recovery_available_bin",
-		recovery_available: true,
-		nocrt: true,
-	}
-
-	cc_prebuilt_library_static {
-		name: "libb",
-		recovery_available: true,
-		srcs: ["libb.a"],
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-	}
-
-	cc_object {
-		name: "obj",
-		recovery_available: true,
-	}
-`
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	ctx := testCcWithConfig(t, config)
-
-	// Check Recovery snapshot output.
-
-	snapshotDir := "recovery-snapshot"
-	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
-
-	var jsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		// For shared libraries, only recovery_available modules are captured.
-		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-		CheckSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", sharedDir, sharedVariant)
-		CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
-		CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(sharedDir, "libvndk.so.json"),
-			filepath.Join(sharedDir, "librecovery.so.json"),
-			filepath.Join(sharedDir, "librecovery_available.so.json"))
-
-		// For static libraries, all recovery:true and recovery_available modules are captured.
-		staticVariant := fmt.Sprintf("android_recovery_%s_%s_static", archType, archVariant)
-		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
-		CheckSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
-		CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.a", staticDir, staticVariant)
-		CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.a", staticDir, staticVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(staticDir, "libb.a.json"),
-			filepath.Join(staticDir, "librecovery.a.json"),
-			filepath.Join(staticDir, "librecovery_available.a.json"))
-
-		// For binary executables, all recovery:true and recovery_available modules are captured.
-		if archType == "arm64" {
-			binaryVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant)
-			binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
-			CheckSnapshot(t, ctx, snapshotSingleton, "recovery_bin", "recovery_bin", binaryDir, binaryVariant)
-			CheckSnapshot(t, ctx, snapshotSingleton, "recovery_available_bin", "recovery_available_bin", binaryDir, binaryVariant)
-			jsonFiles = append(jsonFiles,
-				filepath.Join(binaryDir, "recovery_bin.json"),
-				filepath.Join(binaryDir, "recovery_available_bin.json"))
-		}
-
-		// For header libraries, all vendor:true and vendor_available modules are captured.
-		headerDir := filepath.Join(snapshotVariantPath, archDir, "header")
-		jsonFiles = append(jsonFiles, filepath.Join(headerDir, "librecovery_headers.json"))
-
-		// For object modules, all vendor:true and vendor_available modules are captured.
-		objectVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant)
-		objectDir := filepath.Join(snapshotVariantPath, archDir, "object")
-		CheckSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant)
-		jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json"))
-	}
-
-	for _, jsonFile := range jsonFiles {
-		// verify all json files exist
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("%q expected but not found", jsonFile)
-		}
-	}
-}
-
-func TestRecoverySnapshotExclude(t *testing.T) {
-	// This test verifies that the exclude_from_recovery_snapshot property
-	// makes its way from the Android.bp source file into the module data
-	// structure. It also verifies that modules are correctly included or
-	// excluded in the recovery snapshot based on their path (framework or
-	// vendor) and the exclude_from_recovery_snapshot property.
-
-	frameworkBp := `
-		cc_library_shared {
-			name: "libinclude",
-			srcs: ["src/include.cpp"],
-			recovery_available: true,
-		}
-		cc_library_shared {
-			name: "libexclude",
-			srcs: ["src/exclude.cpp"],
-			recovery: true,
-			exclude_from_recovery_snapshot: true,
-		}
-		cc_library_shared {
-			name: "libavailable_exclude",
-			srcs: ["src/exclude.cpp"],
-			recovery_available: true,
-			exclude_from_recovery_snapshot: true,
-		}
-	`
-
-	vendorProprietaryBp := `
-		cc_library_shared {
-			name: "librecovery",
-			srcs: ["recovery.cpp"],
-			recovery: true,
-		}
-	`
-
-	depsBp := GatherRequiredDepsForTest(android.Android)
-
-	mockFS := map[string][]byte{
-		"deps/Android.bp":       []byte(depsBp),
-		"framework/Android.bp":  []byte(frameworkBp),
-		"framework/include.cpp": nil,
-		"framework/exclude.cpp": nil,
-		"device/Android.bp":     []byte(vendorProprietaryBp),
-		"device/recovery.cpp":   nil,
-	}
-
-	config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS)
-	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	ctx := CreateTestContext(config)
-	ctx.Register()
-
-	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"})
-	android.FailIfErrored(t, errs)
-	_, errs = ctx.PrepareBuildActions(config)
-	android.FailIfErrored(t, errs)
-
-	// Test an include and exclude framework module.
-	AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false, recoveryVariant)
-	AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true, recoveryVariant)
-	AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true, recoveryVariant)
-
-	// A recovery module is excluded, but by its path, not the
-	// exclude_from_recovery_snapshot property.
-	AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false, recoveryVariant)
-
-	// Verify the content of the recovery snapshot.
-
-	snapshotDir := "recovery-snapshot"
-	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
-
-	var includeJsonFiles []string
-	var excludeJsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-
-		// Included modules
-		CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json"))
-
-		// Excluded modules
-		CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
-		CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
-		CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
-	}
-
-	// Verify that each json file for an included module has a rule.
-	for _, jsonFile := range includeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("include json file %q not found", jsonFile)
-		}
-	}
-
-	// Verify that each json file for an excluded module has no rule.
-	for _, jsonFile := range excludeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
-			t.Errorf("exclude json file %q found", jsonFile)
-		}
-	}
-}
-
-func TestRecoverySnapshotDirected(t *testing.T) {
-	bp := `
-	cc_library_shared {
-		name: "librecovery",
-		recovery: true,
-		nocrt: true,
-	}
-
-	cc_library_shared {
-		name: "librecovery_available",
-		recovery_available: true,
-		nocrt: true,
-	}
-
-	genrule {
-		name: "libfoo_gen",
-		cmd: "",
-		out: ["libfoo.so"],
-	}
-
-	cc_prebuilt_library_shared {
-		name: "libfoo",
-		recovery: true,
-		prefer: true,
-		srcs: [":libfoo_gen"],
-	}
-
-	cc_library_shared {
-		name: "libfoo",
-		recovery: true,
-		nocrt: true,
-	}
-`
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	config.TestProductVariables.DirectedRecoverySnapshot = true
-	config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool)
-	config.TestProductVariables.RecoverySnapshotModules["librecovery"] = true
-	config.TestProductVariables.RecoverySnapshotModules["libfoo"] = true
-	ctx := testCcWithConfig(t, config)
-
-	// Check recovery snapshot output.
-
-	snapshotDir := "recovery-snapshot"
-	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
-
-	var includeJsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-
-		// Included modules
-		CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
-		// Check that snapshot captures "prefer: true" prebuilt
-		CheckSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json"))
-
-		// Excluded modules. Modules not included in the directed recovery snapshot
-		// are still include as fake modules.
-		CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery_available.so.json"))
-	}
-
-	// Verify that each json file for an included module has a rule.
-	for _, jsonFile := range includeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("include json file %q not found", jsonFile)
-		}
-	}
-}
-
-func TestSnapshotInRelativeInstallPath(t *testing.T) {
-	bp := `
-	cc_library {
-		name: "libvendor_available",
-		vendor_available: true,
-		nocrt: true,
-	}
-
-	cc_library {
-		name: "libvendor_available_var",
-		vendor_available: true,
-		stem: "libvendor_available",
-		relative_install_path: "var",
-		nocrt: true,
-	}
-`
-
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-	ctx := testCcWithConfig(t, config)
-
-	// Check Vendor snapshot output.
-
-	snapshotDir := "vendor-snapshot"
-	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
-
-	var jsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-		[]string{"arm", "armv7-a-neon"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		// For shared libraries, only non-VNDK vendor_available modules are captured
-		sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-		sharedDirVar := filepath.Join(sharedDir, "var")
-		CheckSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
-		CheckSnapshot(t, ctx, snapshotSingleton, "libvendor_available_var", "libvendor_available.so", sharedDirVar, sharedVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(sharedDir, "libvendor_available.so.json"),
-			filepath.Join(sharedDirVar, "libvendor_available.so.json"))
-	}
-
-	for _, jsonFile := range jsonFiles {
-		// verify all json files exist
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("%q expected but not found", jsonFile)
-		}
-	}
-
-	// fake snapshot should have all outputs in the normal snapshot.
-	fakeSnapshotSingleton := ctx.SingletonForTests("vendor-fake-snapshot")
-	for _, output := range snapshotSingleton.AllOutputs() {
-		fakeOutput := strings.Replace(output, "/vendor-snapshot/", "/fake/vendor-snapshot/", 1)
-		if fakeSnapshotSingleton.MaybeOutput(fakeOutput).Rule == nil {
-			t.Errorf("%q expected but not found", fakeOutput)
-		}
-	}
-}
diff --git a/cc/vndk.go b/cc/vndk.go
index 7a2286e..14b44b6 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -15,23 +15,21 @@
 package cc
 
 import (
-	"encoding/json"
 	"errors"
 	"fmt"
-	"path/filepath"
-	"sort"
 	"strings"
 
 	"android/soong/android"
 	"android/soong/cc/config"
 	"android/soong/etc"
-	"android/soong/snapshot"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
 const (
 	llndkLibrariesTxt                = "llndk.libraries.txt"
+	llndkLibrariesTxtForApex         = "llndk.libraries.txt.apex"
 	vndkCoreLibrariesTxt             = "vndkcore.libraries.txt"
 	vndkSpLibrariesTxt               = "vndksp.libraries.txt"
 	vndkPrivateLibrariesTxt          = "vndkprivate.libraries.txt"
@@ -39,25 +37,18 @@
 	vndkUsingCoreVariantLibrariesTxt = "vndkcorevariant.libraries.txt"
 )
 
-func VndkLibrariesTxtModules(vndkVersion string) []string {
-	if vndkVersion == "current" {
-		return []string{
-			llndkLibrariesTxt,
-			vndkCoreLibrariesTxt,
-			vndkSpLibrariesTxt,
-			vndkPrivateLibrariesTxt,
-			vndkProductLibrariesTxt,
-		}
-	}
+func VndkLibrariesTxtModules(vndkVersion string, ctx android.BaseModuleContext) []string {
 	// Snapshot vndks have their own *.libraries.VER.txt files.
 	// Note that snapshots don't have "vndkcorevariant.libraries.VER.txt"
-	return []string{
-		insertVndkVersion(llndkLibrariesTxt, vndkVersion),
+	result := []string{
 		insertVndkVersion(vndkCoreLibrariesTxt, vndkVersion),
 		insertVndkVersion(vndkSpLibrariesTxt, vndkVersion),
 		insertVndkVersion(vndkPrivateLibrariesTxt, vndkVersion),
 		insertVndkVersion(vndkProductLibrariesTxt, vndkVersion),
+		insertVndkVersion(llndkLibrariesTxt, vndkVersion),
 	}
+
+	return result
 }
 
 type VndkProperties struct {
@@ -352,28 +343,21 @@
 		return false
 	}
 
-	// prebuilt vndk modules should match with device
 	// TODO(b/142675459): Use enabled: to select target device in vndk_prebuilt_shared
 	// When b/142675459 is landed, remove following check
-	if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok && !p.MatchesWithDevice(mctx.DeviceConfig()) {
-		return false
+	if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
+		// prebuilt vndk modules should match with device
+		if !p.MatchesWithDevice(mctx.DeviceConfig()) {
+			return false
+		}
 	}
 
 	if lib, ok := m.linker.(libraryInterface); ok {
-		// VNDK APEX for VNDK-Lite devices will have VNDK-SP libraries from core variants
-		if mctx.DeviceConfig().VndkVersion() == "" {
-			// b/73296261: filter out libz.so because it is considered as LLNDK for VNDK-lite devices
-			if mctx.ModuleName() == "libz" {
-				return false
-			}
-			return m.ImageVariation().Variation == android.CoreVariation && lib.shared() && m.IsVndkSp() && !m.IsVndkExt()
-		}
 		// VNDK APEX doesn't need stub variants
 		if lib.buildStubs() {
 			return false
 		}
-		useCoreVariant := m.VndkVersion() == mctx.DeviceConfig().PlatformVndkVersion() &&
-			mctx.DeviceConfig().VndkUseCoreVariant() && !m.MustUseVendorVariant()
+		useCoreVariant := mctx.DeviceConfig().VndkUseCoreVariant() && !m.MustUseVendorVariant()
 		return lib.shared() && m.InVendor() && m.IsVndk() && !m.IsVndkExt() && !useCoreVariant
 	}
 	return false
@@ -393,11 +377,11 @@
 	lib, isLib := m.linker.(*libraryDecorator)
 	prebuiltLib, isPrebuiltLib := m.linker.(*prebuiltLibraryLinker)
 
-	if m.UseVndk() && isLib && lib.hasLLNDKStubs() {
+	if m.InVendorOrProduct() && isLib && lib.hasLLNDKStubs() {
 		m.VendorProperties.IsLLNDK = true
 		m.VendorProperties.IsVNDKPrivate = Bool(lib.Properties.Llndk.Private)
 	}
-	if m.UseVndk() && isPrebuiltLib && prebuiltLib.hasLLNDKStubs() {
+	if m.InVendorOrProduct() && isPrebuiltLib && prebuiltLib.hasLLNDKStubs() {
 		m.VendorProperties.IsLLNDK = true
 		m.VendorProperties.IsVNDKPrivate = Bool(prebuiltLib.Properties.Llndk.Private)
 	}
@@ -417,11 +401,11 @@
 
 func init() {
 	RegisterVndkLibraryTxtTypes(android.InitRegistrationContext)
-	android.RegisterParallelSingletonType("vndk-snapshot", VndkSnapshotSingleton)
 }
 
 func RegisterVndkLibraryTxtTypes(ctx android.RegistrationContext) {
 	ctx.RegisterParallelSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory)
+	ctx.RegisterParallelSingletonModuleType("llndk_libraries_txt_for_apex", llndkLibrariesTxtApexOnlyFactory)
 	ctx.RegisterParallelSingletonModuleType("vndksp_libraries_txt", vndkSPLibrariesTxtFactory)
 	ctx.RegisterParallelSingletonModuleType("vndkcore_libraries_txt", vndkCoreLibrariesTxtFactory)
 	ctx.RegisterParallelSingletonModuleType("vndkprivate_libraries_txt", vndkPrivateLibrariesTxtFactory)
@@ -445,22 +429,31 @@
 
 type VndkLibrariesTxtProperties struct {
 	Insert_vndk_version *bool
+	Stem                *string
 }
 
 var _ etc.PrebuiltEtcModule = &vndkLibrariesTxt{}
 var _ android.OutputFileProducer = &vndkLibrariesTxt{}
 
 // llndk_libraries_txt is a singleton module whose content is a list of LLNDK libraries
-// generated by Soong but can be referenced by other modules.
-// For example, apex_vndk can depend on these files as prebuilt.
+// generated by Soong.
 // Make uses LLNDK_LIBRARIES to determine which libraries to install.
-// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
+// HWASAN is only part of the LLNDK in builds in which libc depends on HWASAN.
 // Therefore, by removing the library here, we cause it to only be installed if libc
 // depends on it.
 func llndkLibrariesTxtFactory() android.SingletonModule {
 	return newVndkLibrariesWithMakeVarFilter(llndkLibraries, "LLNDK_LIBRARIES", "libclang_rt.hwasan")
 }
 
+// llndk_libraries_txt_for_apex is a singleton module that provide the same LLNDK libraries list
+// with the llndk_libraries_txt, but skips setting make variable LLNDK_LIBRARIES. So, it must not
+// be used without installing llndk_libraries_txt singleton.
+// We include llndk_libraries_txt by default to install the llndk.libraries.txt file to system/etc.
+// This singleton module is to install the llndk.libraries.<ver>.txt file to vndk apex.
+func llndkLibrariesTxtApexOnlyFactory() android.SingletonModule {
+	return newVndkLibrariesWithMakeVarFilter(llndkLibraries, "", "libclang_rt.hwasan")
+}
+
 // vndksp_libraries_txt is a singleton module whose content is a list of VNDKSP libraries
 // generated by Soong but can be referenced by other modules.
 // For example, apex_vndk can depend on these files as prebuilt.
@@ -519,12 +512,7 @@
 }
 
 func (txt *vndkLibrariesTxt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	var filename string
-	if BoolDefault(txt.properties.Insert_vndk_version, true) {
-		filename = insertVndkVersion(txt.Name(), ctx.DeviceConfig().PlatformVndkVersion())
-	} else {
-		filename = txt.Name()
-	}
+	filename := proptools.StringDefault(txt.properties.Stem, txt.Name())
 
 	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
 
@@ -550,6 +538,10 @@
 }
 
 func (txt *vndkLibrariesTxt) MakeVars(ctx android.MakeVarsContext) {
+	if txt.makeVarName == "" {
+		return
+	}
+
 	filter := func(modules []string, prefix string) []string {
 		if prefix == "" {
 			return modules
@@ -585,280 +577,6 @@
 func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) {
 	return android.Paths{txt.outputFile}, nil
 }
-
-func VndkSnapshotSingleton() android.Singleton {
-	return &vndkSnapshotSingleton{}
-}
-
-type vndkSnapshotSingleton struct {
-	vndkLibrariesFile   android.OutputPath
-	vndkSnapshotZipFile android.OptionalPath
-}
-
-func isVndkSnapshotAware(config android.DeviceConfig, m LinkableInterface,
-	apexInfo android.ApexInfo) (vndkType string, isVndkSnapshotLib bool) {
-
-	if m.Target().NativeBridge == android.NativeBridgeEnabled {
-		return "", false
-	}
-	// !inVendor: There's product/vendor variants for VNDK libs. We only care about vendor variants.
-	// !installable: Snapshot only cares about "installable" modules.
-	// !m.IsLlndk: llndk stubs are required for building against snapshots.
-	// IsSnapshotPrebuilt: Snapshotting a snapshot doesn't make sense.
-	// !outputFile.Valid: Snapshot requires valid output file.
-	if !m.InVendor() || (!installable(m, apexInfo) && !m.IsLlndk()) || m.IsSnapshotPrebuilt() || !m.OutputFile().Valid() {
-		return "", false
-	}
-	if !m.IsSnapshotLibrary() || !m.Shared() {
-		return "", false
-	}
-	if m.VndkVersion() == config.PlatformVndkVersion() {
-		if m.IsVndk() && !m.IsVndkExt() {
-			if m.IsVndkSp() {
-				return "vndk-sp", true
-			} else {
-				return "vndk-core", true
-			}
-		} else if m.HasLlndkStubs() && m.StubsVersion() == "" {
-			// Use default version for the snapshot.
-			return "llndk-stub", true
-		}
-	}
-
-	return "", false
-}
-
-func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	// build these files even if PlatformVndkVersion or BoardVndkVersion is not set
-	c.buildVndkLibrariesTxtFiles(ctx)
-
-	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a VNDK snapshot.
-	if ctx.DeviceConfig().VndkVersion() != "current" {
-		return
-	}
-
-	if ctx.DeviceConfig().PlatformVndkVersion() == "" {
-		return
-	}
-
-	var snapshotOutputs android.Paths
-
-	/*
-		VNDK snapshot zipped artifacts directory structure:
-		{SNAPSHOT_ARCH}/
-			arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
-				shared/
-					vndk-core/
-						(VNDK-core libraries, e.g. libbinder.so)
-					vndk-sp/
-						(VNDK-SP libraries, e.g. libc++.so)
-					llndk-stub/
-						(LLNDK stub libraries)
-			arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
-				shared/
-					vndk-core/
-						(VNDK-core libraries, e.g. libbinder.so)
-					vndk-sp/
-						(VNDK-SP libraries, e.g. libc++.so)
-					llndk-stub/
-						(LLNDK stub libraries)
-			binder32/
-				(This directory is newly introduced in v28 (Android P) to hold
-				prebuilts built for 32-bit binder interface.)
-				arch-{TARGET_ARCH}-{TARGE_ARCH_VARIANT}/
-					...
-			configs/
-				(various *.txt configuration files)
-			include/
-				(header files of same directory structure with source tree)
-			NOTICE_FILES/
-				(notice files of libraries, e.g. libcutils.so.txt)
-	*/
-
-	snapshotDir := "vndk-snapshot"
-	snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
-
-	configsDir := filepath.Join(snapshotArchDir, "configs")
-	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
-	includeDir := filepath.Join(snapshotArchDir, "include")
-
-	// set of notice files copied.
-	noticeBuilt := make(map[string]bool)
-
-	// paths of VNDK modules for GPL license checking
-	modulePaths := make(map[string]string)
-
-	// actual module names of .so files
-	// e.g. moduleNames["libprotobuf-cpp-full-3.9.1.so"] = "libprotobuf-cpp-full"
-	moduleNames := make(map[string]string)
-
-	var headers android.Paths
-
-	// installVndkSnapshotLib copies built .so file from the module.
-	// Also, if the build artifacts is on, write a json file which contains all exported flags
-	// with FlagExporterInfo.
-	installVndkSnapshotLib := func(m *Module, vndkType string) (android.Paths, bool) {
-		var ret android.Paths
-
-		targetArch := "arch-" + m.Target().Arch.ArchType.String()
-		if m.Target().Arch.ArchVariant != "" {
-			targetArch += "-" + m.Target().Arch.ArchVariant
-		}
-
-		libPath := m.outputFile.Path()
-		snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "shared", vndkType, libPath.Base())
-		ret = append(ret, snapshot.CopyFileRule(pctx, ctx, libPath, snapshotLibOut))
-
-		// json struct to export snapshot information
-		prop := struct {
-			MinSdkVersion       string   `json:",omitempty"`
-			LicenseKinds        []string `json:",omitempty"`
-			LicenseTexts        []string `json:",omitempty"`
-			ExportedDirs        []string `json:",omitempty"`
-			ExportedSystemDirs  []string `json:",omitempty"`
-			ExportedFlags       []string `json:",omitempty"`
-			RelativeInstallPath string   `json:",omitempty"`
-		}{}
-
-		prop.LicenseKinds = m.EffectiveLicenseKinds()
-		prop.LicenseTexts = m.EffectiveLicenseFiles().Strings()
-		prop.MinSdkVersion = m.MinSdkVersion()
-
-		if ctx.Config().VndkSnapshotBuildArtifacts() {
-			exportedInfo := ctx.ModuleProvider(m, FlagExporterInfoProvider).(FlagExporterInfo)
-			prop.ExportedFlags = exportedInfo.Flags
-			prop.ExportedDirs = exportedInfo.IncludeDirs.Strings()
-			prop.ExportedSystemDirs = exportedInfo.SystemIncludeDirs.Strings()
-			prop.RelativeInstallPath = m.RelativeInstallPath()
-		}
-
-		propOut := snapshotLibOut + ".json"
-
-		j, err := json.Marshal(prop)
-		if err != nil {
-			ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
-			return nil, false
-		}
-		ret = append(ret, snapshot.WriteStringToFileRule(ctx, string(j), propOut))
-
-		return ret, true
-	}
-
-	ctx.VisitAllModules(func(module android.Module) {
-		m, ok := module.(*Module)
-		if !ok || !m.Enabled() {
-			return
-		}
-
-		apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
-
-		vndkType, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo)
-		if !ok {
-			return
-		}
-
-		// For all snapshot candidates, the followings are captured.
-		//   - .so files
-		//   - notice files
-		//
-		// The followings are also captured if VNDK_SNAPSHOT_BUILD_ARTIFACTS.
-		//   - .json files containing exported flags
-		//   - exported headers from collectHeadersForSnapshot()
-		//
-		// Headers are deduplicated after visiting all modules.
-
-		// install .so files for appropriate modules.
-		// Also install .json files if VNDK_SNAPSHOT_BUILD_ARTIFACTS
-		libs, ok := installVndkSnapshotLib(m, vndkType)
-		if !ok {
-			return
-		}
-		snapshotOutputs = append(snapshotOutputs, libs...)
-
-		// These are for generating module_names.txt and module_paths.txt
-		stem := m.outputFile.Path().Base()
-		moduleNames[stem] = ctx.ModuleName(m)
-		modulePaths[stem] = ctx.ModuleDir(m)
-
-		for _, notice := range m.EffectiveLicenseFiles() {
-			if _, ok := noticeBuilt[notice.String()]; !ok {
-				noticeBuilt[notice.String()] = true
-				snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule(
-					pctx, ctx, notice, filepath.Join(noticeDir, notice.String())))
-			}
-		}
-
-		if ctx.Config().VndkSnapshotBuildArtifacts() {
-			headers = append(headers, m.SnapshotHeaders()...)
-		}
-	})
-
-	// install all headers after removing duplicates
-	for _, header := range android.FirstUniquePaths(headers) {
-		snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule(
-			pctx, ctx, header, filepath.Join(includeDir, header.String())))
-	}
-
-	// install *.libraries.txt except vndkcorevariant.libraries.txt
-	ctx.VisitAllModules(func(module android.Module) {
-		m, ok := module.(*vndkLibrariesTxt)
-		if !ok || !m.Enabled() || m.Name() == vndkUsingCoreVariantLibrariesTxt {
-			return
-		}
-		snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule(
-			pctx, ctx, m.OutputFile(), filepath.Join(configsDir, m.Name())))
-	})
-
-	/*
-		module_paths.txt contains paths on which VNDK modules are defined.
-		e.g.,
-			libbase.so system/libbase
-			libc.so bionic/libc
-			...
-	*/
-	snapshotOutputs = append(snapshotOutputs, installMapListFileRule(ctx, modulePaths, filepath.Join(configsDir, "module_paths.txt")))
-
-	/*
-		module_names.txt contains names as which VNDK modules are defined,
-		because output filename and module name can be different with stem and suffix properties.
-
-		e.g.,
-			libcutils.so libcutils
-			libprotobuf-cpp-full-3.9.2.so libprotobuf-cpp-full
-			...
-	*/
-	snapshotOutputs = append(snapshotOutputs, installMapListFileRule(ctx, moduleNames, filepath.Join(configsDir, "module_names.txt")))
-
-	// All artifacts are ready. Sort them to normalize ninja and then zip.
-	sort.Slice(snapshotOutputs, func(i, j int) bool {
-		return snapshotOutputs[i].String() < snapshotOutputs[j].String()
-	})
-
-	zipPath := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+".zip")
-	zipRule := android.NewRuleBuilder(pctx, ctx)
-
-	// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr
-	snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+"_list")
-	rspFile := snapshotOutputList.ReplaceExtension(ctx, "rsp")
-	zipRule.Command().
-		Text("tr").
-		FlagWithArg("-d ", "\\'").
-		FlagWithRspFileInputList("< ", rspFile, snapshotOutputs).
-		FlagWithOutput("> ", snapshotOutputList)
-
-	zipRule.Temporary(snapshotOutputList)
-
-	zipRule.Command().
-		BuiltTool("soong_zip").
-		FlagWithOutput("-o ", zipPath).
-		FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()).
-		FlagWithInput("-l ", snapshotOutputList)
-
-	zipRule.Build(zipPath.String(), "vndk snapshot "+zipPath.String())
-	zipRule.DeleteTemporaryFiles()
-	c.vndkSnapshotZipFile = android.OptionalPathForPath(zipPath)
-}
-
 func getVndkFileName(m *Module) (string, error) {
 	if library, ok := m.linker.(*libraryDecorator); ok {
 		return library.getLibNameHelper(m.BaseModuleName(), true, false) + ".so", nil
@@ -868,43 +586,3 @@
 	}
 	return "", fmt.Errorf("VNDK library should have libraryDecorator or prebuiltLibraryLinker as linker: %T", m.linker)
 }
-
-func (c *vndkSnapshotSingleton) buildVndkLibrariesTxtFiles(ctx android.SingletonContext) {
-	// Build list of vndk libs as merged & tagged & filter-out(libclang_rt):
-	// Since each target have different set of libclang_rt.* files,
-	// keep the common set of files in vndk.libraries.txt
-	_, llndk := vndkModuleListRemover(llndkLibraries, "libclang_rt.")(ctx)
-	_, vndkcore := vndkModuleListRemover(vndkCoreLibraries, "libclang_rt.")(ctx)
-	_, vndksp := vndkSPLibraries(ctx)
-	_, vndkprivate := vndkPrivateLibraries(ctx)
-	_, vndkproduct := vndkModuleListRemover(vndkProductLibraries, "libclang_rt.")(ctx)
-	var merged []string
-	merged = append(merged, addPrefix(llndk, "LLNDK: ")...)
-	merged = append(merged, addPrefix(vndksp, "VNDK-SP: ")...)
-	merged = append(merged, addPrefix(vndkcore, "VNDK-core: ")...)
-	merged = append(merged, addPrefix(vndkprivate, "VNDK-private: ")...)
-	merged = append(merged, addPrefix(vndkproduct, "VNDK-product: ")...)
-	c.vndkLibrariesFile = android.PathForOutput(ctx, "vndk", "vndk.libraries.txt")
-	android.WriteFileRule(ctx, c.vndkLibrariesFile, strings.Join(merged, "\n"))
-}
-
-func (c *vndkSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
-	// Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if
-	// they been moved to an apex.
-	movedToApexLlndkLibraries := make(map[string]bool)
-	ctx.VisitAllModules(func(module android.Module) {
-		if library := moduleLibraryInterface(module); library != nil && library.hasLLNDKStubs() {
-			// Skip bionic libs, they are handled in different manner
-			name := library.implementationModuleName(module.(*Module).BaseModuleName())
-			if module.(android.ApexModule).DirectlyInAnyApex() && !isBionic(name) {
-				movedToApexLlndkLibraries[name] = true
-			}
-		}
-	})
-
-	ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES",
-		strings.Join(android.SortedKeys(movedToApexLlndkLibraries), " "))
-
-	ctx.Strict("VNDK_LIBRARIES_FILE", c.vndkLibrariesFile.String())
-	ctx.Strict("SOONG_VNDK_SNAPSHOT_ZIP", c.vndkSnapshotZipFile.String())
-}
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 37819a4..4d2412f 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -131,7 +131,6 @@
 
 func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
-
 	if !p.MatchesWithDevice(ctx.DeviceConfig()) {
 		ctx.Module().HideFromMake()
 		return nil
@@ -160,12 +159,7 @@
 
 		p.androidMkSuffix = p.NameSuffix()
 
-		vndkVersion := ctx.DeviceConfig().VndkVersion()
-		if vndkVersion == p.Version() {
-			p.androidMkSuffix = ""
-		}
-
-		ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+		android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
 			SharedLibrary: in,
 			Target:        ctx.Target(),
 
@@ -181,6 +175,11 @@
 	return nil
 }
 
+func (p *vndkPrebuiltLibraryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
+	p.libraryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
+	moduleInfoJSON.SubName += p.androidMkSuffix
+}
+
 func (p *vndkPrebuiltLibraryDecorator) MatchesWithDevice(config android.DeviceConfig) bool {
 	arches := config.Arches()
 	if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
@@ -221,6 +220,7 @@
 	prebuilt.properties.Check_elf_files = BoolPtr(false)
 	prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true)
 	prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true)
+	prebuilt.baseLinker.Properties.No_crt_pad_segment = BoolPtr(true)
 
 	// Prevent default system libs (libc, libm, and libdl) from being linked
 	if prebuilt.baseLinker.Properties.System_shared_libs == nil {
@@ -235,14 +235,6 @@
 		&prebuilt.properties,
 	)
 
-	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
-		// empty BOARD_VNDK_VERSION implies that the device won't support
-		// system only OTA. In this case, VNDK snapshots aren't needed.
-		if ctx.DeviceConfig().VndkVersion() == "" {
-			ctx.Module().Disable()
-		}
-	})
-
 	return module
 }
 
diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go
index 2e71fe1..a7308b4 100644
--- a/cmd/extract_apks/main.go
+++ b/cmd/extract_apks/main.go
@@ -76,8 +76,8 @@
 	if err != nil {
 		return nil, err
 	}
-	bytes := make([]byte, tocFile.FileHeader.UncompressedSize64)
-	if _, err := rc.Read(bytes); err != nil && err != io.EOF {
+	bytes, err := io.ReadAll(rc)
+	if err != nil {
 		return nil, err
 	}
 	rc.Close()
diff --git a/starlark_import/Android.bp b/cmd/merge_module_info_json/Android.bp
similarity index 62%
copy from starlark_import/Android.bp
copy to cmd/merge_module_info_json/Android.bp
index b43217b..1ae6a47 100644
--- a/starlark_import/Android.bp
+++ b/cmd/merge_module_info_json/Android.bp
@@ -1,4 +1,4 @@
-// Copyright 2023 Google Inc. All rights reserved.
+// Copyright 2021 Google Inc. All rights reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -16,21 +16,15 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-bootstrap_go_package {
-    name: "soong-starlark",
-    pkgPath: "android/soong/starlark_import",
+blueprint_go_binary {
+    name: "merge_module_info_json",
     srcs: [
-        "starlark_import.go",
-        "unmarshal.go",
-    ],
-    testSrcs: [
-        "starlark_import_test.go",
-        "unmarshal_test.go",
+        "merge_module_info_json.go",
     ],
     deps: [
-        "go-starlark-starlark",
-        "go-starlark-starlarkstruct",
-        "go-starlark-starlarkjson",
-        "go-starlark-starlarktest",
+        "soong-response",
+    ],
+    testSrcs: [
+        "merge_module_info_json_test.go",
     ],
 }
diff --git a/cmd/merge_module_info_json/merge_module_info_json.go b/cmd/merge_module_info_json/merge_module_info_json.go
new file mode 100644
index 0000000..0143984
--- /dev/null
+++ b/cmd/merge_module_info_json/merge_module_info_json.go
@@ -0,0 +1,223 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// merge_module_info_json is a utility that merges module_info.json files generated by
+// Soong and Make.
+
+package main
+
+import (
+	"android/soong/response"
+	"cmp"
+	"encoding/json"
+	"flag"
+	"fmt"
+	"os"
+	"slices"
+)
+
+var (
+	out      = flag.String("o", "", "output file")
+	listFile = flag.String("l", "", "input file list file")
+)
+
+func usage() {
+	fmt.Fprintf(os.Stderr, "usage: %s -o <output file> <input files>\n", os.Args[0])
+	flag.PrintDefaults()
+	fmt.Fprintln(os.Stderr, "merge_module_info_json reads input files that each contain an array of json objects")
+	fmt.Fprintln(os.Stderr, "and writes them out as a single json array to the output file.")
+
+	os.Exit(2)
+}
+
+func main() {
+	flag.Usage = usage
+	flag.Parse()
+
+	if *out == "" {
+		fmt.Fprintf(os.Stderr, "%s: error: -o is required\n", os.Args[0])
+		usage()
+	}
+
+	inputs := flag.Args()
+	if *listFile != "" {
+		listFileInputs, err := readListFile(*listFile)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "failed to read list file %s: %s", *listFile, err)
+			os.Exit(1)
+		}
+		inputs = append(inputs, listFileInputs...)
+	}
+
+	err := mergeJsonObjects(*out, inputs)
+
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "%s: error: %s\n", os.Args[0], err.Error())
+		os.Exit(1)
+	}
+}
+
+func readListFile(file string) ([]string, error) {
+	f, err := os.Open(*listFile)
+	if err != nil {
+		return nil, err
+	}
+	return response.ReadRspFile(f)
+}
+
+func mergeJsonObjects(output string, inputs []string) error {
+	combined := make(map[string]any)
+	for _, input := range inputs {
+		objects, err := decodeObjectFromJson(input)
+		if err != nil {
+			return err
+		}
+
+		for _, object := range objects {
+			for k, v := range object {
+				if old, exists := combined[k]; exists {
+					v = combine(old, v)
+				}
+				combined[k] = v
+			}
+		}
+	}
+
+	f, err := os.Create(output)
+	if err != nil {
+		return fmt.Errorf("failed to open output file: %w", err)
+	}
+	encoder := json.NewEncoder(f)
+	encoder.SetIndent("", "  ")
+	err = encoder.Encode(combined)
+	if err != nil {
+		return fmt.Errorf("failed to encode to output file: %w", err)
+	}
+
+	return nil
+}
+
+func decodeObjectFromJson(input string) ([]map[string]any, error) {
+	f, err := os.Open(input)
+	if err != nil {
+		return nil, fmt.Errorf("failed to open input file: %w", err)
+	}
+
+	decoder := json.NewDecoder(f)
+	var object any
+	err = decoder.Decode(&object)
+	if err != nil {
+		return nil, fmt.Errorf("failed to parse input file %q: %w", input, err)
+	}
+
+	switch o := object.(type) {
+	case []any:
+		var ret []map[string]any
+		for _, arrayElement := range o {
+			if m, ok := arrayElement.(map[string]any); ok {
+				ret = append(ret, m)
+			} else {
+				return nil, fmt.Errorf("unknown JSON type in array %T", arrayElement)
+			}
+		}
+		return ret, nil
+
+	case map[string]any:
+		return []map[string]any{o}, nil
+	}
+
+	return nil, fmt.Errorf("unknown JSON type %T", object)
+}
+
+func combine(old, new any) any {
+	//	fmt.Printf("%#v %#v\n", old, new)
+	switch oldTyped := old.(type) {
+	case map[string]any:
+		if newObject, ok := new.(map[string]any); ok {
+			return combineObjects(oldTyped, newObject)
+		} else {
+			panic(fmt.Errorf("expected map[string]any, got %#v", new))
+		}
+	case []any:
+		if newArray, ok := new.([]any); ok {
+			return combineArrays(oldTyped, newArray)
+		} else {
+			panic(fmt.Errorf("expected []any, got %#v", new))
+		}
+	case string:
+		if newString, ok := new.(string); ok {
+			if oldTyped != newString {
+				panic(fmt.Errorf("strings %q and %q don't match", oldTyped, newString))
+			}
+			return oldTyped
+		} else {
+			panic(fmt.Errorf("expected []any, got %#v", new))
+		}
+	default:
+		panic(fmt.Errorf("can't combine type %T", old))
+	}
+}
+
+func combineObjects(old, new map[string]any) map[string]any {
+	for k, newField := range new {
+		// HACK: Don't merge "test_config" field.  This matches the behavior in base_rules.mk that overwrites
+		// instead of appending ALL_MODULES.$(my_register_name).TEST_CONFIG, keeping the
+		if k == "test_config" {
+			old[k] = newField
+			continue
+		}
+		if oldField, exists := old[k]; exists {
+			oldField = combine(oldField, newField)
+			old[k] = oldField
+		} else {
+			old[k] = newField
+		}
+	}
+
+	return old
+}
+
+func combineArrays(old, new []any) []any {
+	containsNonStrings := false
+	for _, oldElement := range old {
+		switch oldElement.(type) {
+		case string:
+		default:
+			containsNonStrings = true
+		}
+	}
+	for _, newElement := range new {
+		found := false
+		for _, oldElement := range old {
+			if oldElement == newElement {
+				found = true
+				break
+			}
+		}
+		if !found {
+			switch newElement.(type) {
+			case string:
+			default:
+				containsNonStrings = true
+			}
+			old = append(old, newElement)
+		}
+	}
+	if !containsNonStrings {
+		slices.SortFunc(old, func(a, b any) int {
+			return cmp.Compare(a.(string), b.(string))
+		})
+	}
+	return old
+}
diff --git a/cmd/merge_module_info_json/merge_module_info_json_test.go b/cmd/merge_module_info_json/merge_module_info_json_test.go
new file mode 100644
index 0000000..dbf1aa1
--- /dev/null
+++ b/cmd/merge_module_info_json/merge_module_info_json_test.go
@@ -0,0 +1,58 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"reflect"
+	"testing"
+)
+
+func Test_combine(t *testing.T) {
+	tests := []struct {
+		name string
+		old  any
+		new  any
+		want any
+	}{
+		{
+			name: "objects",
+			old: map[string]any{
+				"foo": "bar",
+				"baz": []any{"a"},
+			},
+			new: map[string]any{
+				"foo": "bar",
+				"baz": []any{"b"},
+			},
+			want: map[string]any{
+				"foo": "bar",
+				"baz": []any{"a", "b"},
+			},
+		},
+		{
+			name: "arrays",
+			old:  []any{"foo", "bar"},
+			new:  []any{"foo", "baz"},
+			want: []any{"bar", "baz", "foo"},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := combine(tt.old, tt.new); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("combine() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index a70a9d1..2c57180 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -96,7 +96,9 @@
 	if err := ze.inputZip.Open(); err != nil {
 		return err
 	}
-	return zw.CopyFrom(ze.inputZip.Entries()[ze.index], dest)
+	entry := ze.inputZip.Entries()[ze.index]
+	entry.SetModTime(jar.DefaultTime)
+	return zw.CopyFrom(entry, dest)
 }
 
 // a ZipEntryFromBuffer is a ZipEntryContents that pulls its content from a []byte
@@ -340,7 +342,8 @@
 func (oz *OutputZip) getUninitializedPythonPackages(inputZips []InputZip) ([]string, error) {
 	// the runfiles packages needs to be populated with "__init__.py".
 	// the runfiles dirs have been treated as packages.
-	allPackages := make(map[string]bool)
+	var allPackages []string // Using a slice to preserve input order.
+	seenPkgs := make(map[string]bool)
 	initedPackages := make(map[string]bool)
 	getPackage := func(path string) string {
 		ret := filepath.Dir(path)
@@ -367,16 +370,17 @@
 				initedPackages[pyPkg] = true
 			}
 			for pyPkg != "" {
-				if _, found := allPackages[pyPkg]; found {
+				if _, found := seenPkgs[pyPkg]; found {
 					break
 				}
-				allPackages[pyPkg] = true
+				seenPkgs[pyPkg] = true
+				allPackages = append(allPackages, pyPkg)
 				pyPkg = getPackage(pyPkg)
 			}
 		}
 	}
 	noInitPackages := make([]string, 0)
-	for pyPkg := range allPackages {
+	for _, pyPkg := range allPackages {
 		if _, found := initedPackages[pyPkg]; !found {
 			noInitPackages = append(noInitPackages, pyPkg)
 		}
diff --git a/cmd/merge_zips/merge_zips_test.go b/cmd/merge_zips/merge_zips_test.go
index 767d4e61..17228c4 100644
--- a/cmd/merge_zips/merge_zips_test.go
+++ b/cmd/merge_zips/merge_zips_test.go
@@ -22,40 +22,45 @@
 	"strconv"
 	"strings"
 	"testing"
+	"time"
 
 	"android/soong/jar"
 	"android/soong/third_party/zip"
 )
 
 type testZipEntry struct {
-	name   string
-	mode   os.FileMode
-	data   []byte
-	method uint16
+	name      string
+	mode      os.FileMode
+	data      []byte
+	method    uint16
+	timestamp time.Time
 }
 
 var (
-	A     = testZipEntry{"A", 0755, []byte("foo"), zip.Deflate}
-	a     = testZipEntry{"a", 0755, []byte("foo"), zip.Deflate}
-	a2    = testZipEntry{"a", 0755, []byte("FOO2"), zip.Deflate}
-	a3    = testZipEntry{"a", 0755, []byte("Foo3"), zip.Deflate}
-	bDir  = testZipEntry{"b/", os.ModeDir | 0755, nil, zip.Deflate}
-	bbDir = testZipEntry{"b/b/", os.ModeDir | 0755, nil, zip.Deflate}
-	bbb   = testZipEntry{"b/b/b", 0755, nil, zip.Deflate}
-	ba    = testZipEntry{"b/a", 0755, []byte("foo"), zip.Deflate}
-	bc    = testZipEntry{"b/c", 0755, []byte("bar"), zip.Deflate}
-	bd    = testZipEntry{"b/d", 0700, []byte("baz"), zip.Deflate}
-	be    = testZipEntry{"b/e", 0700, []byte(""), zip.Deflate}
+	A     = testZipEntry{"A", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime}
+	a     = testZipEntry{"a", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime}
+	a2    = testZipEntry{"a", 0755, []byte("FOO2"), zip.Deflate, jar.DefaultTime}
+	a3    = testZipEntry{"a", 0755, []byte("Foo3"), zip.Deflate, jar.DefaultTime}
+	bDir  = testZipEntry{"b/", os.ModeDir | 0755, nil, zip.Deflate, jar.DefaultTime}
+	bbDir = testZipEntry{"b/b/", os.ModeDir | 0755, nil, zip.Deflate, jar.DefaultTime}
+	bbb   = testZipEntry{"b/b/b", 0755, nil, zip.Deflate, jar.DefaultTime}
+	ba    = testZipEntry{"b/a", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime}
+	bc    = testZipEntry{"b/c", 0755, []byte("bar"), zip.Deflate, jar.DefaultTime}
+	bd    = testZipEntry{"b/d", 0700, []byte("baz"), zip.Deflate, jar.DefaultTime}
+	be    = testZipEntry{"b/e", 0700, []byte(""), zip.Deflate, jar.DefaultTime}
 
-	service1a        = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\n"), zip.Store}
-	service1b        = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass3\n"), zip.Deflate}
-	service1combined = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\nclass3\n"), zip.Store}
-	service2         = testZipEntry{"META-INF/services/service2", 0755, []byte("class1\nclass2\n"), zip.Deflate}
+	withTimestamp    = testZipEntry{"timestamped", 0755, nil, zip.Store, jar.DefaultTime.Add(time.Hour)}
+	withoutTimestamp = testZipEntry{"timestamped", 0755, nil, zip.Store, jar.DefaultTime}
 
-	metainfDir     = testZipEntry{jar.MetaDir, os.ModeDir | 0755, nil, zip.Deflate}
-	manifestFile   = testZipEntry{jar.ManifestFile, 0755, []byte("manifest"), zip.Deflate}
-	manifestFile2  = testZipEntry{jar.ManifestFile, 0755, []byte("manifest2"), zip.Deflate}
-	moduleInfoFile = testZipEntry{jar.ModuleInfoClass, 0755, []byte("module-info"), zip.Deflate}
+	service1a        = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\n"), zip.Store, jar.DefaultTime}
+	service1b        = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass3\n"), zip.Deflate, jar.DefaultTime}
+	service1combined = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\nclass3\n"), zip.Store, jar.DefaultTime}
+	service2         = testZipEntry{"META-INF/services/service2", 0755, []byte("class1\nclass2\n"), zip.Deflate, jar.DefaultTime}
+
+	metainfDir     = testZipEntry{jar.MetaDir, os.ModeDir | 0755, nil, zip.Deflate, jar.DefaultTime}
+	manifestFile   = testZipEntry{jar.ManifestFile, 0755, []byte("manifest"), zip.Deflate, jar.DefaultTime}
+	manifestFile2  = testZipEntry{jar.ManifestFile, 0755, []byte("manifest2"), zip.Deflate, jar.DefaultTime}
+	moduleInfoFile = testZipEntry{jar.ModuleInfoClass, 0755, []byte("module-info"), zip.Deflate, jar.DefaultTime}
 )
 
 type testInputZip struct {
@@ -98,6 +103,7 @@
 		stripFiles       []string
 		stripDirs        []string
 		jar              bool
+		par              bool
 		sort             bool
 		ignoreDuplicates bool
 		stripDirEntries  bool
@@ -252,6 +258,42 @@
 			jar: true,
 			out: []testZipEntry{service1combined, service2},
 		},
+		{
+			name: "strip timestamps",
+			in: [][]testZipEntry{
+				{withTimestamp},
+				{a},
+			},
+			out: []testZipEntry{withoutTimestamp, a},
+		},
+		{
+			name: "emulate par",
+			in: [][]testZipEntry{
+				{
+					testZipEntry{name: "3/main.py"},
+					testZipEntry{name: "c/main.py"},
+					testZipEntry{name: "a/main.py"},
+					testZipEntry{name: "2/main.py"},
+					testZipEntry{name: "b/main.py"},
+					testZipEntry{name: "1/main.py"},
+				},
+			},
+			out: []testZipEntry{
+				testZipEntry{name: "3/__init__.py", mode: 0700, timestamp: jar.DefaultTime},
+				testZipEntry{name: "c/__init__.py", mode: 0700, timestamp: jar.DefaultTime},
+				testZipEntry{name: "a/__init__.py", mode: 0700, timestamp: jar.DefaultTime},
+				testZipEntry{name: "2/__init__.py", mode: 0700, timestamp: jar.DefaultTime},
+				testZipEntry{name: "b/__init__.py", mode: 0700, timestamp: jar.DefaultTime},
+				testZipEntry{name: "1/__init__.py", mode: 0700, timestamp: jar.DefaultTime},
+				testZipEntry{name: "3/main.py", timestamp: jar.DefaultTime},
+				testZipEntry{name: "c/main.py", timestamp: jar.DefaultTime},
+				testZipEntry{name: "a/main.py", timestamp: jar.DefaultTime},
+				testZipEntry{name: "2/main.py", timestamp: jar.DefaultTime},
+				testZipEntry{name: "b/main.py", timestamp: jar.DefaultTime},
+				testZipEntry{name: "1/main.py", timestamp: jar.DefaultTime},
+			},
+			par: true,
+		},
 	}
 
 	for _, test := range testCases {
@@ -267,7 +309,7 @@
 			writer := zip.NewWriter(out)
 
 			err := mergeZips(inputZips, writer, "", "",
-				test.sort, test.jar, false, test.stripDirEntries, test.ignoreDuplicates,
+				test.sort, test.jar, test.par, test.stripDirEntries, test.ignoreDuplicates,
 				test.stripFiles, test.stripDirs, test.zipsToNotStrip)
 
 			closeErr := writer.Close()
@@ -307,6 +349,7 @@
 		}
 		fh.SetMode(e.mode)
 		fh.Method = e.method
+		fh.SetModTime(e.timestamp)
 		fh.UncompressedSize64 = uint64(len(e.data))
 		fh.CRC32 = crc32.ChecksumIEEE(e.data)
 		if fh.Method == zip.Store {
@@ -354,7 +397,7 @@
 	var ret string
 
 	for _, f := range zr.File {
-		ret += fmt.Sprintf("%v: %v %v %08x\n", f.Name, f.Mode(), f.UncompressedSize64, f.CRC32)
+		ret += fmt.Sprintf("%v: %v %v %08x %s\n", f.Name, f.Mode(), f.UncompressedSize64, f.CRC32, f.ModTime())
 	}
 
 	return ret
diff --git a/cmd/path_interposer/main.go b/cmd/path_interposer/main.go
index 8b9de52..c8c1464 100644
--- a/cmd/path_interposer/main.go
+++ b/cmd/path_interposer/main.go
@@ -140,7 +140,7 @@
 			defer func() { <-waitForLog }()
 		}
 		if config.Error {
-			return 1, fmt.Errorf("%q is not allowed to be used. See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.", base)
+			return 1, fmt.Errorf("%q is not allowed to be used. See https://android.googlesource.com/platform/build/+/main/Changes.md#PATH_Tools for more information.", base)
 		}
 	}
 
diff --git a/cmd/path_interposer/main_test.go b/cmd/path_interposer/main_test.go
index c89d623..8ae1d7d 100644
--- a/cmd/path_interposer/main_test.go
+++ b/cmd/path_interposer/main_test.go
@@ -138,7 +138,7 @@
 			args: []string{"path_interposer_test_not_allowed"},
 
 			exitCode: 1,
-			err:      fmt.Errorf(`"path_interposer_test_not_allowed" is not allowed to be used. See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.`),
+			err:      fmt.Errorf(`"path_interposer_test_not_allowed" is not allowed to be used. See https://android.googlesource.com/platform/build/+/main/Changes.md#PATH_Tools for more information.`),
 			logEntry: "path_interposer_test_not_allowed",
 		},
 	}
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index 3fb4454..6d1caf9 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -651,7 +651,7 @@
         {{- end}}
     ],
     {{- end}}
-    java_version: "1.7",
+    java_version: "1.8",
 }
 `))
 
diff --git a/cmd/pom2mk/pom2mk.go b/cmd/pom2mk/pom2mk.go
index b347155..5ca770e 100644
--- a/cmd/pom2mk/pom2mk.go
+++ b/cmd/pom2mk/pom2mk.go
@@ -262,7 +262,7 @@
   {{.MkName}}-nodeps{{end}}{{range .MkAarDeps}}  \
   {{.}}{{end}}
 LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_USE_AAPT2 := true
 include $(BUILD_STATIC_JAVA_LIBRARY)
 `))
diff --git a/cmd/release_config/build_flag/Android.bp b/cmd/release_config/build_flag/Android.bp
new file mode 100644
index 0000000..0f10c91
--- /dev/null
+++ b/cmd/release_config/build_flag/Android.bp
@@ -0,0 +1,32 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+    name: "build-flag",
+    deps: [
+        "golang-protobuf-encoding-prototext",
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+        "soong-cmd-release_config-proto",
+        "soong-cmd-release_config-lib",
+    ],
+    srcs: [
+        "main.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "soong-cmd-release_config-build_flag",
+    pkgPath: "android/soong/cmd/release_config/build_flag",
+    deps: [
+        "golang-protobuf-encoding-prototext",
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+        "soong-cmd-release_config-proto",
+        "soong-cmd-release_config-lib",
+    ],
+    srcs: [
+        "main.go",
+    ],
+}
diff --git a/cmd/release_config/build_flag/main.go b/cmd/release_config/build_flag/main.go
new file mode 100644
index 0000000..ec7d64f
--- /dev/null
+++ b/cmd/release_config/build_flag/main.go
@@ -0,0 +1,351 @@
+package main
+
+import (
+	"cmp"
+	"flag"
+	"fmt"
+	"os"
+	"path/filepath"
+	"slices"
+	"strings"
+
+	rc_lib "android/soong/cmd/release_config/release_config_lib"
+	rc_proto "android/soong/cmd/release_config/release_config_proto"
+
+	"google.golang.org/protobuf/proto"
+)
+
+type Flags struct {
+	// The path to the top of the workspace.  Default: ".".
+	top string
+
+	// Pathlist of release config map textproto files.
+	// If not specified, then the value is (if present):
+	// - build/release/release_config_map.textproto
+	// - vendor/google_shared/build/release/release_config_map.textproto
+	// - vendor/google/release/release_config_map.textproto
+	//
+	// Additionally, any maps specified in the environment variable
+	// `PRODUCT_RELEASE_CONFIG_MAPS` are used.
+	maps rc_lib.StringList
+
+	// Output directory (relative to `top`).
+	outDir string
+
+	// Which $TARGET_RELEASE(s) should we use.  Some commands will only
+	// accept one value, others also accept `--release --all`.
+	targetReleases rc_lib.StringList
+
+	// Disable warning messages
+	quiet bool
+
+	// Show all release configs
+	allReleases bool
+
+	// Call get_build_var PRODUCT_RELEASE_CONFIG_MAPS to get the
+	// product-specific map directories.
+	useGetBuildVar bool
+
+	// Panic on errors.
+	debug bool
+}
+
+type CommandFunc func(*rc_lib.ReleaseConfigs, Flags, string, []string) error
+
+var commandMap map[string]CommandFunc = map[string]CommandFunc{
+	"get":   GetCommand,
+	"set":   SetCommand,
+	"trace": GetCommand, // Also handled by GetCommand
+}
+
+// Find the top of the release config contribution directory.
+// Returns the parent of the flag_declarations and flag_values directories.
+func GetMapDir(path string) (string, error) {
+	for p := path; p != "."; p = filepath.Dir(p) {
+		switch filepath.Base(p) {
+		case "flag_declarations":
+			return filepath.Dir(p), nil
+		case "flag_values":
+			return filepath.Dir(p), nil
+		}
+	}
+	return "", fmt.Errorf("Could not determine directory from %s", path)
+}
+
+func MarshalFlagDefaultValue(config *rc_lib.ReleaseConfig, name string) (ret string, err error) {
+	fa, ok := config.FlagArtifacts[name]
+	if !ok {
+		return "", fmt.Errorf("%s not found in %s", name, config.Name)
+	}
+	return rc_lib.MarshalValue(fa.Traces[0].Value), nil
+}
+
+func MarshalFlagValue(config *rc_lib.ReleaseConfig, name string) (ret string, err error) {
+	fa, ok := config.FlagArtifacts[name]
+	if !ok {
+		return "", fmt.Errorf("%s not found in %s", name, config.Name)
+	}
+	return rc_lib.MarshalValue(fa.Value), nil
+}
+
+// Returns a list of ReleaseConfig objects for which to process flags.
+func GetReleaseArgs(configs *rc_lib.ReleaseConfigs, commonFlags Flags) ([]*rc_lib.ReleaseConfig, error) {
+	var all bool
+	relFlags := flag.NewFlagSet("releaseFlags", flag.ExitOnError)
+	relFlags.BoolVar(&all, "all", false, "Display all releases")
+	relFlags.Parse(commonFlags.targetReleases)
+	var ret []*rc_lib.ReleaseConfig
+	if all || commonFlags.allReleases {
+		sortMap := map[string]int{
+			"trunk_staging": 0,
+			"trunk_food":    10,
+			"trunk":         20,
+			// Anything not listed above, uses this for key 1 in the sort.
+			"-default": 100,
+		}
+
+		for _, config := range configs.ReleaseConfigs {
+			ret = append(ret, config)
+		}
+		slices.SortFunc(ret, func(a, b *rc_lib.ReleaseConfig) int {
+			mapValue := func(v *rc_lib.ReleaseConfig) int {
+				if v, ok := sortMap[v.Name]; ok {
+					return v
+				}
+				return sortMap["-default"]
+			}
+			if n := cmp.Compare(mapValue(a), mapValue(b)); n != 0 {
+				return n
+			}
+			return cmp.Compare(a.Name, b.Name)
+		})
+		return ret, nil
+	}
+	for _, arg := range relFlags.Args() {
+		// Return releases in the order that they were given.
+		config, err := configs.GetReleaseConfig(arg)
+		if err != nil {
+			return nil, err
+		}
+		ret = append(ret, config)
+	}
+	return ret, nil
+}
+
+func GetCommand(configs *rc_lib.ReleaseConfigs, commonFlags Flags, cmd string, args []string) error {
+	isTrace := cmd == "trace"
+	isSet := cmd == "set"
+
+	var all bool
+	getFlags := flag.NewFlagSet("get", flag.ExitOnError)
+	getFlags.BoolVar(&all, "all", false, "Display all flags")
+	getFlags.Parse(args)
+	args = getFlags.Args()
+
+	if isSet {
+		commonFlags.allReleases = true
+	}
+	releaseConfigList, err := GetReleaseArgs(configs, commonFlags)
+	if err != nil {
+		return err
+	}
+	if isTrace && len(releaseConfigList) > 1 {
+		return fmt.Errorf("trace command only allows one --release argument.  Got: %s", strings.Join(commonFlags.targetReleases, " "))
+	}
+
+	if all {
+		args = []string{}
+		for _, fa := range configs.FlagArtifacts {
+			args = append(args, *fa.FlagDeclaration.Name)
+		}
+	}
+
+	var maxVariableNameLen, maxReleaseNameLen int
+	var releaseNameFormat, variableNameFormat string
+	valueFormat := "%s"
+	showReleaseName := len(releaseConfigList) > 1
+	showVariableName := len(args) > 1
+	if showVariableName {
+		for _, arg := range args {
+			maxVariableNameLen = max(len(arg), maxVariableNameLen)
+		}
+		variableNameFormat = fmt.Sprintf("%%-%ds ", maxVariableNameLen)
+		valueFormat = "'%s'"
+	}
+	if showReleaseName {
+		for _, config := range releaseConfigList {
+			maxReleaseNameLen = max(len(config.Name), maxReleaseNameLen)
+		}
+		releaseNameFormat = fmt.Sprintf("%%-%ds ", maxReleaseNameLen)
+		valueFormat = "'%s'"
+	}
+
+	outputOneLine := func(variable, release, value, valueFormat string) {
+		var outStr string
+		if showVariableName {
+			outStr += fmt.Sprintf(variableNameFormat, variable)
+		}
+		if showReleaseName {
+			outStr += fmt.Sprintf(releaseNameFormat, release)
+		}
+		outStr += fmt.Sprintf(valueFormat, value)
+		fmt.Println(outStr)
+	}
+
+	for _, arg := range args {
+		if _, ok := configs.FlagArtifacts[arg]; !ok {
+			return fmt.Errorf("%s is not a defined build flag", arg)
+		}
+	}
+
+	for _, arg := range args {
+		for _, config := range releaseConfigList {
+			if isSet {
+				// If this is from the set command, format the output as:
+				// <default>           ""
+				// trunk_staging       ""
+				// trunk               ""
+				//
+				// ap1a                ""
+				// ...
+				switch {
+				case config.Name == "trunk_staging":
+					defaultValue, err := MarshalFlagDefaultValue(config, arg)
+					if err != nil {
+						return err
+					}
+					outputOneLine(arg, "<default>", defaultValue, valueFormat)
+				case config.AconfigFlagsOnly:
+					continue
+				case config.Name == "trunk":
+					fmt.Println()
+				}
+			}
+			val, err := MarshalFlagValue(config, arg)
+			if err == nil {
+				outputOneLine(arg, config.Name, val, valueFormat)
+			} else {
+				outputOneLine(arg, config.Name, "REDACTED", "%s")
+			}
+			if isTrace {
+				for _, trace := range config.FlagArtifacts[arg].Traces {
+					fmt.Printf("  => \"%s\" in %s\n", rc_lib.MarshalValue(trace.Value), *trace.Source)
+				}
+			}
+		}
+	}
+	return nil
+}
+
+func SetCommand(configs *rc_lib.ReleaseConfigs, commonFlags Flags, cmd string, args []string) error {
+	var valueDir string
+	if len(commonFlags.targetReleases) > 1 {
+		return fmt.Errorf("set command only allows one --release argument.  Got: %s", strings.Join(commonFlags.targetReleases, " "))
+	}
+	targetRelease := commonFlags.targetReleases[0]
+
+	setFlags := flag.NewFlagSet("set", flag.ExitOnError)
+	setFlags.StringVar(&valueDir, "dir", "", "Directory in which to place the value")
+	setFlags.Parse(args)
+	setArgs := setFlags.Args()
+	if len(setArgs) != 2 {
+		return fmt.Errorf("set command expected flag and value, got: %s", strings.Join(setArgs, " "))
+	}
+	name := setArgs[0]
+	value := setArgs[1]
+	release, err := configs.GetReleaseConfig(targetRelease)
+	targetRelease = release.Name
+	if err != nil {
+		return err
+	}
+	if release.AconfigFlagsOnly {
+		return fmt.Errorf("%s does not allow build flag overrides", targetRelease)
+	}
+	flagArtifact, ok := release.FlagArtifacts[name]
+	if !ok {
+		return fmt.Errorf("Unknown build flag %s", name)
+	}
+	if valueDir == "" {
+		mapDir, err := GetMapDir(*flagArtifact.Traces[len(flagArtifact.Traces)-1].Source)
+		if err != nil {
+			return err
+		}
+		valueDir = mapDir
+	}
+
+	flagValue := &rc_proto.FlagValue{
+		Name:  proto.String(name),
+		Value: rc_lib.UnmarshalValue(value),
+	}
+	flagPath := filepath.Join(valueDir, "flag_values", targetRelease, fmt.Sprintf("%s.textproto", name))
+	err = rc_lib.WriteMessage(flagPath, flagValue)
+	if err != nil {
+		return err
+	}
+
+	// Reload the release configs.
+	configs, err = rc_lib.ReadReleaseConfigMaps(commonFlags.maps, commonFlags.targetReleases[0], commonFlags.useGetBuildVar)
+	if err != nil {
+		return err
+	}
+	err = GetCommand(configs, commonFlags, cmd, args[0:1])
+	if err != nil {
+		return err
+	}
+	fmt.Printf("Updated: %s\n", flagPath)
+	return nil
+}
+
+func main() {
+	var commonFlags Flags
+	var configs *rc_lib.ReleaseConfigs
+	topDir, err := rc_lib.GetTopDir()
+
+	// Handle the common arguments
+	flag.StringVar(&commonFlags.top, "top", topDir, "path to top of workspace")
+	flag.BoolVar(&commonFlags.quiet, "quiet", false, "disable warning messages")
+	flag.Var(&commonFlags.maps, "map", "path to a release_config_map.textproto. may be repeated")
+	flag.StringVar(&commonFlags.outDir, "out-dir", rc_lib.GetDefaultOutDir(), "basepath for the output. Multiple formats are created")
+	flag.Var(&commonFlags.targetReleases, "release", "TARGET_RELEASE for this build")
+	flag.BoolVar(&commonFlags.allReleases, "all-releases", false, "operate on all releases. (Ignored for set command)")
+	flag.BoolVar(&commonFlags.useGetBuildVar, "use-get-build-var", true, "use get_build_var PRODUCT_RELEASE_CONFIG_MAPS to get needed maps")
+	flag.BoolVar(&commonFlags.debug, "debug", false, "turn on debugging output for errors")
+	flag.Parse()
+
+	errorExit := func(err error) {
+		if commonFlags.debug {
+			panic(err)
+		}
+		fmt.Fprintf(os.Stderr, "%s\n", err)
+		os.Exit(1)
+	}
+
+	if commonFlags.quiet {
+		rc_lib.DisableWarnings()
+	}
+
+	if len(commonFlags.targetReleases) == 0 {
+		commonFlags.targetReleases = rc_lib.StringList{"trunk_staging"}
+	}
+
+	if err = os.Chdir(commonFlags.top); err != nil {
+		errorExit(err)
+	}
+
+	// Get the current state of flagging.
+	relName := commonFlags.targetReleases[0]
+	if relName == "--all" || relName == "-all" {
+		commonFlags.allReleases = true
+	}
+	configs, err = rc_lib.ReadReleaseConfigMaps(commonFlags.maps, relName, commonFlags.useGetBuildVar)
+	if err != nil {
+		errorExit(err)
+	}
+
+	if cmd, ok := commandMap[flag.Arg(0)]; ok {
+		args := flag.Args()
+		if err = cmd(configs, commonFlags, args[0], args[1:]); err != nil {
+			errorExit(err)
+		}
+	}
+}
diff --git a/cmd/release_config/crunch_flags/Android.bp b/cmd/release_config/crunch_flags/Android.bp
new file mode 100644
index 0000000..89c9591
--- /dev/null
+++ b/cmd/release_config/crunch_flags/Android.bp
@@ -0,0 +1,32 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+    name: "crunch-flags",
+    deps: [
+        "golang-protobuf-encoding-prototext",
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+        "soong-cmd-release_config-lib",
+        "soong-cmd-release_config-proto",
+    ],
+    srcs: [
+        "main.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "soong-cmd-release_config-crunch_flags",
+    pkgPath: "android/soong/cmd/release_config/crunch_flags",
+    deps: [
+        "golang-protobuf-encoding-prototext",
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+        "soong-cmd-release_config-lib",
+        "soong-cmd-release_config-proto",
+    ],
+    srcs: [
+        "main.go",
+    ],
+}
diff --git a/cmd/release_config/crunch_flags/main.go b/cmd/release_config/crunch_flags/main.go
new file mode 100644
index 0000000..95342b1
--- /dev/null
+++ b/cmd/release_config/crunch_flags/main.go
@@ -0,0 +1,399 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"io/fs"
+	"os"
+	"path/filepath"
+	"regexp"
+	"strings"
+
+	rc_lib "android/soong/cmd/release_config/release_config_lib"
+	rc_proto "android/soong/cmd/release_config/release_config_proto"
+	"google.golang.org/protobuf/encoding/prototext"
+	"google.golang.org/protobuf/proto"
+)
+
+var (
+	// When a flag declaration has an initial value that is a string, the default workflow is PREBUILT.
+	// If the flag name starts with any of prefixes in manualFlagNamePrefixes, it is MANUAL.
+	manualFlagNamePrefixes []string = []string{
+		"RELEASE_ACONFIG_",
+		"RELEASE_PLATFORM_",
+	}
+
+	// Set `aconfig_flags_only: true` in these release configs.
+	aconfigFlagsOnlyConfigs map[string]bool = map[string]bool{
+		"trunk_food": true,
+	}
+
+	// Default namespace value.  This is intentionally invalid.
+	defaultFlagNamespace string = "android_UNKNOWN"
+
+	// What is the current name for "next".
+	nextName string = "ap3a"
+)
+
+func RenameNext(name string) string {
+	if name == "next" {
+		return nextName
+	}
+	return name
+}
+
+func WriteFile(path string, message proto.Message) error {
+	data, err := prototext.MarshalOptions{Multiline: true}.Marshal(message)
+	if err != nil {
+		return err
+	}
+
+	err = os.MkdirAll(filepath.Dir(path), 0775)
+	if err != nil {
+		return err
+	}
+	return os.WriteFile(path, data, 0644)
+}
+
+func WalkValueFiles(dir string, Func fs.WalkDirFunc) error {
+	valPath := filepath.Join(dir, "build_config")
+	if _, err := os.Stat(valPath); err != nil {
+		fmt.Printf("%s not found, ignoring.\n", valPath)
+		return nil
+	}
+
+	return filepath.WalkDir(valPath, func(path string, d fs.DirEntry, err error) error {
+		if err != nil {
+			return err
+		}
+		if strings.HasSuffix(d.Name(), ".scl") && d.Type().IsRegular() {
+			return Func(path, d, err)
+		}
+		return nil
+	})
+}
+
+func ProcessBuildFlags(dir string, namespaceMap map[string]string) error {
+	var rootAconfigModule string
+
+	path := filepath.Join(dir, "build_flags.scl")
+	if _, err := os.Stat(path); err != nil {
+		fmt.Printf("%s not found, ignoring.\n", path)
+		return nil
+	} else {
+		fmt.Printf("Processing %s\n", path)
+	}
+	commentRegexp, err := regexp.Compile("^[[:space:]]*#(?<comment>.+)")
+	if err != nil {
+		return err
+	}
+	declRegexp, err := regexp.Compile("^[[:space:]]*flag.\"(?<name>[A-Z_0-9]+)\",[[:space:]]*(?<container>[_A-Z]*),[[:space:]]*(?<value>(\"[^\"]*\"|[^\",)]*))")
+	if err != nil {
+		return err
+	}
+	declIn, err := os.ReadFile(path)
+	if err != nil {
+		return err
+	}
+	lines := strings.Split(string(declIn), "\n")
+	var description string
+	for _, line := range lines {
+		if comment := commentRegexp.FindStringSubmatch(commentRegexp.FindString(line)); comment != nil {
+			// Description is the text from any contiguous series of lines before a `flag()` call.
+			descLine := strings.TrimSpace(comment[commentRegexp.SubexpIndex("comment")])
+			if !strings.HasPrefix(descLine, "keep-sorted") {
+				description += fmt.Sprintf(" %s", descLine)
+			}
+			continue
+		}
+		matches := declRegexp.FindStringSubmatch(declRegexp.FindString(line))
+		if matches == nil {
+			// The line is neither a comment nor a `flag()` call.
+			// Discard any description we have gathered and process the next line.
+			description = ""
+			continue
+		}
+		declName := matches[declRegexp.SubexpIndex("name")]
+		declValue := matches[declRegexp.SubexpIndex("value")]
+		description = strings.TrimSpace(description)
+		containers := []string{strings.ToLower(matches[declRegexp.SubexpIndex("container")])}
+		if containers[0] == "all" {
+			containers = []string{"product", "system", "system_ext", "vendor"}
+		}
+		var namespace string
+		var ok bool
+		if namespace, ok = namespaceMap[declName]; !ok {
+			namespace = defaultFlagNamespace
+		}
+		flagDeclaration := &rc_proto.FlagDeclaration{
+			Name:        proto.String(declName),
+			Namespace:   proto.String(namespace),
+			Description: proto.String(description),
+			Containers:  containers,
+		}
+		description = ""
+		// Most build flags are `workflow: PREBUILT`.
+		workflow := rc_proto.Workflow(rc_proto.Workflow_PREBUILT)
+		switch {
+		case declName == "RELEASE_ACONFIG_VALUE_SETS":
+			rootAconfigModule = declValue[1 : len(declValue)-1]
+			continue
+		case strings.HasPrefix(declValue, "\""):
+			// String values mean that the flag workflow is (most likely) either MANUAL or PREBUILT.
+			declValue = declValue[1 : len(declValue)-1]
+			flagDeclaration.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{declValue}}
+			for _, prefix := range manualFlagNamePrefixes {
+				if strings.HasPrefix(declName, prefix) {
+					workflow = rc_proto.Workflow(rc_proto.Workflow_MANUAL)
+					break
+				}
+			}
+		case declValue == "False" || declValue == "True":
+			// Boolean values are LAUNCH flags.
+			flagDeclaration.Value = &rc_proto.Value{Val: &rc_proto.Value_BoolValue{declValue == "True"}}
+			workflow = rc_proto.Workflow(rc_proto.Workflow_LAUNCH)
+		case declValue == "None":
+			// Use PREBUILT workflow with no initial value.
+		default:
+			fmt.Printf("%s: Unexpected value %s=%s\n", path, declName, declValue)
+		}
+		flagDeclaration.Workflow = &workflow
+		if flagDeclaration != nil {
+			declPath := filepath.Join(dir, "flag_declarations", fmt.Sprintf("%s.textproto", declName))
+			err := WriteFile(declPath, flagDeclaration)
+			if err != nil {
+				return err
+			}
+		}
+	}
+	if rootAconfigModule != "" {
+		rootProto := &rc_proto.ReleaseConfig{
+			Name:             proto.String("root"),
+			AconfigValueSets: []string{rootAconfigModule},
+		}
+		return WriteFile(filepath.Join(dir, "release_configs", "root.textproto"), rootProto)
+	}
+	return nil
+}
+
+func ProcessBuildConfigs(dir, name string, paths []string, releaseProto *rc_proto.ReleaseConfig) error {
+	valRegexp, err := regexp.Compile("[[:space:]]+value.\"(?<name>[A-Z_0-9]+)\",[[:space:]]*(?<value>(\"[^\"]*\"|[^\",)]*))")
+	if err != nil {
+		return err
+	}
+	for _, path := range paths {
+		fmt.Printf("Processing %s\n", path)
+		valIn, err := os.ReadFile(path)
+		if err != nil {
+			fmt.Printf("%s: error: %v\n", path, err)
+			return err
+		}
+		vals := valRegexp.FindAllString(string(valIn), -1)
+		for _, val := range vals {
+			matches := valRegexp.FindStringSubmatch(val)
+			valValue := matches[valRegexp.SubexpIndex("value")]
+			valName := matches[valRegexp.SubexpIndex("name")]
+			flagValue := &rc_proto.FlagValue{
+				Name: proto.String(valName),
+			}
+			switch {
+			case valName == "RELEASE_ACONFIG_VALUE_SETS":
+				flagValue = nil
+				if releaseProto.AconfigValueSets == nil {
+					releaseProto.AconfigValueSets = []string{}
+				}
+				releaseProto.AconfigValueSets = append(releaseProto.AconfigValueSets, valValue[1:len(valValue)-1])
+			case strings.HasPrefix(valValue, "\""):
+				valValue = valValue[1 : len(valValue)-1]
+				flagValue.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{valValue}}
+			case valValue == "None":
+				// nothing to do here.
+			case valValue == "True":
+				flagValue.Value = &rc_proto.Value{Val: &rc_proto.Value_BoolValue{true}}
+			case valValue == "False":
+				flagValue.Value = &rc_proto.Value{Val: &rc_proto.Value_BoolValue{false}}
+			default:
+				fmt.Printf("%s: Unexpected value %s=%s\n", path, valName, valValue)
+			}
+			if flagValue != nil {
+				if releaseProto.GetAconfigFlagsOnly() {
+					return fmt.Errorf("%s does not allow build flag overrides", RenameNext(name))
+				}
+				valPath := filepath.Join(dir, "flag_values", RenameNext(name), fmt.Sprintf("%s.textproto", valName))
+				err := WriteFile(valPath, flagValue)
+				if err != nil {
+					return err
+				}
+			}
+		}
+	}
+	return err
+}
+
+var (
+	allContainers = func() []string {
+		return []string{"product", "system", "system_ext", "vendor"}
+	}()
+)
+
+func ProcessReleaseConfigMap(dir string, descriptionMap map[string]string) error {
+	path := filepath.Join(dir, "release_config_map.mk")
+	if _, err := os.Stat(path); err != nil {
+		fmt.Printf("%s not found, ignoring.\n", path)
+		return nil
+	} else {
+		fmt.Printf("Processing %s\n", path)
+	}
+	configRegexp, err := regexp.Compile("^..call[[:space:]]+declare-release-config,[[:space:]]+(?<name>[_a-z0-9A-Z]+),[[:space:]]+(?<files>[^,]*)(,[[:space:]]*(?<inherits>.*)|[[:space:]]*)[)]$")
+	if err != nil {
+		return err
+	}
+	aliasRegexp, err := regexp.Compile("^..call[[:space:]]+alias-release-config,[[:space:]]+(?<name>[_a-z0-9A-Z]+),[[:space:]]+(?<target>[_a-z0-9A-Z]+)")
+	if err != nil {
+		return err
+	}
+
+	mapIn, err := os.ReadFile(path)
+	if err != nil {
+		return err
+	}
+	cleanDir := strings.TrimLeft(dir, "../")
+	var defaultContainers []string
+	switch {
+	case strings.HasPrefix(cleanDir, "build/") || cleanDir == "vendor/google_shared/build":
+		defaultContainers = allContainers
+	case cleanDir == "vendor/google/release":
+		defaultContainers = allContainers
+	default:
+		defaultContainers = []string{"vendor"}
+	}
+	releaseConfigMap := &rc_proto.ReleaseConfigMap{DefaultContainers: defaultContainers}
+	// If we find a description for the directory, include it.
+	if description, ok := descriptionMap[cleanDir]; ok {
+		releaseConfigMap.Description = proto.String(description)
+	}
+	lines := strings.Split(string(mapIn), "\n")
+	for _, line := range lines {
+		alias := aliasRegexp.FindStringSubmatch(aliasRegexp.FindString(line))
+		if alias != nil {
+			fmt.Printf("processing alias %s\n", line)
+			name := alias[aliasRegexp.SubexpIndex("name")]
+			target := alias[aliasRegexp.SubexpIndex("target")]
+			if target == "next" {
+				if RenameNext(target) != name {
+					return fmt.Errorf("Unexpected name for next (%s)", RenameNext(target))
+				}
+				target, name = name, target
+			}
+			releaseConfigMap.Aliases = append(releaseConfigMap.Aliases,
+				&rc_proto.ReleaseAlias{
+					Name:   proto.String(name),
+					Target: proto.String(target),
+				})
+		}
+		config := configRegexp.FindStringSubmatch(configRegexp.FindString(line))
+		if config == nil {
+			continue
+		}
+		name := config[configRegexp.SubexpIndex("name")]
+		releaseConfig := &rc_proto.ReleaseConfig{
+			Name: proto.String(RenameNext(name)),
+		}
+		if aconfigFlagsOnlyConfigs[name] {
+			releaseConfig.AconfigFlagsOnly = proto.Bool(true)
+		}
+		configFiles := config[configRegexp.SubexpIndex("files")]
+		files := strings.Split(strings.ReplaceAll(configFiles, "$(local_dir)", dir+"/"), " ")
+		configInherits := config[configRegexp.SubexpIndex("inherits")]
+		if len(configInherits) > 0 {
+			releaseConfig.Inherits = strings.Split(configInherits, " ")
+		}
+		err := ProcessBuildConfigs(dir, name, files, releaseConfig)
+		if err != nil {
+			return err
+		}
+
+		releasePath := filepath.Join(dir, "release_configs", fmt.Sprintf("%s.textproto", RenameNext(name)))
+		err = WriteFile(releasePath, releaseConfig)
+		if err != nil {
+			return err
+		}
+	}
+	return WriteFile(filepath.Join(dir, "release_config_map.textproto"), releaseConfigMap)
+}
+
+func main() {
+	var err error
+	var top string
+	var dirs rc_lib.StringList
+	var namespacesFile string
+	var descriptionsFile string
+	var debug bool
+	defaultTopDir, err := rc_lib.GetTopDir()
+
+	flag.StringVar(&top, "top", defaultTopDir, "path to top of workspace")
+	flag.Var(&dirs, "dir", "directory to process, relative to the top of the workspace")
+	flag.StringVar(&namespacesFile, "namespaces", "", "location of file with 'flag_name namespace' information")
+	flag.StringVar(&descriptionsFile, "descriptions", "", "location of file with 'directory description' information")
+	flag.BoolVar(&debug, "debug", false, "turn on debugging output for errors")
+	flag.Parse()
+
+	errorExit := func(err error) {
+		if debug {
+			panic(err)
+		}
+		fmt.Fprintf(os.Stderr, "%s\n", err)
+		os.Exit(1)
+	}
+
+	if err = os.Chdir(top); err != nil {
+		errorExit(err)
+	}
+	if len(dirs) == 0 {
+		dirs = rc_lib.StringList{"build/release", "vendor/google_shared/build/release", "vendor/google/release"}
+	}
+
+	namespaceMap := make(map[string]string)
+	if namespacesFile != "" {
+		data, err := os.ReadFile(namespacesFile)
+		if err != nil {
+			errorExit(err)
+		}
+		for idx, line := range strings.Split(string(data), "\n") {
+			fields := strings.Split(line, " ")
+			if len(fields) > 2 {
+				errorExit(fmt.Errorf("line %d: too many fields: %s", idx, line))
+			}
+			namespaceMap[fields[0]] = fields[1]
+		}
+
+	}
+
+	descriptionMap := make(map[string]string)
+	descriptionMap["build/release"] = "Published open-source flags and declarations"
+	if descriptionsFile != "" {
+		data, err := os.ReadFile(descriptionsFile)
+		if err != nil {
+			errorExit(err)
+		}
+		for _, line := range strings.Split(string(data), "\n") {
+			if strings.TrimSpace(line) != "" {
+				fields := strings.SplitN(line, " ", 2)
+				descriptionMap[fields[0]] = fields[1]
+			}
+		}
+
+	}
+
+	for _, dir := range dirs {
+		err = ProcessBuildFlags(dir, namespaceMap)
+		if err != nil {
+			errorExit(err)
+		}
+
+		err = ProcessReleaseConfigMap(dir, descriptionMap)
+		if err != nil {
+			errorExit(err)
+		}
+	}
+}
diff --git a/cmd/release_config/release_config/Android.bp b/cmd/release_config/release_config/Android.bp
new file mode 100644
index 0000000..3c73826
--- /dev/null
+++ b/cmd/release_config/release_config/Android.bp
@@ -0,0 +1,18 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-cmd-release_config-release_config",
+    pkgPath: "android/soong/cmd/release_config/release_config",
+    deps: [
+        "golang-protobuf-encoding-prototext",
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+        "soong-cmd-release_config-proto",
+        "soong-cmd-release_config-lib",
+    ],
+    srcs: [
+        "main.go",
+    ],
+}
diff --git a/cmd/release_config/release_config/main.go b/cmd/release_config/release_config/main.go
new file mode 100644
index 0000000..c443257
--- /dev/null
+++ b/cmd/release_config/release_config/main.go
@@ -0,0 +1,116 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"path/filepath"
+
+	rc_lib "android/soong/cmd/release_config/release_config_lib"
+)
+
+func main() {
+	var top string
+	var quiet bool
+	var releaseConfigMapPaths rc_lib.StringList
+	var targetRelease string
+	var outputDir string
+	var err error
+	var configs *rc_lib.ReleaseConfigs
+	var json, pb, textproto bool
+	var product string
+	var allMake bool
+	var useBuildVar bool
+
+	defaultRelease := os.Getenv("TARGET_RELEASE")
+	if defaultRelease == "" {
+		defaultRelease = "trunk_staging"
+	}
+
+	flag.StringVar(&top, "top", ".", "path to top of workspace")
+	flag.StringVar(&product, "product", os.Getenv("TARGET_PRODUCT"), "TARGET_PRODUCT for the build")
+	flag.BoolVar(&quiet, "quiet", false, "disable warning messages")
+	flag.Var(&releaseConfigMapPaths, "map", "path to a release_config_map.textproto. may be repeated")
+	flag.StringVar(&targetRelease, "release", defaultRelease, "TARGET_RELEASE for this build")
+	flag.StringVar(&outputDir, "out_dir", rc_lib.GetDefaultOutDir(), "basepath for the output. Multiple formats are created")
+	flag.BoolVar(&textproto, "textproto", true, "write artifacts as text protobuf")
+	flag.BoolVar(&json, "json", true, "write artifacts as json")
+	flag.BoolVar(&pb, "pb", true, "write artifacts as binary protobuf")
+	flag.BoolVar(&allMake, "all_make", true, "write makefiles for all release configs")
+	flag.BoolVar(&useBuildVar, "use_get_build_var", false, "use get_build_var PRODUCT_RELEASE_CONFIG_MAPS")
+
+	flag.Parse()
+
+	if quiet {
+		rc_lib.DisableWarnings()
+	}
+
+	if err = os.Chdir(top); err != nil {
+		panic(err)
+	}
+	configs, err = rc_lib.ReadReleaseConfigMaps(releaseConfigMapPaths, targetRelease, useBuildVar)
+	if err != nil {
+		panic(err)
+	}
+	config, err := configs.GetReleaseConfig(targetRelease)
+	if err != nil {
+		panic(err)
+	}
+	releaseName := config.Name
+	err = os.MkdirAll(outputDir, 0775)
+	if err != nil {
+		panic(err)
+	}
+
+	if err = config.WritePartitionBuildFlags(outputDir, product, targetRelease); err != nil {
+		panic(err)
+	}
+
+	if allMake {
+		for k, _ := range configs.ReleaseConfigs {
+			makefilePath := filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.mk", product, k))
+			err = configs.WriteMakefile(makefilePath, k)
+			if err != nil {
+				panic(err)
+			}
+		}
+	} else {
+		makefilePath := filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.mk", product, releaseName))
+		err = configs.WriteMakefile(makefilePath, targetRelease)
+		if err != nil {
+			panic(err)
+		}
+	}
+	if json {
+		err = configs.WriteArtifact(outputDir, product, "json")
+		if err != nil {
+			panic(err)
+		}
+	}
+	if pb {
+		err = configs.WriteArtifact(outputDir, product, "pb")
+		if err != nil {
+			panic(err)
+		}
+	}
+	if textproto {
+		err = configs.WriteArtifact(outputDir, product, "textproto")
+		if err != nil {
+			panic(err)
+		}
+	}
+}
diff --git a/cmd/release_config/release_config_lib/Android.bp b/cmd/release_config/release_config_lib/Android.bp
new file mode 100644
index 0000000..0c67e11
--- /dev/null
+++ b/cmd/release_config/release_config_lib/Android.bp
@@ -0,0 +1,36 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-cmd-release_config-lib",
+    pkgPath: "android/soong/cmd/release_config/release_config_lib",
+    deps: [
+        "golang-protobuf-encoding-prototext",
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+        "soong-cmd-release_config-proto",
+    ],
+    srcs: [
+        "flag_artifact.go",
+        "flag_declaration.go",
+        "flag_value.go",
+        "release_config.go",
+        "release_configs.go",
+        "util.go",
+    ],
+}
diff --git a/cmd/release_config/release_config_lib/flag_artifact.go b/cmd/release_config/release_config_lib/flag_artifact.go
new file mode 100644
index 0000000..cba1b5c
--- /dev/null
+++ b/cmd/release_config/release_config_lib/flag_artifact.go
@@ -0,0 +1,142 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package release_config_lib
+
+import (
+	"fmt"
+
+	rc_proto "android/soong/cmd/release_config/release_config_proto"
+
+	"google.golang.org/protobuf/proto"
+)
+
+// A flag artifact, with its final value and declaration/override history.
+type FlagArtifact struct {
+	// The flag_declaration message.
+	FlagDeclaration *rc_proto.FlagDeclaration
+
+	// The index of the config directory where this flag was declared.
+	// Flag values cannot be set in a location with a lower index.
+	DeclarationIndex int
+
+	// A history of value assignments and overrides.
+	Traces []*rc_proto.Tracepoint
+
+	// The value of the flag.
+	Value *rc_proto.Value
+
+	// This flag is redacted.  Set by UpdateValue when the FlagValue proto
+	// says to redact it.
+	Redacted bool
+}
+
+// Key is flag name.
+type FlagArtifacts map[string]*FlagArtifact
+
+// Create a clone of the flag artifact.
+//
+// Returns:
+//
+//	*FlagArtifact: the copy of the artifact.
+func (src *FlagArtifact) Clone() *FlagArtifact {
+	value := &rc_proto.Value{}
+	proto.Merge(value, src.Value)
+	return &FlagArtifact{
+		FlagDeclaration: src.FlagDeclaration,
+		Traces:          src.Traces,
+		Value:           value,
+	}
+}
+
+// Clone FlagArtifacts.
+//
+// Returns:
+//
+//	FlagArtifacts: a copy of the source FlagArtifacts.
+func (src FlagArtifacts) Clone() (dst FlagArtifacts) {
+	if dst == nil {
+		dst = make(FlagArtifacts)
+	}
+	for k, v := range src {
+		dst[k] = v.Clone()
+	}
+	return
+}
+
+// Update the value of a flag.
+//
+// This appends to flagArtifact.Traces, and updates flagArtifact.Value.
+//
+// Args:
+//
+//	flagValue FlagValue: the value to assign
+//
+// Returns:
+//
+//	error: any error encountered
+func (fa *FlagArtifact) UpdateValue(flagValue FlagValue) error {
+	name := *flagValue.proto.Name
+	fa.Traces = append(fa.Traces, &rc_proto.Tracepoint{Source: proto.String(flagValue.path), Value: flagValue.proto.Value})
+	if flagValue.proto.GetRedacted() {
+		fa.Redacted = true
+		fmt.Printf("Redacting flag %s in %s\n", name, flagValue.path)
+		return nil
+	}
+	if fa.Value.GetObsolete() {
+		return fmt.Errorf("Attempting to set obsolete flag %s. Trace=%v", name, fa.Traces)
+	}
+	var newValue *rc_proto.Value
+	switch val := flagValue.proto.Value.Val.(type) {
+	case *rc_proto.Value_StringValue:
+		newValue = &rc_proto.Value{Val: &rc_proto.Value_StringValue{val.StringValue}}
+	case *rc_proto.Value_BoolValue:
+		newValue = &rc_proto.Value{Val: &rc_proto.Value_BoolValue{val.BoolValue}}
+	case *rc_proto.Value_Obsolete:
+		if !val.Obsolete {
+			return fmt.Errorf("%s: Cannot set obsolete=false.  Trace=%v", name, fa.Traces)
+		}
+		newValue = &rc_proto.Value{Val: &rc_proto.Value_Obsolete{true}}
+	default:
+		return fmt.Errorf("Invalid type for flag_value: %T.  Trace=%v", val, fa.Traces)
+	}
+	if proto.Equal(newValue, fa.Value) {
+		warnf("%s: redundant override (set in %s)\n", flagValue.path, *fa.Traces[len(fa.Traces)-2].Source)
+	}
+	fa.Value = newValue
+	return nil
+}
+
+// Marshal the FlagArtifact into a flag_artifact message.
+func (fa *FlagArtifact) Marshal() (*rc_proto.FlagArtifact, error) {
+	if fa.Redacted {
+		return nil, nil
+	}
+	return &rc_proto.FlagArtifact{
+		FlagDeclaration: fa.FlagDeclaration,
+		Value:           fa.Value,
+		Traces:          fa.Traces,
+	}, nil
+}
+
+// Marshal the FlagArtifact without Traces.
+func (fa *FlagArtifact) MarshalWithoutTraces() (*rc_proto.FlagArtifact, error) {
+	if fa.Redacted {
+		return nil, nil
+	}
+	return &rc_proto.FlagArtifact{
+		FlagDeclaration: fa.FlagDeclaration,
+		Value:           fa.Value,
+	}, nil
+}
diff --git a/cmd/release_config/release_config_lib/flag_declaration.go b/cmd/release_config/release_config_lib/flag_declaration.go
new file mode 100644
index 0000000..97d4d4c
--- /dev/null
+++ b/cmd/release_config/release_config_lib/flag_declaration.go
@@ -0,0 +1,27 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package release_config_lib
+
+import (
+	rc_proto "android/soong/cmd/release_config/release_config_proto"
+)
+
+func FlagDeclarationFactory(protoPath string) (fd *rc_proto.FlagDeclaration) {
+	fd = &rc_proto.FlagDeclaration{}
+	if protoPath != "" {
+		LoadMessage(protoPath, fd)
+	}
+	return fd
+}
diff --git a/cmd/release_config/release_config_lib/flag_value.go b/cmd/release_config/release_config_lib/flag_value.go
new file mode 100644
index 0000000..e155e77
--- /dev/null
+++ b/cmd/release_config/release_config_lib/flag_value.go
@@ -0,0 +1,73 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package release_config_lib
+
+import (
+	"strings"
+
+	rc_proto "android/soong/cmd/release_config/release_config_proto"
+)
+
+type FlagValue struct {
+	// The path providing this value.
+	path string
+
+	// Protobuf
+	proto rc_proto.FlagValue
+}
+
+func FlagValueFactory(protoPath string) (fv *FlagValue) {
+	fv = &FlagValue{path: protoPath}
+	if protoPath != "" {
+		LoadMessage(protoPath, &fv.proto)
+	}
+	return fv
+}
+
+func UnmarshalValue(str string) *rc_proto.Value {
+	ret := &rc_proto.Value{}
+	switch v := strings.ToLower(str); v {
+	case "true":
+		ret = &rc_proto.Value{Val: &rc_proto.Value_BoolValue{true}}
+	case "false":
+		ret = &rc_proto.Value{Val: &rc_proto.Value_BoolValue{false}}
+	case "##obsolete":
+		ret = &rc_proto.Value{Val: &rc_proto.Value_Obsolete{true}}
+	default:
+		ret = &rc_proto.Value{Val: &rc_proto.Value_StringValue{str}}
+	}
+	return ret
+}
+
+func MarshalValue(value *rc_proto.Value) string {
+	switch val := value.Val.(type) {
+	case *rc_proto.Value_UnspecifiedValue:
+		// Value was never set.
+		return ""
+	case *rc_proto.Value_StringValue:
+		return val.StringValue
+	case *rc_proto.Value_BoolValue:
+		if val.BoolValue {
+			return "true"
+		}
+		// False ==> empty string
+		return ""
+	case *rc_proto.Value_Obsolete:
+		return " #OBSOLETE"
+	default:
+		// Flagged as error elsewhere, so return empty string here.
+		return ""
+	}
+}
diff --git a/cmd/release_config/release_config_lib/flag_value_test.go b/cmd/release_config/release_config_lib/flag_value_test.go
new file mode 100644
index 0000000..aaa4caf
--- /dev/null
+++ b/cmd/release_config/release_config_lib/flag_value_test.go
@@ -0,0 +1,67 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package release_config_lib
+
+import (
+	"os"
+	"path/filepath"
+	"testing"
+
+	rc_proto "android/soong/cmd/release_config/release_config_proto"
+
+	"google.golang.org/protobuf/proto"
+)
+
+type testCaseFlagValue struct {
+	protoPath string
+	name      string
+	data      []byte
+	expected  rc_proto.FlagValue
+	err       error
+}
+
+func (tc testCaseFlagValue) assertProtoEqual(t *testing.T, expected, actual proto.Message) {
+	if !proto.Equal(expected, actual) {
+		t.Errorf("Expected %q found %q", expected, actual)
+	}
+}
+
+func TestFlagValue(t *testing.T) {
+	testCases := []testCaseFlagValue{
+		{
+			name:      "stringVal",
+			protoPath: "build/release/flag_values/test/RELEASE_FOO.textproto",
+			data:      []byte(`name: "RELEASE_FOO" value {string_value: "BAR"}`),
+			expected: rc_proto.FlagValue{
+				Name:  proto.String("RELEASE_FOO"),
+				Value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{"BAR"}},
+			},
+			err: nil,
+		},
+	}
+	for _, tc := range testCases {
+		var err error
+		tempdir := t.TempDir()
+		path := filepath.Join(tempdir, tc.protoPath)
+		if err = os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+			t.Fatal(err)
+		}
+		if err = os.WriteFile(path, tc.data, 0644); err != nil {
+			t.Fatal(err)
+		}
+		actual := FlagValueFactory(path)
+		tc.assertProtoEqual(t, &tc.expected, &actual.proto)
+	}
+}
diff --git a/cmd/release_config/release_config_lib/release_config.go b/cmd/release_config/release_config_lib/release_config.go
new file mode 100644
index 0000000..e51ff08
--- /dev/null
+++ b/cmd/release_config/release_config_lib/release_config.go
@@ -0,0 +1,270 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package release_config_lib
+
+import (
+	"cmp"
+	"fmt"
+	"path/filepath"
+	"slices"
+	"sort"
+	"strings"
+
+	rc_proto "android/soong/cmd/release_config/release_config_proto"
+
+	"google.golang.org/protobuf/proto"
+)
+
+// One directory's contribution to the a release config.
+type ReleaseConfigContribution struct {
+	// Paths to files providing this config.
+	path string
+
+	// The index of the config directory where this release config
+	// contribution was declared.
+	// Flag values cannot be set in a location with a lower index.
+	DeclarationIndex int
+
+	// Protobufs relevant to the config.
+	proto rc_proto.ReleaseConfig
+
+	FlagValues []*FlagValue
+}
+
+// A generated release config.
+type ReleaseConfig struct {
+	// the Name of the release config
+	Name string
+
+	// The index of the config directory where this release config was
+	// first declared.
+	// Flag values cannot be set in a location with a lower index.
+	DeclarationIndex int
+
+	// What contributes to this config.
+	Contributions []*ReleaseConfigContribution
+
+	// Aliases for this release
+	OtherNames []string
+
+	// The names of release configs that we inherit
+	InheritNames []string
+
+	// True if this release config only allows inheritance and aconfig flag
+	// overrides. Build flag value overrides are an error.
+	AconfigFlagsOnly bool
+
+	// Unmarshalled flag artifacts
+	FlagArtifacts FlagArtifacts
+
+	// Generated release config
+	ReleaseConfigArtifact *rc_proto.ReleaseConfigArtifact
+
+	// We have begun compiling this release config.
+	compileInProgress bool
+
+	// Partitioned artifacts for {partition}/etc/build_flags.json
+	PartitionBuildFlags map[string]*rc_proto.FlagArtifacts
+}
+
+func ReleaseConfigFactory(name string, index int) (c *ReleaseConfig) {
+	return &ReleaseConfig{Name: name, DeclarationIndex: index}
+}
+
+func (config *ReleaseConfig) InheritConfig(iConfig *ReleaseConfig) error {
+	for _, fa := range iConfig.FlagArtifacts {
+		name := *fa.FlagDeclaration.Name
+		myFa, ok := config.FlagArtifacts[name]
+		if !ok {
+			return fmt.Errorf("Could not inherit flag %s from %s", name, iConfig.Name)
+		}
+		if len(fa.Traces) > 1 {
+			// A value was assigned. Set our value.
+			myFa.Traces = append(myFa.Traces, fa.Traces[1:]...)
+			myFa.Value = fa.Value
+		}
+	}
+	return nil
+}
+
+func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) error {
+	if config.ReleaseConfigArtifact != nil {
+		return nil
+	}
+	if config.compileInProgress {
+		return fmt.Errorf("Loop detected for release config %s", config.Name)
+	}
+	config.compileInProgress = true
+	isRoot := config.Name == "root"
+
+	// Start with only the flag declarations.
+	config.FlagArtifacts = configs.FlagArtifacts.Clone()
+	// Add RELEASE_ACONFIG_VALUE_SETS
+	workflowManual := rc_proto.Workflow(rc_proto.Workflow_MANUAL)
+	releaseAconfigValueSets := FlagArtifact{
+		FlagDeclaration: &rc_proto.FlagDeclaration{
+			Name:        proto.String("RELEASE_ACONFIG_VALUE_SETS"),
+			Namespace:   proto.String("android_UNKNOWN"),
+			Description: proto.String("Aconfig value sets assembled by release-config"),
+			Workflow:    &workflowManual,
+			Containers:  []string{"system", "system_ext", "product", "vendor"},
+			Value:       &rc_proto.Value{Val: &rc_proto.Value_UnspecifiedValue{false}},
+		},
+		DeclarationIndex: -1,
+		Traces:           []*rc_proto.Tracepoint{},
+	}
+	config.FlagArtifacts["RELEASE_ACONFIG_VALUE_SETS"] = &releaseAconfigValueSets
+
+	// Generate any configs we need to inherit.  This will detect loops in
+	// the config.
+	contributionsToApply := []*ReleaseConfigContribution{}
+	myInherits := []string{}
+	myInheritsSet := make(map[string]bool)
+	// If there is a "root" release config, it is the start of every inheritance chain.
+	_, err := configs.GetReleaseConfig("root")
+	if err == nil && !isRoot {
+		config.InheritNames = append([]string{"root"}, config.InheritNames...)
+	}
+	for _, inherit := range config.InheritNames {
+		if _, ok := myInheritsSet[inherit]; ok {
+			continue
+		}
+		myInherits = append(myInherits, inherit)
+		myInheritsSet[inherit] = true
+		iConfig, err := configs.GetReleaseConfig(inherit)
+		if err != nil {
+			return err
+		}
+		iConfig.GenerateReleaseConfig(configs)
+		if err := config.InheritConfig(iConfig); err != nil {
+			return err
+		}
+	}
+	contributionsToApply = append(contributionsToApply, config.Contributions...)
+
+	myAconfigValueSets := strings.Split(releaseAconfigValueSets.Value.GetStringValue(), " ")
+	myAconfigValueSetsMap := map[string]bool{}
+	for _, v := range myAconfigValueSets {
+		myAconfigValueSetsMap[v] = true
+	}
+	myDirsMap := make(map[int]bool)
+	for _, contrib := range contributionsToApply {
+		contribAconfigValueSets := []string{}
+		// Gather the aconfig_value_sets from this contribution that are not already in the list.
+		for _, v := range contrib.proto.AconfigValueSets {
+			if _, ok := myAconfigValueSetsMap[v]; !ok {
+				contribAconfigValueSets = append(contribAconfigValueSets, v)
+				myAconfigValueSetsMap[v] = true
+			}
+		}
+		myAconfigValueSets = append(myAconfigValueSets, contribAconfigValueSets...)
+		releaseAconfigValueSets.Traces = append(
+			releaseAconfigValueSets.Traces,
+			&rc_proto.Tracepoint{
+				Source: proto.String(contrib.path),
+				Value:  &rc_proto.Value{Val: &rc_proto.Value_StringValue{strings.Join(contribAconfigValueSets, " ")}},
+			})
+
+		myDirsMap[contrib.DeclarationIndex] = true
+		if config.AconfigFlagsOnly && len(contrib.FlagValues) > 0 {
+			return fmt.Errorf("%s does not allow build flag overrides", config.Name)
+		}
+		for _, value := range contrib.FlagValues {
+			name := *value.proto.Name
+			fa, ok := config.FlagArtifacts[name]
+			if !ok {
+				return fmt.Errorf("Setting value for undefined flag %s in %s\n", name, value.path)
+			}
+			myDirsMap[fa.DeclarationIndex] = true
+			if fa.DeclarationIndex > contrib.DeclarationIndex {
+				// Setting location is to the left of declaration.
+				return fmt.Errorf("Setting value for flag %s not allowed in %s\n", name, value.path)
+			}
+			if isRoot && *fa.FlagDeclaration.Workflow != workflowManual {
+				// The "root" release config can only contain workflow: MANUAL flags.
+				return fmt.Errorf("Setting value for non-MANUAL flag %s is not allowed in %s", name, value.path)
+			}
+			if err := fa.UpdateValue(*value); err != nil {
+				return err
+			}
+			if fa.Redacted {
+				delete(config.FlagArtifacts, name)
+			}
+		}
+	}
+	releaseAconfigValueSets.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{strings.TrimSpace(strings.Join(myAconfigValueSets, " "))}}
+
+	directories := []string{}
+	for idx, confDir := range configs.configDirs {
+		if _, ok := myDirsMap[idx]; ok {
+			directories = append(directories, confDir)
+		}
+	}
+
+	// Now build the per-partition artifacts
+	config.PartitionBuildFlags = make(map[string]*rc_proto.FlagArtifacts)
+	for _, v := range config.FlagArtifacts {
+		artifact, err := v.MarshalWithoutTraces()
+		if err != nil {
+			return err
+		}
+		for _, container := range v.FlagDeclaration.Containers {
+			if _, ok := config.PartitionBuildFlags[container]; !ok {
+				config.PartitionBuildFlags[container] = &rc_proto.FlagArtifacts{}
+			}
+			config.PartitionBuildFlags[container].FlagArtifacts = append(config.PartitionBuildFlags[container].FlagArtifacts, artifact)
+		}
+	}
+	config.ReleaseConfigArtifact = &rc_proto.ReleaseConfigArtifact{
+		Name:       proto.String(config.Name),
+		OtherNames: config.OtherNames,
+		FlagArtifacts: func() []*rc_proto.FlagArtifact {
+			ret := []*rc_proto.FlagArtifact{}
+			flagNames := []string{}
+			for k := range config.FlagArtifacts {
+				flagNames = append(flagNames, k)
+			}
+			sort.Strings(flagNames)
+			for _, flagName := range flagNames {
+				flag := config.FlagArtifacts[flagName]
+				ret = append(ret, &rc_proto.FlagArtifact{
+					FlagDeclaration: flag.FlagDeclaration,
+					Traces:          flag.Traces,
+					Value:           flag.Value,
+				})
+			}
+			return ret
+		}(),
+		AconfigValueSets: myAconfigValueSets,
+		Inherits:         myInherits,
+		Directories:      directories,
+	}
+
+	config.compileInProgress = false
+	return nil
+}
+
+func (config *ReleaseConfig) WritePartitionBuildFlags(outDir, product, targetRelease string) error {
+	var err error
+	for partition, flags := range config.PartitionBuildFlags {
+		slices.SortFunc(flags.FlagArtifacts, func(a, b *rc_proto.FlagArtifact) int {
+			return cmp.Compare(*a.FlagDeclaration.Name, *b.FlagDeclaration.Name)
+		})
+		if err = WriteMessage(filepath.Join(outDir, fmt.Sprintf("build_flags_%s-%s-%s.json", partition, config.Name, product)), flags); err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/cmd/release_config/release_config_lib/release_configs.go b/cmd/release_config/release_config_lib/release_configs.go
new file mode 100644
index 0000000..cedf247
--- /dev/null
+++ b/cmd/release_config/release_config_lib/release_configs.go
@@ -0,0 +1,410 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package release_config_lib
+
+import (
+	"cmp"
+	"fmt"
+	"io/fs"
+	"os"
+	"path/filepath"
+	"slices"
+	"strings"
+
+	rc_proto "android/soong/cmd/release_config/release_config_proto"
+
+	"google.golang.org/protobuf/proto"
+)
+
+// A single release_config_map.textproto and its associated data.
+// Used primarily for debugging.
+type ReleaseConfigMap struct {
+	// The path to this release_config_map file.
+	path string
+
+	// Data received
+	proto rc_proto.ReleaseConfigMap
+
+	// Map of name:contribution for release config contributions.
+	ReleaseConfigContributions map[string]*ReleaseConfigContribution
+
+	// Flags declared this directory's flag_declarations/*.textproto
+	FlagDeclarations []rc_proto.FlagDeclaration
+}
+
+type ReleaseConfigDirMap map[string]int
+
+// The generated release configs.
+type ReleaseConfigs struct {
+	// Ordered list of release config maps processed.
+	ReleaseConfigMaps []*ReleaseConfigMap
+
+	// Aliases
+	Aliases map[string]*string
+
+	// Dictionary of flag_name:FlagDeclaration, with no overrides applied.
+	FlagArtifacts FlagArtifacts
+
+	// Generated release configs artifact
+	Artifact rc_proto.ReleaseConfigsArtifact
+
+	// Dictionary of name:ReleaseConfig
+	// Use `GetReleaseConfigs(name)` to get a release config.
+	ReleaseConfigs map[string]*ReleaseConfig
+
+	// Map of directory to *ReleaseConfigMap
+	releaseConfigMapsMap map[string]*ReleaseConfigMap
+
+	// The list of config directories used.
+	configDirs []string
+
+	// A map from the config directory to its order in the list of config
+	// directories.
+	configDirIndexes ReleaseConfigDirMap
+}
+
+// Write the "all_release_configs" artifact.
+//
+// The file will be in "{outDir}/all_release_configs-{product}.{format}"
+//
+// Args:
+//
+//	outDir string: directory path. Will be created if not present.
+//	product string: TARGET_PRODUCT for the release_configs.
+//	format string: one of "json", "pb", or "textproto"
+//
+// Returns:
+//
+//	error: Any error encountered.
+func (configs *ReleaseConfigs) WriteArtifact(outDir, product, format string) error {
+	return WriteMessage(
+		filepath.Join(outDir, fmt.Sprintf("all_release_configs-%s.%s", product, format)),
+		&configs.Artifact)
+}
+
+func ReleaseConfigsFactory() (c *ReleaseConfigs) {
+	return &ReleaseConfigs{
+		Aliases:              make(map[string]*string),
+		FlagArtifacts:        make(map[string]*FlagArtifact),
+		ReleaseConfigs:       make(map[string]*ReleaseConfig),
+		releaseConfigMapsMap: make(map[string]*ReleaseConfigMap),
+		configDirs:           []string{},
+		configDirIndexes:     make(ReleaseConfigDirMap),
+	}
+}
+
+func ReleaseConfigMapFactory(protoPath string) (m *ReleaseConfigMap) {
+	m = &ReleaseConfigMap{
+		path:                       protoPath,
+		ReleaseConfigContributions: make(map[string]*ReleaseConfigContribution),
+	}
+	if protoPath != "" {
+		LoadMessage(protoPath, &m.proto)
+	}
+	return m
+}
+
+func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex int) error {
+	if _, err := os.Stat(path); err != nil {
+		return fmt.Errorf("%s does not exist\n", path)
+	}
+	m := ReleaseConfigMapFactory(path)
+	if m.proto.DefaultContainers == nil {
+		return fmt.Errorf("Release config map %s lacks default_containers", path)
+	}
+	for _, container := range m.proto.DefaultContainers {
+		if !validContainer(container) {
+			return fmt.Errorf("Release config map %s has invalid container %s", path, container)
+		}
+	}
+	dir := filepath.Dir(path)
+	// Record any aliases, checking for duplicates.
+	for _, alias := range m.proto.Aliases {
+		name := *alias.Name
+		oldTarget, ok := configs.Aliases[name]
+		if ok {
+			if *oldTarget != *alias.Target {
+				return fmt.Errorf("Conflicting alias declarations: %s vs %s",
+					*oldTarget, *alias.Target)
+			}
+		}
+		configs.Aliases[name] = alias.Target
+	}
+	var err error
+	err = WalkTextprotoFiles(dir, "flag_declarations", func(path string, d fs.DirEntry, err error) error {
+		flagDeclaration := FlagDeclarationFactory(path)
+		// Container must be specified.
+		if flagDeclaration.Containers == nil {
+			flagDeclaration.Containers = m.proto.DefaultContainers
+		} else {
+			for _, container := range flagDeclaration.Containers {
+				if !validContainer(container) {
+					return fmt.Errorf("Flag declaration %s has invalid container %s", path, container)
+				}
+			}
+		}
+
+		// TODO: once we have namespaces initialized, we can throw an error here.
+		if flagDeclaration.Namespace == nil {
+			flagDeclaration.Namespace = proto.String("android_UNKNOWN")
+		}
+		// If the input didn't specify a value, create one (== UnspecifiedValue).
+		if flagDeclaration.Value == nil {
+			flagDeclaration.Value = &rc_proto.Value{Val: &rc_proto.Value_UnspecifiedValue{false}}
+		}
+		m.FlagDeclarations = append(m.FlagDeclarations, *flagDeclaration)
+		name := *flagDeclaration.Name
+		if def, ok := configs.FlagArtifacts[name]; !ok {
+			configs.FlagArtifacts[name] = &FlagArtifact{FlagDeclaration: flagDeclaration, DeclarationIndex: ConfigDirIndex}
+		} else if !proto.Equal(def.FlagDeclaration, flagDeclaration) {
+			return fmt.Errorf("Duplicate definition of %s", *flagDeclaration.Name)
+		}
+		// Set the initial value in the flag artifact.
+		configs.FlagArtifacts[name].UpdateValue(
+			FlagValue{path: path, proto: rc_proto.FlagValue{
+				Name: proto.String(name), Value: flagDeclaration.Value}})
+		if configs.FlagArtifacts[name].Redacted {
+			return fmt.Errorf("%s may not be redacted by default.", *flagDeclaration.Name)
+		}
+		return nil
+	})
+	if err != nil {
+		return err
+	}
+
+	err = WalkTextprotoFiles(dir, "release_configs", func(path string, d fs.DirEntry, err error) error {
+		releaseConfigContribution := &ReleaseConfigContribution{path: path, DeclarationIndex: ConfigDirIndex}
+		LoadMessage(path, &releaseConfigContribution.proto)
+		name := *releaseConfigContribution.proto.Name
+		if fmt.Sprintf("%s.textproto", name) != filepath.Base(path) {
+			return fmt.Errorf("%s incorrectly declares release config %s", path, name)
+		}
+		if _, ok := configs.ReleaseConfigs[name]; !ok {
+			configs.ReleaseConfigs[name] = ReleaseConfigFactory(name, ConfigDirIndex)
+		}
+		config := configs.ReleaseConfigs[name]
+		config.InheritNames = append(config.InheritNames, releaseConfigContribution.proto.Inherits...)
+
+		// Only walk flag_values/{RELEASE} for defined releases.
+		err2 := WalkTextprotoFiles(dir, filepath.Join("flag_values", name), func(path string, d fs.DirEntry, err error) error {
+			flagValue := FlagValueFactory(path)
+			if fmt.Sprintf("%s.textproto", *flagValue.proto.Name) != filepath.Base(path) {
+				return fmt.Errorf("%s incorrectly sets value for flag %s", path, *flagValue.proto.Name)
+			}
+			releaseConfigContribution.FlagValues = append(releaseConfigContribution.FlagValues, flagValue)
+			return nil
+		})
+		if err2 != nil {
+			return err2
+		}
+		if releaseConfigContribution.proto.GetAconfigFlagsOnly() {
+			config.AconfigFlagsOnly = true
+		}
+		m.ReleaseConfigContributions[name] = releaseConfigContribution
+		config.Contributions = append(config.Contributions, releaseConfigContribution)
+		return nil
+	})
+	if err != nil {
+		return err
+	}
+	configs.ReleaseConfigMaps = append(configs.ReleaseConfigMaps, m)
+	configs.releaseConfigMapsMap[dir] = m
+	return nil
+}
+
+func (configs *ReleaseConfigs) GetReleaseConfig(name string) (*ReleaseConfig, error) {
+	trace := []string{name}
+	for target, ok := configs.Aliases[name]; ok; target, ok = configs.Aliases[name] {
+		name = *target
+		trace = append(trace, name)
+	}
+	if config, ok := configs.ReleaseConfigs[name]; ok {
+		return config, nil
+	}
+	return nil, fmt.Errorf("Missing config %s.  Trace=%v", name, trace)
+}
+
+// Write the makefile for this targetRelease.
+func (configs *ReleaseConfigs) WriteMakefile(outFile, targetRelease string) error {
+	makeVars := make(map[string]string)
+	var allReleaseNames []string
+	for _, v := range configs.ReleaseConfigs {
+		allReleaseNames = append(allReleaseNames, v.Name)
+		allReleaseNames = append(allReleaseNames, v.OtherNames...)
+	}
+	config, err := configs.GetReleaseConfig(targetRelease)
+	if err != nil {
+		return err
+	}
+
+	myFlagArtifacts := config.FlagArtifacts.Clone()
+	// Sort the flags by name first.
+	names := []string{}
+	for k, _ := range myFlagArtifacts {
+		names = append(names, k)
+	}
+	slices.SortFunc(names, func(a, b string) int {
+		return cmp.Compare(a, b)
+	})
+	partitions := make(map[string][]string)
+
+	vNames := []string{}
+	addVar := func(name, suffix, value string) {
+		fullName := fmt.Sprintf("_ALL_RELEASE_FLAGS.%s.%s", name, suffix)
+		vNames = append(vNames, fullName)
+		makeVars[fullName] = value
+	}
+
+	for _, name := range names {
+		flag := myFlagArtifacts[name]
+		decl := flag.FlagDeclaration
+
+		for _, container := range decl.Containers {
+			partitions[container] = append(partitions[container], name)
+		}
+		value := MarshalValue(flag.Value)
+		makeVars[name] = value
+		addVar(name, "PARTITIONS", strings.Join(decl.Containers, " "))
+		addVar(name, "DEFAULT", MarshalValue(decl.Value))
+		addVar(name, "VALUE", value)
+		addVar(name, "DECLARED_IN", *flag.Traces[0].Source)
+		addVar(name, "SET_IN", *flag.Traces[len(flag.Traces)-1].Source)
+		addVar(name, "NAMESPACE", *decl.Namespace)
+	}
+	pNames := []string{}
+	for k, _ := range partitions {
+		pNames = append(pNames, k)
+	}
+	slices.SortFunc(pNames, func(a, b string) int {
+		return cmp.Compare(a, b)
+	})
+
+	// Now sort the make variables, and output them.
+	slices.SortFunc(vNames, func(a, b string) int {
+		return cmp.Compare(a, b)
+	})
+
+	// Write the flags as:
+	//   _ALL_RELELASE_FLAGS
+	//   _ALL_RELEASE_FLAGS.PARTITIONS.*
+	//   all _ALL_RELEASE_FLAGS.*, sorted by name
+	//   Final flag values, sorted by name.
+	data := fmt.Sprintf("# TARGET_RELEASE=%s\n", config.Name)
+	if targetRelease != config.Name {
+		data += fmt.Sprintf("# User specified TARGET_RELEASE=%s\n", targetRelease)
+	}
+	// The variable _all_release_configs will get deleted during processing, so do not mark it read-only.
+	data += fmt.Sprintf("_all_release_configs := %s\n", strings.Join(allReleaseNames, " "))
+	data += fmt.Sprintf("_ALL_RELEASE_FLAGS :=$= %s\n", strings.Join(names, " "))
+	for _, pName := range pNames {
+		data += fmt.Sprintf("_ALL_RELEASE_FLAGS.PARTITIONS.%s :=$= %s\n", pName, strings.Join(partitions[pName], " "))
+	}
+	for _, vName := range vNames {
+		data += fmt.Sprintf("%s :=$= %s\n", vName, makeVars[vName])
+	}
+	data += "\n\n# Values for all build flags\n"
+	for _, name := range names {
+		data += fmt.Sprintf("%s :=$= %s\n", name, makeVars[name])
+	}
+	return os.WriteFile(outFile, []byte(data), 0644)
+}
+
+func (configs *ReleaseConfigs) GenerateReleaseConfigs(targetRelease string) error {
+	otherNames := make(map[string][]string)
+	for aliasName, aliasTarget := range configs.Aliases {
+		if _, ok := configs.ReleaseConfigs[aliasName]; ok {
+			return fmt.Errorf("Alias %s is a declared release config", aliasName)
+		}
+		if _, ok := configs.ReleaseConfigs[*aliasTarget]; !ok {
+			if _, ok2 := configs.Aliases[*aliasTarget]; !ok2 {
+				return fmt.Errorf("Alias %s points to non-existing config %s", aliasName, *aliasTarget)
+			}
+		}
+		otherNames[*aliasTarget] = append(otherNames[*aliasTarget], aliasName)
+	}
+	for name, aliases := range otherNames {
+		configs.ReleaseConfigs[name].OtherNames = aliases
+	}
+
+	for _, config := range configs.ReleaseConfigs {
+		err := config.GenerateReleaseConfig(configs)
+		if err != nil {
+			return err
+		}
+	}
+
+	releaseConfig, err := configs.GetReleaseConfig(targetRelease)
+	if err != nil {
+		return err
+	}
+	configs.Artifact = rc_proto.ReleaseConfigsArtifact{
+		ReleaseConfig: releaseConfig.ReleaseConfigArtifact,
+		OtherReleaseConfigs: func() []*rc_proto.ReleaseConfigArtifact {
+			orc := []*rc_proto.ReleaseConfigArtifact{}
+			for name, config := range configs.ReleaseConfigs {
+				if name != releaseConfig.Name {
+					orc = append(orc, config.ReleaseConfigArtifact)
+				}
+			}
+			return orc
+		}(),
+		ReleaseConfigMapsMap: func() map[string]*rc_proto.ReleaseConfigMap {
+			ret := make(map[string]*rc_proto.ReleaseConfigMap)
+			for k, v := range configs.releaseConfigMapsMap {
+				ret[k] = &v.proto
+			}
+			return ret
+		}(),
+	}
+	return nil
+}
+
+func ReadReleaseConfigMaps(releaseConfigMapPaths StringList, targetRelease string, useBuildVar bool) (*ReleaseConfigs, error) {
+	var err error
+
+	if len(releaseConfigMapPaths) == 0 {
+		releaseConfigMapPaths, err = GetDefaultMapPaths(useBuildVar)
+		if err != nil {
+			return nil, err
+		}
+		if len(releaseConfigMapPaths) == 0 {
+			return nil, fmt.Errorf("No maps found")
+		}
+		warnf("No --map argument provided.  Using: --map %s\n", strings.Join(releaseConfigMapPaths, " --map "))
+	}
+
+	configs := ReleaseConfigsFactory()
+	mapsRead := make(map[string]bool)
+	for idx, releaseConfigMapPath := range releaseConfigMapPaths {
+		// Maintain an ordered list of release config directories.
+		configDir := filepath.Dir(releaseConfigMapPath)
+		if mapsRead[configDir] {
+			continue
+		}
+		mapsRead[configDir] = true
+		configs.configDirIndexes[configDir] = idx
+		configs.configDirs = append(configs.configDirs, configDir)
+		// Force the path to be the textproto path, so that both the scl and textproto formats can coexist.
+		releaseConfigMapPath = filepath.Join(configDir, "release_config_map.textproto")
+		err = configs.LoadReleaseConfigMap(releaseConfigMapPath, idx)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	// Now that we have all of the release config maps, can meld them and generate the artifacts.
+	err = configs.GenerateReleaseConfigs(targetRelease)
+	return configs, err
+}
diff --git a/cmd/release_config/release_config_lib/util.go b/cmd/release_config/release_config_lib/util.go
new file mode 100644
index 0000000..c0ea789
--- /dev/null
+++ b/cmd/release_config/release_config_lib/util.go
@@ -0,0 +1,209 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package release_config_lib
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/fs"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"strings"
+
+	"google.golang.org/protobuf/encoding/prototext"
+	"google.golang.org/protobuf/proto"
+)
+
+var (
+	disableWarnings    bool
+	containerRegexp, _ = regexp.Compile("^[a-z][a-z0-9]*([._][a-z][a-z0-9]*)*$")
+)
+
+type StringList []string
+
+func (l *StringList) Set(v string) error {
+	*l = append(*l, v)
+	return nil
+}
+
+func (l *StringList) String() string {
+	return fmt.Sprintf("%v", *l)
+}
+
+// Write a marshalled message to a file.
+//
+// Marshal the message based on the extension of the path we are writing it to.
+//
+// Args:
+//
+//	path string: the path of the file to write to.  Directories are not created.
+//	  Supported extensions are: ".json", ".pb", and ".textproto".
+//	message proto.Message: the message to write.
+//
+// Returns:
+//
+//	error: any error encountered.
+func WriteMessage(path string, message proto.Message) (err error) {
+	var data []byte
+	switch filepath.Ext(path) {
+	case ".json":
+		data, err = json.MarshalIndent(message, "", "  ")
+	case ".pb":
+		data, err = proto.Marshal(message)
+	case ".textproto":
+		data, err = prototext.MarshalOptions{Multiline: true}.Marshal(message)
+	default:
+		return fmt.Errorf("Unknown message format for %s", path)
+	}
+	if err != nil {
+		return err
+	}
+	return os.WriteFile(path, data, 0644)
+}
+
+// Read a message from a file.
+//
+// The message is unmarshalled based on the extension of the file read.
+//
+// Args:
+//
+//	path string: the path of the file to read.
+//	message proto.Message: the message to unmarshal the message into.
+//
+// Returns:
+//
+//	error: any error encountered.
+func LoadMessage(path string, message proto.Message) error {
+	data, err := os.ReadFile(path)
+	if err != nil {
+		return err
+	}
+	switch filepath.Ext(path) {
+	case ".json":
+		return json.Unmarshal(data, message)
+	case ".pb":
+		return proto.Unmarshal(data, message)
+	case ".textproto":
+		return prototext.Unmarshal(data, message)
+	}
+	return fmt.Errorf("Unknown message format for %s", path)
+}
+
+// Call Func for any textproto files found in {root}/{subdir}.
+func WalkTextprotoFiles(root string, subdir string, Func fs.WalkDirFunc) error {
+	path := filepath.Join(root, subdir)
+	if _, err := os.Stat(path); err != nil {
+		// Missing subdirs are not an error.
+		return nil
+	}
+	return filepath.WalkDir(path, func(path string, d fs.DirEntry, err error) error {
+		if err != nil {
+			return err
+		}
+		if strings.HasSuffix(d.Name(), ".textproto") && d.Type().IsRegular() {
+			return Func(path, d, err)
+		}
+		return nil
+	})
+}
+
+// Turn off all warning output
+func DisableWarnings() {
+	disableWarnings = true
+}
+
+func warnf(format string, args ...any) (n int, err error) {
+	if !disableWarnings {
+		return fmt.Fprintf(os.Stderr, format, args...)
+	}
+	return 0, nil
+}
+
+func validContainer(container string) bool {
+	return containerRegexp.MatchString(container)
+}
+
+// Returns the default value for release config artifacts.
+func GetDefaultOutDir() string {
+	outEnv := os.Getenv("OUT_DIR")
+	if outEnv == "" {
+		outEnv = "out"
+	}
+	return filepath.Join(outEnv, "soong", "release-config")
+}
+
+// Find the top of the workspace.
+//
+// This mirrors the logic in build/envsetup.sh's gettop().
+func GetTopDir() (topDir string, err error) {
+	workingDir, err := os.Getwd()
+	if err != nil {
+		return
+	}
+	topFile := "build/make/core/envsetup.mk"
+	for topDir = workingDir; topDir != "/"; topDir = filepath.Dir(topDir) {
+		if _, err = os.Stat(filepath.Join(topDir, topFile)); err == nil {
+			return filepath.Rel(workingDir, topDir)
+		}
+	}
+	return "", fmt.Errorf("Unable to locate top of workspace")
+}
+
+// Return the default list of map files to use.
+func GetDefaultMapPaths(queryMaps bool) (defaultMapPaths StringList, err error) {
+	var defaultLocations StringList
+	workingDir, err := os.Getwd()
+	if err != nil {
+		return
+	}
+	defer func() {
+		os.Chdir(workingDir)
+	}()
+	topDir, err := GetTopDir()
+	os.Chdir(topDir)
+
+	defaultLocations = StringList{
+		"build/release/release_config_map.textproto",
+		"vendor/google_shared/build/release/release_config_map.textproto",
+		"vendor/google/release/release_config_map.textproto",
+	}
+	for _, path := range defaultLocations {
+		if _, err = os.Stat(path); err == nil {
+			defaultMapPaths = append(defaultMapPaths, path)
+		}
+	}
+
+	var prodMaps string
+	if queryMaps {
+		getBuildVar := exec.Command("build/soong/soong_ui.bash", "--dumpvar-mode", "PRODUCT_RELEASE_CONFIG_MAPS")
+		var stdout strings.Builder
+		getBuildVar.Stdin = strings.NewReader("")
+		getBuildVar.Stdout = &stdout
+		err = getBuildVar.Run()
+		if err != nil {
+			return
+		}
+		prodMaps = stdout.String()
+	} else {
+		prodMaps = os.Getenv("PRODUCT_RELEASE_CONFIG_MAPS")
+	}
+	prodMaps = strings.TrimSpace(prodMaps)
+	if len(prodMaps) > 0 {
+		defaultMapPaths = append(defaultMapPaths, strings.Split(prodMaps, " ")...)
+	}
+	return
+}
diff --git a/starlark_import/Android.bp b/cmd/release_config/release_config_proto/Android.bp
similarity index 62%
copy from starlark_import/Android.bp
copy to cmd/release_config/release_config_proto/Android.bp
index b43217b..8c47f2a 100644
--- a/starlark_import/Android.bp
+++ b/cmd/release_config/release_config_proto/Android.bp
@@ -1,4 +1,4 @@
-// Copyright 2023 Google Inc. All rights reserved.
+// Copyright 2024 Google Inc. All rights reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -17,20 +17,14 @@
 }
 
 bootstrap_go_package {
-    name: "soong-starlark",
-    pkgPath: "android/soong/starlark_import",
-    srcs: [
-        "starlark_import.go",
-        "unmarshal.go",
-    ],
-    testSrcs: [
-        "starlark_import_test.go",
-        "unmarshal_test.go",
-    ],
+    name: "soong-cmd-release_config-proto",
+    pkgPath: "android/soong/cmd/release_config/release_config_proto",
     deps: [
-        "go-starlark-starlark",
-        "go-starlark-starlarkstruct",
-        "go-starlark-starlarkjson",
-        "go-starlark-starlarktest",
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+    ],
+    srcs: [
+        "build_flags_src.pb.go",
+        "build_flags_out.pb.go",
     ],
 }
diff --git a/cmd/release_config/release_config_proto/build_flags_out.pb.go b/cmd/release_config/release_config_proto/build_flags_out.pb.go
new file mode 100644
index 0000000..483cffa
--- /dev/null
+++ b/cmd/release_config/release_config_proto/build_flags_out.pb.go
@@ -0,0 +1,583 @@
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.30.0
+// 	protoc        v3.21.12
+// source: build_flags_out.proto
+
+package release_config_proto
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Tracepoint struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Path to declaration or value file relative to $TOP
+	Source *string `protobuf:"bytes,1,opt,name=source" json:"source,omitempty"`
+	Value  *Value  `protobuf:"bytes,201,opt,name=value" json:"value,omitempty"`
+}
+
+func (x *Tracepoint) Reset() {
+	*x = Tracepoint{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_build_flags_out_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Tracepoint) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Tracepoint) ProtoMessage() {}
+
+func (x *Tracepoint) ProtoReflect() protoreflect.Message {
+	mi := &file_build_flags_out_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Tracepoint.ProtoReflect.Descriptor instead.
+func (*Tracepoint) Descriptor() ([]byte, []int) {
+	return file_build_flags_out_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Tracepoint) GetSource() string {
+	if x != nil && x.Source != nil {
+		return *x.Source
+	}
+	return ""
+}
+
+func (x *Tracepoint) GetValue() *Value {
+	if x != nil {
+		return x.Value
+	}
+	return nil
+}
+
+type FlagArtifact struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The original declaration
+	FlagDeclaration *FlagDeclaration `protobuf:"bytes,1,opt,name=flag_declaration,json=flagDeclaration" json:"flag_declaration,omitempty"`
+	// Value for the flag
+	Value *Value `protobuf:"bytes,201,opt,name=value" json:"value,omitempty"`
+	// Trace of where the flag value was assigned.
+	Traces []*Tracepoint `protobuf:"bytes,8,rep,name=traces" json:"traces,omitempty"`
+}
+
+func (x *FlagArtifact) Reset() {
+	*x = FlagArtifact{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_build_flags_out_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *FlagArtifact) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FlagArtifact) ProtoMessage() {}
+
+func (x *FlagArtifact) ProtoReflect() protoreflect.Message {
+	mi := &file_build_flags_out_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FlagArtifact.ProtoReflect.Descriptor instead.
+func (*FlagArtifact) Descriptor() ([]byte, []int) {
+	return file_build_flags_out_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *FlagArtifact) GetFlagDeclaration() *FlagDeclaration {
+	if x != nil {
+		return x.FlagDeclaration
+	}
+	return nil
+}
+
+func (x *FlagArtifact) GetValue() *Value {
+	if x != nil {
+		return x.Value
+	}
+	return nil
+}
+
+func (x *FlagArtifact) GetTraces() []*Tracepoint {
+	if x != nil {
+		return x.Traces
+	}
+	return nil
+}
+
+type FlagArtifacts struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The artifacts
+	FlagArtifacts []*FlagArtifact `protobuf:"bytes,1,rep,name=flag_artifacts,json=flagArtifacts" json:"flag_artifacts,omitempty"`
+}
+
+func (x *FlagArtifacts) Reset() {
+	*x = FlagArtifacts{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_build_flags_out_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *FlagArtifacts) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FlagArtifacts) ProtoMessage() {}
+
+func (x *FlagArtifacts) ProtoReflect() protoreflect.Message {
+	mi := &file_build_flags_out_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FlagArtifacts.ProtoReflect.Descriptor instead.
+func (*FlagArtifacts) Descriptor() ([]byte, []int) {
+	return file_build_flags_out_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *FlagArtifacts) GetFlagArtifacts() []*FlagArtifact {
+	if x != nil {
+		return x.FlagArtifacts
+	}
+	return nil
+}
+
+type ReleaseConfigArtifact struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The name of the release config.
+	// See # name for format detail
+	Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+	// Other names by which this release is known (for example, `next`)
+	OtherNames []string `protobuf:"bytes,2,rep,name=other_names,json=otherNames" json:"other_names,omitempty"`
+	// The complete set of build flags in this release config, after all
+	// inheritance and other processing is complete.
+	FlagArtifacts []*FlagArtifact `protobuf:"bytes,3,rep,name=flag_artifacts,json=flagArtifacts" json:"flag_artifacts,omitempty"`
+	// The (complete) list of aconfig_value_sets Soong modules to use.
+	AconfigValueSets []string `protobuf:"bytes,4,rep,name=aconfig_value_sets,json=aconfigValueSets" json:"aconfig_value_sets,omitempty"`
+	// The names of the release_config_artifacts from which we inherited.
+	// Included for reference only.
+	Inherits []string `protobuf:"bytes,5,rep,name=inherits" json:"inherits,omitempty"`
+	// The release config directories used for this config.
+	// For example, "build/release".
+	Directories []string `protobuf:"bytes,6,rep,name=directories" json:"directories,omitempty"`
+}
+
+func (x *ReleaseConfigArtifact) Reset() {
+	*x = ReleaseConfigArtifact{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_build_flags_out_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReleaseConfigArtifact) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReleaseConfigArtifact) ProtoMessage() {}
+
+func (x *ReleaseConfigArtifact) ProtoReflect() protoreflect.Message {
+	mi := &file_build_flags_out_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReleaseConfigArtifact.ProtoReflect.Descriptor instead.
+func (*ReleaseConfigArtifact) Descriptor() ([]byte, []int) {
+	return file_build_flags_out_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *ReleaseConfigArtifact) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (x *ReleaseConfigArtifact) GetOtherNames() []string {
+	if x != nil {
+		return x.OtherNames
+	}
+	return nil
+}
+
+func (x *ReleaseConfigArtifact) GetFlagArtifacts() []*FlagArtifact {
+	if x != nil {
+		return x.FlagArtifacts
+	}
+	return nil
+}
+
+func (x *ReleaseConfigArtifact) GetAconfigValueSets() []string {
+	if x != nil {
+		return x.AconfigValueSets
+	}
+	return nil
+}
+
+func (x *ReleaseConfigArtifact) GetInherits() []string {
+	if x != nil {
+		return x.Inherits
+	}
+	return nil
+}
+
+func (x *ReleaseConfigArtifact) GetDirectories() []string {
+	if x != nil {
+		return x.Directories
+	}
+	return nil
+}
+
+type ReleaseConfigsArtifact struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The active release config for this build.
+	ReleaseConfig *ReleaseConfigArtifact `protobuf:"bytes,1,opt,name=release_config,json=releaseConfig" json:"release_config,omitempty"`
+	// All other release configs defined for this TARGET_PRODUCT.
+	OtherReleaseConfigs []*ReleaseConfigArtifact `protobuf:"bytes,2,rep,name=other_release_configs,json=otherReleaseConfigs" json:"other_release_configs,omitempty"`
+	// Map of release_config_artifact.directories to release_config_map message.
+	ReleaseConfigMapsMap map[string]*ReleaseConfigMap `protobuf:"bytes,3,rep,name=release_config_maps_map,json=releaseConfigMapsMap" json:"release_config_maps_map,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+}
+
+func (x *ReleaseConfigsArtifact) Reset() {
+	*x = ReleaseConfigsArtifact{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_build_flags_out_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReleaseConfigsArtifact) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReleaseConfigsArtifact) ProtoMessage() {}
+
+func (x *ReleaseConfigsArtifact) ProtoReflect() protoreflect.Message {
+	mi := &file_build_flags_out_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReleaseConfigsArtifact.ProtoReflect.Descriptor instead.
+func (*ReleaseConfigsArtifact) Descriptor() ([]byte, []int) {
+	return file_build_flags_out_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *ReleaseConfigsArtifact) GetReleaseConfig() *ReleaseConfigArtifact {
+	if x != nil {
+		return x.ReleaseConfig
+	}
+	return nil
+}
+
+func (x *ReleaseConfigsArtifact) GetOtherReleaseConfigs() []*ReleaseConfigArtifact {
+	if x != nil {
+		return x.OtherReleaseConfigs
+	}
+	return nil
+}
+
+func (x *ReleaseConfigsArtifact) GetReleaseConfigMapsMap() map[string]*ReleaseConfigMap {
+	if x != nil {
+		return x.ReleaseConfigMapsMap
+	}
+	return nil
+}
+
+var File_build_flags_out_proto protoreflect.FileDescriptor
+
+var file_build_flags_out_proto_rawDesc = []byte{
+	0x0a, 0x15, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x5f, 0x6f, 0x75,
+	0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
+	0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x61,
+	0x67, 0x73, 0x5f, 0x73, 0x72, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x60, 0x0a, 0x0a,
+	0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f,
+	0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72,
+	0x63, 0x65, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c,
+	0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xe8,
+	0x01, 0x0a, 0x0d, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74,
+	0x12, 0x59, 0x0a, 0x10, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61,
+	0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x61, 0x6e, 0x64,
+	0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x64,
+	0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0f, 0x66, 0x6c, 0x61, 0x67,
+	0x44, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e,
+	0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f,
+	0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x40, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65,
+	0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
+	0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+	0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x72, 0x61, 0x63, 0x65, 0x70, 0x6f, 0x69, 0x6e,
+	0x74, 0x52, 0x06, 0x74, 0x72, 0x61, 0x63, 0x65, 0x73, 0x22, 0x64, 0x0a, 0x0e, 0x66, 0x6c, 0x61,
+	0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x52, 0x0a, 0x0e, 0x66,
+	0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65,
+	0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74,
+	0x52, 0x0d, 0x66, 0x6c, 0x61, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22,
+	0x8e, 0x02, 0x0a, 0x17, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
+	0x69, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e,
+	0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
+	0x1f, 0x0a, 0x0b, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73,
+	0x12, 0x52, 0x0a, 0x0e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63,
+	0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f,
+	0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
+	0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74,
+	0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x0d, 0x66, 0x6c, 0x61, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66,
+	0x61, 0x63, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09,
+	0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x65,
+	0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x18, 0x05,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x12, 0x20,
+	0x0a, 0x0b, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x06, 0x20,
+	0x03, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73,
+	0x22, 0xe8, 0x03, 0x0a, 0x18, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x73, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x5c, 0x0a,
+	0x0e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e,
+	0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x0d, 0x72, 0x65,
+	0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x69, 0x0a, 0x15, 0x6f,
+	0x74, 0x68, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x61, 0x6e, 0x64,
+	0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73,
+	0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63,
+	0x74, 0x52, 0x13, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43,
+	0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x87, 0x01, 0x0a, 0x17, 0x72, 0x65, 0x6c, 0x65, 0x61,
+	0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, 0x73, 0x5f, 0x6d,
+	0x61, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x50, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f,
+	0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
+	0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f,
+	0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74,
+	0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61,
+	0x70, 0x73, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x72, 0x65, 0x6c, 0x65,
+	0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x73, 0x4d, 0x61, 0x70,
+	0x1a, 0x79, 0x0a, 0x19, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69,
+	0x67, 0x4d, 0x61, 0x70, 0x73, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
+	0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+	0x46, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30,
+	0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
+	0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65,
+	0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70,
+	0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x33, 0x5a, 0x31, 0x61,
+	0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c,
+	0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65,
+	0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+}
+
+var (
+	file_build_flags_out_proto_rawDescOnce sync.Once
+	file_build_flags_out_proto_rawDescData = file_build_flags_out_proto_rawDesc
+)
+
+func file_build_flags_out_proto_rawDescGZIP() []byte {
+	file_build_flags_out_proto_rawDescOnce.Do(func() {
+		file_build_flags_out_proto_rawDescData = protoimpl.X.CompressGZIP(file_build_flags_out_proto_rawDescData)
+	})
+	return file_build_flags_out_proto_rawDescData
+}
+
+var file_build_flags_out_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
+var file_build_flags_out_proto_goTypes = []interface{}{
+	(*Tracepoint)(nil),             // 0: android.release_config_proto.tracepoint
+	(*FlagArtifact)(nil),           // 1: android.release_config_proto.flag_artifact
+	(*FlagArtifacts)(nil),          // 2: android.release_config_proto.flag_artifacts
+	(*ReleaseConfigArtifact)(nil),  // 3: android.release_config_proto.release_config_artifact
+	(*ReleaseConfigsArtifact)(nil), // 4: android.release_config_proto.release_configs_artifact
+	nil,                            // 5: android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry
+	(*Value)(nil),                  // 6: android.release_config_proto.value
+	(*FlagDeclaration)(nil),        // 7: android.release_config_proto.flag_declaration
+	(*ReleaseConfigMap)(nil),       // 8: android.release_config_proto.release_config_map
+}
+var file_build_flags_out_proto_depIdxs = []int32{
+	6,  // 0: android.release_config_proto.tracepoint.value:type_name -> android.release_config_proto.value
+	7,  // 1: android.release_config_proto.flag_artifact.flag_declaration:type_name -> android.release_config_proto.flag_declaration
+	6,  // 2: android.release_config_proto.flag_artifact.value:type_name -> android.release_config_proto.value
+	0,  // 3: android.release_config_proto.flag_artifact.traces:type_name -> android.release_config_proto.tracepoint
+	1,  // 4: android.release_config_proto.flag_artifacts.flag_artifacts:type_name -> android.release_config_proto.flag_artifact
+	1,  // 5: android.release_config_proto.release_config_artifact.flag_artifacts:type_name -> android.release_config_proto.flag_artifact
+	3,  // 6: android.release_config_proto.release_configs_artifact.release_config:type_name -> android.release_config_proto.release_config_artifact
+	3,  // 7: android.release_config_proto.release_configs_artifact.other_release_configs:type_name -> android.release_config_proto.release_config_artifact
+	5,  // 8: android.release_config_proto.release_configs_artifact.release_config_maps_map:type_name -> android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry
+	8,  // 9: android.release_config_proto.release_configs_artifact.ReleaseConfigMapsMapEntry.value:type_name -> android.release_config_proto.release_config_map
+	10, // [10:10] is the sub-list for method output_type
+	10, // [10:10] is the sub-list for method input_type
+	10, // [10:10] is the sub-list for extension type_name
+	10, // [10:10] is the sub-list for extension extendee
+	0,  // [0:10] is the sub-list for field type_name
+}
+
+func init() { file_build_flags_out_proto_init() }
+func file_build_flags_out_proto_init() {
+	if File_build_flags_out_proto != nil {
+		return
+	}
+	file_build_flags_src_proto_init()
+	if !protoimpl.UnsafeEnabled {
+		file_build_flags_out_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Tracepoint); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_build_flags_out_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*FlagArtifact); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_build_flags_out_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*FlagArtifacts); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_build_flags_out_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReleaseConfigArtifact); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_build_flags_out_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReleaseConfigsArtifact); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_build_flags_out_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   6,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_build_flags_out_proto_goTypes,
+		DependencyIndexes: file_build_flags_out_proto_depIdxs,
+		MessageInfos:      file_build_flags_out_proto_msgTypes,
+	}.Build()
+	File_build_flags_out_proto = out.File
+	file_build_flags_out_proto_rawDesc = nil
+	file_build_flags_out_proto_goTypes = nil
+	file_build_flags_out_proto_depIdxs = nil
+}
diff --git a/cmd/release_config/release_config_proto/build_flags_out.proto b/cmd/release_config/release_config_proto/build_flags_out.proto
new file mode 100644
index 0000000..6f34d6f
--- /dev/null
+++ b/cmd/release_config/release_config_proto/build_flags_out.proto
@@ -0,0 +1,94 @@
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+package android.release_config_proto;
+option go_package = "android/soong/release_config/release_config_proto";
+
+import "build_flags_src.proto";
+
+// This protobuf file defines messages used to represent the release config for
+// the android build system, delivered as a build artifact for use by tools such
+// as Gantry.
+//
+// The following format requirements apply across various message fields:
+//
+// # name: name of the flag
+//
+//    format: an uppercase string in SNAKE_CASE format starting with RELEASE_,
+//      no consecutive underscores, and no leading digit. For example
+//      RELEASE_MY_PACKAGE_FLAG is a valid name, while MY_PACKAGE_FLAG, and
+//      RELEASE_MY_PACKAGE__FLAG are invalid.
+//
+// # package: package to which the flag belongs
+//
+//    format: lowercase strings in snake_case format, delimited by dots, no
+//      consecutive underscores and no leading digit in each string. For example
+//      com.android.mypackage is a valid name while com.android.myPackage,
+//      com.android.1mypackage are invalid
+
+message tracepoint {
+  // Path to declaration or value file relative to $TOP
+  optional string source = 1;
+  optional value value = 201;
+}
+
+message flag_artifact {
+  // The original declaration
+  optional flag_declaration flag_declaration = 1;
+
+  // Value for the flag
+  optional value value = 201;
+
+  // Trace of where the flag value was assigned.
+  repeated tracepoint traces = 8;
+}
+
+message flag_artifacts {
+  // The artifacts
+  repeated flag_artifact flag_artifacts = 1;
+}
+
+message release_config_artifact {
+  // The name of the release config.
+  // See # name for format detail
+  optional string name = 1;
+
+  // Other names by which this release is known (for example, `next`)
+  repeated string other_names = 2;
+
+  // The complete set of build flags in this release config, after all
+  // inheritance and other processing is complete.
+  repeated flag_artifact flag_artifacts = 3;
+
+  // The (complete) list of aconfig_value_sets Soong modules to use.
+  repeated string aconfig_value_sets = 4;
+
+  // The names of the release_config_artifacts from which we inherited.
+  // Included for reference only.
+  repeated string inherits = 5;
+
+  // The release config directories used for this config.
+  // For example, "build/release".
+  repeated string directories = 6;
+}
+
+message release_configs_artifact {
+  // The active release config for this build.
+  optional release_config_artifact release_config = 1;
+
+  // All other release configs defined for this TARGET_PRODUCT.
+  repeated release_config_artifact other_release_configs = 2;
+
+  // Map of release_config_artifact.directories to release_config_map message.
+  map<string, release_config_map> release_config_maps_map = 3;
+}
+
diff --git a/cmd/release_config/release_config_proto/build_flags_src.pb.go b/cmd/release_config/release_config_proto/build_flags_src.pb.go
new file mode 100644
index 0000000..dded975
--- /dev/null
+++ b/cmd/release_config/release_config_proto/build_flags_src.pb.go
@@ -0,0 +1,795 @@
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.30.0
+// 	protoc        v3.21.12
+// source: build_flags_src.proto
+
+package release_config_proto
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Workflow int32
+
+const (
+	Workflow_UNSPECIFIED_workflow Workflow = 0
+	// Boolean value flags that progress from false to true.
+	Workflow_LAUNCH Workflow = 1
+	// String value flags that get updated with new version strings to control
+	// prebuilt inclusion.
+	Workflow_PREBUILT Workflow = 2
+	// Manually managed outside flags.  These are likely to be found in a
+	// different directory than flags with other workflows.
+	Workflow_MANUAL Workflow = 3
+)
+
+// Enum value maps for Workflow.
+var (
+	Workflow_name = map[int32]string{
+		0: "UNSPECIFIED_workflow",
+		1: "LAUNCH",
+		2: "PREBUILT",
+		3: "MANUAL",
+	}
+	Workflow_value = map[string]int32{
+		"UNSPECIFIED_workflow": 0,
+		"LAUNCH":               1,
+		"PREBUILT":             2,
+		"MANUAL":               3,
+	}
+)
+
+func (x Workflow) Enum() *Workflow {
+	p := new(Workflow)
+	*p = x
+	return p
+}
+
+func (x Workflow) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (Workflow) Descriptor() protoreflect.EnumDescriptor {
+	return file_build_flags_src_proto_enumTypes[0].Descriptor()
+}
+
+func (Workflow) Type() protoreflect.EnumType {
+	return &file_build_flags_src_proto_enumTypes[0]
+}
+
+func (x Workflow) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Do not use.
+func (x *Workflow) UnmarshalJSON(b []byte) error {
+	num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
+	if err != nil {
+		return err
+	}
+	*x = Workflow(num)
+	return nil
+}
+
+// Deprecated: Use Workflow.Descriptor instead.
+func (Workflow) EnumDescriptor() ([]byte, []int) {
+	return file_build_flags_src_proto_rawDescGZIP(), []int{0}
+}
+
+type Value struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Types that are assignable to Val:
+	//
+	//	*Value_UnspecifiedValue
+	//	*Value_StringValue
+	//	*Value_BoolValue
+	//	*Value_Obsolete
+	Val isValue_Val `protobuf_oneof:"val"`
+}
+
+func (x *Value) Reset() {
+	*x = Value{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_build_flags_src_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Value) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Value) ProtoMessage() {}
+
+func (x *Value) ProtoReflect() protoreflect.Message {
+	mi := &file_build_flags_src_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Value.ProtoReflect.Descriptor instead.
+func (*Value) Descriptor() ([]byte, []int) {
+	return file_build_flags_src_proto_rawDescGZIP(), []int{0}
+}
+
+func (m *Value) GetVal() isValue_Val {
+	if m != nil {
+		return m.Val
+	}
+	return nil
+}
+
+func (x *Value) GetUnspecifiedValue() bool {
+	if x, ok := x.GetVal().(*Value_UnspecifiedValue); ok {
+		return x.UnspecifiedValue
+	}
+	return false
+}
+
+func (x *Value) GetStringValue() string {
+	if x, ok := x.GetVal().(*Value_StringValue); ok {
+		return x.StringValue
+	}
+	return ""
+}
+
+func (x *Value) GetBoolValue() bool {
+	if x, ok := x.GetVal().(*Value_BoolValue); ok {
+		return x.BoolValue
+	}
+	return false
+}
+
+func (x *Value) GetObsolete() bool {
+	if x, ok := x.GetVal().(*Value_Obsolete); ok {
+		return x.Obsolete
+	}
+	return false
+}
+
+type isValue_Val interface {
+	isValue_Val()
+}
+
+type Value_UnspecifiedValue struct {
+	UnspecifiedValue bool `protobuf:"varint,200,opt,name=unspecified_value,json=unspecifiedValue,oneof"`
+}
+
+type Value_StringValue struct {
+	StringValue string `protobuf:"bytes,201,opt,name=string_value,json=stringValue,oneof"`
+}
+
+type Value_BoolValue struct {
+	BoolValue bool `protobuf:"varint,202,opt,name=bool_value,json=boolValue,oneof"`
+}
+
+type Value_Obsolete struct {
+	// If true, the flag is obsolete.  Assigning it further will be flagged.
+	Obsolete bool `protobuf:"varint,203,opt,name=obsolete,oneof"`
+}
+
+func (*Value_UnspecifiedValue) isValue_Val() {}
+
+func (*Value_StringValue) isValue_Val() {}
+
+func (*Value_BoolValue) isValue_Val() {}
+
+func (*Value_Obsolete) isValue_Val() {}
+
+// The proto used in the source tree.
+type FlagDeclaration struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The name of the flag.
+	// See # name for format detail
+	Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+	// Namespace the flag belongs to (required)
+	// See # namespace for format detail
+	Namespace *string `protobuf:"bytes,2,opt,name=namespace" json:"namespace,omitempty"`
+	// Text description of the flag's purpose.
+	Description *string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"`
+	// Value for the flag
+	Value *Value `protobuf:"bytes,201,opt,name=value" json:"value,omitempty"`
+	// Workflow for this flag.
+	Workflow *Workflow `protobuf:"varint,205,opt,name=workflow,enum=android.release_config_proto.Workflow" json:"workflow,omitempty"`
+	// The container for this flag.  This overrides any default container given
+	// in the release_config_map message.
+	Containers []string `protobuf:"bytes,206,rep,name=containers" json:"containers,omitempty"`
+}
+
+func (x *FlagDeclaration) Reset() {
+	*x = FlagDeclaration{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_build_flags_src_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *FlagDeclaration) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FlagDeclaration) ProtoMessage() {}
+
+func (x *FlagDeclaration) ProtoReflect() protoreflect.Message {
+	mi := &file_build_flags_src_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FlagDeclaration.ProtoReflect.Descriptor instead.
+func (*FlagDeclaration) Descriptor() ([]byte, []int) {
+	return file_build_flags_src_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *FlagDeclaration) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (x *FlagDeclaration) GetNamespace() string {
+	if x != nil && x.Namespace != nil {
+		return *x.Namespace
+	}
+	return ""
+}
+
+func (x *FlagDeclaration) GetDescription() string {
+	if x != nil && x.Description != nil {
+		return *x.Description
+	}
+	return ""
+}
+
+func (x *FlagDeclaration) GetValue() *Value {
+	if x != nil {
+		return x.Value
+	}
+	return nil
+}
+
+func (x *FlagDeclaration) GetWorkflow() Workflow {
+	if x != nil && x.Workflow != nil {
+		return *x.Workflow
+	}
+	return Workflow_UNSPECIFIED_workflow
+}
+
+func (x *FlagDeclaration) GetContainers() []string {
+	if x != nil {
+		return x.Containers
+	}
+	return nil
+}
+
+type FlagValue struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Name of the flag.
+	// See # name for format detail
+	Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
+	// Value for the flag
+	Value *Value `protobuf:"bytes,201,opt,name=value" json:"value,omitempty"`
+	// If true, the flag is completely removed from the release config as if
+	// never declared.
+	Redacted *bool `protobuf:"varint,202,opt,name=redacted" json:"redacted,omitempty"`
+}
+
+func (x *FlagValue) Reset() {
+	*x = FlagValue{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_build_flags_src_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *FlagValue) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*FlagValue) ProtoMessage() {}
+
+func (x *FlagValue) ProtoReflect() protoreflect.Message {
+	mi := &file_build_flags_src_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use FlagValue.ProtoReflect.Descriptor instead.
+func (*FlagValue) Descriptor() ([]byte, []int) {
+	return file_build_flags_src_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *FlagValue) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (x *FlagValue) GetValue() *Value {
+	if x != nil {
+		return x.Value
+	}
+	return nil
+}
+
+func (x *FlagValue) GetRedacted() bool {
+	if x != nil && x.Redacted != nil {
+		return *x.Redacted
+	}
+	return false
+}
+
+// This replaces $(call declare-release-config).
+type ReleaseConfig struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The name of the release config.
+	// See # name for format detail
+	Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+	// From which other release configs does this one inherit?
+	Inherits []string `protobuf:"bytes,2,rep,name=inherits" json:"inherits,omitempty"`
+	// List of names of the aconfig_value_set soong module(s) for this
+	// contribution.
+	AconfigValueSets []string `protobuf:"bytes,3,rep,name=aconfig_value_sets,json=aconfigValueSets" json:"aconfig_value_sets,omitempty"`
+	// Only aconfig flags are allowed in this release config.
+	AconfigFlagsOnly *bool `protobuf:"varint,4,opt,name=aconfig_flags_only,json=aconfigFlagsOnly" json:"aconfig_flags_only,omitempty"`
+}
+
+func (x *ReleaseConfig) Reset() {
+	*x = ReleaseConfig{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_build_flags_src_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReleaseConfig) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReleaseConfig) ProtoMessage() {}
+
+func (x *ReleaseConfig) ProtoReflect() protoreflect.Message {
+	mi := &file_build_flags_src_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReleaseConfig.ProtoReflect.Descriptor instead.
+func (*ReleaseConfig) Descriptor() ([]byte, []int) {
+	return file_build_flags_src_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *ReleaseConfig) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (x *ReleaseConfig) GetInherits() []string {
+	if x != nil {
+		return x.Inherits
+	}
+	return nil
+}
+
+func (x *ReleaseConfig) GetAconfigValueSets() []string {
+	if x != nil {
+		return x.AconfigValueSets
+	}
+	return nil
+}
+
+func (x *ReleaseConfig) GetAconfigFlagsOnly() bool {
+	if x != nil && x.AconfigFlagsOnly != nil {
+		return *x.AconfigFlagsOnly
+	}
+	return false
+}
+
+// Any aliases.  These are used for continuous integration builder config.
+type ReleaseAlias struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The name of the alias.
+	Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+	// The release that `name` is an alias for.
+	Target *string `protobuf:"bytes,2,opt,name=target" json:"target,omitempty"`
+}
+
+func (x *ReleaseAlias) Reset() {
+	*x = ReleaseAlias{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_build_flags_src_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReleaseAlias) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReleaseAlias) ProtoMessage() {}
+
+func (x *ReleaseAlias) ProtoReflect() protoreflect.Message {
+	mi := &file_build_flags_src_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReleaseAlias.ProtoReflect.Descriptor instead.
+func (*ReleaseAlias) Descriptor() ([]byte, []int) {
+	return file_build_flags_src_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *ReleaseAlias) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (x *ReleaseAlias) GetTarget() string {
+	if x != nil && x.Target != nil {
+		return *x.Target
+	}
+	return ""
+}
+
+// This provides the data from release_config_map.mk
+type ReleaseConfigMap struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// Any aliases.
+	Aliases []*ReleaseAlias `protobuf:"bytes,1,rep,name=aliases" json:"aliases,omitempty"`
+	// Description of this map and its intended use.
+	Description *string `protobuf:"bytes,2,opt,name=description" json:"description,omitempty"`
+	// The default container for flags declared here.
+	DefaultContainers []string `protobuf:"bytes,3,rep,name=default_containers,json=defaultContainers" json:"default_containers,omitempty"`
+}
+
+func (x *ReleaseConfigMap) Reset() {
+	*x = ReleaseConfigMap{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_build_flags_src_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ReleaseConfigMap) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReleaseConfigMap) ProtoMessage() {}
+
+func (x *ReleaseConfigMap) ProtoReflect() protoreflect.Message {
+	mi := &file_build_flags_src_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReleaseConfigMap.ProtoReflect.Descriptor instead.
+func (*ReleaseConfigMap) Descriptor() ([]byte, []int) {
+	return file_build_flags_src_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *ReleaseConfigMap) GetAliases() []*ReleaseAlias {
+	if x != nil {
+		return x.Aliases
+	}
+	return nil
+}
+
+func (x *ReleaseConfigMap) GetDescription() string {
+	if x != nil && x.Description != nil {
+		return *x.Description
+	}
+	return ""
+}
+
+func (x *ReleaseConfigMap) GetDefaultContainers() []string {
+	if x != nil {
+		return x.DefaultContainers
+	}
+	return nil
+}
+
+var File_build_flags_src_proto protoreflect.FileDescriptor
+
+var file_build_flags_src_proto_rawDesc = []byte{
+	0x0a, 0x15, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x5f, 0x73, 0x72,
+	0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
+	0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa5, 0x01, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12,
+	0x2e, 0x0a, 0x11, 0x75, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x18, 0xc8, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x10, 0x75,
+	0x6e, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12,
+	0x24, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+	0xc9, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67,
+	0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x20, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, 0x5f, 0x76, 0x61,
+	0x6c, 0x75, 0x65, 0x18, 0xca, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6f,
+	0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1d, 0x0a, 0x08, 0x6f, 0x62, 0x73, 0x6f, 0x6c,
+	0x65, 0x74, 0x65, 0x18, 0xcb, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x62,
+	0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x05, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x22, 0x96, 0x02,
+	0x0a, 0x10, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70,
+	0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73,
+	0x70, 0x61, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74,
+	0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
+	0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+	0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64,
+	0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c,
+	0x75, 0x65, 0x12, 0x43, 0x0a, 0x08, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x18, 0xcd,
+	0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e,
+	0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x52, 0x08, 0x77,
+	0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x1f, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61,
+	0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0xce, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f,
+	0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x06,
+	0x08, 0xcf, 0x01, 0x10, 0xd0, 0x01, 0x22, 0x79, 0x0a, 0x0a, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
+	0x65, 0x18, 0xc9, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f,
+	0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
+	0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x12, 0x1b, 0x0a, 0x08, 0x72, 0x65, 0x64, 0x61, 0x63, 0x74, 0x65, 0x64,
+	0x18, 0xca, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x64, 0x61, 0x63, 0x74, 0x65,
+	0x64, 0x22, 0x9c, 0x01, 0x0a, 0x0e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f,
+	0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x68, 0x65,
+	0x72, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x6e, 0x68, 0x65,
+	0x72, 0x69, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09,
+	0x52, 0x10, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x53, 0x65,
+	0x74, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x66, 0x6c,
+	0x61, 0x67, 0x73, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10,
+	0x61, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x6c, 0x61, 0x67, 0x73, 0x4f, 0x6e, 0x6c, 0x79,
+	0x22, 0x3b, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x61, 0x6c, 0x69, 0x61,
+	0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0xac, 0x01,
+	0x0a, 0x12, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+	0x5f, 0x6d, 0x61, 0x70, 0x12, 0x45, 0x0a, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x18,
+	0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e,
+	0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70,
+	0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x61, 0x6c, 0x69,
+	0x61, 0x73, 0x52, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64,
+	0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a,
+	0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
+	0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75,
+	0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2a, 0x4a, 0x0a, 0x08,
+	0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x0a, 0x14, 0x55, 0x4e, 0x53, 0x50,
+	0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
+	0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x41, 0x55, 0x4e, 0x43, 0x48, 0x10, 0x01, 0x12, 0x0c,
+	0x0a, 0x08, 0x50, 0x52, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06,
+	0x4d, 0x41, 0x4e, 0x55, 0x41, 0x4c, 0x10, 0x03, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72,
+	0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73,
+	0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
+	0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+}
+
+var (
+	file_build_flags_src_proto_rawDescOnce sync.Once
+	file_build_flags_src_proto_rawDescData = file_build_flags_src_proto_rawDesc
+)
+
+func file_build_flags_src_proto_rawDescGZIP() []byte {
+	file_build_flags_src_proto_rawDescOnce.Do(func() {
+		file_build_flags_src_proto_rawDescData = protoimpl.X.CompressGZIP(file_build_flags_src_proto_rawDescData)
+	})
+	return file_build_flags_src_proto_rawDescData
+}
+
+var file_build_flags_src_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_build_flags_src_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
+var file_build_flags_src_proto_goTypes = []interface{}{
+	(Workflow)(0),            // 0: android.release_config_proto.workflow
+	(*Value)(nil),            // 1: android.release_config_proto.value
+	(*FlagDeclaration)(nil),  // 2: android.release_config_proto.flag_declaration
+	(*FlagValue)(nil),        // 3: android.release_config_proto.flag_value
+	(*ReleaseConfig)(nil),    // 4: android.release_config_proto.release_config
+	(*ReleaseAlias)(nil),     // 5: android.release_config_proto.release_alias
+	(*ReleaseConfigMap)(nil), // 6: android.release_config_proto.release_config_map
+}
+var file_build_flags_src_proto_depIdxs = []int32{
+	1, // 0: android.release_config_proto.flag_declaration.value:type_name -> android.release_config_proto.value
+	0, // 1: android.release_config_proto.flag_declaration.workflow:type_name -> android.release_config_proto.workflow
+	1, // 2: android.release_config_proto.flag_value.value:type_name -> android.release_config_proto.value
+	5, // 3: android.release_config_proto.release_config_map.aliases:type_name -> android.release_config_proto.release_alias
+	4, // [4:4] is the sub-list for method output_type
+	4, // [4:4] is the sub-list for method input_type
+	4, // [4:4] is the sub-list for extension type_name
+	4, // [4:4] is the sub-list for extension extendee
+	0, // [0:4] is the sub-list for field type_name
+}
+
+func init() { file_build_flags_src_proto_init() }
+func file_build_flags_src_proto_init() {
+	if File_build_flags_src_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_build_flags_src_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Value); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_build_flags_src_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*FlagDeclaration); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_build_flags_src_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*FlagValue); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_build_flags_src_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReleaseConfig); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_build_flags_src_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReleaseAlias); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_build_flags_src_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ReleaseConfigMap); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	file_build_flags_src_proto_msgTypes[0].OneofWrappers = []interface{}{
+		(*Value_UnspecifiedValue)(nil),
+		(*Value_StringValue)(nil),
+		(*Value_BoolValue)(nil),
+		(*Value_Obsolete)(nil),
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_build_flags_src_proto_rawDesc,
+			NumEnums:      1,
+			NumMessages:   6,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_build_flags_src_proto_goTypes,
+		DependencyIndexes: file_build_flags_src_proto_depIdxs,
+		EnumInfos:         file_build_flags_src_proto_enumTypes,
+		MessageInfos:      file_build_flags_src_proto_msgTypes,
+	}.Build()
+	File_build_flags_src_proto = out.File
+	file_build_flags_src_proto_rawDesc = nil
+	file_build_flags_src_proto_goTypes = nil
+	file_build_flags_src_proto_depIdxs = nil
+}
diff --git a/cmd/release_config/release_config_proto/build_flags_src.proto b/cmd/release_config/release_config_proto/build_flags_src.proto
new file mode 100644
index 0000000..0ef1a5f
--- /dev/null
+++ b/cmd/release_config/release_config_proto/build_flags_src.proto
@@ -0,0 +1,151 @@
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+package android.release_config_proto;
+option go_package = "android/soong/release_config/release_config_proto";
+
+// This protobuf file defines messages used to represent the build flags used by
+// a release in a more human-editable form.  It is used for on-disk files in the
+// source tree.
+//
+// The following format requirements apply across various message fields:
+//
+// # name: name of the flag
+//
+//    format: an uppercase string in SNAKE_CASE format starting with RELEASE_,
+//      no consecutive underscores, and no leading digit. For example
+//      RELEASE_MY_PACKAGE_FLAG is a valid name, while MY_PACKAGE_FLAG, and
+//      RELEASE_MY_PACKAGE__FLAG are invalid.
+//
+// # namespace: namespace the flag belongs to
+//
+//    format: a lowercase string in snake_case format, no consecutive underscores, and no leading
+//      digit. For example android_bar_system
+//
+// # package: package to which the flag belongs
+//
+//    format: lowercase strings in snake_case format, delimited by dots, no
+//      consecutive underscores and no leading digit in each string. For example
+//      com.android.mypackage is a valid name while com.android.myPackage,
+//      com.android.1mypackage are invalid
+
+enum workflow {
+  UNSPECIFIED_workflow = 0;
+
+  // Boolean value flags that progress from false to true.
+  LAUNCH = 1;
+
+  // String value flags that get updated with new version strings to control
+  // prebuilt inclusion.
+  PREBUILT = 2;
+
+  // Manually managed outside flags.  These are likely to be found in a
+  // different directory than flags with other workflows.
+  MANUAL = 3;
+}
+
+message value {
+  oneof val {
+    bool unspecified_value = 200;
+    string string_value = 201;
+    bool bool_value = 202;
+    // If true, the flag is obsolete.  Assigning it further will be flagged.
+    bool obsolete = 203;
+  }
+}
+
+// The proto used in the source tree.
+message flag_declaration {
+  // The name of the flag.
+  // See # name for format detail
+  optional string name = 1;
+
+  // Namespace the flag belongs to (required)
+  // See # namespace for format detail
+  optional string namespace = 2;
+
+  // Text description of the flag's purpose.
+  optional string description = 3;
+
+  // reserve this for bug, if needed.
+  reserved 4;
+
+  // Value for the flag
+  optional value value = 201;
+
+  // Workflow for this flag.
+  optional workflow workflow = 205;
+
+  // The container for this flag.  This overrides any default container given
+  // in the release_config_map message.
+  repeated string containers = 206;
+
+  // The package associated with this flag.
+  // (when Gantry is ready for it) optional string package = 207;
+  reserved 207;
+}
+
+message flag_value {
+  // Name of the flag.
+  // See # name for format detail
+  optional string name = 2;
+
+  // Value for the flag
+  optional value value = 201;
+
+  // If true, the flag is completely removed from the release config as if
+  // never declared.
+  optional bool redacted = 202;
+}
+
+// This replaces $(call declare-release-config).
+message release_config {
+  // The name of the release config.
+  // See # name for format detail
+  optional string name = 1;
+
+  // From which other release configs does this one inherit?
+  repeated string inherits = 2;
+
+  // List of names of the aconfig_value_set soong module(s) for this
+  // contribution.
+  repeated string aconfig_value_sets = 3;
+
+  // Only aconfig flags are allowed in this release config.
+  optional bool aconfig_flags_only = 4;
+}
+
+// Any aliases.  These are used for continuous integration builder config.
+message release_alias {
+  // The name of the alias.
+  optional string name = 1;
+
+  // The release that `name` is an alias for.
+  optional string target = 2;
+}
+
+// This provides the data from release_config_map.mk
+message release_config_map {
+  // Any aliases.
+  repeated release_alias aliases = 1;
+
+  // Description of this map and its intended use.
+  optional string description = 2;
+
+  // The default container for flags declared here.
+  repeated string default_containers = 3;
+
+  // If needed, we can add these fields instead of hardcoding the location.
+  // Flag declarations: `flag_declarations/*.textproto`
+  // Release config contributions: `release_configs/*.textproto`
+  // Flag values: `flag_values/{RELEASE_NAME}/*.textproto`
+}
diff --git a/cmd/release_config/release_config_proto/regen.sh b/cmd/release_config/release_config_proto/regen.sh
new file mode 100644
index 0000000..1846c4d
--- /dev/null
+++ b/cmd/release_config/release_config_proto/regen.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+aprotoc --go_out=paths=source_relative:. build_flags_src.proto build_flags_out.proto
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index fc56dd5..e69a930 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -22,6 +22,7 @@
 	"flag"
 	"fmt"
 	"io"
+	"io/fs"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -119,6 +120,9 @@
 	}
 
 	manifest, err := readManifest(manifestFile)
+	if err != nil {
+		return err
+	}
 
 	if len(manifest.Commands) == 0 {
 		return fmt.Errorf("at least one commands entry is required in %q", manifestFile)
@@ -475,7 +479,8 @@
 // copyOneFile copies a file and its permissions.  If forceExecutable is true it adds u+x to the
 // permissions.  If exists is allowFromNotExists it returns nil if the from path doesn't exist.
 // If write is onlyWriteIfChanged then the output file is compared to the input file and not written to
-// if it is the same, avoiding updating the timestamp.
+// if it is the same, avoiding updating the timestamp. If from is a symlink, the symlink itself
+// will be copied, instead of what it points to.
 func copyOneFile(from string, to string, forceExecutable bool, exists existsType,
 	write writeType) error {
 	err := os.MkdirAll(filepath.Dir(to), 0777)
@@ -483,7 +488,7 @@
 		return err
 	}
 
-	stat, err := os.Stat(from)
+	stat, err := os.Lstat(from)
 	if err != nil {
 		if os.IsNotExist(err) && exists == allowFromNotExists {
 			return nil
@@ -491,6 +496,25 @@
 		return err
 	}
 
+	if stat.Mode()&fs.ModeSymlink != 0 {
+		linkTarget, err := os.Readlink(from)
+		if err != nil {
+			return err
+		}
+		if write == onlyWriteIfChanged {
+			toLinkTarget, err := os.Readlink(to)
+			if err == nil && toLinkTarget == linkTarget {
+				return nil
+			}
+		}
+		err = os.Remove(to)
+		if err != nil && !os.IsNotExist(err) {
+			return err
+		}
+
+		return os.Symlink(linkTarget, to)
+	}
+
 	perm := stat.Mode()
 	if forceExecutable {
 		perm = perm | 0100 // u+x
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 20e366e..d64010e 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -21,16 +21,13 @@
 	"fmt"
 	"os"
 	"path/filepath"
-	"regexp"
 	"strings"
 	"time"
 
 	"android/soong/android"
 	"android/soong/android/allowlists"
-	"android/soong/bazel"
 	"android/soong/bp2build"
 	"android/soong/shared"
-	"android/soong/ui/metrics/bp2build_metrics_proto"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
@@ -76,19 +73,12 @@
 	flag.StringVar(&cmdlineArgs.ModuleActionsFile, "module_actions_file", "", "JSON file to output inputs/outputs of actions of modules")
 	flag.StringVar(&cmdlineArgs.DocFile, "soong_docs", "", "build documentation file to output")
 	flag.StringVar(&cmdlineArgs.BazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top")
-	flag.StringVar(&cmdlineArgs.BazelApiBp2buildDir, "bazel_api_bp2build_dir", "", "path to the bazel api_bp2build directory relative to --top")
-	flag.StringVar(&cmdlineArgs.Bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
-	flag.StringVar(&cmdlineArgs.SymlinkForestMarker, "symlink_forest_marker", "", "If set, create the bp2build symlink forest, touch the specified marker file, then exit")
 	flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
 	flag.StringVar(&cmdlineArgs.SoongVariables, "soong_variables", "soong.variables", "the file contains all build variables")
-	flag.StringVar(&cmdlineArgs.BazelForceEnabledModules, "bazel-force-enabled-modules", "", "additional modules to build with Bazel. Comma-delimited")
 	flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
-	flag.BoolVar(&cmdlineArgs.MultitreeBuild, "multitree-build", false, "this is a multitree build")
-	flag.BoolVar(&cmdlineArgs.BazelMode, "bazel-mode", false, "use bazel for analysis of certain modules")
-	flag.BoolVar(&cmdlineArgs.BazelModeStaging, "bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules")
-	flag.BoolVar(&cmdlineArgs.UseBazelProxy, "use-bazel-proxy", false, "communicate with bazel using unix socket proxy instead of spawning subprocesses")
-	flag.BoolVar(&cmdlineArgs.BuildFromTextStub, "build-from-text-stub", false, "build Java stubs from API text files instead of source files")
+	flag.BoolVar(&cmdlineArgs.BuildFromSourceStub, "build-from-source-stub", false, "build Java stubs from source files instead of API text files")
 	flag.BoolVar(&cmdlineArgs.EnsureAllowlistIntegrity, "ensure-allowlist-integrity", false, "verify that allowlisted modules are mixed-built")
+	flag.StringVar(&cmdlineArgs.ModuleDebugFile, "soong_module_debug", "", "soong module debug info file to write")
 	// Flags that probably shouldn't be flags of soong_build, but we haven't found
 	// the time to remove them yet
 	flag.BoolVar(&cmdlineArgs.RunGoTests, "t", false, "build and run go tests during bootstrap")
@@ -113,40 +103,6 @@
 	return ctx
 }
 
-// Bazel-enabled mode. Attaches a mutator to queue Bazel requests, adds a
-// BeforePrepareBuildActionsHook to invoke Bazel, and then uses Bazel metadata
-// for modules that should be handled by Bazel.
-func runMixedModeBuild(ctx *android.Context, extraNinjaDeps []string) string {
-	ctx.EventHandler.Begin("mixed_build")
-	defer ctx.EventHandler.End("mixed_build")
-
-	bazelHook := func() error {
-		err := ctx.Config().BazelContext.QueueBazelSandwichCqueryRequests(ctx.Config())
-		if err != nil {
-			return err
-		}
-		return ctx.Config().BazelContext.InvokeBazel(ctx.Config(), ctx)
-	}
-	ctx.SetBeforePrepareBuildActionsHook(bazelHook)
-	ninjaDeps, err := bootstrap.RunBlueprint(cmdlineArgs.Args, bootstrap.DoEverything, ctx.Context, ctx.Config())
-	maybeQuit(err, "")
-	ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
-
-	bazelPaths, err := readFileLines(ctx.Config().Getenv("BAZEL_DEPS_FILE"))
-	if err != nil {
-		panic("Bazel deps file not found: " + err.Error())
-	}
-	ninjaDeps = append(ninjaDeps, bazelPaths...)
-	ninjaDeps = append(ninjaDeps, writeBuildGlobsNinjaFile(ctx)...)
-
-	writeDepFile(cmdlineArgs.OutFile, ctx.EventHandler, ninjaDeps)
-
-	if needToWriteNinjaHint(ctx) {
-		writeNinjaHint(ctx)
-	}
-	return cmdlineArgs.OutFile
-}
-
 func needToWriteNinjaHint(ctx *android.Context) bool {
 	switch ctx.Config().GetenvWithDefault("SOONG_GENERATES_NINJA_HINT", "") {
 	case "always":
@@ -169,120 +125,6 @@
 	touch(shared.JoinPath(topDir, queryviewMarker))
 }
 
-// Run the code-generation phase to convert API contributions to BUILD files.
-// Return marker file for the new synthetic workspace
-func runApiBp2build(ctx *android.Context, extraNinjaDeps []string) string {
-	ctx.EventHandler.Begin("api_bp2build")
-	defer ctx.EventHandler.End("api_bp2build")
-	// api_bp2build does not run the typical pipeline of soong mutators.
-	// Hoevever, it still runs the defaults mutator which can create dependencies.
-	// These dependencies might not always exist (e.g. in tests)
-	ctx.SetAllowMissingDependencies(ctx.Config().AllowMissingDependencies())
-	ctx.RegisterForApiBazelConversion()
-
-	// Register the Android.bp files in the tree
-	// Add them to the workspace's .d file
-	ctx.SetModuleListFile(cmdlineArgs.ModuleListFile)
-	if paths, err := ctx.ListModulePaths("."); err == nil {
-		extraNinjaDeps = append(extraNinjaDeps, paths...)
-	} else {
-		panic(err)
-	}
-
-	// Run the loading and analysis phase
-	ninjaDeps, err := bootstrap.RunBlueprint(cmdlineArgs.Args,
-		bootstrap.StopBeforePrepareBuildActions,
-		ctx.Context,
-		ctx.Config())
-	maybeQuit(err, "")
-	ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
-
-	// Add the globbed dependencies
-	ninjaDeps = append(ninjaDeps, writeBuildGlobsNinjaFile(ctx)...)
-
-	// Run codegen to generate BUILD files
-	codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.ApiBp2build, topDir)
-	absoluteApiBp2buildDir := shared.JoinPath(topDir, cmdlineArgs.BazelApiBp2buildDir)
-	// Always generate bp2build_all_srcs filegroups in api_bp2build.
-	// This is necessary to force each Android.bp file to create an equivalent BUILD file
-	// and prevent package boundray issues.
-	// e.g.
-	// Source
-	// f/b/Android.bp
-	// java_library{
-	//   name: "foo",
-	//   api: "api/current.txt",
-	// }
-	//
-	// f/b/api/Android.bp <- will cause package boundary issues
-	//
-	// Gen
-	// f/b/BUILD
-	// java_contribution{
-	//   name: "foo.contribution",
-	//   api: "//f/b/api:current.txt",
-	// }
-	//
-	// If we don't generate f/b/api/BUILD, foo.contribution will be unbuildable.
-	err = createBazelWorkspace(codegenContext, absoluteApiBp2buildDir, true)
-	maybeQuit(err, "")
-	ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
-
-	// Create soong_injection repository
-	soongInjectionFiles, workspaceFiles, err := bp2build.CreateSoongInjectionDirFiles(codegenContext, bp2build.CreateCodegenMetrics())
-	maybeQuit(err, "")
-	absoluteSoongInjectionDir := shared.JoinPath(topDir, ctx.Config().SoongOutDir(), bazel.SoongInjectionDirName)
-	for _, file := range soongInjectionFiles {
-		// The API targets in api_bp2build workspace do not have any dependency on api_bp2build.
-		// But we need to create these files to prevent errors during Bazel analysis.
-		// These need to be created in Read-Write mode.
-		// This is because the subsequent step (bp2build in api domain analysis) creates them in Read-Write mode
-		// to allow users to edit/experiment in the synthetic workspace.
-		writeReadWriteFile(absoluteSoongInjectionDir, file)
-	}
-	for _, file := range workspaceFiles {
-		writeReadWriteFile(absoluteApiBp2buildDir, file)
-	}
-
-	workspace := shared.JoinPath(ctx.Config().SoongOutDir(), "api_bp2build")
-	// Create the symlink forest
-	symlinkDeps, _, _ := bp2build.PlantSymlinkForest(
-		ctx.Config().IsEnvTrue("BP2BUILD_VERBOSE"),
-		topDir,
-		workspace,
-		cmdlineArgs.BazelApiBp2buildDir,
-		apiBuildFileExcludes(ctx))
-	ninjaDeps = append(ninjaDeps, symlinkDeps...)
-
-	workspaceMarkerFile := workspace + ".marker"
-	writeDepFile(workspaceMarkerFile, ctx.EventHandler, ninjaDeps)
-	touch(shared.JoinPath(topDir, workspaceMarkerFile))
-	return workspaceMarkerFile
-}
-
-// With some exceptions, api_bp2build does not have any dependencies on the checked-in BUILD files
-// Exclude them from the generated workspace to prevent unrelated errors during the loading phase
-func apiBuildFileExcludes(ctx *android.Context) []string {
-	ret := bazelArtifacts()
-	srcs, err := getExistingBazelRelatedFiles(topDir)
-	maybeQuit(err, "Error determining existing Bazel-related files")
-	for _, src := range srcs {
-		// Exclude all src BUILD files
-		if src != "WORKSPACE" &&
-			src != "BUILD" &&
-			src != "BUILD.bazel" &&
-			!strings.HasPrefix(src, "build/bazel") &&
-			!strings.HasPrefix(src, "external/bazel-skylib") &&
-			!strings.HasPrefix(src, "prebuilts/clang") {
-			ret = append(ret, src)
-		}
-	}
-	// Android.bp files for api surfaces are mounted to out/, but out/ should not be a
-	// dep for api_bp2build. Otherwise, api_bp2build will be run every single time
-	ret = append(ret, ctx.Config().OutDir())
-	return ret
-}
-
 func writeNinjaHint(ctx *android.Context) error {
 	ctx.BeginEvent("ninja_hint")
 	defer ctx.EndEvent("ninja_hint")
@@ -345,67 +187,6 @@
 	maybeQuit(err, "error writing soong_build metrics %s", metricsFile)
 }
 
-// Errors out if any modules expected to be mixed_built were not, unless
-// the modules did not exist.
-func checkForAllowlistIntegrityError(configuration android.Config, isStagingMode bool) error {
-	modules := findMisconfiguredModules(configuration, isStagingMode)
-	if len(modules) == 0 {
-		return nil
-	}
-
-	return fmt.Errorf("Error: expected the following modules to be mixed_built: %s", modules)
-}
-
-// Returns true if the given module has all of the following true:
-//  1. Is allowlisted to be built with Bazel.
-//  2. Has a variant which is *not* built with Bazel.
-//  3. Has no variant which is built with Bazel.
-//
-// This indicates the allowlisting of this variant had no effect.
-// TODO(b/280457637): Return true for nonexistent modules.
-func isAllowlistMisconfiguredForModule(module string, mixedBuildsEnabled map[string]struct{}, mixedBuildsDisabled map[string]struct{}) bool {
-	_, enabled := mixedBuildsEnabled[module]
-
-	if enabled {
-		return false
-	}
-
-	_, disabled := mixedBuildsDisabled[module]
-	return disabled
-
-}
-
-// Returns the list of modules that should have been mixed_built (per the
-// allowlists and cmdline flags) but were not.
-// Note: nonexistent modules are excluded from the list. See b/280457637
-func findMisconfiguredModules(configuration android.Config, isStagingMode bool) []string {
-	retval := []string{}
-	forceEnabledModules := configuration.BazelModulesForceEnabledByFlag()
-
-	mixedBuildsEnabled := configuration.GetMixedBuildsEnabledModules()
-	mixedBuildsDisabled := configuration.GetMixedBuildsDisabledModules()
-	for _, module := range allowlists.ProdMixedBuildsEnabledList {
-		if isAllowlistMisconfiguredForModule(module, mixedBuildsEnabled, mixedBuildsDisabled) {
-			retval = append(retval, module)
-		}
-	}
-
-	if isStagingMode {
-		for _, module := range allowlists.StagingMixedBuildsEnabledList {
-			if isAllowlistMisconfiguredForModule(module, mixedBuildsEnabled, mixedBuildsDisabled) {
-				retval = append(retval, module)
-			}
-		}
-	}
-
-	for module, _ := range forceEnabledModules {
-		if isAllowlistMisconfiguredForModule(module, mixedBuildsEnabled, mixedBuildsDisabled) {
-			retval = append(retval, module)
-		}
-	}
-	return retval
-}
-
 func writeJsonModuleGraphAndActions(ctx *android.Context, cmdArgs android.CmdArgs) {
 	graphFile, graphErr := os.Create(shared.JoinPath(topDir, cmdArgs.ModuleGraphFile))
 	maybeQuit(graphErr, "graph err")
@@ -416,7 +197,7 @@
 	ctx.Context.PrintJSONGraphAndActions(graphFile, actionsFile)
 }
 
-func writeBuildGlobsNinjaFile(ctx *android.Context) []string {
+func writeBuildGlobsNinjaFile(ctx *android.Context) {
 	ctx.EventHandler.Begin("globs_ninja_file")
 	defer ctx.EventHandler.End("globs_ninja_file")
 
@@ -428,7 +209,6 @@
 		SrcDir:     ctx.SrcDir(),
 	}, ctx.Config())
 	maybeQuit(err, "")
-	return bootstrap.GlobFileListFiles(globDir)
 }
 
 func writeDepFile(outputFile string, eventHandler *metrics.EventHandler, ninjaDeps []string) {
@@ -458,8 +238,7 @@
 	maybeQuit(err, "")
 	ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
 
-	globListFiles := writeBuildGlobsNinjaFile(ctx)
-	ninjaDeps = append(ninjaDeps, globListFiles...)
+	writeBuildGlobsNinjaFile(ctx)
 
 	// Convert the Soong module graph into Bazel BUILD files.
 	switch ctx.Config().BuildMode {
@@ -539,41 +318,11 @@
 	metricsDir := availableEnv["LOG_DIR"]
 
 	ctx := newContext(configuration)
+	android.StartBackgroundMetrics(configuration)
 
-	var finalOutputFile string
-
-	// Run Soong for a specific activity, like bp2build, queryview
-	// or the actual Soong build for the build.ninja file.
-	switch configuration.BuildMode {
-	case android.SymlinkForest:
-		finalOutputFile = runSymlinkForestCreation(ctx, extraNinjaDeps, metricsDir)
-	case android.Bp2build:
-		// Run the alternate pipeline of bp2build mutators and singleton to convert
-		// Blueprint to BUILD files before everything else.
-		finalOutputFile = runBp2Build(ctx, extraNinjaDeps, metricsDir)
-	case android.ApiBp2build:
-		finalOutputFile = runApiBp2build(ctx, extraNinjaDeps)
-		writeMetrics(configuration, ctx.EventHandler, metricsDir)
-	default:
-		ctx.Register()
-		isMixedBuildsEnabled := configuration.IsMixedBuildsEnabled()
-		if isMixedBuildsEnabled {
-			finalOutputFile = runMixedModeBuild(ctx, extraNinjaDeps)
-			if cmdlineArgs.EnsureAllowlistIntegrity {
-				if err := checkForAllowlistIntegrityError(configuration, cmdlineArgs.BazelModeStaging); err != nil {
-					maybeQuit(err, "")
-				}
-			}
-		} else {
-			finalOutputFile = runSoongOnlyBuild(ctx, extraNinjaDeps)
-		}
-		writeMetrics(configuration, ctx.EventHandler, metricsDir)
-	}
-
-	// Register this environment variablesas being an implicit dependencies of
-	// soong_build. Changes to this environment variable will result in
-	// retriggering soong_build.
-	configuration.Getenv("USE_BAZEL_VERSION")
+	ctx.Register()
+	finalOutputFile := runSoongOnlyBuild(ctx, extraNinjaDeps)
+	writeMetrics(configuration, ctx.EventHandler, metricsDir)
 
 	writeUsedEnvironmentFile(configuration)
 
@@ -616,246 +365,6 @@
 	maybeQuit(err, "error touching '%s'", path)
 }
 
-// Read the bazel.list file that the Soong Finder already dumped earlier (hopefully)
-// It contains the locations of BUILD files, BUILD.bazel files, etc. in the source dir
-func getExistingBazelRelatedFiles(topDir string) ([]string, error) {
-	bazelFinderFile := filepath.Join(filepath.Dir(cmdlineArgs.ModuleListFile), "bazel.list")
-	if !filepath.IsAbs(bazelFinderFile) {
-		// Assume this was a relative path under topDir
-		bazelFinderFile = filepath.Join(topDir, bazelFinderFile)
-	}
-	return readFileLines(bazelFinderFile)
-}
-
-func bazelArtifacts() []string {
-	return []string{
-		"bazel-bin",
-		"bazel-genfiles",
-		"bazel-out",
-		"bazel-testlogs",
-		"bazel-workspace",
-		"bazel-" + filepath.Base(topDir),
-	}
-}
-
-// This could in theory easily be separated into a binary that generically
-// merges two directories into a symlink tree. The main obstacle is that this
-// function currently depends on both Bazel-specific knowledge (the existence
-// of bazel-* symlinks) and configuration (the set of BUILD.bazel files that
-// should and should not be kept)
-//
-// Ideally, bp2build would write a file that contains instructions to the
-// symlink tree creation binary. Then the latter would not need to depend on
-// the very heavy-weight machinery of soong_build .
-func runSymlinkForestCreation(ctx *android.Context, extraNinjaDeps []string, metricsDir string) string {
-	var ninjaDeps []string
-	var mkdirCount, symlinkCount uint64
-
-	ctx.EventHandler.Do("symlink_forest", func() {
-		ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
-		verbose := ctx.Config().IsEnvTrue("BP2BUILD_VERBOSE")
-
-		// PlantSymlinkForest() returns all the directories that were readdir()'ed.
-		// Such a directory SHOULD be added to `ninjaDeps` so that a child directory
-		// or file created/deleted under it would trigger an update of the symlink forest.
-		generatedRoot := shared.JoinPath(ctx.Config().SoongOutDir(), "bp2build")
-		workspaceRoot := shared.JoinPath(ctx.Config().SoongOutDir(), "workspace")
-		var symlinkForestDeps []string
-		ctx.EventHandler.Do("plant", func() {
-			symlinkForestDeps, mkdirCount, symlinkCount = bp2build.PlantSymlinkForest(
-				verbose, topDir, workspaceRoot, generatedRoot, excludedFromSymlinkForest(ctx, verbose))
-		})
-		ninjaDeps = append(ninjaDeps, symlinkForestDeps...)
-	})
-
-	writeDepFile(cmdlineArgs.SymlinkForestMarker, ctx.EventHandler, ninjaDeps)
-	touch(shared.JoinPath(topDir, cmdlineArgs.SymlinkForestMarker))
-	codegenMetrics := bp2build.ReadCodegenMetrics(metricsDir)
-	if codegenMetrics == nil {
-		m := bp2build.CreateCodegenMetrics()
-		codegenMetrics = &m
-	} else {
-		//TODO (usta) we cannot determine if we loaded a stale file, i.e. from an unrelated prior
-		//invocation of codegen. We should simply use a separate .pb file
-	}
-	codegenMetrics.SetSymlinkCount(symlinkCount)
-	codegenMetrics.SetMkDirCount(mkdirCount)
-	writeBp2BuildMetrics(codegenMetrics, ctx.EventHandler, metricsDir)
-	return cmdlineArgs.SymlinkForestMarker
-}
-
-func excludedFromSymlinkForest(ctx *android.Context, verbose bool) []string {
-	excluded := bazelArtifacts()
-	if cmdlineArgs.OutDir[0] != '/' {
-		excluded = append(excluded, cmdlineArgs.OutDir)
-	}
-
-	// Find BUILD files in the srcDir which are not in the allowlist
-	// (android.Bp2BuildConversionAllowlist#ShouldKeepExistingBuildFileForDir)
-	// and return their paths so they can be left out of the Bazel workspace dir (i.e. ignored)
-	existingBazelFiles, err := getExistingBazelRelatedFiles(topDir)
-	maybeQuit(err, "Error determining existing Bazel-related files")
-
-	for _, path := range existingBazelFiles {
-		fullPath := shared.JoinPath(topDir, path)
-		fileInfo, err2 := os.Stat(fullPath)
-		if err2 != nil {
-			// Warn about error, but continue trying to check files
-			fmt.Fprintf(os.Stderr, "WARNING: Error accessing path '%s', err: %s\n", fullPath, err2)
-			continue
-		}
-		// Exclude only files named 'BUILD' or 'BUILD.bazel' and unless forcibly kept
-		if fileInfo.IsDir() ||
-			(fileInfo.Name() != "BUILD" && fileInfo.Name() != "BUILD.bazel") ||
-			ctx.Config().Bp2buildPackageConfig.ShouldKeepExistingBuildFileForDir(filepath.Dir(path)) {
-			// Don't ignore this existing build file
-			continue
-		}
-		if verbose {
-			fmt.Fprintf(os.Stderr, "Ignoring existing BUILD file: %s\n", path)
-		}
-		excluded = append(excluded, path)
-	}
-
-	// Temporarily exclude stuff to make `bazel build //external/...` (and `bazel build //frameworks/...`)  work
-	excluded = append(excluded,
-		// FIXME: 'autotest_lib' is a symlink back to external/autotest, and this causes an infinite
-		// symlink expansion error for Bazel
-		"external/autotest/venv/autotest_lib",
-		"external/autotest/autotest_lib",
-		"external/autotest/client/autotest_lib/client",
-
-		// FIXME: The external/google-fruit/extras/bazel_root/third_party/fruit dir is poison
-		// It contains several symlinks back to real source dirs, and those source dirs contain
-		// BUILD files we want to ignore
-		"external/google-fruit/extras/bazel_root/third_party/fruit",
-
-		// FIXME: 'frameworks/compile/slang' has a filegroup error due to an escaping issue
-		"frameworks/compile/slang",
-	)
-	return excluded
-}
-
-// buildTargetsByPackage parses Bazel BUILD.bazel and BUILD files under
-// the workspace, and returns a map containing names of Bazel targets defined in
-// these BUILD files.
-// For example, maps "//foo/bar" to ["baz", "qux"] if `//foo/bar:{baz,qux}` exist.
-func buildTargetsByPackage(ctx *android.Context) map[string][]string {
-	existingBazelFiles, err := getExistingBazelRelatedFiles(topDir)
-	maybeQuit(err, "Error determining existing Bazel-related files")
-
-	result := map[string][]string{}
-
-	// Search for instances of `name = "$NAME"` (with arbitrary spacing).
-	targetNameRegex := regexp.MustCompile(`(?m)^\s*name\s*=\s*\"([^\"]+)\"`)
-
-	for _, path := range existingBazelFiles {
-		if !ctx.Config().Bp2buildPackageConfig.ShouldKeepExistingBuildFileForDir(filepath.Dir(path)) {
-			continue
-		}
-		fullPath := shared.JoinPath(topDir, path)
-		sourceDir := filepath.Dir(path)
-		fileInfo, err := os.Stat(fullPath)
-		maybeQuit(err, "Error accessing Bazel file '%s'", fullPath)
-
-		if !fileInfo.IsDir() &&
-			(fileInfo.Name() == "BUILD" || fileInfo.Name() == "BUILD.bazel") {
-			// Process this BUILD file.
-			buildFileContent, err := os.ReadFile(fullPath)
-			maybeQuit(err, "Error reading Bazel file '%s'", fullPath)
-
-			matches := targetNameRegex.FindAllStringSubmatch(string(buildFileContent), -1)
-			for _, match := range matches {
-				result[sourceDir] = append(result[sourceDir], match[1])
-			}
-		}
-	}
-	return result
-}
-
-// Run Soong in the bp2build mode. This creates a standalone context that registers
-// an alternate pipeline of mutators and singletons specifically for generating
-// Bazel BUILD files instead of Ninja files.
-func runBp2Build(ctx *android.Context, extraNinjaDeps []string, metricsDir string) string {
-	var codegenMetrics *bp2build.CodegenMetrics
-	ctx.EventHandler.Do("bp2build", func() {
-
-		ctx.EventHandler.Do("read_build", func() {
-			ctx.Config().SetBazelBuildFileTargets(buildTargetsByPackage(ctx))
-		})
-
-		// Propagate "allow misssing dependencies" bit. This is normally set in
-		// newContext(), but we create ctx without calling that method.
-		ctx.SetAllowMissingDependencies(ctx.Config().AllowMissingDependencies())
-		ctx.SetNameInterface(newNameResolver(ctx.Config()))
-		ctx.RegisterForBazelConversion()
-		ctx.SetModuleListFile(cmdlineArgs.ModuleListFile)
-		// Skip cloning modules during bp2build's blueprint run. Some mutators set
-		// bp2build-related module values which should be preserved during codegen.
-		ctx.SkipCloneModulesAfterMutators = true
-
-		var ninjaDeps []string
-		ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
-
-		// Run the loading and analysis pipeline to prepare the graph of regular
-		// Modules parsed from Android.bp files, and the BazelTargetModules mapped
-		// from the regular Modules.
-		ctx.EventHandler.Do("bootstrap", func() {
-			blueprintArgs := cmdlineArgs
-			bootstrapDeps, err := bootstrap.RunBlueprint(blueprintArgs.Args,
-				bootstrap.StopBeforePrepareBuildActions, ctx.Context, ctx.Config())
-			maybeQuit(err, "")
-			ninjaDeps = append(ninjaDeps, bootstrapDeps...)
-		})
-
-		globListFiles := writeBuildGlobsNinjaFile(ctx)
-		ninjaDeps = append(ninjaDeps, globListFiles...)
-
-		// Run the code-generation phase to convert BazelTargetModules to BUILD files
-		// and print conversion codegenMetrics to the user.
-		codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.Bp2Build, topDir)
-		codegenMetrics = bp2build.Codegen(codegenContext)
-
-		ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
-
-		writeDepFile(cmdlineArgs.Bp2buildMarker, ctx.EventHandler, ninjaDeps)
-		touch(shared.JoinPath(topDir, cmdlineArgs.Bp2buildMarker))
-	})
-
-	// Only report metrics when in bp2build mode. The metrics aren't relevant
-	// for queryview, since that's a total repo-wide conversion and there's a
-	// 1:1 mapping for each module.
-	if ctx.Config().IsEnvTrue("BP2BUILD_VERBOSE") {
-		codegenMetrics.Print()
-	}
-	writeBp2BuildMetrics(codegenMetrics, ctx.EventHandler, metricsDir)
-	return cmdlineArgs.Bp2buildMarker
-}
-
-// Write Bp2Build metrics into $LOG_DIR
-func writeBp2BuildMetrics(codegenMetrics *bp2build.CodegenMetrics, eventHandler *metrics.EventHandler, metricsDir string) {
-	for _, event := range eventHandler.CompletedEvents() {
-		codegenMetrics.AddEvent(&bp2build_metrics_proto.Event{
-			Name:      event.Id,
-			StartTime: uint64(event.Start.UnixNano()),
-			RealTime:  event.RuntimeNanoseconds(),
-		})
-	}
-	if len(metricsDir) < 1 {
-		fmt.Fprintf(os.Stderr, "\nMissing required env var for generating bp2build metrics: LOG_DIR\n")
-		os.Exit(1)
-	}
-	codegenMetrics.Write(metricsDir)
-}
-
-func readFileLines(path string) ([]string, error) {
-	data, err := os.ReadFile(path)
-	if err == nil {
-		return strings.Split(strings.TrimSpace(string(data)), "\n"), nil
-	}
-	return nil, err
-
-}
 func maybeQuit(err error, format string, args ...interface{}) {
 	if err == nil {
 		return
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index 5c2316a..eafd67a 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -22,7 +22,6 @@
 
 	"android/soong/android"
 	"android/soong/bp2build"
-	"android/soong/starlark_import"
 )
 
 // A helper function to generate a Read-only Bazel workspace in outDir
@@ -47,14 +46,6 @@
 		}
 	}
 
-	// Add starlark deps here, so that they apply to both queryview and apibp2build which
-	// both run this function.
-	starlarkDeps, err2 := starlark_import.GetNinjaDeps()
-	if err2 != nil {
-		return err2
-	}
-	ctx.AddNinjaFileDeps(starlarkDeps...)
-
 	return nil
 }
 
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 4097e8a..fe3f8f7 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -18,7 +18,6 @@
 	"context"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strconv"
@@ -91,14 +90,6 @@
 		config:      buildActionConfig,
 		stdio:       stdio,
 		run:         runMake,
-	}, {
-		flag:        "--finalize-bazel-metrics",
-		description: "finalize b metrics and upload",
-		config:      build.UploadOnlyConfig,
-		stdio:       stdio,
-		// Finalize-bazel-metrics mode updates metrics files and calls the metrics
-		// uploader. This marks the end of a b invocation.
-		run: finalizeBazelMetrics,
 	},
 }
 
@@ -190,26 +181,25 @@
 		CriticalPath: criticalPath,
 	}}
 
-	config := c.config(buildCtx, args...)
-	config.SetLogsPrefix(c.logsPrefix)
+	freshConfig := func() build.Config {
+		config := c.config(buildCtx, args...)
+		config.SetLogsPrefix(c.logsPrefix)
+		return config
+	}
+	config := freshConfig()
 	logsDir := config.LogsDir()
 	buildStarted = config.BuildStartedTimeOrDefault(buildStarted)
 
 	buildErrorFile := filepath.Join(logsDir, c.logsPrefix+"build_error")
 	soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
 	rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
-	bp2buildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"bp2build_metrics.pb")
-	bazelMetricsFile := filepath.Join(logsDir, c.logsPrefix+"bazel_metrics.pb")
 	soongBuildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_build_metrics.pb")
 
 	metricsFiles := []string{
-		buildErrorFile,           // build error strings
-		rbeMetricsFile,           // high level metrics related to remote build execution.
-		bp2buildMetricsFile,      // high level metrics related to bp2build.
-		soongMetricsFile,         // high level metrics related to this build system.
-		bazelMetricsFile,         // high level metrics related to bazel execution
-		soongBuildMetricsFile,    // high level metrics related to soong build(except bp2build)
-		config.BazelMetricsDir(), // directory that contains a set of bazel metrics.
+		buildErrorFile,        // build error strings
+		rbeMetricsFile,        // high level metrics related to remote build execution.
+		soongMetricsFile,      // high level metrics related to this build system.
+		soongBuildMetricsFile, // high level metrics related to soong build
 	}
 
 	os.MkdirAll(logsDir, 0777)
@@ -223,6 +213,15 @@
 		log.Verbosef("  [%d] %s", i, arg)
 	}
 
+	// We need to call preProductConfigSetup before we can do product config, which is how we get
+	// PRODUCT_CONFIG_RELEASE_MAPS set for the final product config for the build.
+	// When product config uses a declarative language, we won't need to rerun product config.
+	preProductConfigSetup(buildCtx, config)
+	if build.SetProductReleaseConfigMaps(buildCtx, config) {
+		log.Verbose("Product release config maps found\n")
+		config = freshConfig()
+	}
+
 	defer func() {
 		stat.Finish()
 		criticalPath.WriteToMetrics(met)
@@ -235,7 +234,9 @@
 
 }
 
-func logAndSymlinkSetup(buildCtx build.Context, config build.Config) {
+// This function must not modify config, since product config may cause us to recreate the config,
+// and we won't call this function a second time.
+func preProductConfigSetup(buildCtx build.Context, config build.Config) {
 	log := buildCtx.ContextImpl.Logger
 	logsPrefix := config.GetLogsPrefix()
 	build.SetupOutDir(buildCtx, config)
@@ -247,10 +248,9 @@
 	soongMetricsFile := filepath.Join(logsDir, logsPrefix+"soong_metrics")
 	bp2buildMetricsFile := filepath.Join(logsDir, logsPrefix+"bp2build_metrics.pb")
 	soongBuildMetricsFile := filepath.Join(logsDir, logsPrefix+"soong_build_metrics.pb")
-	bazelMetricsFile := filepath.Join(logsDir, logsPrefix+"bazel_metrics.pb")
 
 	//Delete the stale metrics files
-	staleFileSlice := []string{buildErrorFile, rbeMetricsFile, soongMetricsFile, bp2buildMetricsFile, soongBuildMetricsFile, bazelMetricsFile}
+	staleFileSlice := []string{buildErrorFile, rbeMetricsFile, soongMetricsFile, bp2buildMetricsFile, soongBuildMetricsFile}
 	if err := deleteStaleMetrics(staleFileSlice); err != nil {
 		log.Fatalln(err)
 	}
@@ -289,33 +289,13 @@
 		}
 	}
 
-	// Fix up the source tree due to a repo bug where it doesn't remove
-	// linkfiles that have been removed
-	fixBadDanglingLink(buildCtx, "hardware/qcom/sdm710/Android.bp")
-	fixBadDanglingLink(buildCtx, "hardware/qcom/sdm710/Android.mk")
-
 	// Create a source finder.
 	f := build.NewSourceFinder(buildCtx, config)
 	defer f.Shutdown()
 	build.FindSources(buildCtx, config, f)
 }
 
-func fixBadDanglingLink(ctx build.Context, name string) {
-	_, err := os.Lstat(name)
-	if err != nil {
-		return
-	}
-	_, err = os.Stat(name)
-	if os.IsNotExist(err) {
-		err = os.Remove(name)
-		if err != nil {
-			ctx.Fatalf("Failed to remove dangling link %q: %v", name, err)
-		}
-	}
-}
-
 func dumpVar(ctx build.Context, config build.Config, args []string) {
-	logAndSymlinkSetup(ctx, config)
 	flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
 	flags.SetOutput(ctx.Writer)
 
@@ -368,7 +348,6 @@
 }
 
 func dumpVars(ctx build.Context, config build.Config, args []string) {
-	logAndSymlinkSetup(ctx, config)
 
 	flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
 	flags.SetOutput(ctx.Writer)
@@ -548,7 +527,6 @@
 }
 
 func runMake(ctx build.Context, config build.Config, _ []string) {
-	logAndSymlinkSetup(ctx, config)
 	logsDir := config.LogsDir()
 	if config.IsVerbose() {
 		writer := ctx.Writer
@@ -599,81 +577,6 @@
 	return nil, nil, fmt.Errorf("Command not found: %q\nDid you mean one of these: %q", args[1], listFlags())
 }
 
-// For Bazel support, this moves files and directories from e.g. out/dist/$f to DIST_DIR/$f if necessary.
-func populateExternalDistDir(ctx build.Context, config build.Config) {
-	// Make sure that internalDistDirPath and externalDistDirPath are both absolute paths, so we can compare them
-	var err error
-	var internalDistDirPath string
-	var externalDistDirPath string
-	if internalDistDirPath, err = filepath.Abs(config.DistDir()); err != nil {
-		ctx.Fatalf("Unable to find absolute path of %s: %s", internalDistDirPath, err)
-	}
-	if externalDistDirPath, err = filepath.Abs(config.RealDistDir()); err != nil {
-		ctx.Fatalf("Unable to find absolute path of %s: %s", externalDistDirPath, err)
-	}
-	if externalDistDirPath == internalDistDirPath {
-		return
-	}
-
-	// Make sure the internal DIST_DIR actually exists before trying to read from it
-	if _, err = os.Stat(internalDistDirPath); os.IsNotExist(err) {
-		ctx.Println("Skipping Bazel dist dir migration - nothing to do!")
-		return
-	}
-
-	// Make sure the external DIST_DIR actually exists before trying to write to it
-	if err = os.MkdirAll(externalDistDirPath, 0755); err != nil {
-		ctx.Fatalf("Unable to make directory %s: %s", externalDistDirPath, err)
-	}
-
-	ctx.Println("Populating external DIST_DIR...")
-
-	populateExternalDistDirHelper(ctx, config, internalDistDirPath, externalDistDirPath)
-}
-
-func populateExternalDistDirHelper(ctx build.Context, config build.Config, internalDistDirPath string, externalDistDirPath string) {
-	files, err := ioutil.ReadDir(internalDistDirPath)
-	if err != nil {
-		ctx.Fatalf("Can't read internal distdir %s: %s", internalDistDirPath, err)
-	}
-	for _, f := range files {
-		internalFilePath := filepath.Join(internalDistDirPath, f.Name())
-		externalFilePath := filepath.Join(externalDistDirPath, f.Name())
-
-		if f.IsDir() {
-			// Moving a directory - check if there is an existing directory to merge with
-			externalLstat, err := os.Lstat(externalFilePath)
-			if err != nil {
-				if !os.IsNotExist(err) {
-					ctx.Fatalf("Can't lstat external %s: %s", externalDistDirPath, err)
-				}
-				// Otherwise, if the error was os.IsNotExist, that's fine and we fall through to the rename at the bottom
-			} else {
-				if externalLstat.IsDir() {
-					// Existing dir - try to merge the directories?
-					populateExternalDistDirHelper(ctx, config, internalFilePath, externalFilePath)
-					continue
-				} else {
-					// Existing file being replaced with a directory. Delete the existing file...
-					if err := os.RemoveAll(externalFilePath); err != nil {
-						ctx.Fatalf("Unable to remove existing %s: %s", externalFilePath, err)
-					}
-				}
-			}
-		} else {
-			// Moving a file (not a dir) - delete any existing file or directory
-			if err := os.RemoveAll(externalFilePath); err != nil {
-				ctx.Fatalf("Unable to remove existing %s: %s", externalFilePath, err)
-			}
-		}
-
-		// The actual move - do a rename instead of a copy in order to save disk space.
-		if err := os.Rename(internalFilePath, externalFilePath); err != nil {
-			ctx.Fatalf("Unable to rename %s -> %s due to error %s", internalFilePath, externalFilePath, err)
-		}
-	}
-}
-
 func setMaxFiles(ctx build.Context) {
 	var limits syscall.Rlimit
 
@@ -684,9 +587,11 @@
 	}
 
 	ctx.Verbosef("Current file limits: %d soft, %d hard", limits.Cur, limits.Max)
-	if limits.Cur == limits.Max {
-		return
-	}
+
+	// Go 1.21 modifies the file limit but restores the original when
+	// execing subprocesses if it hasn't be overridden.  Call Setrlimit
+	// here even if it doesn't appear to be necessary so that the
+	// syscall package considers it set.
 
 	limits.Cur = limits.Max
 	err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limits)
@@ -694,28 +599,3 @@
 		ctx.Println("Failed to increase file limit:", err)
 	}
 }
-
-func finalizeBazelMetrics(ctx build.Context, config build.Config, args []string) {
-	updateTotalRealTime(ctx, config, args)
-
-	logsDir := config.LogsDir()
-	logsPrefix := config.GetLogsPrefix()
-	bazelMetricsFile := filepath.Join(logsDir, logsPrefix+"bazel_metrics.pb")
-	bazelProfileFile := filepath.Join(logsDir, logsPrefix+"analyzed_bazel_profile.txt")
-	build.ProcessBazelMetrics(bazelProfileFile, bazelMetricsFile, ctx, config)
-}
-func updateTotalRealTime(ctx build.Context, config build.Config, args []string) {
-	soongMetricsFile := filepath.Join(config.LogsDir(), "soong_metrics")
-
-	//read file into proto
-	data, err := os.ReadFile(soongMetricsFile)
-	if err != nil {
-		ctx.Fatal(err)
-	}
-	met := ctx.ContextImpl.Metrics
-
-	err = met.UpdateTotalRealTimeAndNonZeroExit(data, config.BazelExitCode())
-	if err != nil {
-		ctx.Fatal(err)
-	}
-}
diff --git a/cmd/symbols_map/Android.bp b/cmd/symbols_map/Android.bp
index 0ba3b07..e3ae6ed 100644
--- a/cmd/symbols_map/Android.bp
+++ b/cmd/symbols_map/Android.bp
@@ -5,17 +5,16 @@
 blueprint_go_binary {
     name: "symbols_map",
     srcs: [
-        "elf.go",
         "r8.go",
         "symbols_map.go",
     ],
     testSrcs: [
-        "elf_test.go",
         "r8_test.go",
     ],
     deps: [
         "blueprint-pathtools",
         "golang-protobuf-encoding-prototext",
+        "soong-elf",
         "soong-response",
         "symbols_map_proto",
     ],
diff --git a/cmd/symbols_map/symbols_map.go b/cmd/symbols_map/symbols_map.go
index 938446d..c56cf93 100644
--- a/cmd/symbols_map/symbols_map.go
+++ b/cmd/symbols_map/symbols_map.go
@@ -22,6 +22,7 @@
 	"strings"
 
 	"android/soong/cmd/symbols_map/symbols_map_proto"
+	"android/soong/elf"
 	"android/soong/response"
 
 	"github.com/google/blueprint/pathtools"
@@ -116,7 +117,7 @@
 	if *elfFile != "" {
 		typ = symbols_map_proto.Mapping_ELF
 		location = *elfFile
-		identifier, err = elfIdentifier(*elfFile, true)
+		identifier, err = elf.Identifier(*elfFile, true)
 		if err != nil {
 			fmt.Fprintf(os.Stderr, "error reading elf identifier: %s\n", err)
 			os.Exit(1)
diff --git a/cmd/zip2zip/zip2zip_test.go b/cmd/zip2zip/zip2zip_test.go
index c238098..85a69ef 100644
--- a/cmd/zip2zip/zip2zip_test.go
+++ b/cmd/zip2zip/zip2zip_test.go
@@ -471,6 +471,56 @@
 	}
 }
 
+// TestZip2Zip64 tests that zip2zip on zip file larger than 4GB produces a valid zip file.
+func TestZip2Zip64(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping slow test in short mode")
+	}
+	inputBuf := &bytes.Buffer{}
+	outputBuf := &bytes.Buffer{}
+
+	inputWriter := zip.NewWriter(inputBuf)
+	w, err := inputWriter.CreateHeaderAndroid(&zip.FileHeader{
+		Name:   "a",
+		Method: zip.Store,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+	buf := make([]byte, 4*1024*1024)
+	for i := 0; i < 1025; i++ {
+		w.Write(buf)
+	}
+	w, err = inputWriter.CreateHeaderAndroid(&zip.FileHeader{
+		Name:   "b",
+		Method: zip.Store,
+	})
+	for i := 0; i < 1025; i++ {
+		w.Write(buf)
+	}
+	inputWriter.Close()
+	inputBytes := inputBuf.Bytes()
+
+	inputReader, err := zip.NewReader(bytes.NewReader(inputBytes), int64(len(inputBytes)))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	outputWriter := zip.NewWriter(outputBuf)
+	err = zip2zip(inputReader, outputWriter, false, false, false,
+		nil, nil, nil, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	outputWriter.Close()
+	outputBytes := outputBuf.Bytes()
+	_, err = zip.NewReader(bytes.NewReader(outputBytes), int64(len(outputBytes)))
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
 func TestConstantPartOfPattern(t *testing.T) {
 	testCases := []struct{ in, out string }{
 		{
diff --git a/compliance/OWNERS b/compliance/OWNERS
deleted file mode 100644
index f52e201..0000000
--- a/compliance/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-# OSEP Build
-bbadour@google.com
-kanouche@google.com
-napier@google.com
-
-# Open Source Compliance Tools
-rtp@google.com
-austinyuan@google.com
diff --git a/dexpreopt/DEXPREOPT_IMPLEMENTATION.md b/dexpreopt/DEXPREOPT_IMPLEMENTATION.md
index c3a1730..1cb0add 100644
--- a/dexpreopt/DEXPREOPT_IMPLEMENTATION.md
+++ b/dexpreopt/DEXPREOPT_IMPLEMENTATION.md
@@ -237,22 +237,22 @@
 app.
 
 
-[make/core/dex_preopt.mk]: https://cs.android.com/android/platform/superproject/+/master:build/make/core/dex_preopt.mk
-[make/core/dex_preopt_config.mk]: https://cs.android.com/android/platform/superproject/+/master:build/make/core/dex_preopt_config.mk
-[make/core/dex_preopt_config_merger.py]: https://cs.android.com/android/platform/superproject/+/master:build/make/core/dex_preopt_config_merger.py
-[make/core/dex_preopt_odex_install.mk]: https://cs.android.com/android/platform/superproject/+/master:build/make/core/dex_preopt_odex_install.mk
-[soong/dexpreopt]: https://cs.android.com/android/platform/superproject/+/master:build/soong/dexpreopt
-[soong/dexpreopt/class_loader_context.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/dexpreopt/class_loader_context.go
-[soong/dexpreopt/config.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/dexpreopt/config.go
-[soong/dexpreopt/dexpreopt.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/dexpreopt/dexpreopt.go
-[soong/java]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java
-[soong/java/app.go:deps]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/app.go?q=%22func%20\(u%20*usesLibrary\)%20deps%22
-[soong/java/app.go:verifyUsesLibraries]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/app.go?q=%22func%20\(u%20*usesLibrary\)%20verifyUsesLibraries%22
-[soong/java/bootclasspath_fragment.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/bootclasspath_fragment.go
-[soong/java/dexpreopt.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/dexpreopt.go
-[soong/java/dexpreopt_bootjars.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/dexpreopt_bootjars.go
-[soong/java/dexpreopt_config.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/dexpreopt_config.go
-[soong/java/java.go:addCLCFromDep]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/java.go?q=%22func%20addCLCfromDep%22
-[soong/java/platform_bootclasspath.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/platform_bootclasspath.go
-[soong/scripts/construct_context.py]: https://cs.android.com/android/platform/superproject/+/master:build/soong/scripts/construct_context.py
-[soong/scripts/manifest_check.py]: https://cs.android.com/android/platform/superproject/+/master:build/soong/scripts/manifest_check.py
+[make/core/dex_preopt.mk]: https://cs.android.com/android/platform/superproject/+/main:build/make/core/dex_preopt.mk
+[make/core/dex_preopt_config.mk]: https://cs.android.com/android/platform/superproject/+/main:build/make/core/dex_preopt_config.mk
+[make/core/dex_preopt_config_merger.py]: https://cs.android.com/android/platform/superproject/+/main:build/make/core/dex_preopt_config_merger.py
+[make/core/dex_preopt_odex_install.mk]: https://cs.android.com/android/platform/superproject/+/main:build/make/core/dex_preopt_odex_install.mk
+[soong/dexpreopt]: https://cs.android.com/android/platform/superproject/+/main:build/soong/dexpreopt
+[soong/dexpreopt/class_loader_context.go]: https://cs.android.com/android/platform/superproject/+/main:build/soong/dexpreopt/class_loader_context.go
+[soong/dexpreopt/config.go]: https://cs.android.com/android/platform/superproject/+/main:build/soong/dexpreopt/config.go
+[soong/dexpreopt/dexpreopt.go]: https://cs.android.com/android/platform/superproject/+/main:build/soong/dexpreopt/dexpreopt.go
+[soong/java]: https://cs.android.com/android/platform/superproject/+/main:build/soong/java
+[soong/java/app.go:deps]: https://cs.android.com/android/platform/superproject/+/main:build/soong/java/app.go?q=%22func%20\(u%20*usesLibrary\)%20deps%22
+[soong/java/app.go:verifyUsesLibraries]: https://cs.android.com/android/platform/superproject/+/main:build/soong/java/app.go?q=%22func%20\(u%20*usesLibrary\)%20verifyUsesLibraries%22
+[soong/java/bootclasspath_fragment.go]: https://cs.android.com/android/platform/superproject/+/main:build/soong/java/bootclasspath_fragment.go
+[soong/java/dexpreopt.go]: https://cs.android.com/android/platform/superproject/+/main:build/soong/java/dexpreopt.go
+[soong/java/dexpreopt_bootjars.go]: https://cs.android.com/android/platform/superproject/+/main:build/soong/java/dexpreopt_bootjars.go
+[soong/java/dexpreopt_config.go]: https://cs.android.com/android/platform/superproject/+/main:build/soong/java/dexpreopt_config.go
+[soong/java/java.go:addCLCFromDep]: https://cs.android.com/android/platform/superproject/+/main:build/soong/java/java.go?q=%22func%20addCLCfromDep%22
+[soong/java/platform_bootclasspath.go]: https://cs.android.com/android/platform/superproject/+/main:build/soong/java/platform_bootclasspath.go
+[soong/scripts/construct_context.py]: https://cs.android.com/android/platform/superproject/+/main:build/soong/scripts/construct_context.py
+[soong/scripts/manifest_check.py]: https://cs.android.com/android/platform/superproject/+/main:build/soong/scripts/manifest_check.py
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index 57c7ae8..af1d33d 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -323,6 +323,7 @@
 		} else if clc.Host == hostPath && clc.Device == devicePath {
 			// Ok, the same library with the same paths. Don't re-add it, but don't raise an error
 			// either, as the same library may be reachable via different transitional dependencies.
+			clc.Optional = clc.Optional && optional
 			return nil
 		} else {
 			// Fail, as someone is trying to add the same library with different paths. This likely
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index ba41f4a..fe6317c 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -32,7 +32,7 @@
 	DisablePreoptBootImages bool     // disable prepot for boot images
 	DisablePreoptModules    []string // modules with preopt disabled by product-specific config
 
-	OnlyPreoptBootImageAndSystemServer bool // only preopt jars in the boot image or system server
+	OnlyPreoptArtBootImage bool // only preopt jars in the ART boot image
 
 	PreoptWithUpdatableBcp bool // If updatable boot jars are included in dexpreopt or not.
 
@@ -98,7 +98,9 @@
 	// measure, as it masks real errors and affects performance.
 	RelaxUsesLibraryCheck bool
 
-	EnableUffdGc bool // preopt with the assumption that userfaultfd GC will be used on device.
+	// "true" to force preopt with CMC GC (a.k.a., UFFD GC); "false" to force preopt with CC GC;
+	// "default" to determine the GC type based on the kernel version file.
+	EnableUffdGc string
 }
 
 var allPlatformSystemServerJarsKey = android.NewOnceKey("allPlatformSystemServerJars")
@@ -154,6 +156,7 @@
 	Zip2zip          android.Path
 	ManifestCheck    android.Path
 	ConstructContext android.Path
+	UffdGcFlag       android.WritablePath
 }
 
 type ModuleConfig struct {
@@ -184,8 +187,6 @@
 	PreoptBootClassPathDexFiles     android.Paths // file paths of boot class path files
 	PreoptBootClassPathDexLocations []string      // virtual locations of boot class path files
 
-	PreoptExtractedApk bool // Overrides OnlyPreoptModules
-
 	NoCreateAppImage    bool
 	ForceCreateAppImage bool
 
@@ -539,6 +540,7 @@
 		Zip2zip:          ctx.Config().HostToolPath(ctx, "zip2zip"),
 		ManifestCheck:    ctx.Config().HostToolPath(ctx, "manifest_check"),
 		ConstructContext: ctx.Config().HostToolPath(ctx, "construct_context"),
+		UffdGcFlag:       getUffdGcFlagPath(ctx),
 	}
 }
 
@@ -590,6 +592,7 @@
 	Zip2zip          string
 	ManifestCheck    string
 	ConstructContext string
+	UffdGcFlag       string
 }
 
 // ParseGlobalSoongConfig parses the given data assumed to be read from the
@@ -611,6 +614,7 @@
 		Zip2zip:          constructPath(ctx, jc.Zip2zip),
 		ManifestCheck:    constructPath(ctx, jc.ManifestCheck),
 		ConstructContext: constructPath(ctx, jc.ConstructContext),
+		UffdGcFlag:       constructWritablePath(ctx, jc.UffdGcFlag),
 	}
 
 	return config, nil
@@ -635,12 +639,15 @@
 }
 
 func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	checkBootJarsConfigConsistency(ctx, GetGlobalConfig(ctx), ctx.Config())
+	global := GetGlobalConfig(ctx)
+	checkBootJarsConfigConsistency(ctx, global, ctx.Config())
 
-	if GetGlobalConfig(ctx).DisablePreopt {
+	if global.DisablePreopt {
 		return
 	}
 
+	buildUffdGcFlag(ctx, global)
+
 	config := GetCachedGlobalSoongConfig(ctx)
 	if config == nil {
 		// No module has enabled dexpreopting, so we assume there will be no calls
@@ -656,6 +663,7 @@
 		Zip2zip:          config.Zip2zip.String(),
 		ManifestCheck:    config.ManifestCheck.String(),
 		ConstructContext: config.ConstructContext.String(),
+		UffdGcFlag:       config.UffdGcFlag.String(),
 	}
 
 	data, err := json.Marshal(jc)
@@ -686,54 +694,77 @@
 		config.Zip2zip.String(),
 		config.ManifestCheck.String(),
 		config.ConstructContext.String(),
+		config.UffdGcFlag.String(),
 	}, " "))
 }
 
+func buildUffdGcFlag(ctx android.BuilderContext, global *GlobalConfig) {
+	uffdGcFlag := getUffdGcFlagPath(ctx)
+
+	if global.EnableUffdGc == "true" {
+		android.WriteFileRuleVerbatim(ctx, uffdGcFlag, "--runtime-arg -Xgc:CMC")
+	} else if global.EnableUffdGc == "false" {
+		android.WriteFileRuleVerbatim(ctx, uffdGcFlag, "")
+	} else if global.EnableUffdGc == "default" {
+		// Generated by `build/make/core/Makefile`.
+		kernelVersionFile := android.PathForOutput(ctx, "dexpreopt/kernel_version_for_uffd_gc.txt")
+		// Determine the UFFD GC flag by the kernel version file.
+		rule := android.NewRuleBuilder(pctx, ctx)
+		rule.Command().
+			Tool(ctx.Config().HostToolPath(ctx, "construct_uffd_gc_flag")).
+			Input(kernelVersionFile).
+			Output(uffdGcFlag)
+		rule.Restat().Build("dexpreopt_uffd_gc_flag", "dexpreopt_uffd_gc_flag")
+	} else {
+		panic(fmt.Sprintf("Unknown value of PRODUCT_ENABLE_UFFD_GC: %s", global.EnableUffdGc))
+	}
+}
+
 func GlobalConfigForTests(ctx android.PathContext) *GlobalConfig {
 	return &GlobalConfig{
-		DisablePreopt:                      false,
-		DisablePreoptModules:               nil,
-		OnlyPreoptBootImageAndSystemServer: false,
-		HasSystemOther:                     false,
-		PatternsOnSystemOther:              nil,
-		DisableGenerateProfile:             false,
-		ProfileDir:                         "",
-		BootJars:                           android.EmptyConfiguredJarList(),
-		ApexBootJars:                       android.EmptyConfiguredJarList(),
-		ArtApexJars:                        android.EmptyConfiguredJarList(),
-		TestOnlyArtBootImageJars:           android.EmptyConfiguredJarList(),
-		SystemServerJars:                   android.EmptyConfiguredJarList(),
-		SystemServerApps:                   nil,
-		ApexSystemServerJars:               android.EmptyConfiguredJarList(),
-		StandaloneSystemServerJars:         android.EmptyConfiguredJarList(),
-		ApexStandaloneSystemServerJars:     android.EmptyConfiguredJarList(),
-		SpeedApps:                          nil,
-		PreoptFlags:                        nil,
-		DefaultCompilerFilter:              "",
-		SystemServerCompilerFilter:         "",
-		GenerateDMFiles:                    false,
-		NoDebugInfo:                        false,
-		DontResolveStartupStrings:          false,
-		AlwaysSystemServerDebugInfo:        false,
-		NeverSystemServerDebugInfo:         false,
-		AlwaysOtherDebugInfo:               false,
-		NeverOtherDebugInfo:                false,
-		IsEng:                              false,
-		SanitizeLite:                       false,
-		DefaultAppImages:                   false,
-		Dex2oatXmx:                         "",
-		Dex2oatXms:                         "",
-		EmptyDirectory:                     "empty_dir",
-		CpuVariant:                         nil,
-		InstructionSetFeatures:             nil,
-		BootImageProfiles:                  nil,
-		BootFlags:                          "",
-		Dex2oatImageXmx:                    "",
-		Dex2oatImageXms:                    "",
+		DisablePreopt:                  false,
+		DisablePreoptModules:           nil,
+		OnlyPreoptArtBootImage:         false,
+		HasSystemOther:                 false,
+		PatternsOnSystemOther:          nil,
+		DisableGenerateProfile:         false,
+		ProfileDir:                     "",
+		BootJars:                       android.EmptyConfiguredJarList(),
+		ApexBootJars:                   android.EmptyConfiguredJarList(),
+		ArtApexJars:                    android.EmptyConfiguredJarList(),
+		TestOnlyArtBootImageJars:       android.EmptyConfiguredJarList(),
+		SystemServerJars:               android.EmptyConfiguredJarList(),
+		SystemServerApps:               nil,
+		ApexSystemServerJars:           android.EmptyConfiguredJarList(),
+		StandaloneSystemServerJars:     android.EmptyConfiguredJarList(),
+		ApexStandaloneSystemServerJars: android.EmptyConfiguredJarList(),
+		SpeedApps:                      nil,
+		PreoptFlags:                    nil,
+		DefaultCompilerFilter:          "",
+		SystemServerCompilerFilter:     "",
+		GenerateDMFiles:                false,
+		NoDebugInfo:                    false,
+		DontResolveStartupStrings:      false,
+		AlwaysSystemServerDebugInfo:    false,
+		NeverSystemServerDebugInfo:     false,
+		AlwaysOtherDebugInfo:           false,
+		NeverOtherDebugInfo:            false,
+		IsEng:                          false,
+		SanitizeLite:                   false,
+		DefaultAppImages:               false,
+		Dex2oatXmx:                     "",
+		Dex2oatXms:                     "",
+		EmptyDirectory:                 "empty_dir",
+		CpuVariant:                     nil,
+		InstructionSetFeatures:         nil,
+		BootImageProfiles:              nil,
+		BootFlags:                      "",
+		Dex2oatImageXmx:                "",
+		Dex2oatImageXms:                "",
 	}
 }
 
-func globalSoongConfigForTests() *GlobalSoongConfig {
+func globalSoongConfigForTests(ctx android.BuilderContext) *GlobalSoongConfig {
 	return &GlobalSoongConfig{
 		Profman:          android.PathForTesting("profman"),
 		Dex2oat:          android.PathForTesting("dex2oat"),
@@ -742,5 +773,19 @@
 		Zip2zip:          android.PathForTesting("zip2zip"),
 		ManifestCheck:    android.PathForTesting("manifest_check"),
 		ConstructContext: android.PathForTesting("construct_context"),
+		UffdGcFlag:       android.PathForOutput(ctx, "dexpreopt_test", "uffd_gc_flag.txt"),
 	}
 }
+
+func GetDexpreoptDirName(ctx android.PathContext) string {
+	prefix := "dexpreopt_"
+	targets := ctx.Config().Targets[android.Android]
+	if len(targets) > 0 {
+		return prefix + targets[0].Arch.ArchType.String()
+	}
+	return prefix + "unknown_target"
+}
+
+func getUffdGcFlagPath(ctx android.PathContext) android.WritablePath {
+	return android.PathForOutput(ctx, "dexpreopt/uffd_gc_flag.txt")
+}
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 29ae188..93351f1 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -52,7 +52,7 @@
 // GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a
 // ModuleConfig.  The produced files and their install locations will be available through rule.Installs().
 func GenerateDexpreoptRule(ctx android.BuilderContext, globalSoong *GlobalSoongConfig,
-	global *GlobalConfig, module *ModuleConfig, productPackages android.Path) (
+	global *GlobalConfig, module *ModuleConfig, productPackages android.Path, copyApexSystemServerJarDex bool) (
 	rule *android.RuleBuilder, err error) {
 
 	defer func() {
@@ -94,7 +94,7 @@
 
 			for archIdx, _ := range module.Archs {
 				dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage,
-					generateDM, productPackages)
+					generateDM, productPackages, copyApexSystemServerJarDex)
 			}
 		}
 	}
@@ -124,12 +124,7 @@
 		return true
 	}
 
-	// If OnlyPreoptBootImageAndSystemServer=true and module is not in boot class path skip
-	// Also preopt system server jars since selinux prevents system server from loading anything from
-	// /data. If we don't do this they will need to be extracted which is not favorable for RAM usage
-	// or performance. If PreoptExtractedApk is true, we ignore the only preopt boot image options.
-	if global.OnlyPreoptBootImageAndSystemServer && !global.BootJars.ContainsJar(module.Name) &&
-		!global.AllSystemServerJars(ctx).ContainsJar(module.Name) && !module.PreoptExtractedApk {
+	if global.OnlyPreoptArtBootImage {
 		return true
 	}
 
@@ -236,7 +231,7 @@
 
 func dexpreoptCommand(ctx android.BuilderContext, globalSoong *GlobalSoongConfig,
 	global *GlobalConfig, module *ModuleConfig, rule *android.RuleBuilder, archIdx int,
-	profile android.WritablePath, appImage bool, generateDM bool, productPackages android.Path) {
+	profile android.WritablePath, appImage bool, generateDM bool, productPackages android.Path, copyApexSystemServerJarDex bool) {
 
 	arch := module.Archs[archIdx]
 
@@ -282,7 +277,7 @@
 			clcTarget = append(clcTarget, GetSystemServerDexLocation(ctx, global, lib))
 		}
 
-		if DexpreoptRunningInSoong {
+		if DexpreoptRunningInSoong && copyApexSystemServerJarDex {
 			// Copy the system server jar to a predefined location where dex2oat will find it.
 			dexPathHost := SystemServerDexJarHostPath(ctx, module.Name)
 			rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String()))
@@ -395,7 +390,8 @@
 		Flag("--generate-build-id").
 		Flag("--abort-on-hard-verifier-error").
 		Flag("--force-determinism").
-		FlagWithArg("--no-inline-from=", "core-oj.jar")
+		FlagWithArg("--no-inline-from=", "core-oj.jar").
+		Text("$(cat").Input(globalSoong.UffdGcFlag).Text(")")
 
 	var preoptFlags []string
 	if len(module.PreoptFlags) > 0 {
@@ -511,10 +507,6 @@
 		cmd.FlagWithInput("--profile-file=", profile)
 	}
 
-	if global.EnableUffdGc {
-		cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
-	}
-
 	rule.Install(odexPath, odexInstallPath)
 	rule.Install(vdexPath, vdexInstallPath)
 }
diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index 8033b48..7512005 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -205,8 +205,9 @@
 			panic(err)
 		}
 	}
+	cpApexSscpServerJar := false // dexpreopt_gen operates on make modules, and since sscp libraries are in soong, this should be a noop
 	dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
-		ctx, globalSoong, global, module, android.PathForTesting(productPackagesPath))
+		ctx, globalSoong, global, module, android.PathForTesting(productPackagesPath), cpApexSscpServerJar)
 	if err != nil {
 		panic(err)
 	}
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 2b19c9d..eff2416 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -87,7 +87,6 @@
 		DexPreoptImageLocationsOnHost:   []string{},
 		PreoptBootClassPathDexFiles:     nil,
 		PreoptBootClassPathDexLocations: nil,
-		PreoptExtractedApk:              false,
 		NoCreateAppImage:                false,
 		ForceCreateAppImage:             false,
 		PresignedPrebuilt:               false,
@@ -97,12 +96,12 @@
 func TestDexPreopt(t *testing.T) {
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
-	globalSoong := globalSoongConfigForTests()
+	globalSoong := globalSoongConfigForTests(ctx)
 	global := GlobalConfigForTests(ctx)
 	module := testSystemModuleConfig(ctx, "test")
 	productPackages := android.PathForTesting("product_packages.txt")
 
-	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -115,12 +114,15 @@
 	if rule.Installs().String() != wantInstalls.String() {
 		t.Errorf("\nwant installs:\n   %v\ngot:\n   %v", wantInstalls, rule.Installs())
 	}
+
+	android.AssertStringListContains(t, "", rule.Inputs().RelativeToTop().Strings(),
+		"out/soong/dexpreopt_test/uffd_gc_flag.txt")
 }
 
 func TestDexPreoptSystemOther(t *testing.T) {
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
-	globalSoong := globalSoongConfigForTests()
+	globalSoong := globalSoongConfigForTests(ctx)
 	global := GlobalConfigForTests(ctx)
 	systemModule := testSystemModuleConfig(ctx, "Stest")
 	systemProductModule := testSystemProductModuleConfig(ctx, "SPtest")
@@ -159,7 +161,7 @@
 	for _, test := range tests {
 		global.PatternsOnSystemOther = test.patterns
 		for _, mt := range test.moduleTests {
-			rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module, productPackages)
+			rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module, productPackages, true)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -179,9 +181,14 @@
 }
 
 func TestDexPreoptApexSystemServerJars(t *testing.T) {
+	// modify the global variable for test
+	var oldDexpreoptRunningInSoong = DexpreoptRunningInSoong
+	DexpreoptRunningInSoong = true
+
+	// test begin
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
-	globalSoong := globalSoongConfigForTests()
+	globalSoong := globalSoongConfigForTests(ctx)
 	global := GlobalConfigForTests(ctx)
 	module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
 	productPackages := android.PathForTesting("product_packages.txt")
@@ -189,7 +196,7 @@
 	global.ApexSystemServerJars = android.CreateTestConfiguredJarList(
 		[]string{"com.android.apex1:service-A"})
 
-	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -200,12 +207,24 @@
 	}
 
 	android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String())
+
+	android.AssertStringListContains(t, "apex sscp jar copy", rule.Outputs().Strings(), "out/soong/system_server_dexjars/service-A.jar")
+
+	// rule with apex sscp cp as false
+	rule, err = GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, false)
+	if err != nil {
+		t.Fatal(err)
+	}
+	android.AssertStringListDoesNotContain(t, "apex sscp jar copy", rule.Outputs().Strings(), "out/soong/system_server_dexjars/service-A.jar")
+
+	// cleanup the global variable for test
+	DexpreoptRunningInSoong = oldDexpreoptRunningInSoong
 }
 
 func TestDexPreoptStandaloneSystemServerJars(t *testing.T) {
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
-	globalSoong := globalSoongConfigForTests()
+	globalSoong := globalSoongConfigForTests(ctx)
 	global := GlobalConfigForTests(ctx)
 	module := testPlatformSystemServerModuleConfig(ctx, "service-A")
 	productPackages := android.PathForTesting("product_packages.txt")
@@ -213,7 +232,7 @@
 	global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
 		[]string{"platform:service-A"})
 
-	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -229,7 +248,7 @@
 func TestDexPreoptSystemExtSystemServerJars(t *testing.T) {
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
-	globalSoong := globalSoongConfigForTests()
+	globalSoong := globalSoongConfigForTests(ctx)
 	global := GlobalConfigForTests(ctx)
 	module := testSystemExtSystemServerModuleConfig(ctx, "service-A")
 	productPackages := android.PathForTesting("product_packages.txt")
@@ -237,7 +256,7 @@
 	global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
 		[]string{"system_ext:service-A"})
 
-	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -253,7 +272,7 @@
 func TestDexPreoptApexStandaloneSystemServerJars(t *testing.T) {
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
-	globalSoong := globalSoongConfigForTests()
+	globalSoong := globalSoongConfigForTests(ctx)
 	global := GlobalConfigForTests(ctx)
 	module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
 	productPackages := android.PathForTesting("product_packages.txt")
@@ -261,7 +280,7 @@
 	global.ApexStandaloneSystemServerJars = android.CreateTestConfiguredJarList(
 		[]string{"com.android.apex1:service-A"})
 
-	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -277,14 +296,14 @@
 func TestDexPreoptProfile(t *testing.T) {
 	config := android.TestConfig("out", nil, "", nil)
 	ctx := android.BuilderContextForTesting(config)
-	globalSoong := globalSoongConfigForTests()
+	globalSoong := globalSoongConfigForTests(ctx)
 	global := GlobalConfigForTests(ctx)
 	module := testSystemModuleConfig(ctx, "test")
 	productPackages := android.PathForTesting("product_packages.txt")
 
 	module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile"))
 
-	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -317,3 +336,55 @@
 	after := fmt.Sprintf("%v", parsed)
 	android.AssertStringEquals(t, "The result must be the same as the original after marshalling and unmarshalling it.", before, after)
 }
+
+func TestUffdGcFlagForce(t *testing.T) {
+	for _, enableUffdGc := range []string{"true", "false"} {
+		t.Run(enableUffdGc, func(t *testing.T) {
+			preparers := android.GroupFixturePreparers(
+				PrepareForTestWithFakeDex2oatd,
+				PrepareForTestWithDexpreoptConfig,
+				FixtureSetEnableUffdGc(enableUffdGc),
+			)
+
+			result := preparers.RunTest(t)
+			ctx := result.TestContext
+
+			ctx.SingletonForTests("dexpreopt-soong-config").Output("out/soong/dexpreopt/uffd_gc_flag.txt")
+		})
+	}
+}
+
+func TestUffdGcFlagDefault(t *testing.T) {
+	preparers := android.GroupFixturePreparers(
+		PrepareForTestWithFakeDex2oatd,
+		PrepareForTestWithDexpreoptConfig,
+		FixtureSetEnableUffdGc("default"),
+	)
+
+	result := preparers.RunTest(t)
+	ctx := result.TestContext
+	config := ctx.Config()
+
+	rule := ctx.SingletonForTests("dexpreopt-soong-config").Rule("dexpreopt_uffd_gc_flag")
+
+	android.AssertStringDoesContain(t, "", rule.RuleParams.Command, "construct_uffd_gc_flag")
+	android.AssertStringPathsRelativeToTopEquals(t, "", config, []string{
+		"out/soong/dexpreopt/uffd_gc_flag.txt",
+	}, rule.AllOutputs())
+	android.AssertPathsRelativeToTopEquals(t, "", []string{
+		"out/soong/dexpreopt/kernel_version_for_uffd_gc.txt",
+	}, rule.Implicits)
+}
+
+func TestUffdGcFlagBogus(t *testing.T) {
+	preparers := android.GroupFixturePreparers(
+		PrepareForTestWithFakeDex2oatd,
+		PrepareForTestWithDexpreoptConfig,
+		FixtureSetEnableUffdGc("bogus"),
+	)
+
+	preparers.
+		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+			"Unknown value of PRODUCT_ENABLE_UFFD_GC: bogus")).
+		RunTest(t)
+}
diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go
index 147a562..b1fbef5 100644
--- a/dexpreopt/testing.go
+++ b/dexpreopt/testing.go
@@ -88,6 +88,15 @@
 	FixtureModifyGlobalConfig(func(android.PathContext, *GlobalConfig) {}),
 )
 
+var PrepareForTestWithDexpreoptConfig = android.GroupFixturePreparers(
+	android.PrepareForTestWithAndroidBuildComponents,
+	android.FixtureModifyContext(func(ctx *android.TestContext) {
+		ctx.RegisterParallelSingletonType("dexpreopt-soong-config", func() android.Singleton {
+			return &globalSoongConfigSingleton{}
+		})
+	}),
+)
+
 // FixtureModifyGlobalConfig enables dexpreopt (unless modified by the mutator) and modifies the
 // configuration.
 func FixtureModifyGlobalConfig(configModifier func(ctx android.PathContext, dexpreoptConfig *GlobalConfig)) android.FixturePreparer {
@@ -195,3 +204,10 @@
 		dexpreoptConfig.DisablePreopt = disable
 	})
 }
+
+// FixtureSetEnableUffdGc sets the EnableUffdGc property in the global config.
+func FixtureSetEnableUffdGc(value string) android.FixturePreparer {
+	return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
+		dexpreoptConfig.EnableUffdGc = value
+	})
+}
diff --git a/docs/best_practices.md b/docs/best_practices.md
index bc760b8..48ed996 100644
--- a/docs/best_practices.md
+++ b/docs/best_practices.md
@@ -285,6 +285,6 @@
 and will require ongoing maintenance as the build system is changed; so
 plugins should be used only when absolutely required.
 
-See [art/build/art.go](https://android.googlesource.com/platform/art/+/master/build/art.go)
-or [external/llvm/soong/llvm.go](https://android.googlesource.com/platform/external/llvm/+/master/soong/llvm.go)
+See [art/build/art.go](https://android.googlesource.com/platform/art/+/main/build/art.go)
+or [external/llvm/soong/llvm.go](https://android.googlesource.com/platform/external/llvm/+/main/soong/llvm.go)
 for examples of more complex conditionals on product variables or environment variables.
diff --git a/docs/clion.md b/docs/clion.md
index d6ae19a..8e2c597 100644
--- a/docs/clion.md
+++ b/docs/clion.md
@@ -3,6 +3,10 @@
 Soong can generate CLion projects. This is intended for source code editing
 only. Build should still be done via make/m/mm(a)/mmm(a).
 
+Note: alternatively, you can use
+[aidegen to generate a Clion or VSCode project](https://android.googlesource.com/platform/tools/asuite/+/refs/heads/main/aidegen/README.md)
+with a single command, using the `-i c` flag.
+
 CMakeLists.txt project file generation is enabled via environment variable:
 
 ```bash
diff --git a/docs/map_files.md b/docs/map_files.md
index 35e8cbb..e1ddefc 100644
--- a/docs/map_files.md
+++ b/docs/map_files.md
@@ -5,8 +5,8 @@
 semantically meaningful to [gen_stub_libs.py]. For an example of a map file, see
 [libc.map.txt].
 
-[gen_stub_libs.py]: https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/gen_stub_libs.py
-[libc.map.txt]: https://cs.android.com/android/platform/superproject/+/master:bionic/libc/libc.map.txt
+[gen_stub_libs.py]: https://cs.android.com/android/platform/superproject/+/main:build/soong/cc/gen_stub_libs.py
+[libc.map.txt]: https://cs.android.com/android/platform/superproject/+/main:bionic/libc/libc.map.txt
 [linker version scripts]: https://www.gnu.org/software/gnulib/manual/html_node/LD-Version-Scripts.html
 
 ## Basic format
@@ -134,6 +134,9 @@
 
 Historically this annotation was spelled `vndk`, but it has always meant LL-NDK.
 
+When an llndk API is deprecated, the `llndk` tag is dropped and
+`llndk-deprecate=<V>` is added.
+
 ### platform-only
 
 Indicates that the version or symbol is public in the implementation library but
diff --git a/docs/rbe.md b/docs/rbe.md
index cfe86d7..be60c83 100644
--- a/docs/rbe.md
+++ b/docs/rbe.md
@@ -11,7 +11,7 @@
 
 To enable RBE, you need to set several environment variables before triggering
 the build. You can set them through a
-[environment variables config file](https://android.googlesource.com/platform/build/soong/+/master/README.md#environment-variables-config-file).
+[environment variables config file](https://android.googlesource.com/platform/build/soong/+/main/README.md#environment-variables-config-file).
 As an example, [build/soong/docs/rbe.json](rbe.json) is a config that enables
 RBE in the build. Once the config file is created, you need to let Soong load
 the config file by specifying `ANDROID_BUILD_ENVIRONMENT_CONFIG_DIR` environment
diff --git a/docs/tidy.md b/docs/tidy.md
index 2eb8234..ae0ca93 100644
--- a/docs/tidy.md
+++ b/docs/tidy.md
@@ -24,7 +24,7 @@
 ```
 
 The default global clang-tidy checks and flags are defined in
-[build/soong/cc/config/tidy.go](https://android.googlesource.com/platform/build/soong/+/refs/heads/master/cc/config/tidy.go).
+[build/soong/cc/config/tidy.go](https://android.googlesource.com/platform/build/soong/+/refs/heads/main/cc/config/tidy.go).
 
 
 ## Module clang-tidy properties
@@ -34,7 +34,7 @@
 ### `tidy`, `tidy_checks`, and `ALLOW_LOCAL_TIDY_TRUE`
 
 For example, in
-[system/bpf/Android.bp](https://android.googlesource.com/platform/system/bpf/+/refs/heads/master/Android.bp),
+[system/bpf/Android.bp](https://android.googlesource.com/platform/system/bpf/+/refs/heads/main/Android.bp),
 clang-tidy is enabled explicitly and with a different check list:
 ```
 cc_defaults {
@@ -69,7 +69,7 @@
 Some modules might want to disable clang-tidy even when
 environment variable `WITH_TIDY=1` is set.
 Examples can be found in
-[system/netd/tests/Android.bp](https://android.googlesource.com/platform/system/netd/+/refs/heads/master/tests/Android.bp)
+[system/netd/tests/Android.bp](https://android.googlesource.com/platform/system/netd/+/refs/heads/main/tests/Android.bp)
 ```
 cc_test {
     name: "netd_integration_test",
@@ -78,7 +78,7 @@
     tidy: false,  // cuts test build time by almost 1 minute
 ```
 and in
-[bionic/tests/Android.bp](https://android.googlesource.com/platform/bionic/+/refs/heads/master/tests/Android.bp).
+[bionic/tests/Android.bp](https://android.googlesource.com/platform/bionic/+/refs/heads/main/tests/Android.bp).
 ```
 cc_test_library {
     name: "fortify_disabled_for_tidy",
@@ -97,7 +97,7 @@
 If a C/C++ module wants to be free of certain clang-tidy warnings,
 it can chose those checks to be treated as errors.
 For example
-[system/core/libsysutils/Android.bp](https://android.googlesource.com/platform/system/core/+/refs/heads/master/libsysutils/Android.bp)
+[system/core/libsysutils/Android.bp](https://android.googlesource.com/platform/system/core/+/refs/heads/main/libsysutils/Android.bp)
 has enabled clang-tidy explicitly, selected its own tidy checks,
 and set three groups of tidy checks as errors:
 ```
@@ -130,7 +130,7 @@
 
 Some other tidy flags examples are `-format-style=` and `-header-filter=`
 For example, in
-[art/odrefresh/Android.bp](https://android.googlesource.com/platform/art/+/refs/heads/master/odrefresh/Android.bp),
+[art/odrefresh/Android.bp](https://android.googlesource.com/platform/art/+/refs/heads/main/odrefresh/Android.bp),
 we found
 ```
 cc_defaults {
diff --git a/starlark_import/Android.bp b/elf/Android.bp
similarity index 63%
rename from starlark_import/Android.bp
rename to elf/Android.bp
index b43217b..6450be1 100644
--- a/starlark_import/Android.bp
+++ b/elf/Android.bp
@@ -1,4 +1,4 @@
-// Copyright 2023 Google Inc. All rights reserved.
+// Copyright 2016 Google Inc. All rights reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -17,20 +17,12 @@
 }
 
 bootstrap_go_package {
-    name: "soong-starlark",
-    pkgPath: "android/soong/starlark_import",
+    name: "soong-elf",
+    pkgPath: "android/soong/elf",
     srcs: [
-        "starlark_import.go",
-        "unmarshal.go",
+        "elf.go",
     ],
     testSrcs: [
-        "starlark_import_test.go",
-        "unmarshal_test.go",
-    ],
-    deps: [
-        "go-starlark-starlark",
-        "go-starlark-starlarkstruct",
-        "go-starlark-starlarkjson",
-        "go-starlark-starlarktest",
+        "elf_test.go",
     ],
 }
diff --git a/cmd/symbols_map/elf.go b/elf/elf.go
similarity index 94%
rename from cmd/symbols_map/elf.go
rename to elf/elf.go
index 950e3b2..e84a8ae 100644
--- a/cmd/symbols_map/elf.go
+++ b/elf/elf.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package elf
 
 import (
 	"debug/elf"
@@ -26,9 +26,9 @@
 
 const gnuBuildID = "GNU\x00"
 
-// elfIdentifier extracts the elf build ID from an elf file.  If allowMissing is true it returns
+// Identifier extracts the elf build ID from an elf file.  If allowMissing is true it returns
 // an empty identifier if the file exists but the build ID note does not.
-func elfIdentifier(filename string, allowMissing bool) (string, error) {
+func Identifier(filename string, allowMissing bool) (string, error) {
 	f, err := os.Open(filename)
 	if err != nil {
 		return "", fmt.Errorf("failed to open %s: %w", filename, err)
diff --git a/cmd/symbols_map/elf_test.go b/elf/elf_test.go
similarity index 99%
rename from cmd/symbols_map/elf_test.go
rename to elf/elf_test.go
index a94c87f..a220770 100644
--- a/cmd/symbols_map/elf_test.go
+++ b/elf/elf_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package main
+package elf
 
 import (
 	"bytes"
diff --git a/etc/Android.bp b/etc/Android.bp
index c670236..97788e4 100644
--- a/etc/Android.bp
+++ b/etc/Android.bp
@@ -9,15 +9,14 @@
         "blueprint",
         "soong",
         "soong-android",
-        "soong-snapshot",
     ],
     srcs: [
         "prebuilt_etc.go",
-        "snapshot_etc.go",
+        "install_symlink.go",
     ],
     testSrcs: [
         "prebuilt_etc_test.go",
-        "snapshot_etc_test.go",
+        "install_symlink_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/etc/install_symlink.go b/etc/install_symlink.go
new file mode 100644
index 0000000..2182b86
--- /dev/null
+++ b/etc/install_symlink.go
@@ -0,0 +1,92 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package etc
+
+import (
+	"android/soong/android"
+	"path/filepath"
+	"strings"
+)
+
+func init() {
+	RegisterInstallSymlinkBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterInstallSymlinkBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("install_symlink", InstallSymlinkFactory)
+}
+
+// install_symlink can be used to install an symlink with an arbitrary target to an arbitrary path
+// on the device.
+func InstallSymlinkFactory() android.Module {
+	module := &InstallSymlink{}
+	module.AddProperties(&module.properties)
+	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	return module
+}
+
+type InstallSymlinkProperties struct {
+	// Where to install this symlink, relative to the partition it's installed on.
+	// Which partition it's installed on can be controlled by the vendor, system_ext, ramdisk, etc.
+	// properties.
+	Installed_location string
+	// The target of the symlink, aka where the symlink points.
+	Symlink_target string
+}
+
+type InstallSymlink struct {
+	android.ModuleBase
+	properties InstallSymlinkProperties
+
+	output        android.Path
+	installedPath android.InstallPath
+}
+
+func (m *InstallSymlink) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if filepath.Clean(m.properties.Symlink_target) != m.properties.Symlink_target {
+		ctx.PropertyErrorf("symlink_target", "Should be a clean filepath")
+		return
+	}
+	if filepath.Clean(m.properties.Installed_location) != m.properties.Installed_location {
+		ctx.PropertyErrorf("installed_location", "Should be a clean filepath")
+		return
+	}
+	if strings.HasPrefix(m.properties.Installed_location, "../") || strings.HasPrefix(m.properties.Installed_location, "/") {
+		ctx.PropertyErrorf("installed_location", "Should not start with / or ../")
+		return
+	}
+
+	out := android.PathForModuleOut(ctx, "out.txt")
+	android.WriteFileRuleVerbatim(ctx, out, "")
+	m.output = out
+
+	name := filepath.Base(m.properties.Installed_location)
+	installDir := android.PathForModuleInstall(ctx, filepath.Dir(m.properties.Installed_location))
+	m.installedPath = ctx.InstallAbsoluteSymlink(installDir, name, m.properties.Symlink_target)
+}
+
+func (m *InstallSymlink) AndroidMkEntries() []android.AndroidMkEntries {
+	return []android.AndroidMkEntries{{
+		Class: "FAKE",
+		// Need at least one output file in order for this to take effect.
+		OutputFile: android.OptionalPathForPath(m.output),
+		Include:    "$(BUILD_PHONY_PACKAGE)",
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+				entries.AddStrings("LOCAL_SOONG_INSTALL_SYMLINKS", m.installedPath.String())
+			},
+		},
+	}}
+}
diff --git a/etc/install_symlink_test.go b/etc/install_symlink_test.go
new file mode 100644
index 0000000..d7165e5
--- /dev/null
+++ b/etc/install_symlink_test.go
@@ -0,0 +1,135 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package etc
+
+import (
+	"android/soong/android"
+	"strings"
+	"testing"
+)
+
+var prepareForInstallSymlinkTest = android.GroupFixturePreparers(
+	android.PrepareForTestWithArchMutator,
+	android.FixtureRegisterWithContext(RegisterInstallSymlinkBuildComponents),
+)
+
+func TestInstallSymlinkBasic(t *testing.T) {
+	result := prepareForInstallSymlinkTest.RunTestWithBp(t, `
+		install_symlink {
+			name: "foo",
+			installed_location: "bin/foo",
+			symlink_target: "/system/system_ext/bin/foo",
+		}
+	`)
+
+	foo_variants := result.ModuleVariantsForTests("foo")
+	if len(foo_variants) != 1 {
+		t.Fatalf("expected 1 variant, got %#v", foo_variants)
+	}
+
+	foo := result.ModuleForTests("foo", "android_common").Module()
+	androidMkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, foo)
+	if len(androidMkEntries) != 1 {
+		t.Fatalf("expected 1 androidmkentry, got %d", len(androidMkEntries))
+	}
+
+	symlinks := androidMkEntries[0].EntryMap["LOCAL_SOONG_INSTALL_SYMLINKS"]
+	if len(symlinks) != 1 {
+		t.Fatalf("Expected 1 symlink, got %d", len(symlinks))
+	}
+
+	if !strings.HasSuffix(symlinks[0], "system/bin/foo") {
+		t.Fatalf("Expected symlink install path to end in system/bin/foo, got: %s", symlinks[0])
+	}
+}
+
+func TestInstallSymlinkToRecovery(t *testing.T) {
+	result := prepareForInstallSymlinkTest.RunTestWithBp(t, `
+		install_symlink {
+			name: "foo",
+			installed_location: "bin/foo",
+			symlink_target: "/system/system_ext/bin/foo",
+			recovery: true,
+		}
+	`)
+
+	foo_variants := result.ModuleVariantsForTests("foo")
+	if len(foo_variants) != 1 {
+		t.Fatalf("expected 1 variant, got %#v", foo_variants)
+	}
+
+	foo := result.ModuleForTests("foo", "android_common").Module()
+	androidMkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, foo)
+	if len(androidMkEntries) != 1 {
+		t.Fatalf("expected 1 androidmkentry, got %d", len(androidMkEntries))
+	}
+
+	symlinks := androidMkEntries[0].EntryMap["LOCAL_SOONG_INSTALL_SYMLINKS"]
+	if len(symlinks) != 1 {
+		t.Fatalf("Expected 1 symlink, got %d", len(symlinks))
+	}
+
+	if !strings.HasSuffix(symlinks[0], "recovery/root/system/bin/foo") {
+		t.Fatalf("Expected symlink install path to end in recovery/root/system/bin/foo, got: %s", symlinks[0])
+	}
+}
+
+func TestErrorOnNonCleanTarget(t *testing.T) {
+	prepareForInstallSymlinkTest.
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Should be a clean filepath")).
+		RunTestWithBp(t, `
+		install_symlink {
+			name: "foo",
+			installed_location: "bin/foo",
+			symlink_target: "/system/system_ext/../bin/foo",
+		}
+	`)
+}
+
+func TestErrorOnNonCleanInstalledLocation(t *testing.T) {
+	prepareForInstallSymlinkTest.
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Should be a clean filepath")).
+		RunTestWithBp(t, `
+		install_symlink {
+			name: "foo",
+			installed_location: "bin/../foo",
+			symlink_target: "/system/system_ext/bin/foo",
+		}
+	`)
+}
+
+func TestErrorOnInstalledPathStartingWithDotDot(t *testing.T) {
+	prepareForInstallSymlinkTest.
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Should not start with / or \\.\\./")).
+		RunTestWithBp(t, `
+		install_symlink {
+			name: "foo",
+			installed_location: "../bin/foo",
+			symlink_target: "/system/system_ext/bin/foo",
+		}
+	`)
+}
+
+func TestErrorOnInstalledPathStartingWithSlash(t *testing.T) {
+	prepareForInstallSymlinkTest.
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Should not start with / or \\.\\./")).
+		RunTestWithBp(t, `
+		install_symlink {
+			name: "foo",
+			installed_location: "/bin/foo",
+			symlink_target: "/system/system_ext/bin/foo",
+		}
+	`)
+}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 370a423..d1c1d85 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -28,18 +28,13 @@
 // various `prebuilt_*` mutators.
 
 import (
-	"encoding/json"
 	"fmt"
 	"path/filepath"
-	"reflect"
 	"strings"
 
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
-	"android/soong/bazel/cquery"
-	"android/soong/snapshot"
 )
 
 var pctx = android.NewPackageContext("android/soong/etc")
@@ -49,7 +44,6 @@
 func init() {
 	pctx.Import("android/soong/android")
 	RegisterPrebuiltEtcBuildComponents(android.InitRegistrationContext)
-	snapshot.RegisterSnapshotAction(generatePrebuiltSnapshot)
 }
 
 func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) {
@@ -60,10 +54,12 @@
 	ctx.RegisterModuleType("prebuilt_root_host", PrebuiltRootHostFactory)
 	ctx.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
 	ctx.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
+	ctx.RegisterModuleType("prebuilt_usr_hyphendata", PrebuiltUserHyphenDataFactory)
 	ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
 	ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
 	ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
 	ctx.RegisterModuleType("prebuilt_rfsa", PrebuiltRFSAFactory)
+	ctx.RegisterModuleType("prebuilt_renderscript_bitcode", PrebuiltRenderScriptBitcodeFactory)
 
 	ctx.RegisterModuleType("prebuilt_defaults", defaultsFactory)
 
@@ -73,10 +69,15 @@
 
 type prebuiltEtcProperties struct {
 	// Source file of this prebuilt. Can reference a genrule type module with the ":module" syntax.
+	// Mutually exclusive with srcs.
 	Src *string `android:"path,arch_variant"`
 
+	// Source files of this prebuilt. Can reference a genrule type module with the ":module" syntax.
+	// Mutually exclusive with src. When used, filename_from_src is set to true.
+	Srcs []string `android:"path,arch_variant"`
+
 	// Optional name for the installed file. If unspecified, name of the module is used as the file
-	// name.
+	// name. Only available when using a single source (src).
 	Filename *string `android:"arch_variant"`
 
 	// When set to true, and filename property is not set, the name for the installed file
@@ -129,31 +130,34 @@
 	// Returns the sub install directory relative to BaseDir().
 	SubDir() string
 
-	// Returns an android.OutputPath to the intermeidate file, which is the renamed prebuilt source
+	// Returns an android.OutputPath to the intermediate file, which is the renamed prebuilt source
 	// file.
-	OutputFile() android.OutputPath
+	OutputFiles(tag string) (android.Paths, error)
 }
 
 type PrebuiltEtc struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
-	android.BazelModuleBase
-
-	snapshot.VendorSnapshotModuleInterface
-	snapshot.RecoverySnapshotModuleInterface
 
 	properties       prebuiltEtcProperties
 	subdirProperties prebuiltSubdirProperties
 
-	sourceFilePath android.Path
-	outputFilePath android.OutputPath
+	sourceFilePaths android.Paths
+	outputFilePaths android.OutputPaths
 	// The base install location, e.g. "etc" for prebuilt_etc, "usr/share" for prebuilt_usr_share.
-	installDirBase string
+	installDirBase               string
+	installDirBase64             string
+	installAvoidMultilibConflict bool
 	// The base install location when soc_specific property is set to true, e.g. "firmware" for
 	// prebuilt_firmware.
 	socInstallDirBase      string
 	installDirPath         android.InstallPath
 	additionalDependencies *android.Paths
+
+	makeClass string
+
+	// Aconfig files for all transitive deps.  Also exposed via TransitiveDeclarationsInfo
+	mergedAconfigFiles map[string]android.Paths
 }
 
 type Defaults struct {
@@ -242,6 +246,9 @@
 }
 
 func (p *PrebuiltEtc) SourceFilePath(ctx android.ModuleContext) android.Path {
+	if len(p.properties.Srcs) > 0 {
+		panic(fmt.Errorf("SourceFilePath not available on multi-source prebuilt %q", p.Name()))
+	}
 	return android.PathForModuleSrc(ctx, proptools.String(p.properties.Src))
 }
 
@@ -256,7 +263,10 @@
 }
 
 func (p *PrebuiltEtc) OutputFile() android.OutputPath {
-	return p.outputFilePath
+	if len(p.properties.Srcs) > 0 {
+		panic(fmt.Errorf("OutputFile not available on multi-source prebuilt %q", p.Name()))
+	}
+	return p.outputFilePaths[0]
 }
 
 var _ android.OutputFileProducer = (*PrebuiltEtc)(nil)
@@ -264,7 +274,7 @@
 func (p *PrebuiltEtc) OutputFiles(tag string) (android.Paths, error) {
 	switch tag {
 	case "":
-		return android.Paths{p.outputFilePath}, nil
+		return p.outputFilePaths.Paths(), nil
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
@@ -289,19 +299,44 @@
 	return p.ModuleBase.InstallInVendor()
 }
 
-func (p *PrebuiltEtc) ExcludeFromVendorSnapshot() bool {
-	return false
-}
-
-func (p *PrebuiltEtc) ExcludeFromRecoverySnapshot() bool {
-	return false
+func (p *PrebuiltEtc) installBaseDir(ctx android.ModuleContext) string {
+	// If soc install dir was specified and SOC specific is set, set the installDirPath to the
+	// specified socInstallDirBase.
+	installBaseDir := p.installDirBase
+	if p.Target().Arch.ArchType.Multilib == "lib64" && p.installDirBase64 != "" {
+		installBaseDir = p.installDirBase64
+	}
+	if p.SocSpecific() && p.socInstallDirBase != "" {
+		installBaseDir = p.socInstallDirBase
+	}
+	if p.installAvoidMultilibConflict && !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
+		installBaseDir = filepath.Join(installBaseDir, ctx.Arch().ArchType.String())
+	}
+	return installBaseDir
 }
 
 func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	var installs []installProperties
+
+	if p.properties.Src != nil && len(p.properties.Srcs) > 0 {
+		ctx.PropertyErrorf("src", "src is set. Cannot set srcs")
+	}
+
+	// Check that `sub_dir` and `relative_install_path` are not set at the same time.
+	if p.subdirProperties.Sub_dir != nil && p.subdirProperties.Relative_install_path != nil {
+		ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
+	}
+	p.installDirPath = android.PathForModuleInstall(ctx, p.installBaseDir(ctx), p.SubDir())
+
 	filename := proptools.String(p.properties.Filename)
 	filenameFromSrc := proptools.Bool(p.properties.Filename_from_src)
 	if p.properties.Src != nil {
-		p.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(p.properties.Src))
+		p.sourceFilePaths = android.PathsForModuleSrc(ctx, []string{proptools.String(p.properties.Src)})
+		// If the source was not found, set a fake source path to
+		// support AllowMissingDependencies executions.
+		if len(p.sourceFilePaths) == 0 {
+			p.sourceFilePaths = android.Paths{android.PathForModuleSrc(ctx)}
+		}
 
 		// Determine the output file basename.
 		// If Filename is set, use the name specified by the property.
@@ -313,79 +348,102 @@
 				return
 			}
 		} else if filenameFromSrc {
-			filename = p.sourceFilePath.Base()
+			filename = p.sourceFilePaths[0].Base()
 		} else {
 			filename = ctx.ModuleName()
 		}
+		if strings.Contains(filename, "/") {
+			ctx.PropertyErrorf("filename", "filename cannot contain separator '/'")
+			return
+		}
+		p.outputFilePaths = android.OutputPaths{android.PathForModuleOut(ctx, filename).OutputPath}
+
+		ip := installProperties{
+			filename:       filename,
+			sourceFilePath: p.sourceFilePaths[0],
+			outputFilePath: p.outputFilePaths[0],
+			installDirPath: p.installDirPath,
+			symlinks:       p.properties.Symlinks,
+		}
+		installs = append(installs, ip)
+	} else if len(p.properties.Srcs) > 0 {
+		if filename != "" {
+			ctx.PropertyErrorf("filename", "filename cannot be set when using srcs")
+		}
+		if len(p.properties.Symlinks) > 0 {
+			ctx.PropertyErrorf("symlinks", "symlinks cannot be set when using srcs")
+		}
+		if p.properties.Filename_from_src != nil {
+			ctx.PropertyErrorf("filename_from_src", "filename_from_src is implicitly set to true when using srcs")
+		}
+		p.sourceFilePaths = android.PathsForModuleSrc(ctx, p.properties.Srcs)
+		for _, src := range p.sourceFilePaths {
+			filename := src.Base()
+			output := android.PathForModuleOut(ctx, filename).OutputPath
+			ip := installProperties{
+				filename:       filename,
+				sourceFilePath: src,
+				outputFilePath: output,
+				installDirPath: p.installDirPath,
+			}
+			p.outputFilePaths = append(p.outputFilePaths, output)
+			installs = append(installs, ip)
+		}
 	} else if ctx.Config().AllowMissingDependencies() {
 		// If no srcs was set and AllowMissingDependencies is enabled then
 		// mark the module as missing dependencies and set a fake source path
 		// and file name.
 		ctx.AddMissingDependencies([]string{"MISSING_PREBUILT_SRC_FILE"})
-		p.sourceFilePath = android.PathForModuleSrc(ctx)
+		p.sourceFilePaths = android.Paths{android.PathForModuleSrc(ctx)}
 		if filename == "" {
 			filename = ctx.ModuleName()
 		}
+		p.outputFilePaths = android.OutputPaths{android.PathForModuleOut(ctx, filename).OutputPath}
+		ip := installProperties{
+			filename:       filename,
+			sourceFilePath: p.sourceFilePaths[0],
+			outputFilePath: p.outputFilePaths[0],
+			installDirPath: p.installDirPath,
+		}
+		installs = append(installs, ip)
 	} else {
 		ctx.PropertyErrorf("src", "missing prebuilt source file")
 		return
 	}
 
-	if strings.Contains(filename, "/") {
-		ctx.PropertyErrorf("filename", "filename cannot contain separator '/'")
-		return
+	// Call InstallFile even when uninstallable to make the module included in the package.
+	if !p.Installable() {
+		p.SkipInstall()
 	}
-
-	// Check that `sub_dir` and `relative_install_path` are not set at the same time.
-	if p.subdirProperties.Sub_dir != nil && p.subdirProperties.Relative_install_path != nil {
-		ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
+	for _, ip := range installs {
+		ip.addInstallRules(ctx)
 	}
-
-	// If soc install dir was specified and SOC specific is set, set the installDirPath to the
-	// specified socInstallDirBase.
-	installBaseDir := p.installDirBase
-	if p.SocSpecific() && p.socInstallDirBase != "" {
-		installBaseDir = p.socInstallDirBase
-	}
-	p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, p.SubDir())
-
-	// Call InstallFile even when uninstallable to make the module included in the package
-	ip := installProperties{
-		installable:    p.Installable(),
-		filename:       filename,
-		sourceFilePath: p.sourceFilePath,
-		symlinks:       p.properties.Symlinks,
-	}
-	p.addInstallRules(ctx, ip)
+	android.CollectDependencyAconfigFiles(ctx, &p.mergedAconfigFiles)
 }
 
 type installProperties struct {
-	installable    bool
 	filename       string
 	sourceFilePath android.Path
+	outputFilePath android.OutputPath
+	installDirPath android.InstallPath
 	symlinks       []string
 }
 
 // utility function to add install rules to the build graph.
 // Reduces code duplication between Soong and Mixed build analysis
-func (p *PrebuiltEtc) addInstallRules(ctx android.ModuleContext, ip installProperties) {
-	if !ip.installable {
-		p.SkipInstall()
-	}
-
+func (ip *installProperties) addInstallRules(ctx android.ModuleContext) {
 	// Copy the file from src to a location in out/ with the correct `filename`
 	// This ensures that outputFilePath has the correct name for others to
 	// use, as the source file may have a different name.
-	p.outputFilePath = android.PathForModuleOut(ctx, ip.filename).OutputPath
 	ctx.Build(pctx, android.BuildParams{
 		Rule:   android.Cp,
-		Output: p.outputFilePath,
+		Output: ip.outputFilePath,
 		Input:  ip.sourceFilePath,
 	})
 
-	installPath := ctx.InstallFile(p.installDirPath, ip.filename, p.outputFilePath)
+	installPath := ctx.InstallFile(ip.installDirPath, ip.filename, ip.outputFilePath)
 	for _, sl := range ip.symlinks {
-		ctx.InstallSymlink(p.installDirPath, sl, installPath)
+		ctx.InstallSymlink(ip.installDirPath, sl, installPath)
 	}
 }
 
@@ -403,15 +461,21 @@
 	if p.InRecovery() && !p.onlyInRecovery() {
 		nameSuffix = ".recovery"
 	}
-	return []android.AndroidMkEntries{android.AndroidMkEntries{
-		Class:      "ETC",
+
+	class := p.makeClass
+	if class == "" {
+		class = "ETC"
+	}
+
+	return []android.AndroidMkEntries{{
+		Class:      class,
 		SubName:    nameSuffix,
-		OutputFile: android.OptionalPathForPath(p.outputFilePath),
+		OutputFile: android.OptionalPathForPath(p.outputFilePaths[0]),
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 				entries.SetString("LOCAL_MODULE_TAGS", "optional")
 				entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.String())
-				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
+				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePaths[0].Base())
 				if len(p.properties.Symlinks) > 0 {
 					entries.AddStrings("LOCAL_MODULE_SYMLINKS", p.properties.Symlinks...)
 				}
@@ -419,11 +483,16 @@
 				if p.additionalDependencies != nil {
 					entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES", p.additionalDependencies.Strings()...)
 				}
+				android.SetAconfigFileMkEntries(p.AndroidModuleBase(), entries, p.mergedAconfigFiles)
 			},
 		},
 	}}
 }
 
+func (p *PrebuiltEtc) AndroidModuleBase() *android.ModuleBase {
+	return &p.ModuleBase
+}
+
 func InitPrebuiltEtcModule(p *PrebuiltEtc, dirBase string) {
 	p.installDirBase = dirBase
 	p.AddProperties(&p.properties)
@@ -443,7 +512,6 @@
 	// This module is device-only
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
 	android.InitDefaultableModule(module)
-	android.InitBazelModule(module)
 	return module
 }
 
@@ -473,7 +541,6 @@
 	// This module is host-only
 	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
-	android.InitBazelModule(module)
 	return module
 }
 
@@ -484,7 +551,6 @@
 	InitPrebuiltEtcModule(module, "cacerts")
 	// This module is device-only
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
-	android.InitBazelModule(module)
 	return module
 }
 
@@ -518,7 +584,6 @@
 	// This module is device-only
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
 	android.InitDefaultableModule(module)
-	android.InitBazelModule(module)
 	return module
 }
 
@@ -533,6 +598,17 @@
 	return module
 }
 
+// prebuilt_usr_hyphendata is for a prebuilt artifact that is installed in
+// <partition>/usr/hyphen-data/<sub_dir> directory.
+func PrebuiltUserHyphenDataFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "usr/hyphen-data")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	android.InitDefaultableModule(module)
+	return module
+}
+
 // prebuilt_font installs a font in <partition>/fonts directory.
 func PrebuiltFontFactory() android.Module {
 	module := &PrebuiltEtc{}
@@ -570,6 +646,19 @@
 	return module
 }
 
+// prebuilt_renderscript_bitcode installs a *.bc file into /system/lib or /system/lib64.
+func PrebuiltRenderScriptBitcodeFactory() android.Module {
+	module := &PrebuiltEtc{}
+	module.makeClass = "RENDERSCRIPT_BITCODE"
+	module.installDirBase64 = "lib64"
+	module.installAvoidMultilibConflict = true
+	InitPrebuiltEtcModule(module, "lib")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
+	android.InitDefaultableModule(module)
+	return module
+}
+
 // prebuilt_rfsa installs a firmware file that will be available through Qualcomm's RFSA
 // to the <partition>/lib/rfsa directory.
 func PrebuiltRFSAFactory() android.Module {
@@ -583,257 +672,3 @@
 	android.InitDefaultableModule(module)
 	return module
 }
-
-// Copy file into the snapshot
-func copyFile(ctx android.SingletonContext, path android.Path, out string, fake bool) android.OutputPath {
-	if fake {
-		// Create empty file instead for the fake snapshot
-		return snapshot.WriteStringToFileRule(ctx, "", out)
-	} else {
-		return snapshot.CopyFileRule(pctx, ctx, path, out)
-	}
-}
-
-// Check if the module is target of the snapshot
-func isSnapshotAware(ctx android.SingletonContext, m *PrebuiltEtc, image snapshot.SnapshotImage) bool {
-	if !m.Enabled() {
-		return false
-	}
-
-	// Skip if the module is not included in the image
-	if !image.InImage(m)() {
-		return false
-	}
-
-	// When android/prebuilt.go selects between source and prebuilt, it sets
-	// HideFromMake on the other one to avoid duplicate install rules in make.
-	if m.IsHideFromMake() {
-		return false
-	}
-
-	// There are some prebuilt_etc module with multiple definition of same name.
-	// Check if the target would be included from the build
-	if !m.ExportedToMake() {
-		return false
-	}
-
-	// Skip if the module is in the predefined path list to skip
-	if image.IsProprietaryPath(ctx.ModuleDir(m), ctx.DeviceConfig()) {
-		return false
-	}
-
-	// Skip if the module should be excluded
-	if image.ExcludeFromSnapshot(m) || image.ExcludeFromDirectedSnapshot(ctx.DeviceConfig(), m.BaseModuleName()) {
-		return false
-	}
-
-	// Skip from other exceptional cases
-	if m.Target().Os.Class != android.Device {
-		return false
-	}
-	if m.Target().NativeBridge == android.NativeBridgeEnabled {
-		return false
-	}
-
-	return true
-}
-
-func generatePrebuiltSnapshot(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) snapshot.SnapshotPaths {
-	/*
-		Snapshot zipped artifacts directory structure for etc modules:
-		{SNAPSHOT_ARCH}/
-			arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
-				etc/
-					(prebuilt etc files)
-			arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
-				etc/
-					(prebuilt etc files)
-			NOTICE_FILES/
-				(notice files)
-	*/
-	var snapshotOutputs android.Paths
-	var snapshotNotices android.Paths
-	installedNotices := make(map[string]bool)
-
-	ctx.VisitAllModules(func(module android.Module) {
-		m, ok := module.(*PrebuiltEtc)
-		if !ok {
-			return
-		}
-
-		if !isSnapshotAware(ctx, m, s.Image) {
-			return
-		}
-
-		targetArch := "arch-" + m.Target().Arch.ArchType.String()
-
-		snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "etc", m.BaseModuleName())
-		snapshotOutputs = append(snapshotOutputs, copyFile(ctx, m.OutputFile(), snapshotLibOut, s.Fake))
-
-		prop := snapshot.SnapshotJsonFlags{}
-		propOut := snapshotLibOut + ".json"
-		prop.InitBaseSnapshotProps(m)
-		prop.RelativeInstallPath = m.SubDir()
-
-		if m.properties.Filename != nil {
-			prop.Filename = *m.properties.Filename
-		}
-
-		j, err := json.Marshal(prop)
-		if err != nil {
-			ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
-			return
-		}
-		snapshotOutputs = append(snapshotOutputs, snapshot.WriteStringToFileRule(ctx, string(j), propOut))
-
-		for _, notice := range m.EffectiveLicenseFiles() {
-			if _, ok := installedNotices[notice.String()]; !ok {
-				installedNotices[notice.String()] = true
-				snapshotNotices = append(snapshotNotices, notice)
-			}
-		}
-
-	})
-
-	return snapshot.SnapshotPaths{OutputFiles: snapshotOutputs, NoticeFiles: snapshotNotices}
-}
-
-// For Bazel / bp2build
-
-type bazelPrebuiltFileAttributes struct {
-	Src               bazel.LabelAttribute
-	Filename          bazel.LabelAttribute
-	Dir               string
-	Installable       bazel.BoolAttribute
-	Filename_from_src bazel.BoolAttribute
-}
-
-// Bp2buildHelper returns a bazelPrebuiltFileAttributes used for the conversion
-// of prebuilt_*  modules. bazelPrebuiltFileAttributes has the common attributes
-// used by both prebuilt_etc_xml and other prebuilt_* moodules
-func (module *PrebuiltEtc) Bp2buildHelper(ctx android.TopDownMutatorContext) *bazelPrebuiltFileAttributes {
-	var src bazel.LabelAttribute
-	for axis, configToProps := range module.GetArchVariantProperties(ctx, &prebuiltEtcProperties{}) {
-		for config, p := range configToProps {
-			props, ok := p.(*prebuiltEtcProperties)
-			if !ok {
-				continue
-			}
-			if props.Src != nil {
-				label := android.BazelLabelForModuleSrcSingle(ctx, *props.Src)
-				src.SetSelectValue(axis, config, label)
-			}
-		}
-
-		for propName, productConfigProps := range android.ProductVariableProperties(ctx, ctx.Module()) {
-			for configProp, propVal := range productConfigProps {
-				if propName == "Src" {
-					props, ok := propVal.(*string)
-					if !ok {
-						ctx.PropertyErrorf(" Expected Property to have type string, but was %s\n", reflect.TypeOf(propVal).String())
-						continue
-					}
-					if props != nil {
-						label := android.BazelLabelForModuleSrcSingle(ctx, *props)
-						src.SetSelectValue(configProp.ConfigurationAxis(), configProp.SelectKey(), label)
-					}
-				}
-			}
-		}
-	}
-
-	var filename string
-	var filenameFromSrc bool
-	moduleProps := module.properties
-
-	if moduleProps.Filename != nil && *moduleProps.Filename != "" {
-		filename = *moduleProps.Filename
-	} else if moduleProps.Filename_from_src != nil && *moduleProps.Filename_from_src {
-		if moduleProps.Src != nil {
-			filename = *moduleProps.Src
-		}
-		filenameFromSrc = true
-	} else {
-		filename = ctx.ModuleName()
-	}
-
-	var dir = module.installDirBase
-	if subDir := module.subdirProperties.Sub_dir; subDir != nil {
-		dir = dir + "/" + *subDir
-	}
-
-	var installable bazel.BoolAttribute
-	if install := module.properties.Installable; install != nil {
-		installable.Value = install
-	}
-
-	attrs := &bazelPrebuiltFileAttributes{
-		Src:         src,
-		Dir:         dir,
-		Installable: installable,
-	}
-
-	if filename != "" {
-		attrs.Filename = bazel.LabelAttribute{Value: &bazel.Label{Label: filename}}
-	} else if filenameFromSrc {
-		attrs.Filename_from_src = bazel.BoolAttribute{Value: moduleProps.Filename_from_src}
-	}
-
-	return attrs
-
-}
-
-// ConvertWithBp2build performs bp2build conversion of PrebuiltEtc
-// prebuilt_* modules (except prebuilt_etc_xml) are PrebuiltEtc,
-// which we treat as *PrebuiltFile*
-func (module *PrebuiltEtc) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	var dir = module.installDirBase
-	// prebuilt_file supports only `etc` or `usr/share`
-	if !(dir == "etc" || dir == "usr/share") {
-		return
-	}
-
-	attrs := module.Bp2buildHelper(ctx)
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "prebuilt_file",
-		Bzl_load_location: "//build/bazel/rules:prebuilt_file.bzl",
-	}
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
-}
-
-var _ android.MixedBuildBuildable = (*PrebuiltEtc)(nil)
-
-func (pe *PrebuiltEtc) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
-	return true
-}
-
-func (pe *PrebuiltEtc) QueueBazelCall(ctx android.BaseModuleContext) {
-	ctx.Config().BazelContext.QueueBazelRequest(
-		pe.GetBazelLabel(ctx, pe),
-		cquery.GetPrebuiltFileInfo,
-		android.GetConfigKey(ctx),
-	)
-}
-
-func (pe *PrebuiltEtc) ProcessBazelQueryResponse(ctx android.ModuleContext) {
-	bazelCtx := ctx.Config().BazelContext
-	pfi, err := bazelCtx.GetPrebuiltFileInfo(pe.GetBazelLabel(ctx, pe), android.GetConfigKey(ctx))
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-		return
-	}
-
-	// Set properties for androidmk
-	pe.installDirPath = android.PathForModuleInstall(ctx, pfi.Dir)
-
-	// Installation rules
-	ip := installProperties{
-		installable:    pfi.Installable,
-		filename:       pfi.Filename,
-		sourceFilePath: android.PathForSource(ctx, pfi.Src),
-		// symlinks: pe.properties.Symlinks, // TODO: b/207489266 - Fully support all properties in prebuilt_file
-	}
-	pe.addInstallRules(ctx, ip)
-}
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index df7664d..dd9958c 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -15,7 +15,6 @@
 package etc
 
 import (
-	"fmt"
 	"os"
 	"path/filepath"
 	"testing"
@@ -23,8 +22,6 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel/cquery"
-	"android/soong/snapshot"
 )
 
 func TestMain(m *testing.M) {
@@ -41,18 +38,6 @@
 	}),
 )
 
-var prepareForPrebuiltEtcSnapshotTest = android.GroupFixturePreparers(
-	prepareForPrebuiltEtcTest,
-	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
-		snapshot.VendorSnapshotImageSingleton.Init(ctx)
-		snapshot.RecoverySnapshotImageSingleton.Init(ctx)
-	}),
-	android.FixtureModifyConfig(func(config android.Config) {
-		config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
-		config.TestProductVariables.RecoverySnapshotVersion = proptools.StringPtr("current")
-	}),
-)
-
 func TestPrebuiltEtcVariants(t *testing.T) {
 	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
 		prebuilt_etc {
@@ -83,7 +68,7 @@
 
 	baz_variants := result.ModuleVariantsForTests("baz.conf")
 	if len(baz_variants) != 1 {
-		t.Errorf("expected 1, got %#v", bar_variants)
+		t.Errorf("expected 1, got %#v", baz_variants)
 	}
 }
 
@@ -97,7 +82,7 @@
 	`)
 
 	p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
-	android.AssertStringEquals(t, "output file path", "foo.installed.conf", p.outputFilePath.Base())
+	android.AssertStringEquals(t, "output file path", "foo.installed.conf", p.outputFilePaths[0].Base())
 }
 
 func TestPrebuiltEtcGlob(t *testing.T) {
@@ -114,10 +99,24 @@
 	`)
 
 	p := result.Module("my_foo", "android_arm64_armv8-a").(*PrebuiltEtc)
-	android.AssertStringEquals(t, "my_foo output file path", "my_foo", p.outputFilePath.Base())
+	android.AssertStringEquals(t, "my_foo output file path", "my_foo", p.outputFilePaths[0].Base())
 
 	p = result.Module("my_bar", "android_arm64_armv8-a").(*PrebuiltEtc)
-	android.AssertStringEquals(t, "my_bar output file path", "bar.conf", p.outputFilePath.Base())
+	android.AssertStringEquals(t, "my_bar output file path", "bar.conf", p.outputFilePaths[0].Base())
+}
+
+func TestPrebuiltEtcMultipleSrcs(t *testing.T) {
+	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
+		prebuilt_etc {
+			name: "foo",
+			srcs: ["*.conf"],
+		}
+	`)
+
+	p := result.Module("foo", "android_arm64_armv8-a").(*PrebuiltEtc)
+	android.AssertStringEquals(t, "output file path", "bar.conf", p.outputFilePaths[0].Base())
+	android.AssertStringEquals(t, "output file path", "baz.conf", p.outputFilePaths[1].Base())
+	android.AssertStringEquals(t, "output file path", "foo.conf", p.outputFilePaths[2].Base())
 }
 
 func TestPrebuiltEtcAndroidMk(t *testing.T) {
@@ -274,6 +273,20 @@
 	android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
 }
 
+func TestPrebuiltPrebuiltUserHyphenDataInstallDirPath(t *testing.T) {
+	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
+	prebuilt_usr_hyphendata {
+			name: "foo.conf",
+			src: "foo.conf",
+			sub_dir: "bar",
+		}
+	`)
+
+	p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
+	expected := "out/soong/target/product/test_device/system/usr/hyphen-data/bar"
+	android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+}
+
 func TestPrebuiltFontInstallDirPath(t *testing.T) {
 	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
 		prebuilt_font {
@@ -388,148 +401,3 @@
 		})
 	}
 }
-
-func checkIfSnapshotTaken(t *testing.T, result *android.TestResult, image string, moduleName string) {
-	checkIfSnapshotExistAsExpected(t, result, image, moduleName, true)
-}
-
-func checkIfSnapshotNotTaken(t *testing.T, result *android.TestResult, image string, moduleName string) {
-	checkIfSnapshotExistAsExpected(t, result, image, moduleName, false)
-}
-
-func checkIfSnapshotExistAsExpected(t *testing.T, result *android.TestResult, image string, moduleName string, expectToExist bool) {
-	snapshotSingleton := result.SingletonForTests(image + "-snapshot")
-	archType := "arm64"
-	archVariant := "armv8-a"
-	archDir := fmt.Sprintf("arch-%s", archType)
-
-	snapshotDir := fmt.Sprintf("%s-snapshot", image)
-	snapshotVariantPath := filepath.Join(snapshotDir, archType)
-	outputDir := filepath.Join(snapshotVariantPath, archDir, "etc")
-	imageVariant := ""
-	if image == "recovery" {
-		imageVariant = "recovery_"
-	}
-	mod := result.ModuleForTests(moduleName, fmt.Sprintf("android_%s%s_%s", imageVariant, archType, archVariant))
-	outputFiles := mod.OutputFiles(t, "")
-	if len(outputFiles) != 1 {
-		t.Errorf("%q must have single output\n", moduleName)
-		return
-	}
-	snapshotPath := filepath.Join(outputDir, moduleName)
-
-	if expectToExist {
-		out := snapshotSingleton.Output(snapshotPath)
-
-		if out.Input.String() != outputFiles[0].String() {
-			t.Errorf("The input of snapshot %q must be %q, but %q", "prebuilt_vendor", out.Input.String(), outputFiles[0])
-		}
-
-		snapshotJsonPath := snapshotPath + ".json"
-
-		if snapshotSingleton.MaybeOutput(snapshotJsonPath).Rule == nil {
-			t.Errorf("%q expected but not found", snapshotJsonPath)
-		}
-	} else {
-		out := snapshotSingleton.MaybeOutput(snapshotPath)
-		if out.Rule != nil {
-			t.Errorf("There must be no rule for module %q output file %q", moduleName, outputFiles[0])
-		}
-	}
-}
-
-func TestPrebuiltTakeSnapshot(t *testing.T) {
-	var testBp = `
-	prebuilt_etc {
-		name: "prebuilt_vendor",
-		src: "foo.conf",
-		vendor: true,
-	}
-
-	prebuilt_etc {
-		name: "prebuilt_vendor_indirect",
-		src: "foo.conf",
-		vendor: true,
-	}
-
-	prebuilt_etc {
-		name: "prebuilt_recovery",
-		src: "bar.conf",
-		recovery: true,
-	}
-
-	prebuilt_etc {
-		name: "prebuilt_recovery_indirect",
-		src: "bar.conf",
-		recovery: true,
-	}
-	`
-
-	t.Run("prebuilt: vendor and recovery snapshot", func(t *testing.T) {
-		result := prepareForPrebuiltEtcSnapshotTest.RunTestWithBp(t, testBp)
-
-		checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor")
-		checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor_indirect")
-		checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery")
-		checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery_indirect")
-	})
-
-	t.Run("prebuilt: directed snapshot", func(t *testing.T) {
-		prepareForPrebuiltEtcDirectedSnapshotTest := android.GroupFixturePreparers(
-			prepareForPrebuiltEtcSnapshotTest,
-			android.FixtureModifyConfig(func(config android.Config) {
-				config.TestProductVariables.DirectedVendorSnapshot = true
-				config.TestProductVariables.VendorSnapshotModules = make(map[string]bool)
-				config.TestProductVariables.VendorSnapshotModules["prebuilt_vendor"] = true
-				config.TestProductVariables.DirectedRecoverySnapshot = true
-				config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool)
-				config.TestProductVariables.RecoverySnapshotModules["prebuilt_recovery"] = true
-			}),
-		)
-
-		result := prepareForPrebuiltEtcDirectedSnapshotTest.RunTestWithBp(t, testBp)
-
-		checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor")
-		checkIfSnapshotNotTaken(t, result, "vendor", "prebuilt_vendor_indirect")
-		checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery")
-		checkIfSnapshotNotTaken(t, result, "recovery", "prebuilt_recovery_indirect")
-	})
-}
-
-func TestPrebuiltEtcAndroidMkEntriesWithBazel(t *testing.T) {
-	t.Parallel()
-	bp := `
-prebuilt_etc {
-	name: "myetc",
-	src: "prebuilt_etc.rc", // filename in src tree
-	filename: "init.rc", // target filename on device
-	sub_dir: "subdir", // relative subdir for installation
-	bazel_module: { label: "//foo/bar:myetc" },
-}
-`
-	res := android.GroupFixturePreparers(
-		prepareForPrebuiltEtcTest,
-		android.FixtureModifyConfig(func(cfg android.Config) {
-			cfg.BazelContext = android.MockBazelContext{
-				LabelToPrebuiltFileInfo: map[string]cquery.PrebuiltFileInfo{
-					"//foo/bar:myetc": cquery.PrebuiltFileInfo{
-						Src:         "foo/bar/prebuilt_etc.rc",
-						Dir:         "etc/subdir",
-						Filename:    "init.rc",
-						Installable: true,
-					},
-				},
-			}
-		}),
-	).RunTestWithBp(t, bp)
-	ctx := res.ModuleForTests("myetc", "android_arm64_armv8-a")
-	mod := ctx.Module()
-	entries := android.AndroidMkEntriesForTest(t, res.TestContext, mod)[0]
-	// verify androidmk entries
-	android.AssertStringDoesContain(t, "LOCAL_MODULE_PATH should contain", entries.EntryMap["LOCAL_MODULE_PATH"][0], "etc/subdir")
-	android.AssertStringEquals(t, "LOCAL_INSTALLED_MODULE_STEM is incorrect", "init.rc", entries.EntryMap["LOCAL_INSTALLED_MODULE_STEM"][0])
-	// verify installation rules
-	install := ctx.Description("install")
-	android.AssertStringEquals(t, "Source location of prebuilt_etc installation", "out/soong/.intermediates/myetc/android_arm64_armv8-a/init.rc", install.Input.String())
-	android.AssertStringEquals(t, "Target location of prebuilt_etc installation", "out/soong/target/product/test_device/system/etc/subdir/init.rc", install.Output.String())
-}
diff --git a/etc/snapshot_etc.go b/etc/snapshot_etc.go
deleted file mode 100644
index 0d65ab6..0000000
--- a/etc/snapshot_etc.go
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package etc
-
-// This file implements snapshot module of 'prebuilt_etc' type
-// 'snapshot_etc' module defines android.PrebuiltInterface so it can be handled
-// as prebuilt of 'prebuilt_etc' type.
-// Properties of 'snapshot_etc' follows properties from snapshotJsonFlags type
-
-import (
-	"android/soong/android"
-	"fmt"
-	"strings"
-
-	"github.com/google/blueprint"
-	"github.com/google/blueprint/proptools"
-)
-
-func RegisterSnapshotEtcModule(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("snapshot_etc", SnapshotEtcFactory)
-}
-
-func init() {
-	RegisterSnapshotEtcModule(android.InitRegistrationContext)
-}
-
-// snapshot_etc is a prebuilt module type to be installed under etc which is auto-generated by
-// development/vendor_snapshot/update.py. This module will override prebuilt_etc module with same
-// name when 'prefer' property is true.
-func SnapshotEtcFactory() android.Module {
-	module := &SnapshotEtc{}
-	module.AddProperties(&module.properties)
-
-	var srcsSupplier = func(_ android.BaseModuleContext, prebuilt android.Module) []string {
-		s, ok := prebuilt.(*SnapshotEtc)
-		if !ok || s.properties.Src == nil {
-			return []string{}
-		}
-
-		return []string{*s.properties.Src}
-	}
-
-	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
-	android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "src")
-	return module
-}
-
-type snapshotEtcProperties struct {
-	Src                   *string `android:"path,arch_variant"` // Source of snapshot_etc file
-	Filename              *string `android:"arch_variant"`      // Target file name when it differs from module name
-	Relative_install_path *string `android:"arch_variant"`      // Relative install path when it should be installed subdirectory of etc
-}
-
-type SnapshotEtc struct {
-	android.ModuleBase
-	prebuilt   android.Prebuilt
-	properties snapshotEtcProperties
-
-	outputFilePath android.OutputPath
-	installDirPath android.InstallPath
-}
-
-func (s *SnapshotEtc) Prebuilt() *android.Prebuilt {
-	return &s.prebuilt
-}
-
-func (s *SnapshotEtc) Name() string {
-	return s.prebuilt.Name(s.BaseModuleName())
-}
-
-func (s *SnapshotEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	if s.properties.Src == nil {
-		ctx.PropertyErrorf("src", "missing prebuilt source file")
-		return
-	}
-
-	sourceFilePath := s.prebuilt.SingleSourcePath(ctx)
-
-	// Determine the output file basename.
-	// If Filename is set, use the name specified by the property.
-	// Otherwise use the module name.
-	filename := proptools.String(s.properties.Filename)
-	if filename == "" {
-		filename = ctx.ModuleName()
-	}
-
-	s.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
-
-	if strings.Contains(filename, "/") {
-		ctx.PropertyErrorf("filename", "filename cannot contain separator '/'")
-		return
-	}
-
-	subDir := ""
-	if s.properties.Relative_install_path != nil {
-		subDir = *s.properties.Relative_install_path
-	}
-
-	s.installDirPath = android.PathForModuleInstall(ctx, "etc", subDir)
-
-	// This ensures that outputFilePath has the correct name for others to
-	// use, as the source file may have a different name.
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.Cp,
-		Input:       sourceFilePath,
-		Output:      s.outputFilePath,
-		Description: "Install snapshot etc module " + s.BaseModuleName(),
-	})
-
-	ctx.InstallFile(s.installDirPath, s.outputFilePath.Base(), sourceFilePath)
-}
-
-func (p *SnapshotEtc) AndroidMkEntries() []android.AndroidMkEntries {
-	return []android.AndroidMkEntries{{
-		Class:      "ETC",
-		OutputFile: android.OptionalPathForPath(p.outputFilePath),
-		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
-			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
-				entries.SetString("LOCAL_MODULE_TAGS", "optional")
-				entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.String())
-				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
-			},
-		},
-	}}
-}
-
-type snapshotEtcDependencyTag struct {
-	blueprint.DependencyTag
-}
-
-var tag = snapshotEtcDependencyTag{}
-
-func (s *SnapshotEtc) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
-	return !s.ModuleBase.InstallInRecovery() && !s.ModuleBase.InstallInRamdisk() &&
-		!s.ModuleBase.InstallInVendorRamdisk() && !s.ModuleBase.InstallInDebugRamdisk()
-}
-
-func (p *SnapshotEtc) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
-	return p.ModuleBase.InstallInRamdisk()
-}
-
-func (p *SnapshotEtc) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
-	return p.ModuleBase.InstallInVendorRamdisk()
-}
-
-func (p *SnapshotEtc) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
-	return p.ModuleBase.InstallInDebugRamdisk()
-}
-
-func (p *SnapshotEtc) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
-	return p.ModuleBase.InstallInRecovery()
-}
-
-func (p *SnapshotEtc) ExtraImageVariations(ctx android.BaseModuleContext) []string {
-	return nil
-}
-
-func (p *SnapshotEtc) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
-}
-
-func (p *SnapshotEtc) ImageMutatorBegin(ctx android.BaseModuleContext) {}
-
-func (p *SnapshotEtc) OutputFiles(tag string) (android.Paths, error) {
-	switch tag {
-	case "":
-		return android.Paths{p.outputFilePath}, nil
-	default:
-		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
-	}
-
-}
-
-var _ android.PrebuiltInterface = (*SnapshotEtc)(nil)
-var _ android.ImageInterface = (*SnapshotEtc)(nil)
-var _ android.OutputFileProducer = (*SnapshotEtc)(nil)
diff --git a/etc/snapshot_etc_test.go b/etc/snapshot_etc_test.go
deleted file mode 100644
index b9d5504..0000000
--- a/etc/snapshot_etc_test.go
+++ /dev/null
@@ -1,185 +0,0 @@
-// Copyright 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package etc
-
-import (
-	"android/soong/android"
-	"testing"
-
-	"github.com/google/blueprint"
-)
-
-var registerSourceModule = func(ctx android.RegistrationContext) {
-	ctx.RegisterModuleType("source", newSourceModule)
-}
-
-type sourceModuleProperties struct {
-	Deps []string `android:"path,arch_variant"`
-}
-
-type sourceModule struct {
-	android.ModuleBase
-	android.OverridableModuleBase
-
-	properties                                     sourceModuleProperties
-	dependsOnSourceModule, dependsOnPrebuiltModule bool
-	deps                                           android.Paths
-	src                                            android.Path
-}
-
-func newSourceModule() android.Module {
-	m := &sourceModule{}
-	m.AddProperties(&m.properties)
-	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibFirst)
-	android.InitOverridableModule(m, nil)
-	return m
-}
-
-func (s *sourceModule) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) {
-	// s.properties.Deps are annotated with android:path, so they are
-	// automatically added to the dependency by pathDeps mutator
-}
-
-func (s *sourceModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	s.deps = android.PathsForModuleSrc(ctx, s.properties.Deps)
-	s.src = android.PathForModuleSrc(ctx, "source_file")
-}
-
-func (s *sourceModule) Srcs() android.Paths {
-	return android.Paths{s.src}
-}
-
-var prepareForSnapshotEtcTest = android.GroupFixturePreparers(
-	android.PrepareForTestWithArchMutator,
-	android.PrepareForTestWithPrebuilts,
-	PrepareForTestWithPrebuiltEtc,
-	android.FixtureRegisterWithContext(RegisterSnapshotEtcModule),
-	android.FixtureRegisterWithContext(registerSourceModule),
-	android.FixtureMergeMockFs(android.MockFS{
-		"foo.conf": nil,
-		"bar.conf": nil,
-	}),
-)
-
-func TestSnapshotWithFilename(t *testing.T) {
-	var androidBp = `
-	snapshot_etc {
-		name: "etc_module",
-		src: "foo.conf",
-		filename: "bar.conf",
-	}
-	`
-
-	result := prepareForSnapshotEtcTest.RunTestWithBp(t, androidBp)
-	for _, variant := range result.ModuleVariantsForTests("etc_module") {
-		module := result.ModuleForTests("etc_module", variant)
-		s, ok := module.Module().(*SnapshotEtc)
-		if !ok {
-			t.Errorf("Expected snapshot_etc module type")
-		}
-		if s.outputFilePath.Base() != "bar.conf" {
-			t.Errorf("Output file path does not match with specified filename")
-		}
-	}
-}
-
-func TestSnapshotEtcWithOrigin(t *testing.T) {
-	var androidBp = `
-	prebuilt_etc {
-		name: "etc_module",
-		src: "foo.conf",
-	}
-
-	snapshot_etc {
-		name: "etc_module",
-		src: "bar.conf",
-	}
-
-	source {
-		name: "source",
-		deps: [":etc_module"],
-	}
-	`
-
-	result := prepareForSnapshotEtcTest.RunTestWithBp(t, androidBp)
-
-	for _, variant := range result.ModuleVariantsForTests("source") {
-		source := result.ModuleForTests("source", variant)
-
-		result.VisitDirectDeps(source.Module(), func(m blueprint.Module) {
-			if _, ok := m.(*PrebuiltEtc); !ok {
-				t.Errorf("Original prebuilt_etc module expected.")
-			}
-		})
-	}
-}
-
-func TestSnapshotEtcWithOriginAndPrefer(t *testing.T) {
-	var androidBp = `
-	prebuilt_etc {
-		name: "etc_module",
-		src: "foo.conf",
-	}
-
-	snapshot_etc {
-		name: "etc_module",
-		src: "bar.conf",
-		prefer: true,
-	}
-
-	source {
-		name: "source",
-		deps: [":etc_module"],
-	}
-	`
-
-	result := prepareForSnapshotEtcTest.RunTestWithBp(t, androidBp)
-
-	for _, variant := range result.ModuleVariantsForTests("source") {
-		source := result.ModuleForTests("source", variant)
-
-		result.VisitDirectDeps(source.Module(), func(m blueprint.Module) {
-			if _, ok := m.(*SnapshotEtc); !ok {
-				t.Errorf("Preferred snapshot_etc module expected.")
-			}
-		})
-	}
-}
-
-func TestSnapshotEtcWithoutOrigin(t *testing.T) {
-	var androidBp = `
-	snapshot_etc {
-		name: "etc_module",
-		src: "bar.conf",
-	}
-
-	source {
-		name: "source",
-		deps: [":etc_module"],
-	}
-	`
-
-	result := prepareForSnapshotEtcTest.RunTestWithBp(t, androidBp)
-
-	for _, variant := range result.ModuleVariantsForTests("source") {
-		source := result.ModuleForTests("source", variant)
-
-		result.VisitDirectDeps(source.Module(), func(m blueprint.Module) {
-			if _, ok := m.(*SnapshotEtc); !ok {
-				t.Errorf("Only source snapshot_etc module expected.")
-			}
-		})
-	}
-}
diff --git a/filesystem/Android.bp b/filesystem/Android.bp
index 07d57c9..854a366 100644
--- a/filesystem/Android.bp
+++ b/filesystem/Android.bp
@@ -9,13 +9,17 @@
         "blueprint",
         "soong",
         "soong-android",
+        "soong-bpf", // for testing
+        "soong-java", // for testing
         "soong-linkerconfig",
+        "soong-phony", // for testing
     ],
     srcs: [
         "avb_add_hash_footer.go",
         "avb_gen_vbmeta_image.go",
         "bootimg.go",
         "filesystem.go",
+        "fsverity_metadata.go",
         "logical_partition.go",
         "raw_binary.go",
         "system_image.go",
diff --git a/filesystem/avb_add_hash_footer.go b/filesystem/avb_add_hash_footer.go
index f3fecd0..469f1fb 100644
--- a/filesystem/avb_add_hash_footer.go
+++ b/filesystem/avb_add_hash_footer.go
@@ -25,6 +25,7 @@
 
 type avbAddHashFooter struct {
 	android.ModuleBase
+	android.DefaultableModuleBase
 
 	properties avbAddHashFooterProperties
 
@@ -68,6 +69,9 @@
 	// List of properties to add to the footer
 	Props []avbProp
 
+	// The index used to prevent rollback of the image on device.
+	Rollback_index *int64
+
 	// Include descriptors from images
 	Include_descriptors_from_images []string `android:"path,arch_variant"`
 }
@@ -77,6 +81,7 @@
 	module := &avbAddHashFooter{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	android.InitDefaultableModule(module)
 	return module
 }
 
@@ -128,6 +133,14 @@
 		addAvbProp(ctx, cmd, prop)
 	}
 
+	if a.properties.Rollback_index != nil {
+		rollbackIndex := proptools.Int(a.properties.Rollback_index)
+		if rollbackIndex < 0 {
+			ctx.PropertyErrorf("rollback_index", "Rollback index must be non-negative")
+		}
+		cmd.Flag(fmt.Sprintf(" --rollback_index %d", rollbackIndex))
+	}
+
 	cmd.FlagWithOutput("--image ", a.output)
 
 	builder.Build("avbAddHashFooter", fmt.Sprintf("avbAddHashFooter %s", ctx.ModuleName()))
@@ -195,3 +208,19 @@
 func (a *avbAddHashFooter) Srcs() android.Paths {
 	return append(android.Paths{}, a.output)
 }
+
+type avbAddHashFooterDefaults struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+}
+
+// avb_add_hash_footer_defaults provides a set of properties that can be inherited by other
+// avb_add_hash_footer modules. A module can use the properties from an avb_add_hash_footer_defaults
+// using `defaults: ["<:default_module_name>"]`. Properties of both modules are erged (when
+// possible) by prepending the default module's values to the depending module's values.
+func avbAddHashFooterDefaultsFactory() android.Module {
+	module := &avbAddHashFooterDefaults{}
+	module.AddProperties(&avbAddHashFooterProperties{})
+	android.InitDefaultsModule(module)
+	return module
+}
diff --git a/filesystem/avb_gen_vbmeta_image.go b/filesystem/avb_gen_vbmeta_image.go
index 0f331f9..985f0ea 100644
--- a/filesystem/avb_gen_vbmeta_image.go
+++ b/filesystem/avb_gen_vbmeta_image.go
@@ -24,6 +24,7 @@
 
 type avbGenVbmetaImage struct {
 	android.ModuleBase
+	android.DefaultableModuleBase
 
 	properties avbGenVbmetaImageProperties
 
@@ -47,6 +48,7 @@
 	module := &avbGenVbmetaImage{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	android.InitDefaultableModule(module)
 	return module
 }
 
@@ -106,3 +108,20 @@
 	}
 	return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 }
+
+type avbGenVbmetaImageDefaults struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+}
+
+// avb_gen_vbmeta_image_defaults provides a set of properties that can be inherited by other
+// avb_gen_vbmeta_image modules. A module can use the properties from an
+// avb_gen_vbmeta_image_defaults using `defaults: ["<:default_module_name>"]`. Properties of both
+// modules are erged (when possible) by prepending the default module's values to the depending
+// module's values.
+func avbGenVbmetaImageDefaultsFactory() android.Module {
+	module := &avbGenVbmetaImageDefaults{}
+	module.AddProperties(&avbGenVbmetaImageProperties{})
+	android.InitDefaultsModule(module)
+	return module
+}
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 023c69a..cadf9c24 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -19,6 +19,8 @@
 	"fmt"
 	"io"
 	"path/filepath"
+	"slices"
+	"strconv"
 	"strings"
 
 	"android/soong/android"
@@ -34,27 +36,31 @@
 
 func registerBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("android_filesystem", filesystemFactory)
+	ctx.RegisterModuleType("android_filesystem_defaults", filesystemDefaultsFactory)
 	ctx.RegisterModuleType("android_system_image", systemImageFactory)
 	ctx.RegisterModuleType("avb_add_hash_footer", avbAddHashFooterFactory)
+	ctx.RegisterModuleType("avb_add_hash_footer_defaults", avbAddHashFooterDefaultsFactory)
 	ctx.RegisterModuleType("avb_gen_vbmeta_image", avbGenVbmetaImageFactory)
+	ctx.RegisterModuleType("avb_gen_vbmeta_image_defaults", avbGenVbmetaImageDefaultsFactory)
 }
 
 type filesystem struct {
 	android.ModuleBase
 	android.PackagingBase
+	android.DefaultableModuleBase
 
 	properties filesystemProperties
 
 	// Function that builds extra files under the root directory and returns the files
 	buildExtraFiles func(ctx android.ModuleContext, root android.OutputPath) android.OutputPaths
 
-	// Function that filters PackagingSpecs returned by PackagingBase.GatherPackagingSpecs()
-	filterPackagingSpecs func(specs map[string]android.PackagingSpec)
+	// Function that filters PackagingSpec in PackagingBase.GatherPackagingSpecs()
+	filterPackagingSpec func(spec android.PackagingSpec) bool
 
 	output     android.OutputPath
 	installDir android.InstallPath
 
-	// For testing. Keeps the result of CopyDepsToZip()
+	// For testing. Keeps the result of CopySpecsToDir()
 	entries []string
 }
 
@@ -78,6 +84,9 @@
 	// avbtool. Default used by avbtool is sha1.
 	Avb_hash_algorithm *string
 
+	// The index used to prevent rollback of the image. Only used if use_avb is true.
+	Rollback_index *int64
+
 	// Name of the partition stored in vbmeta desc. Defaults to the name of this module.
 	Partition_name *string
 
@@ -85,6 +94,10 @@
 	// is ext4.
 	Type *string
 
+	// Identifies which partition this is for //visibility:any_system_image (and others) visibility
+	// checks, and will be used in the future for API surface checks.
+	Partition_type *string
+
 	// file_contexts file to make image. Currently, only ext4 is supported.
 	File_contexts *string `android:"path"`
 
@@ -104,6 +117,17 @@
 	// When set, passed to mkuserimg_mke2fs --mke2fs_uuid & --mke2fs_hash_seed.
 	// Otherwise, they'll be set as random which might cause indeterministic build output.
 	Uuid *string
+
+	// Mount point for this image. Default is "/"
+	Mount_point *string
+
+	// If set to the name of a partition ("system", "vendor", etc), this filesystem module
+	// will also include the contents of the make-built staging directories. If any soong
+	// modules would be installed to the same location as a make module, they will overwrite
+	// the make version.
+	Include_make_built_files string
+
+	Fsverity fsverityProperties
 }
 
 // android_filesystem packages a set of modules and their transitive dependencies into a filesystem
@@ -121,6 +145,7 @@
 	module.AddProperties(&module.properties)
 	android.InitPackageModule(module)
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
 }
 
 var dependencyTag = struct {
@@ -160,9 +185,14 @@
 	return f.BaseModuleName() + ".img"
 }
 
+func (f *filesystem) partitionName() string {
+	return proptools.StringDefault(f.properties.Partition_name, f.Name())
+}
+
 var pctx = android.NewPackageContext("android/soong/filesystem")
 
 func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	validatePartitionType(ctx, f)
 	switch f.fsType(ctx) {
 	case ext4Type:
 		f.output = f.buildImageUsingBuildImage(ctx)
@@ -178,13 +208,25 @@
 	ctx.InstallFile(f.installDir, f.installFileName(), f.output)
 }
 
-// root zip will contain extra files/dirs that are not from the `deps` property.
-func (f *filesystem) buildRootZip(ctx android.ModuleContext) android.OutputPath {
-	rootDir := android.PathForModuleGen(ctx, "root").OutputPath
-	builder := android.NewRuleBuilder(pctx, ctx)
-	builder.Command().Text("rm -rf").Text(rootDir.String())
-	builder.Command().Text("mkdir -p").Text(rootDir.String())
+func validatePartitionType(ctx android.ModuleContext, p partition) {
+	if !android.InList(p.PartitionType(), validPartitions) {
+		ctx.PropertyErrorf("partition_type", "partition_type must be one of %s, found: %s", validPartitions, p.PartitionType())
+	}
 
+	ctx.VisitDirectDepsWithTag(android.DefaultsDepTag, func(m android.Module) {
+		if fdm, ok := m.(*filesystemDefaults); ok {
+			if p.PartitionType() != fdm.PartitionType() {
+				ctx.PropertyErrorf("partition_type",
+					"%s doesn't match with the partition type %s of the filesystem default module %s",
+					p.PartitionType(), fdm.PartitionType(), m.Name())
+			}
+		}
+	})
+}
+
+// Copy extra files/dirs that are not from the `deps` property to `rootDir`, checking for conflicts with files
+// already in `rootDir`.
+func (f *filesystem) buildNonDepsFiles(ctx android.ModuleContext, builder *android.RuleBuilder, rootDir android.OutputPath) {
 	// create dirs and symlinks
 	for _, dir := range f.properties.Dirs {
 		// OutputPath.Join verifies dir
@@ -207,65 +249,45 @@
 
 		// OutputPath.Join verifies name. don't need to verify target.
 		dst := rootDir.Join(ctx, name)
-
+		builder.Command().Textf("(! [ -e %s -o -L %s ] || (echo \"%s already exists from an earlier stage of the build\" && exit 1))", dst, dst, dst)
 		builder.Command().Text("mkdir -p").Text(filepath.Dir(dst.String()))
 		builder.Command().Text("ln -sf").Text(proptools.ShellEscape(target)).Text(dst.String())
 	}
 
 	// create extra files if there's any
-	rootForExtraFiles := android.PathForModuleGen(ctx, "root-extra").OutputPath
-	var extraFiles android.OutputPaths
 	if f.buildExtraFiles != nil {
-		extraFiles = f.buildExtraFiles(ctx, rootForExtraFiles)
+		rootForExtraFiles := android.PathForModuleGen(ctx, "root-extra").OutputPath
+		extraFiles := f.buildExtraFiles(ctx, rootForExtraFiles)
 		for _, f := range extraFiles {
-			rel, _ := filepath.Rel(rootForExtraFiles.String(), f.String())
-			if strings.HasPrefix(rel, "..") {
-				panic(fmt.Errorf("%q is not under %q\n", f, rootForExtraFiles))
+			rel, err := filepath.Rel(rootForExtraFiles.String(), f.String())
+			if err != nil || strings.HasPrefix(rel, "..") {
+				ctx.ModuleErrorf("can't make %q relative to %q", f, rootForExtraFiles)
 			}
 		}
-	}
-
-	// Zip them all
-	zipOut := android.PathForModuleGen(ctx, "root.zip").OutputPath
-	zipCommand := builder.Command().BuiltTool("soong_zip")
-	zipCommand.FlagWithOutput("-o ", zipOut).
-		FlagWithArg("-C ", rootDir.String()).
-		Flag("-L 0"). // no compression because this will be unzipped soon
-		FlagWithArg("-D ", rootDir.String()).
-		Flag("-d") // include empty directories
-	if len(extraFiles) > 0 {
-		zipCommand.FlagWithArg("-C ", rootForExtraFiles.String())
-		for _, f := range extraFiles {
-			zipCommand.FlagWithInput("-f ", f)
+		if len(extraFiles) > 0 {
+			builder.Command().BuiltTool("merge_directories").
+				Implicits(extraFiles.Paths()).
+				Text(rootDir.String()).
+				Text(rootForExtraFiles.String())
 		}
 	}
-
-	builder.Command().Text("rm -rf").Text(rootDir.String())
-
-	builder.Build("zip_root", fmt.Sprintf("zipping root contents for %s", ctx.ModuleName()))
-	return zipOut
 }
 
 func (f *filesystem) buildImageUsingBuildImage(ctx android.ModuleContext) android.OutputPath {
-	depsZipFile := android.PathForModuleOut(ctx, "deps.zip").OutputPath
-	f.entries = f.CopyDepsToZip(ctx, f.gatherFilteredPackagingSpecs(ctx), depsZipFile)
-
-	builder := android.NewRuleBuilder(pctx, ctx)
-	depsBase := proptools.StringDefault(f.properties.Base_dir, ".")
-	rebasedDepsZip := android.PathForModuleOut(ctx, "rebased_deps.zip").OutputPath
-	builder.Command().
-		BuiltTool("zip2zip").
-		FlagWithInput("-i ", depsZipFile).
-		FlagWithOutput("-o ", rebasedDepsZip).
-		Text("**/*:" + proptools.ShellEscape(depsBase)) // zip2zip verifies depsBase
-
 	rootDir := android.PathForModuleOut(ctx, "root").OutputPath
-	rootZip := f.buildRootZip(ctx)
-	builder.Command().
-		BuiltTool("zipsync").
-		FlagWithArg("-d ", rootDir.String()). // zipsync wipes this. No need to clear.
-		Input(rootZip).
-		Input(rebasedDepsZip)
+	rebasedDir := rootDir
+	if f.properties.Base_dir != nil {
+		rebasedDir = rootDir.Join(ctx, *f.properties.Base_dir)
+	}
+	builder := android.NewRuleBuilder(pctx, ctx)
+	// Wipe the root dir to get rid of leftover files from prior builds
+	builder.Command().Textf("rm -rf %s && mkdir -p %s", rootDir, rootDir)
+	specs := f.gatherFilteredPackagingSpecs(ctx)
+	f.entries = f.CopySpecsToDir(ctx, builder, specs, rebasedDir)
+
+	f.buildNonDepsFiles(ctx, builder, rootDir)
+	f.addMakeBuiltFiles(ctx, builder, rootDir)
+	f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir)
 
 	// run host_init_verifier
 	// Ideally we should have a concept of pluggable linters that verify the generated image.
@@ -306,18 +328,16 @@
 }
 
 func (f *filesystem) buildPropFile(ctx android.ModuleContext) (propFile android.OutputPath, toolDeps android.Paths) {
-	type prop struct {
-		name  string
-		value string
-	}
-
-	var props []prop
 	var deps android.Paths
+	var propFileString strings.Builder
 	addStr := func(name string, value string) {
-		props = append(props, prop{name, value})
+		propFileString.WriteString(name)
+		propFileString.WriteRune('=')
+		propFileString.WriteString(value)
+		propFileString.WriteRune('\n')
 	}
 	addPath := func(name string, path android.Path) {
-		props = append(props, prop{name, path.String()})
+		addStr(name, path.String())
 		deps = append(deps, path)
 	}
 
@@ -332,7 +352,7 @@
 	}
 
 	addStr("fs_type", fsTypeStr(f.fsType(ctx)))
-	addStr("mount_point", "/")
+	addStr("mount_point", proptools.StringDefault(f.properties.Mount_point, "/"))
 	addStr("use_dynamic_partition_size", "true")
 	addPath("ext_mkuserimg", ctx.Config().HostToolPath(ctx, "mkuserimg_mke2fs"))
 	// b/177813163 deps of the host tools have to be added. Remove this.
@@ -347,13 +367,22 @@
 		addStr("avb_algorithm", algorithm)
 		key := android.PathForModuleSrc(ctx, proptools.String(f.properties.Avb_private_key))
 		addPath("avb_key_path", key)
+		addStr("partition_name", f.partitionName())
 		avb_add_hashtree_footer_args := "--do_not_generate_fec"
 		if hashAlgorithm := proptools.String(f.properties.Avb_hash_algorithm); hashAlgorithm != "" {
 			avb_add_hashtree_footer_args += " --hash_algorithm " + hashAlgorithm
 		}
+		if f.properties.Rollback_index != nil {
+			rollbackIndex := proptools.Int(f.properties.Rollback_index)
+			if rollbackIndex < 0 {
+				ctx.PropertyErrorf("rollback_index", "Rollback index must be non-negative")
+			}
+			avb_add_hashtree_footer_args += " --rollback_index " + strconv.Itoa(rollbackIndex)
+		}
+		securityPatchKey := "com.android.build." + f.partitionName() + ".security_patch"
+		securityPatchValue := ctx.Config().PlatformSecurityPatch()
+		avb_add_hashtree_footer_args += " --prop " + securityPatchKey + ":" + securityPatchValue
 		addStr("avb_add_hashtree_footer_args", avb_add_hashtree_footer_args)
-		partitionName := proptools.StringDefault(f.properties.Partition_name, f.Name())
-		addStr("partition_name", partitionName)
 		addStr("avb_salt", f.salt())
 	}
 
@@ -368,15 +397,7 @@
 		addStr("hash_seed", uuid)
 	}
 	propFile = android.PathForModuleOut(ctx, "prop").OutputPath
-	builder := android.NewRuleBuilder(pctx, ctx)
-	builder.Command().Text("rm").Flag("-rf").Output(propFile)
-	for _, p := range props {
-		builder.Command().
-			Text("echo").
-			Flag(`"` + p.name + "=" + p.value + `"`).
-			Text(">>").Output(propFile)
-	}
-	builder.Build("build_filesystem_prop", fmt.Sprintf("Creating filesystem props for %s", f.BaseModuleName()))
+	android.WriteFileRuleVerbatim(ctx, propFile, propFileString.String())
 	return propFile, deps
 }
 
@@ -390,25 +411,23 @@
 		ctx.PropertyErrorf("file_contexts", "file_contexts is not supported for compressed cpio image.")
 	}
 
-	depsZipFile := android.PathForModuleOut(ctx, "deps.zip").OutputPath
-	f.entries = f.CopyDepsToZip(ctx, f.gatherFilteredPackagingSpecs(ctx), depsZipFile)
-
-	builder := android.NewRuleBuilder(pctx, ctx)
-	depsBase := proptools.StringDefault(f.properties.Base_dir, ".")
-	rebasedDepsZip := android.PathForModuleOut(ctx, "rebased_deps.zip").OutputPath
-	builder.Command().
-		BuiltTool("zip2zip").
-		FlagWithInput("-i ", depsZipFile).
-		FlagWithOutput("-o ", rebasedDepsZip).
-		Text("**/*:" + proptools.ShellEscape(depsBase)) // zip2zip verifies depsBase
+	if f.properties.Include_make_built_files != "" {
+		ctx.PropertyErrorf("include_make_built_files", "include_make_built_files is not supported for compressed cpio image.")
+	}
 
 	rootDir := android.PathForModuleOut(ctx, "root").OutputPath
-	rootZip := f.buildRootZip(ctx)
-	builder.Command().
-		BuiltTool("zipsync").
-		FlagWithArg("-d ", rootDir.String()). // zipsync wipes this. No need to clear.
-		Input(rootZip).
-		Input(rebasedDepsZip)
+	rebasedDir := rootDir
+	if f.properties.Base_dir != nil {
+		rebasedDir = rootDir.Join(ctx, *f.properties.Base_dir)
+	}
+	builder := android.NewRuleBuilder(pctx, ctx)
+	// Wipe the root dir to get rid of leftover files from prior builds
+	builder.Command().Textf("rm -rf %s && mkdir -p %s", rootDir, rootDir)
+	specs := f.gatherFilteredPackagingSpecs(ctx)
+	f.entries = f.CopySpecsToDir(ctx, builder, specs, rebasedDir)
+
+	f.buildNonDepsFiles(ctx, builder, rootDir)
+	f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir)
 
 	output := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
 	cmd := builder.Command().
@@ -431,6 +450,51 @@
 	return output
 }
 
+var validPartitions = []string{
+	"system",
+	"userdata",
+	"cache",
+	"system_other",
+	"vendor",
+	"product",
+	"system_ext",
+	"odm",
+	"vendor_dlkm",
+	"odm_dlkm",
+	"system_dlkm",
+}
+
+func (f *filesystem) addMakeBuiltFiles(ctx android.ModuleContext, builder *android.RuleBuilder, rootDir android.Path) {
+	partition := f.properties.Include_make_built_files
+	if partition == "" {
+		return
+	}
+	if !slices.Contains(validPartitions, partition) {
+		ctx.PropertyErrorf("include_make_built_files", "Expected one of %#v, found %q", validPartitions, partition)
+		return
+	}
+	stampFile := fmt.Sprintf("target/product/%s/obj/PACKAGING/%s_intermediates/staging_dir.stamp", ctx.Config().DeviceName(), partition)
+	fileListFile := fmt.Sprintf("target/product/%s/obj/PACKAGING/%s_intermediates/file_list.txt", ctx.Config().DeviceName(), partition)
+	stagingDir := fmt.Sprintf("target/product/%s/%s", ctx.Config().DeviceName(), partition)
+
+	builder.Command().BuiltTool("merge_directories").
+		Implicit(android.PathForArbitraryOutput(ctx, stampFile)).
+		Text("--ignore-duplicates").
+		FlagWithInput("--file-list", android.PathForArbitraryOutput(ctx, fileListFile)).
+		Text(rootDir.String()).
+		Text(android.PathForArbitraryOutput(ctx, stagingDir).String())
+}
+
+type partition interface {
+	PartitionType() string
+}
+
+func (f *filesystem) PartitionType() string {
+	return proptools.StringDefault(f.properties.Partition_type, "system")
+}
+
+var _ partition = (*filesystem)(nil)
+
 var _ android.AndroidMkEntriesProvider = (*filesystem)(nil)
 
 // Implements android.AndroidMkEntriesProvider
@@ -485,10 +549,7 @@
 // Note that "apex" module installs its contents to "apex"(fake partition) as well
 // for symbol lookup by imitating "activated" paths.
 func (f *filesystem) gatherFilteredPackagingSpecs(ctx android.ModuleContext) map[string]android.PackagingSpec {
-	specs := f.PackagingBase.GatherPackagingSpecs(ctx)
-	if f.filterPackagingSpecs != nil {
-		f.filterPackagingSpecs(specs)
-	}
+	specs := f.PackagingBase.GatherPackagingSpecsWithFilter(ctx, f.filterPackagingSpec)
 	return specs
 }
 
@@ -504,6 +565,40 @@
 
 var _ cc.UseCoverage = (*filesystem)(nil)
 
-func (*filesystem) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
+func (*filesystem) IsNativeCoverageNeeded(ctx android.IncomingTransitionContext) bool {
 	return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
 }
+
+// android_filesystem_defaults
+
+type filesystemDefaults struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+
+	properties filesystemDefaultsProperties
+}
+
+type filesystemDefaultsProperties struct {
+	// Identifies which partition this is for //visibility:any_system_image (and others) visibility
+	// checks, and will be used in the future for API surface checks.
+	Partition_type *string
+}
+
+// android_filesystem_defaults is a default module for android_filesystem and android_system_image
+func filesystemDefaultsFactory() android.Module {
+	module := &filesystemDefaults{}
+	module.AddProperties(&module.properties)
+	module.AddProperties(&android.PackagingProperties{})
+	android.InitDefaultsModule(module)
+	return module
+}
+
+func (f *filesystemDefaults) PartitionType() string {
+	return proptools.StringDefault(f.properties.Partition_type, "system")
+}
+
+var _ partition = (*filesystemDefaults)(nil)
+
+func (f *filesystemDefaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	validatePartitionType(ctx, f)
+}
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index aef4756..1215048 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -16,11 +16,15 @@
 
 import (
 	"os"
+	"path/filepath"
 	"testing"
 
 	"android/soong/android"
+	"android/soong/bpf"
 	"android/soong/cc"
 	"android/soong/etc"
+	"android/soong/java"
+	"android/soong/phony"
 
 	"github.com/google/blueprint/proptools"
 )
@@ -31,8 +35,13 @@
 
 var fixture = android.GroupFixturePreparers(
 	android.PrepareForIntegrationTestWithAndroid,
-	etc.PrepareForTestWithPrebuiltEtc,
+	android.PrepareForTestWithAndroidBuildComponents,
+	bpf.PrepareForTestWithBpf,
 	cc.PrepareForIntegrationTestWithCc,
+	etc.PrepareForTestWithPrebuiltEtc,
+	java.PrepareForTestWithJavaBuildComponents,
+	java.PrepareForTestWithJavaDefaultModules,
+	phony.PrepareForTestWithPhony,
 	PrepareForTestWithFilesystemBuildComponents,
 )
 
@@ -40,11 +49,108 @@
 	result := fixture.RunTestWithBp(t, `
 		android_filesystem {
 			name: "myfilesystem",
+			multilib: {
+				common: {
+					deps: [
+						"bpf.o",
+						"phony",
+					],
+				},
+				lib32: {
+					deps: [
+						"foo",
+						"libbar",
+					],
+				},
+				lib64: {
+					deps: [
+						"libbar",
+					],
+				},
+			},
+			compile_multilib: "both",
+		}
+
+		bpf {
+			name: "bpf.o",
+			srcs: ["bpf.c"],
+		}
+
+		cc_binary {
+			name: "foo",
+			compile_multilib: "prefer32",
+		}
+
+		cc_library {
+			name: "libbar",
+			required: ["libbaz"],
+			target: {
+				platform: {
+					required: ["lib_platform_only"],
+				},
+			},
+		}
+
+		cc_library {
+			name: "libbaz",
+		}
+
+		cc_library {
+			name: "lib_platform_only",
+		}
+
+		phony {
+			name: "phony",
+			required: [
+				"libquz",
+				"myapp",
+			],
+		}
+
+		cc_library {
+			name: "libquz",
+		}
+
+		android_app {
+			name: "myapp",
+			platform_apis: true,
+			installable: true,
 		}
 	`)
 
 	// produces "myfilesystem.img"
 	result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img")
+
+	fs := result.ModuleForTests("myfilesystem", "android_common").Module().(*filesystem)
+	expected := []string{
+		"app/myapp/myapp.apk",
+		"bin/foo",
+		"lib/libbar.so",
+		"lib64/libbar.so",
+		"lib64/libbaz.so",
+		"lib64/libquz.so",
+		"lib64/lib_platform_only.so",
+		"etc/bpf/bpf.o",
+	}
+	for _, e := range expected {
+		android.AssertStringListContains(t, "missing entry", fs.entries, e)
+	}
+}
+
+func TestIncludeMakeBuiltFiles(t *testing.T) {
+	result := fixture.RunTestWithBp(t, `
+		android_filesystem {
+			name: "myfilesystem",
+			include_make_built_files: "system",
+		}
+	`)
+
+	output := result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img")
+
+	stampFile := filepath.Join(result.Config.OutDir(), "target/product/test_device/obj/PACKAGING/system_intermediates/staging_dir.stamp")
+	fileListFile := filepath.Join(result.Config.OutDir(), "target/product/test_device/obj/PACKAGING/system_intermediates/file_list.txt")
+	android.AssertStringListContains(t, "deps of filesystem must include the staging dir stamp file", output.Implicits.Strings(), stampFile)
+	android.AssertStringListContains(t, "deps of filesystem must include the staging dir file list", output.Implicits.Strings(), fileListFile)
 }
 
 func TestFileSystemFillsLinkerConfigWithStubLibs(t *testing.T) {
@@ -193,43 +299,6 @@
 		cmd, "--include_descriptors_from_image ")
 }
 
-func TestFileSystemShouldInstallCoreVariantIfTargetBuildAppsIsSet(t *testing.T) {
-	context := android.GroupFixturePreparers(
-		fixture,
-		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-			variables.Unbundled_build_apps = []string{"bar"}
-		}),
-	)
-	result := context.RunTestWithBp(t, `
-		android_system_image {
-			name: "myfilesystem",
-			deps: [
-				"libfoo",
-			],
-			linker_config_src: "linker.config.json",
-		}
-
-		cc_library {
-			name: "libfoo",
-			shared_libs: [
-				"libbar",
-			],
-			stl: "none",
-		}
-
-		cc_library {
-			name: "libbar",
-			sdk_version: "9",
-			stl: "none",
-		}
-	`)
-
-	inputs := result.ModuleForTests("myfilesystem", "android_common").Output("deps.zip").Implicits
-	android.AssertStringListContains(t, "filesystem should have libbar even for unbundled build",
-		inputs.Strings(),
-		"out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so")
-}
-
 func TestFileSystemWithCoverageVariants(t *testing.T) {
 	context := android.GroupFixturePreparers(
 		fixture,
@@ -268,7 +337,7 @@
 	`)
 
 	filesystem := result.ModuleForTests("myfilesystem", "android_common_cov")
-	inputs := filesystem.Output("deps.zip").Implicits
+	inputs := filesystem.Output("myfilesystem.img").Implicits
 	android.AssertStringListContains(t, "filesystem should have libfoo(cov)",
 		inputs.Strings(),
 		"out/soong/.intermediates/libfoo/android_arm64_armv8-a_shared_cov/libfoo.so")
@@ -282,3 +351,94 @@
 		t.Error("prebuilt should use cov variant of filesystem")
 	}
 }
+
+func TestSystemImageDefaults(t *testing.T) {
+	result := fixture.RunTestWithBp(t, `
+		android_filesystem_defaults {
+			name: "defaults",
+			multilib: {
+				common: {
+					deps: [
+						"phony",
+					],
+				},
+				lib64: {
+					deps: [
+						"libbar",
+					],
+				},
+			},
+			compile_multilib: "both",
+		}
+
+		android_system_image {
+			name: "system",
+			defaults: ["defaults"],
+			multilib: {
+				lib32: {
+					deps: [
+						"foo",
+						"libbar",
+					],
+				},
+			},
+		}
+
+		cc_binary {
+			name: "foo",
+			compile_multilib: "prefer32",
+		}
+
+		cc_library {
+			name: "libbar",
+			required: ["libbaz"],
+		}
+
+		cc_library {
+			name: "libbaz",
+		}
+
+		phony {
+			name: "phony",
+			required: ["libquz"],
+		}
+
+		cc_library {
+			name: "libquz",
+		}
+	`)
+
+	fs := result.ModuleForTests("system", "android_common").Module().(*systemImage)
+	expected := []string{
+		"bin/foo",
+		"lib/libbar.so",
+		"lib64/libbar.so",
+		"lib64/libbaz.so",
+		"lib64/libquz.so",
+	}
+	for _, e := range expected {
+		android.AssertStringListContains(t, "missing entry", fs.entries, e)
+	}
+}
+
+func TestInconsistentPartitionTypesInDefaults(t *testing.T) {
+	fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
+		"doesn't match with the partition type")).
+		RunTestWithBp(t, `
+		android_filesystem_defaults {
+			name: "system_ext_def",
+			partition_type: "system_ext",
+		}
+
+		android_filesystem_defaults {
+			name: "system_def",
+			partition_type: "system",
+			defaults: ["system_ext_def"],
+		}
+
+		android_system_image {
+			name: "system",
+			defaults: ["system_def"],
+		}
+	`)
+}
diff --git a/filesystem/fsverity_metadata.go b/filesystem/fsverity_metadata.go
new file mode 100644
index 0000000..3e50ff7
--- /dev/null
+++ b/filesystem/fsverity_metadata.go
@@ -0,0 +1,169 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package filesystem
+
+import (
+	"path/filepath"
+	"strings"
+
+	"android/soong/android"
+)
+
+type fsverityProperties struct {
+	// Patterns of files for fsverity metadata generation.  For each matched file, a .fsv_meta file
+	// will be generated and included to the filesystem image.
+	// etc/security/fsverity/BuildManifest.apk will also be generated which contains information
+	// about generated .fsv_meta files.
+	Inputs []string
+
+	// APK libraries to link against, for etc/security/fsverity/BuildManifest.apk
+	Libs []string `android:"path"`
+}
+
+func (f *filesystem) writeManifestGeneratorListFile(ctx android.ModuleContext, outputPath android.OutputPath, matchedSpecs []android.PackagingSpec, rebasedDir android.OutputPath) {
+	var buf strings.Builder
+	for _, spec := range matchedSpecs {
+		buf.WriteString(rebasedDir.Join(ctx, spec.RelPathInPackage()).String())
+		buf.WriteRune('\n')
+	}
+	android.WriteFileRuleVerbatim(ctx, outputPath, buf.String())
+}
+
+func (f *filesystem) buildFsverityMetadataFiles(ctx android.ModuleContext, builder *android.RuleBuilder, specs map[string]android.PackagingSpec, rootDir android.OutputPath, rebasedDir android.OutputPath) {
+	match := func(path string) bool {
+		for _, pattern := range f.properties.Fsverity.Inputs {
+			if matched, err := filepath.Match(pattern, path); matched {
+				return true
+			} else if err != nil {
+				ctx.PropertyErrorf("fsverity.inputs", "bad pattern %q", pattern)
+				return false
+			}
+		}
+		return false
+	}
+
+	var matchedSpecs []android.PackagingSpec
+	for _, relPath := range android.SortedKeys(specs) {
+		if match(relPath) {
+			matchedSpecs = append(matchedSpecs, specs[relPath])
+		}
+	}
+
+	if len(matchedSpecs) == 0 {
+		return
+	}
+
+	fsverityBuilderPath := android.PathForModuleOut(ctx, "fsverity_builder.sh")
+	metadataGeneratorPath := ctx.Config().HostToolPath(ctx, "fsverity_metadata_generator")
+	fsverityPath := ctx.Config().HostToolPath(ctx, "fsverity")
+
+	cmd := builder.Command().Tool(fsverityBuilderPath)
+
+	// STEP 1: generate .fsv_meta
+	var sb strings.Builder
+	sb.WriteString("set -e\n")
+	cmd.Implicit(metadataGeneratorPath).Implicit(fsverityPath)
+	for _, spec := range matchedSpecs {
+		// srcPath is copied by CopySpecsToDir()
+		srcPath := rebasedDir.Join(ctx, spec.RelPathInPackage())
+		destPath := rebasedDir.Join(ctx, spec.RelPathInPackage()+".fsv_meta")
+		sb.WriteString(metadataGeneratorPath.String())
+		sb.WriteString(" --fsverity-path ")
+		sb.WriteString(fsverityPath.String())
+		sb.WriteString(" --signature none --hash-alg sha256 --output ")
+		sb.WriteString(destPath.String())
+		sb.WriteRune(' ')
+		sb.WriteString(srcPath.String())
+		sb.WriteRune('\n')
+	}
+
+	// STEP 2: generate signed BuildManifest.apk
+	// STEP 2-1: generate build_manifest.pb
+	assetsPath := android.PathForModuleOut(ctx, "fsverity_manifest/assets")
+	manifestPbPath := assetsPath.Join(ctx, "build_manifest.pb")
+	manifestGeneratorPath := ctx.Config().HostToolPath(ctx, "fsverity_manifest_generator")
+	cmd.Implicit(manifestGeneratorPath)
+	sb.WriteString("rm -rf ")
+	sb.WriteString(assetsPath.String())
+	sb.WriteString(" && mkdir -p ")
+	sb.WriteString(assetsPath.String())
+	sb.WriteRune('\n')
+	sb.WriteString(manifestGeneratorPath.String())
+	sb.WriteString(" --fsverity-path ")
+	sb.WriteString(fsverityPath.String())
+	sb.WriteString(" --base-dir ")
+	sb.WriteString(rootDir.String())
+	sb.WriteString(" --output ")
+	sb.WriteString(manifestPbPath.String())
+	sb.WriteRune(' ')
+
+	manifestGeneratorListPath := android.PathForModuleOut(ctx, "fsverity_manifest.list")
+	f.writeManifestGeneratorListFile(ctx, manifestGeneratorListPath.OutputPath, matchedSpecs, rebasedDir)
+	sb.WriteRune('@')
+	sb.WriteString(manifestGeneratorListPath.String())
+	sb.WriteRune('\n')
+	cmd.Implicit(manifestGeneratorListPath)
+
+	// STEP 2-2: generate BuildManifest.apk (unsigned)
+	aapt2Path := ctx.Config().HostToolPath(ctx, "aapt2")
+	apkPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", "BuildManifest.apk")
+	manifestTemplatePath := android.PathForSource(ctx, "system/security/fsverity/AndroidManifest.xml")
+	libs := android.PathsForModuleSrc(ctx, f.properties.Fsverity.Libs)
+	cmd.Implicit(aapt2Path)
+	cmd.Implicit(manifestTemplatePath)
+	cmd.Implicits(libs)
+
+	sb.WriteString(aapt2Path.String())
+	sb.WriteString(" link -o ")
+	sb.WriteString(apkPath.String())
+	sb.WriteString(" -A ")
+	sb.WriteString(assetsPath.String())
+	for _, lib := range libs {
+		sb.WriteString(" -I ")
+		sb.WriteString(lib.String())
+	}
+	minSdkVersion := ctx.Config().PlatformSdkCodename()
+	if minSdkVersion == "REL" {
+		minSdkVersion = ctx.Config().PlatformSdkVersion().String()
+	}
+	sb.WriteString(" --min-sdk-version ")
+	sb.WriteString(minSdkVersion)
+	sb.WriteString(" --version-code ")
+	sb.WriteString(ctx.Config().PlatformSdkVersion().String())
+	sb.WriteString(" --version-name ")
+	sb.WriteString(ctx.Config().AppsDefaultVersionName())
+	sb.WriteString(" --manifest ")
+	sb.WriteString(manifestTemplatePath.String())
+	sb.WriteString(" --rename-manifest-package com.android.security.fsverity_metadata.")
+	sb.WriteString(f.partitionName())
+	sb.WriteRune('\n')
+
+	// STEP 2-3: sign BuildManifest.apk
+	apksignerPath := ctx.Config().HostToolPath(ctx, "apksigner")
+	pemPath, keyPath := ctx.Config().DefaultAppCertificate(ctx)
+	cmd.Implicit(apksignerPath)
+	cmd.Implicit(pemPath)
+	cmd.Implicit(keyPath)
+	sb.WriteString(apksignerPath.String())
+	sb.WriteString(" sign --in ")
+	sb.WriteString(apkPath.String())
+	sb.WriteString(" --cert ")
+	sb.WriteString(pemPath.String())
+	sb.WriteString(" --key ")
+	sb.WriteString(keyPath.String())
+	sb.WriteRune('\n')
+
+	android.WriteExecutableFileRuleVerbatim(ctx, fsverityBuilderPath, sb.String())
+}
diff --git a/filesystem/system_image.go b/filesystem/system_image.go
index 75abf70..5028a49 100644
--- a/filesystem/system_image.go
+++ b/filesystem/system_image.go
@@ -37,12 +37,15 @@
 	module := &systemImage{}
 	module.AddProperties(&module.properties)
 	module.filesystem.buildExtraFiles = module.buildExtraFiles
-	module.filesystem.filterPackagingSpecs = module.filterPackagingSpecs
+	module.filesystem.filterPackagingSpec = module.filterPackagingSpec
 	initFilesystemModule(&module.filesystem)
 	return module
 }
 
 func (s *systemImage) buildExtraFiles(ctx android.ModuleContext, root android.OutputPath) android.OutputPaths {
+	if s.filesystem.properties.Partition_type != nil {
+		ctx.PropertyErrorf("partition_type", "partition_type must be unset on an android_system_image module. It is assumed to be 'system'.")
+	}
 	lc := s.buildLinkerConfigFile(ctx, root)
 	// Add more files if needed
 	return []android.OutputPath{lc}
@@ -53,19 +56,40 @@
 	output := root.Join(ctx, "system", "etc", "linker.config.pb")
 
 	// we need "Module"s for packaging items
-	var otherModules []android.Module
+	modulesInPackageByModule := make(map[android.Module]bool)
+	modulesInPackageByName := make(map[string]bool)
+
 	deps := s.gatherFilteredPackagingSpecs(ctx)
 	ctx.WalkDeps(func(child, parent android.Module) bool {
 		for _, ps := range child.PackagingSpecs() {
 			if _, ok := deps[ps.RelPathInPackage()]; ok {
-				otherModules = append(otherModules, child)
+				modulesInPackageByModule[child] = true
+				modulesInPackageByName[child.Name()] = true
+				return true
 			}
 		}
 		return true
 	})
 
+	provideModules := make([]android.Module, 0, len(modulesInPackageByModule))
+	for mod := range modulesInPackageByModule {
+		provideModules = append(provideModules, mod)
+	}
+
+	var requireModules []android.Module
+	ctx.WalkDeps(func(child, parent android.Module) bool {
+		_, parentInPackage := modulesInPackageByModule[parent]
+		_, childInPackageName := modulesInPackageByName[child.Name()]
+
+		// When parent is in the package, and child (or its variant) is not, this can be from an interface.
+		if parentInPackage && !childInPackageName {
+			requireModules = append(requireModules, child)
+		}
+		return true
+	})
+
 	builder := android.NewRuleBuilder(pctx, ctx)
-	linkerconfig.BuildLinkerConfig(ctx, builder, input, otherModules, output)
+	linkerconfig.BuildLinkerConfig(ctx, builder, input, provideModules, requireModules, output)
 	builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
 	return output
 }
@@ -73,10 +97,6 @@
 // Filter the result of GatherPackagingSpecs to discard items targeting outside "system" partition.
 // Note that "apex" module installs its contents to "apex"(fake partition) as well
 // for symbol lookup by imitating "activated" paths.
-func (s *systemImage) filterPackagingSpecs(specs map[string]android.PackagingSpec) {
-	for k, ps := range specs {
-		if ps.Partition() != "system" {
-			delete(specs, k)
-		}
-	}
+func (s *systemImage) filterPackagingSpec(ps android.PackagingSpec) bool {
+	return ps.Partition() == "system"
 }
diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go
index 63e0aba..43a2f37 100644
--- a/filesystem/vbmeta.go
+++ b/filesystem/vbmeta.go
@@ -63,6 +63,17 @@
 
 	// List of chained partitions that this vbmeta deletages the verification.
 	Chained_partitions []chainedPartitionProperties
+
+	// List of key-value pair of avb properties
+	Avb_properties []avbProperty
+}
+
+type avbProperty struct {
+	// Key of given avb property
+	Key *string
+
+	// Value of given avb property
+	Value *string
 }
 
 type chainedPartitionProperties struct {
@@ -135,6 +146,20 @@
 	}
 	cmd.FlagWithArg("--rollback_index_location ", strconv.Itoa(ril))
 
+	for _, avb_prop := range v.properties.Avb_properties {
+		key := proptools.String(avb_prop.Key)
+		if key == "" {
+			ctx.PropertyErrorf("avb_properties", "key must be specified")
+			continue
+		}
+		value := proptools.String(avb_prop.Value)
+		if value == "" {
+			ctx.PropertyErrorf("avb_properties", "value must be specified")
+			continue
+		}
+		cmd.FlagWithArg("--prop ", key+":"+value)
+	}
+
 	for _, p := range ctx.GetDirectDepsWithTag(vbmetaPartitionDep) {
 		f, ok := p.(Filesystem)
 		if !ok {
diff --git a/finder/finder_test.go b/finder/finder_test.go
index 8f73719..be22d13 100644
--- a/finder/finder_test.go
+++ b/finder/finder_test.go
@@ -813,6 +813,7 @@
 			IncludeFiles: []string{"findme.txt"},
 		},
 	)
+	finder.WaitForDbDump()
 	filesystem.Clock.Tick()
 	foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
 	finder.Shutdown()
@@ -1445,6 +1446,7 @@
 			IncludeFiles: []string{"hi.txt"},
 		},
 	)
+	finder.WaitForDbDump()
 	filesystem.Clock.Tick()
 	foundPaths := finder.FindAll()
 	finder.Shutdown()
@@ -1506,6 +1508,7 @@
 			IncludeFiles: []string{"hi.txt"},
 		},
 	)
+	finder.WaitForDbDump()
 	filesystem.Clock.Tick()
 	foundPaths := finder.FindAll()
 	finder.Shutdown()
@@ -1552,6 +1555,7 @@
 			IncludeFiles: []string{"hi.txt"},
 		},
 	)
+	finder.WaitForDbDump()
 	filesystem.Clock.Tick()
 	foundPaths := finder.FindAll()
 	finder.Shutdown()
@@ -1573,6 +1577,7 @@
 			IncludeFiles: []string{"hi.txt"},
 		},
 	)
+	finder.WaitForDbDump()
 	filesystem.Clock.Tick()
 	foundPaths := finder.FindAll()
 	finder.Shutdown()
diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go
index 94b795f..47fd8f4 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -399,13 +399,11 @@
 }
 
 type FuzzPackagedModule struct {
-	FuzzProperties        FuzzProperties
-	Dictionary            android.Path
-	Corpus                android.Paths
-	CorpusIntermediateDir android.Path
-	Config                android.Path
-	Data                  android.Paths
-	DataIntermediateDir   android.Path
+	FuzzProperties FuzzProperties
+	Dictionary     android.Path
+	Corpus         android.Paths
+	Config         android.Path
+	Data           android.Paths
 }
 
 func GetFramework(ctx android.LoadHookContext, lang Lang) Framework {
@@ -527,12 +525,10 @@
 	builder.Build("create-"+fuzzZip.String(),
 		"Package "+module.Name()+" for "+archString+"-"+hostOrTargetString)
 
-	// Don't add modules to 'make haiku-rust' that are set to not be
-	// exported to the fuzzing infrastructure.
 	if config := fuzzModule.FuzzProperties.Fuzz_config; config != nil {
 		if strings.Contains(hostOrTargetString, "host") && !BoolDefault(config.Fuzz_on_haiku_host, true) {
 			return archDirs[archOs], false
-		} else if !BoolDefault(config.Fuzz_on_haiku_device, true) {
+		} else if !strings.Contains(hostOrTargetString, "host") && !BoolDefault(config.Fuzz_on_haiku_device, true) {
 			return archDirs[archOs], false
 		}
 	}
diff --git a/genrule/Android.bp b/genrule/Android.bp
index b201cae..7331741 100644
--- a/genrule/Android.bp
+++ b/genrule/Android.bp
@@ -11,7 +11,6 @@
         "sbox_proto",
         "soong",
         "soong-android",
-        "soong-bazel",
         "soong-shared",
     ],
     srcs: [
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index afa52cc..7c71b77 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -15,130 +15,10 @@
 package genrule
 
 var (
-	DepfileAllowList = []string{
-		"depfile_allowed_for_test",
-		"tflite_support_spm_config",
-		"tflite_support_spm_encoder_config",
-		"gen_uwb_core_proto",
-		"libtextclassifier_fbgen_utils_flatbuffers_flatbuffers_test",
-		"libtextclassifier_fbgen_utils_lua_utils_tests",
-		"libtextclassifier_fbgen_lang_id_common_flatbuffers_model",
-		"libtextclassifier_fbgen_lang_id_common_flatbuffers_embedding-network",
-		"libtextclassifier_fbgen_annotator_datetime_datetime",
-		"libtextclassifier_fbgen_annotator_model",
-		"libtextclassifier_fbgen_annotator_experimental_experimental",
-		"libtextclassifier_fbgen_annotator_entity-data",
-		"libtextclassifier_fbgen_annotator_person_name_person_name_model",
-		"libtextclassifier_fbgen_utils_tflite_text_encoder_config",
-		"libtextclassifier_fbgen_utils_codepoint-range",
-		"libtextclassifier_fbgen_utils_intents_intent-config",
-		"libtextclassifier_fbgen_utils_flatbuffers_flatbuffers",
-		"libtextclassifier_fbgen_utils_zlib_buffer",
-		"libtextclassifier_fbgen_utils_tokenizer",
-		"libtextclassifier_fbgen_utils_grammar_rules",
-		"libtextclassifier_fbgen_utils_grammar_semantics_expression",
-		"libtextclassifier_fbgen_utils_resources",
-		"libtextclassifier_fbgen_utils_i18n_language-tag",
-		"libtextclassifier_fbgen_utils_normalization",
-		"libtextclassifier_fbgen_utils_container_bit-vector",
-		"libtextclassifier_fbgen_actions_actions-entity-data",
-		"libtextclassifier_fbgen_actions_actions_model",
-		"libtextclassifier_fbgen_utils_grammar_testing_value",
-	}
-
 	SandboxingDenyModuleList = []string{
-		"RsBalls-rscript",
-		"pvmfw_fdt_template_rs",
-		"RSTest_v14-rscript",
-		"com.android.apex.test.bar_stripped",
-		"com.android.apex.test.sharedlibs_secondary_generated",
-		"ImageProcessingJB-rscript",
-		"RSTest-rscript",
-		"BluetoothGeneratedDumpsysBinarySchema_bfbs",
-		"TracingVMProtoStub_h",
-		"VehicleServerProtoStub_cc",
-		"AudioFocusControlProtoStub_cc",
-		"AudioFocusControlProtoStub_h",
-		"TracingVMProtoStub_cc",
-		"VehicleServerProtoStub_h",
-		"hidl2aidl_translate_cpp_test_gen_headers",
-		"hidl2aidl_translate_cpp_test_gen_src",
-		"hidl2aidl_translate_java_test_gen_src",
-		"hidl2aidl_translate_ndk_test_gen_headers",
-		"hidl2aidl_translate_ndk_test_gen_src",
-		"hidl_hash_test_gen",
-		"nos_app_avb_service_genc++",
-		"nos_app_avb_service_genc++_headers",
-		"nos_app_avb_service_genc++_mock",
-		"nos_app_identity_service_genc++",
-		"nos_app_keymaster_service_genc++",
-		"nos_generator_test_service_genc++_headers",
-		"nos_generator_test_service_genc++_mock",
-		"r8retrace-run-retrace",
-		"ltp_config_arm",
-		"ltp_config_arm_64_hwasan",
-		"ltp_config_arm_lowmem",
-		"ltp_config_arm_64",
-		"ltp_config_riscv_64",
-		"ltp_config_x86_64",
-		"vm-tests-tf-lib",
-		"hidl_cpp_impl_test_gen-headers",
-		"Refocus-rscript",
-		"RSTest_v11-rscript",
-		"RSTest_v16-rscript",
-		"ScriptGroupTest-rscript",
-		"ImageProcessing2-rscript",
-		"ImageProcessing-rscript",
-		"com.android.apex.test.pony_stripped",
-		"com.android.apex.test.baz_stripped",
-		"com.android.apex.test.foo_stripped",
-		"com.android.apex.test.sharedlibs_generated",
-		"BlueberryFacadeAndCertGeneratedStub_py",
-		"BlueberryFacadeGeneratedStub_cc",
-		"BlueberryFacadeGeneratedStub_h",
-		"BluetoothGeneratedDumpsysDataSchema_h",
-		"c2hal_test_genc++",
-		"c2hal_test_genc++_headers",
-		"hidl2aidl_test_gen_aidl",
-		"hidl_error_test_gen",
-		"hidl_export_test_gen-headers",
-		"hidl_format_test_diff",
-		"hidl_hash_version_gen",
-		"libbt_topshim_facade_py_proto",
-		"nos_app_identity_service_genc++_headers",
-		"nos_app_identity_service_genc++_mock",
-		"nos_app_keymaster_service_genc++_headers",
-		"nos_app_keymaster_service_genc++_mock",
-		"nos_app_weaver_service_genc++",
-		"nos_app_weaver_service_genc++_headers",
-		"nos_app_weaver_service_genc++_mock",
-		"nos_generator_test_service_genc++",
+		// go/keep-sorted start
 		"aidl_camera_build_version",
-		"cronet_aml_base_android_runtime_unchecked_jni_headers",
-		"cronet_aml_base_android_runtime_jni_headers",
-		"aidl-golden-test-build-hook-gen",
-		"PacketStreamerStub_h",
-		"FrontendStub_cc",
-		"FrontendStub_h",
-		"PacketStreamerStub_cc",
-		"pixelstatsatoms.h",
-		"pixelatoms_defs.h",
-		"pixelstatsatoms.cpp",
-		"hidl_java_impl_test_gen",
-		"cronet_aml_base_android_runtime_jni_headers__testing",
-		"cronet_aml_base_android_runtime_unchecked_jni_headers__testing",
-		"hidl_cpp_impl_test_gen-sources",
-		"fdt_test_tree_multiple_memory_ranges_dtb",
-		"fdt_test_tree_one_memory_range_dtb",
-		"fdt_test_tree_empty_memory_range_dtb",
-		"ltp_config_arm_64_lowmem",
-		"ltp_config_arm_64_lowmem_hwasan",
-		"ltp_config_x86",
-		"libbssl_sys_src_nostd",
-	}
-
-	SandboxingDenyPathList = []string{
-		"art/test",
-		"external/perfetto",
+		"com.google.pixel.camera.hal.manifest",
+		// go/keep-sorted end
 	}
 )
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 8a8d605..43f4fe5 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -21,18 +21,14 @@
 import (
 	"fmt"
 	"io"
-	"path/filepath"
 	"strconv"
 	"strings"
 
-	"android/soong/bazel/cquery"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 )
 
 func init() {
@@ -128,19 +124,15 @@
 	//  $(locations <label>): the paths to the tools, tool_files, inputs or outputs with name <label>. Use $(locations) if <label> refers to a rule that outputs two or more files.
 	//  $(in): one or more input files.
 	//  $(out): a single output file.
-	//  $(depfile): a file to which dependencies will be written, if the depfile property is set to true.
 	//  $(genDir): the sandbox directory for this tool; contains $(out).
 	//  $$: a literal $
 	Cmd *string
 
-	// Enable reading a file containing dependencies in gcc format after the command completes
-	Depfile *bool
-
 	// name of the modules (if any) that produces the host executable.   Leave empty for
 	// prebuilts or scripts that do not need a module to build them.
 	Tools []string
 
-	// Local file that is used as the tool
+	// Local files that are used by the tool
 	Tool_files []string `android:"path"`
 
 	// List of directories to export generated headers from
@@ -159,7 +151,6 @@
 type Module struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
-	android.BazelModuleBase
 	android.ApexModuleBase
 
 	// For other packages to make their own genrules with extra
@@ -190,21 +181,17 @@
 	subName string
 	subDir  string
 
-	// Collect the module directory for IDE info in java/jdeps.go.
-	modulePaths []string
+	// Aconfig files for all transitive deps.  Also exposed via TransitiveDeclarationsInfo
+	mergedAconfigFiles map[string]android.Paths
 }
 
-var _ android.MixedBuildBuildable = (*Module)(nil)
-
 type taskFunc func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) []generateTask
 
 type generateTask struct {
 	in          android.Paths
 	out         android.WritablePaths
-	depFile     android.WritablePath
 	copyTo      android.WritablePaths // For gensrcs to set on gensrcsMerge rule.
 	genDir      android.WritablePath
-	extraTools  android.Paths // dependencies on tools used by the generator
 	extraInputs map[string][]string
 
 	cmd string
@@ -257,30 +244,6 @@
 	}
 }
 
-func (g *Module) ProcessBazelQueryResponse(ctx android.ModuleContext) {
-	g.generateCommonBuildActions(ctx)
-
-	label := g.GetBazelLabel(ctx, g)
-	bazelCtx := ctx.Config().BazelContext
-	filePaths, err := bazelCtx.GetOutputFiles(label, android.GetConfigKey(ctx))
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-		return
-	}
-
-	var bazelOutputFiles android.Paths
-	exportIncludeDirs := map[string]bool{}
-	for _, bazelOutputFile := range filePaths {
-		bazelOutputFiles = append(bazelOutputFiles, android.PathForBazelOutRelative(ctx, ctx.ModuleDir(), bazelOutputFile))
-		exportIncludeDirs[filepath.Dir(bazelOutputFile)] = true
-	}
-	g.outputFiles = bazelOutputFiles
-	g.outputDeps = bazelOutputFiles
-	for includePath, _ := range exportIncludeDirs {
-		g.exportedIncludeDirs = append(g.exportedIncludeDirs, android.PathForBazelOut(ctx, includePath))
-	}
-}
-
 // generateCommonBuildActions contains build action generation logic
 // common to both the mixed build case and the legacy case of genrule processing.
 // To fully support genrule in mixed builds, the contents of this function should
@@ -289,9 +252,6 @@
 func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) {
 	g.subName = ctx.ModuleSubDir()
 
-	// Collect the module directory for IDE info in java/jdeps.go.
-	g.modulePaths = append(g.modulePaths, ctx.ModuleDir())
-
 	if len(g.properties.Export_include_dirs) > 0 {
 		for _, dir := range g.properties.Export_include_dirs {
 			g.exportedIncludeDirs = append(g.exportedIncludeDirs,
@@ -357,7 +317,17 @@
 						// required relative locations of the tool and its dependencies, use those
 						// instead.  They will be copied to those relative locations in the sbox
 						// sandbox.
-						packagedTools = append(packagedTools, specs...)
+						// Care must be taken since TransitivePackagingSpec may return device-side
+						// paths via the required property. Filter them out.
+						for i, ps := range specs {
+							if ps.Partition() != "" {
+								if i == 0 {
+									panic("first PackagingSpec is assumed to be the host-side tool")
+								}
+								continue
+							}
+							packagedTools = append(packagedTools, ps)
+						}
 						// Assume that the first PackagingSpec of the module is the tool.
 						addLocationLabel(tag.label, packagedToolLocation{specs[0]})
 					} else {
@@ -403,7 +373,6 @@
 	}
 
 	addLabelsForInputs := func(propName string, include, exclude []string) android.Paths {
-
 		includeDirInPaths := ctx.DeviceConfig().BuildBrokenInputDir(g.Name())
 		var srcFiles android.Paths
 		for _, in := range include {
@@ -431,6 +400,7 @@
 		return srcFiles
 	}
 	srcFiles := addLabelsForInputs("srcs", g.properties.Srcs, g.properties.Exclude_srcs)
+	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcFiles.Strings()})
 
 	var copyFrom android.Paths
 	var outputFiles android.WritablePaths
@@ -482,8 +452,6 @@
 			addLocationLabel(out.Rel(), outputLocation{out})
 		}
 
-		referencedDepfile := false
-
 		rawCommand, err := android.Expand(task.cmd, func(name string) (string, error) {
 			// report the error directly without returning an error to android.Expand to catch multiple errors in a
 			// single run
@@ -515,12 +483,6 @@
 					sandboxOuts = append(sandboxOuts, cmd.PathForOutput(out))
 				}
 				return strings.Join(proptools.ShellEscapeList(sandboxOuts), " "), nil
-			case "depfile":
-				referencedDepfile = true
-				if !Bool(g.properties.Depfile) {
-					return reportError("$(depfile) used without depfile property")
-				}
-				return "__SBOX_DEPFILE__", nil
 			case "genDir":
 				return proptools.ShellEscape(cmd.PathForOutput(task.genDir)), nil
 			default:
@@ -545,7 +507,7 @@
 						if len(paths) == 0 {
 							return reportError("label %q has no files", label)
 						}
-						return proptools.ShellEscape(strings.Join(paths, " ")), nil
+						return strings.Join(proptools.ShellEscapeList(paths), " "), nil
 					} else {
 						return reportError("unknown locations label %q is not in srcs, out, tools or tool_files.", label)
 					}
@@ -560,10 +522,6 @@
 			return
 		}
 
-		if Bool(g.properties.Depfile) && !referencedDepfile {
-			ctx.PropertyErrorf("cmd", "specified depfile=true but did not include a reference to '${depfile}' in cmd")
-			return
-		}
 		g.rawCommands = append(g.rawCommands, rawCommand)
 
 		cmd.Text(rawCommand)
@@ -572,11 +530,7 @@
 		cmd.ImplicitOutputs(task.out)
 		cmd.Implicits(task.in)
 		cmd.ImplicitTools(tools)
-		cmd.ImplicitTools(task.extraTools)
 		cmd.ImplicitPackagedTools(packagedTools)
-		if Bool(g.properties.Depfile) {
-			cmd.ImplicitDepFile(task.depFile)
-		}
 
 		// Create the rule to run the genrule command inside sbox.
 		rule.Build(name, desc)
@@ -617,21 +571,6 @@
 }
 
 func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	// Allowlist genrule to use depfile until we have a solution to remove it.
-	// TODO(b/235582219): Remove allowlist for genrule
-	if Bool(g.properties.Depfile) {
-		sandboxingAllowlistSets := getSandboxingAllowlistSets(ctx)
-		// TODO(b/283852474): Checking the GenruleSandboxing flag is temporary in
-		// order to pass the presubmit before internal master is updated.
-		if ctx.DeviceConfig().GenruleSandboxing() && !sandboxingAllowlistSets.depfileAllowSet[g.Name()] {
-			ctx.PropertyErrorf(
-				"depfile",
-				"Deprecated to ensure the module type is convertible to Bazel. "+
-					"Try specifying the dependencies explicitly so that there is no need to use depfile. "+
-					"If not possible, the escape hatch is to add the module to allowlists.go to bypass the error.")
-		}
-	}
-
 	g.generateCommonBuildActions(ctx)
 
 	// For <= 6 outputs, just embed those directly in the users. Right now, that covers >90% of
@@ -649,15 +588,24 @@
 		})
 		g.outputDeps = android.Paths{phonyFile}
 	}
+	android.CollectDependencyAconfigFiles(ctx, &g.mergedAconfigFiles)
 }
 
-func (g *Module) QueueBazelCall(ctx android.BaseModuleContext) {
-	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(g.GetBazelLabel(ctx, g), cquery.GetOutputFiles, android.GetConfigKey(ctx))
+func (g *Module) AndroidMkEntries() []android.AndroidMkEntries {
+	ret := android.AndroidMkEntries{
+		OutputFile: android.OptionalPathForPath(g.outputFiles[0]),
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+				android.SetAconfigFileMkEntries(g.AndroidModuleBase(), entries, g.mergedAconfigFiles)
+			},
+		},
+	}
+
+	return []android.AndroidMkEntries{ret}
 }
 
-func (g *Module) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
-	return true
+func (g *Module) AndroidModuleBase() *android.ModuleBase {
+	return &g.ModuleBase
 }
 
 // Collect information for opening IDE project files in java/jdeps.go.
@@ -669,7 +617,6 @@
 			dpInfo.Deps = append(dpInfo.Deps, src)
 		}
 	}
-	dpInfo.Paths = append(dpInfo.Paths, g.modulePaths...)
 }
 
 func (g *Module) AndroidMk() android.AndroidMkData {
@@ -749,7 +696,6 @@
 		for i, shard := range shards {
 			var commands []string
 			var outFiles android.WritablePaths
-			var commandDepFiles []string
 			var copyTo android.WritablePaths
 
 			// When sharding is enabled (i.e. len(shards) > 1), the sbox rules for each
@@ -789,12 +735,6 @@
 						return in.String(), nil
 					case "out":
 						return rule.Command().PathForOutput(outFile), nil
-					case "depfile":
-						// Generate a depfile for each output file.  Store the list for
-						// later in order to combine them all into a single depfile.
-						depFile := rule.Command().PathForOutput(outFile.ReplaceExtension(ctx, "d"))
-						commandDepFiles = append(commandDepFiles, depFile)
-						return depFile, nil
 					default:
 						return "$(" + name + ")", nil
 					}
@@ -809,30 +749,14 @@
 			}
 			fullCommand := strings.Join(commands, " && ")
 
-			var outputDepfile android.WritablePath
-			var extraTools android.Paths
-			if len(commandDepFiles) > 0 {
-				// Each command wrote to a depfile, but ninja can only handle one
-				// depfile per rule.  Use the dep_fixer tool at the end of the
-				// command to combine all the depfiles into a single output depfile.
-				outputDepfile = android.PathForModuleGen(ctx, genSubDir, "gensrcs.d")
-				depFixerTool := ctx.Config().HostToolPath(ctx, "dep_fixer")
-				fullCommand += fmt.Sprintf(" && %s -o $(depfile) %s",
-					rule.Command().PathForTool(depFixerTool),
-					strings.Join(commandDepFiles, " "))
-				extraTools = append(extraTools, depFixerTool)
-			}
-
 			generateTasks = append(generateTasks, generateTask{
-				in:         shard,
-				out:        outFiles,
-				depFile:    outputDepfile,
-				copyTo:     copyTo,
-				genDir:     genDir,
-				cmd:        fullCommand,
-				shard:      i,
-				shards:     len(shards),
-				extraTools: extraTools,
+				in:     shard,
+				out:    outFiles,
+				copyTo: copyTo,
+				genDir: genDir,
+				cmd:    fullCommand,
+				shard:  i,
+				shards: len(shards),
 				extraInputs: map[string][]string{
 					"data": properties.Data,
 				},
@@ -850,7 +774,6 @@
 func GenSrcsFactory() android.Module {
 	m := NewGenSrcs()
 	android.InitAndroidModule(m)
-	android.InitBazelModule(m)
 	return m
 }
 
@@ -865,14 +788,6 @@
 	Data []string `android:"path"`
 }
 
-type bazelGensrcsAttributes struct {
-	Srcs             bazel.LabelListAttribute
-	Output_extension *string
-	Tools            bazel.LabelListAttribute
-	Cmd              string
-	Data             bazel.LabelListAttribute
-}
-
 const defaultShardSize = 50
 
 func NewGenRule() *Module {
@@ -880,20 +795,14 @@
 
 	taskGenerator := func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) []generateTask {
 		outs := make(android.WritablePaths, len(properties.Out))
-		var depFile android.WritablePath
 		for i, out := range properties.Out {
-			outPath := android.PathForModuleGen(ctx, out)
-			if i == 0 {
-				depFile = outPath.ReplaceExtension(ctx, "d")
-			}
-			outs[i] = outPath
+			outs[i] = android.PathForModuleGen(ctx, out)
 		}
 		return []generateTask{{
-			in:      srcFiles,
-			out:     outs,
-			depFile: depFile,
-			genDir:  android.PathForModuleGen(ctx),
-			cmd:     rawCommand,
+			in:     srcFiles,
+			out:    outs,
+			genDir: android.PathForModuleGen(ctx),
+			cmd:    rawCommand,
 		}}
 	}
 
@@ -904,206 +813,12 @@
 	m := NewGenRule()
 	android.InitAndroidModule(m)
 	android.InitDefaultableModule(m)
-	android.InitBazelModule(m)
 	return m
 }
 
 type genRuleProperties struct {
 	// names of the output files that will be generated
-	Out []string
-}
-
-type bazelGenruleAttributes struct {
-	Srcs  bazel.LabelListAttribute
-	Outs  []string
-	Tools bazel.LabelListAttribute
-	Cmd   string
-}
-
-// ConvertWithBp2build converts a Soong module -> Bazel target.
-func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	// Bazel only has the "tools" attribute.
-	tools_prop := android.BazelLabelForModuleDeps(ctx, m.properties.Tools)
-	tool_files_prop := android.BazelLabelForModuleSrc(ctx, m.properties.Tool_files)
-	tools_prop.Append(tool_files_prop)
-
-	tools := bazel.MakeLabelListAttribute(tools_prop)
-	srcs := bazel.LabelListAttribute{}
-	srcs_labels := bazel.LabelList{}
-	// Only cc_genrule is arch specific
-	if ctx.ModuleType() == "cc_genrule" {
-		for axis, configToProps := range m.GetArchVariantProperties(ctx, &generatorProperties{}) {
-			for config, props := range configToProps {
-				if props, ok := props.(*generatorProperties); ok {
-					labels := android.BazelLabelForModuleSrcExcludes(ctx, props.Srcs, props.Exclude_srcs)
-					srcs_labels.Append(labels)
-					srcs.SetSelectValue(axis, config, labels)
-				}
-			}
-		}
-	} else {
-		srcs_labels = android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
-		srcs = bazel.MakeLabelListAttribute(srcs_labels)
-	}
-
-	var allReplacements bazel.LabelList
-	allReplacements.Append(tools.Value)
-	allReplacements.Append(bazel.FirstUniqueBazelLabelList(srcs_labels))
-
-	// The Output_extension prop is not in an immediately accessible field
-	// in the Module struct, so use GetProperties and cast it
-	// to the known struct prop.
-	var outputExtension *string
-	var data bazel.LabelListAttribute
-	if ctx.ModuleType() == "gensrcs" {
-		for _, propIntf := range m.GetProperties() {
-			if props, ok := propIntf.(*genSrcsProperties); ok {
-				outputExtension = props.Output_extension
-				dataFiles := android.BazelLabelForModuleSrc(ctx, props.Data)
-				allReplacements.Append(bazel.FirstUniqueBazelLabelList(dataFiles))
-				data = bazel.MakeLabelListAttribute(dataFiles)
-				break
-			}
-		}
-	}
-
-	// Replace in and out variables with $< and $@
-	var cmd string
-	if m.properties.Cmd != nil {
-		if ctx.ModuleType() == "gensrcs" {
-			cmd = strings.ReplaceAll(*m.properties.Cmd, "$(in)", "$(SRC)")
-			cmd = strings.ReplaceAll(cmd, "$(out)", "$(OUT)")
-		} else {
-			cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1)
-			cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1)
-		}
-		cmd = strings.Replace(cmd, "$(genDir)", "$(RULEDIR)", -1)
-		if len(tools.Value.Includes) > 0 {
-			cmd = strings.Replace(cmd, "$(location)", fmt.Sprintf("$(location %s)", tools.Value.Includes[0].Label), -1)
-			cmd = strings.Replace(cmd, "$(locations)", fmt.Sprintf("$(locations %s)", tools.Value.Includes[0].Label), -1)
-		}
-		for _, l := range allReplacements.Includes {
-			bpLoc := fmt.Sprintf("$(location %s)", l.OriginalModuleName)
-			bpLocs := fmt.Sprintf("$(locations %s)", l.OriginalModuleName)
-			bazelLoc := fmt.Sprintf("$(location %s)", l.Label)
-			bazelLocs := fmt.Sprintf("$(locations %s)", l.Label)
-			cmd = strings.Replace(cmd, bpLoc, bazelLoc, -1)
-			cmd = strings.Replace(cmd, bpLocs, bazelLocs, -1)
-		}
-	}
-
-	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
-
-	bazelName := m.Name()
-	if ctx.ModuleType() == "gensrcs" {
-		props := bazel.BazelTargetModuleProperties{
-			Rule_class:        "gensrcs",
-			Bzl_load_location: "//build/bazel/rules:gensrcs.bzl",
-		}
-		attrs := &bazelGensrcsAttributes{
-			Srcs:             srcs,
-			Output_extension: outputExtension,
-			Cmd:              cmd,
-			Tools:            tools,
-			Data:             data,
-		}
-		ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-			Name: m.Name(),
-			Tags: tags,
-		}, attrs)
-	} else {
-		outs := m.RawOutputFiles(ctx)
-		for _, out := range outs {
-			if out == bazelName {
-				// This is a workaround to circumvent a Bazel warning where a genrule's
-				// out may not have the same name as the target itself. This makes no
-				// difference for reverse dependencies, because they may depend on the
-				// out file by name.
-				bazelName = bazelName + "-gen"
-				break
-			}
-		}
-		attrs := &bazelGenruleAttributes{
-			Srcs:  srcs,
-			Outs:  outs,
-			Cmd:   cmd,
-			Tools: tools,
-		}
-		props := bazel.BazelTargetModuleProperties{
-			Rule_class: "genrule",
-		}
-		ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-			Name: bazelName,
-			Tags: tags,
-		}, attrs)
-	}
-
-	if m.needsCcLibraryHeadersBp2build() {
-		includeDirs := make([]string, len(m.properties.Export_include_dirs)*2)
-		for i, dir := range m.properties.Export_include_dirs {
-			includeDirs[i*2] = dir
-			includeDirs[i*2+1] = filepath.Clean(filepath.Join(ctx.ModuleDir(), dir))
-		}
-		attrs := &ccHeaderLibraryAttrs{
-			Hdrs:            []string{":" + bazelName},
-			Export_includes: includeDirs,
-		}
-		props := bazel.BazelTargetModuleProperties{
-			Rule_class:        "cc_library_headers",
-			Bzl_load_location: "//build/bazel/rules/cc:cc_library_headers.bzl",
-		}
-		ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-			Name: m.Name() + genruleHeaderLibrarySuffix,
-			Tags: tags,
-		}, attrs)
-
-	}
-}
-
-const genruleHeaderLibrarySuffix = "__header_library"
-
-func (m *Module) needsCcLibraryHeadersBp2build() bool {
-	return len(m.properties.Export_include_dirs) > 0
-}
-
-// GenruleCcHeaderMapper is a bazel.LabelMapper function to map genrules to a cc_library_headers
-// target when they export multiple include directories.
-func GenruleCcHeaderLabelMapper(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
-	mod, exists := ctx.ModuleFromName(label.OriginalModuleName)
-	if !exists {
-		return label.Label, false
-	}
-	if m, ok := mod.(*Module); ok {
-		if m.needsCcLibraryHeadersBp2build() {
-			return label.Label + genruleHeaderLibrarySuffix, true
-		}
-	}
-	return label.Label, false
-}
-
-type ccHeaderLibraryAttrs struct {
-	Hdrs []string
-
-	Export_includes []string
-}
-
-// RawOutputFfiles returns the raw outputs specified in Android.bp
-// This does not contain the fully resolved path relative to the top of the tree
-func (g *Module) RawOutputFiles(ctx android.BazelConversionContext) []string {
-	if ctx.Config().BuildMode != android.Bp2build {
-		ctx.ModuleErrorf("RawOutputFiles is only supported in bp2build mode")
-	}
-	// The Out prop is not in an immediately accessible field
-	// in the Module struct, so use GetProperties and cast it
-	// to the known struct prop.
-	var outs []string
-	for _, propIntf := range g.GetProperties() {
-		if props, ok := propIntf.(*genRuleProperties); ok {
-			outs = props.Out
-			break
-		}
-	}
-	return outs
+	Out []string `android:"arch_variant"`
 }
 
 var Bool = proptools.Bool
@@ -1137,23 +852,15 @@
 
 type sandboxingAllowlistSets struct {
 	sandboxingDenyModuleSet map[string]bool
-	sandboxingDenyPathSet   map[string]bool
-	depfileAllowSet         map[string]bool
 }
 
 func getSandboxingAllowlistSets(ctx android.PathContext) *sandboxingAllowlistSets {
 	return ctx.Config().Once(sandboxingAllowlistKey, func() interface{} {
 		sandboxingDenyModuleSet := map[string]bool{}
-		sandboxingDenyPathSet := map[string]bool{}
-		depfileAllowSet := map[string]bool{}
 
-		android.AddToStringSet(sandboxingDenyModuleSet, append(DepfileAllowList, SandboxingDenyModuleList...))
-		android.AddToStringSet(sandboxingDenyPathSet, SandboxingDenyPathList)
-		android.AddToStringSet(depfileAllowSet, DepfileAllowList)
+		android.AddToStringSet(sandboxingDenyModuleSet, SandboxingDenyModuleList)
 		return &sandboxingAllowlistSets{
 			sandboxingDenyModuleSet: sandboxingDenyModuleSet,
-			sandboxingDenyPathSet:   sandboxingDenyPathSet,
-			depfileAllowSet:         depfileAllowSet,
 		}
 	}).(*sandboxingAllowlistSets)
 }
@@ -1163,8 +870,7 @@
 		return r.SandboxTools()
 	}
 	sandboxingAllowlistSets := getSandboxingAllowlistSets(ctx)
-	if sandboxingAllowlistSets.sandboxingDenyPathSet[ctx.ModuleDir()] ||
-		sandboxingAllowlistSets.sandboxingDenyModuleSet[ctx.ModuleName()] {
+	if sandboxingAllowlistSets.sandboxingDenyModuleSet[ctx.ModuleName()] {
 		return r.SandboxTools()
 	}
 	return r.SandboxInputs()
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 7c14531..2dc6a79 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -287,16 +287,6 @@
 			expect: "echo foo > __SBOX_SANDBOX_DIR__/out/out2",
 		},
 		{
-			name:       "depfile",
-			moduleName: "depfile_allowed_for_test",
-			prop: `
-				out: ["out"],
-				depfile: true,
-				cmd: "echo foo > $(out) && touch $(depfile)",
-			`,
-			expect: "echo foo > __SBOX_SANDBOX_DIR__/out/out && touch __SBOX_DEPFILE__",
-		},
-		{
 			name: "gendir",
 			prop: `
 				out: ["out"],
@@ -392,24 +382,6 @@
 			err: `unknown variable '$(foo)'`,
 		},
 		{
-			name: "error depfile",
-			prop: `
-				out: ["out"],
-				cmd: "echo foo > $(out) && touch $(depfile)",
-			`,
-			err: "$(depfile) used without depfile property",
-		},
-		{
-			name:       "error no depfile",
-			moduleName: "depfile_allowed_for_test",
-			prop: `
-				out: ["out"],
-				depfile: true,
-				cmd: "echo foo > $(out)",
-			`,
-			err: "specified depfile=true but did not include a reference to '${depfile}' in cmd",
-		},
-		{
 			name: "error no out",
 			prop: `
 				cmd: "echo foo > $(out)",
@@ -543,7 +515,7 @@
 	for _, test := range testcases {
 		t.Run(test.name, func(t *testing.T) {
 			gen := result.ModuleForTests(test.name, "")
-			manifest := android.RuleBuilderSboxProtoForTests(t, gen.Output("genrule.sbox.textproto"))
+			manifest := android.RuleBuilderSboxProtoForTests(t, result.TestContext, gen.Output("genrule.sbox.textproto"))
 			hash := manifest.Commands[0].GetInputHash()
 
 			android.AssertStringEquals(t, "hash", test.expectedHash, hash)
@@ -695,60 +667,6 @@
 	}
 }
 
-func TestGenruleAllowlistingDepfile(t *testing.T) {
-	tests := []struct {
-		name       string
-		prop       string
-		err        string
-		moduleName string
-	}{
-		{
-			name: `error when module is not allowlisted`,
-			prop: `
-				depfile: true,
-				cmd: "cat $(in) > $(out) && cat $(depfile)",
-			`,
-			err: "depfile: Deprecated to ensure the module type is convertible to Bazel",
-		},
-		{
-			name: `no error when module is allowlisted`,
-			prop: `
-				depfile: true,
-				cmd: "cat $(in) > $(out) && cat $(depfile)",
-			`,
-			moduleName: `depfile_allowed_for_test`,
-		},
-	}
-	for _, test := range tests {
-		t.Run(test.name, func(t *testing.T) {
-			moduleName := "foo"
-			if test.moduleName != "" {
-				moduleName = test.moduleName
-			}
-			bp := fmt.Sprintf(`
-			gensrcs {
-			   name: "%s",
-			   srcs: ["data.txt"],
-			   %s
-			}`, moduleName, test.prop)
-
-			var expectedErrors []string
-			if test.err != "" {
-				expectedErrors = append(expectedErrors, test.err)
-			}
-			android.GroupFixturePreparers(
-				prepareForGenRuleTest,
-				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-					variables.GenruleSandboxing = proptools.BoolPtr(true)
-				}),
-			).
-				ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
-				RunTestWithBp(t, bp)
-		})
-
-	}
-}
-
 func TestGenruleDefaults(t *testing.T) {
 	bp := `
 				genrule_defaults {
@@ -1039,31 +957,6 @@
 	}
 }
 
-func TestGenruleWithBazel(t *testing.T) {
-	bp := `
-		genrule {
-				name: "foo",
-				out: ["one.txt", "two.txt"],
-				bazel_module: { label: "//foo/bar:bar" },
-		}
-	`
-
-	result := android.GroupFixturePreparers(
-		prepareForGenRuleTest, android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: "outputbase",
-				LabelToOutputFiles: map[string][]string{
-					"//foo/bar:bar": []string{"bazelone.txt", "bazeltwo.txt"}}}
-		})).RunTestWithBp(t, testGenruleBp()+bp)
-
-	gen := result.Module("foo", "").(*Module)
-
-	expectedOutputFiles := []string{"outputbase/execroot/__main__/bazelone.txt",
-		"outputbase/execroot/__main__/bazeltwo.txt"}
-	android.AssertDeepEquals(t, "output files", expectedOutputFiles, gen.outputFiles.Strings())
-	android.AssertDeepEquals(t, "output deps", expectedOutputFiles, gen.outputDeps.Strings())
-}
-
 func TestGenruleWithGlobPaths(t *testing.T) {
 	testcases := []struct {
 		name            string
diff --git a/go.mod b/go.mod
index 0a11bd2..1174958 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module android/soong
 
-go 1.20
+go 1.21
 
 require (
 	github.com/google/blueprint v0.0.0
diff --git a/go.work b/go.work
index 67f6549..7c6022b 100644
--- a/go.work
+++ b/go.work
@@ -1,4 +1,4 @@
-go 1.19
+go 1.21
 
 use (
 	.
diff --git a/jar/jar.go b/jar/jar.go
index f164ee1..54eded9 100644
--- a/jar/jar.go
+++ b/jar/jar.go
@@ -166,10 +166,23 @@
 	}
 	s.IsIdentRune = javaIdentRune
 
-	tok := s.Scan()
-	if sErr != nil {
-		return "", sErr
+	var tok rune
+	for {
+		tok = s.Scan()
+		if sErr != nil {
+			return "", sErr
+		}
+		// If the first token is an annotation, it could be annotating a package declaration, so consume them.
+		// Note that this does not support "complex" annotations with attributes, e.g. @Foo(x=y).
+		if tok != '@' {
+			break
+		}
+		tok = s.Scan()
+		if tok != scanner.Ident || sErr != nil {
+			return "", fmt.Errorf("expected annotation identifier, got @%v", tok)
+		}
 	}
+
 	if tok == scanner.Ident {
 		switch s.TokenText() {
 		case "package":
@@ -189,9 +202,6 @@
 		default:
 			return "", fmt.Errorf(`expected first token of java file to be "package", got %q`, s.TokenText())
 		}
-	} else if tok == '@' {
-		// File has no package statement, first token is an annotation
-		return "", nil
 	} else if tok == scanner.EOF {
 		// File no package statement, it has no non-whitespace non-comment tokens
 		return "", nil
diff --git a/jar/jar_test.go b/jar/jar_test.go
index c92011e..61da9bb 100644
--- a/jar/jar_test.go
+++ b/jar/jar_test.go
@@ -61,6 +61,16 @@
 			in:      "package 0foo.bar;",
 			wantErr: true,
 		},
+		{
+			name: "annotations",
+			in:   "@NonNullApi\n@X\npackage foo.bar;",
+			want: "foo.bar",
+		},
+		{
+			name:    "complex annotation",
+			in:      "@Foo(x=y)\n@package foo.bar;",
+			wantErr: true, // Complex annotation not supported yet.
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/java/Android.bp b/java/Android.bp
index 4450c42..54b36ab 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -9,12 +9,13 @@
         "blueprint",
         "blueprint-pathtools",
         "soong",
+        "soong-aconfig",
         "soong-android",
-        "soong-bazel",
         "soong-cc",
         "soong-dexpreopt",
         "soong-genrule",
         "soong-java-config",
+        "soong-testing",
         "soong-provenance",
         "soong-python",
         "soong-remoteexec",
@@ -66,7 +67,7 @@
         "plugin.go",
         "prebuilt_apis.go",
         "proto.go",
-        "resourceshrinker.go",
+        "ravenwood.go",
         "robolectric.go",
         "rro.go",
         "sdk.go",
@@ -85,6 +86,7 @@
         "app_import_test.go",
         "app_set_test.go",
         "app_test.go",
+        "code_metadata_test.go",
         "bootclasspath_fragment_test.go",
         "device_host_converter_test.go",
         "dex_test.go",
@@ -106,12 +108,14 @@
         "plugin_test.go",
         "prebuilt_apis_test.go",
         "proto_test.go",
-        "resourceshrinker_test.go",
+        "ravenwood_test.go",
         "rro_test.go",
-        "sdk_test.go",
         "sdk_library_test.go",
+        "sdk_test.go",
+        "sdk_version_test.go",
         "system_modules_test.go",
         "systemserver_classpath_fragment_test.go",
+        "test_spec_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/java/aapt2.go b/java/aapt2.go
index 3bb70b5..f704fc6 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -25,17 +25,23 @@
 	"android/soong/android"
 )
 
+func isPathValueResource(res android.Path) bool {
+	subDir := filepath.Dir(res.String())
+	subDir, lastDir := filepath.Split(subDir)
+	return strings.HasPrefix(lastDir, "values")
+}
+
 // Convert input resource file path to output file path.
 // values-[config]/<file>.xml -> values-[config]_<file>.arsc.flat;
 // For other resource file, just replace the last "/" with "_" and add .flat extension.
 func pathToAapt2Path(ctx android.ModuleContext, res android.Path) android.WritablePath {
 
 	name := res.Base()
-	subDir := filepath.Dir(res.String())
-	subDir, lastDir := filepath.Split(subDir)
-	if strings.HasPrefix(lastDir, "values") {
+	if isPathValueResource(res) {
 		name = strings.TrimSuffix(name, ".xml") + ".arsc"
 	}
+	subDir := filepath.Dir(res.String())
+	subDir, lastDir := filepath.Split(subDir)
 	name = lastDir + "_" + name + ".flat"
 	return android.PathForModuleOut(ctx, "aapt2", subDir, name)
 }
@@ -63,7 +69,21 @@
 
 // aapt2Compile compiles resources and puts the results in the requested directory.
 func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths,
-	flags []string) android.WritablePaths {
+	flags []string, productToFilter string) android.WritablePaths {
+	if productToFilter != "" && productToFilter != "default" {
+		// --filter-product leaves only product-specific resources. Product-specific resources only exist
+		// in value resources (values/*.xml), so filter value resource files only. Ignore other types of
+		// resources as they don't need to be in product characteristics RRO (and they will cause aapt2
+		// compile errors)
+		filteredPaths := android.Paths{}
+		for _, path := range paths {
+			if isPathValueResource(path) {
+				filteredPaths = append(filteredPaths, path)
+			}
+		}
+		paths = filteredPaths
+		flags = append([]string{"--filter-product " + productToFilter}, flags...)
+	}
 
 	// Shard the input paths so that they can be processed in parallel. If we shard them into too
 	// small chunks, the additional cost of spinning up aapt2 outweighs the performance gain. The
@@ -182,7 +202,8 @@
 func aapt2Link(ctx android.ModuleContext,
 	packageRes, genJar, proguardOptions, rTxt android.WritablePath,
 	flags []string, deps android.Paths,
-	compiledRes, compiledOverlay, assetPackages android.Paths, splitPackages android.WritablePaths) {
+	compiledRes, compiledOverlay, assetPackages android.Paths, splitPackages android.WritablePaths,
+	featureFlagsPaths android.Paths) {
 
 	var inFlags []string
 
@@ -235,6 +256,11 @@
 		})
 	}
 
+	for _, featureFlagsPath := range featureFlagsPaths {
+		deps = append(deps, featureFlagsPath)
+		inFlags = append(inFlags, "--feature-flags", "@"+featureFlagsPath.String())
+	}
+
 	// Note the absence of splitPackages. The caller is supposed to compose and provide --split flag
 	// values via the flags parameter when it wants to split outputs.
 	// TODO(b/174509108): Perhaps we can process it in this func while keeping the code reasonably
@@ -283,7 +309,8 @@
 
 var aapt2ConvertRule = pctx.AndroidStaticRule("aapt2Convert",
 	blueprint.RuleParams{
-		Command:     `${config.Aapt2Cmd} convert --output-format $format $in -o $out`,
+		Command: `${config.Aapt2Cmd} convert --enable-compact-entries ` +
+			`--output-format $format $in -o $out`,
 		CommandDeps: []string{"${config.Aapt2Cmd}"},
 	}, "format",
 )
diff --git a/java/aar.go b/java/aar.go
index 1e38efc..47c64bf 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -17,11 +17,11 @@
 import (
 	"fmt"
 	"path/filepath"
+	"slices"
 	"strconv"
 	"strings"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/dexpreopt"
 
 	"github.com/google/blueprint"
@@ -29,7 +29,6 @@
 )
 
 type AndroidLibraryDependency interface {
-	LibraryDependency
 	ExportPackage() android.Path
 	ResourcesNodeDepSet() *android.DepSet[*resourcesNode]
 	RRODirsDepSet() *android.DepSet[rroDir]
@@ -46,7 +45,7 @@
 	ctx.RegisterModuleType("android_library_import", AARImportFactory)
 	ctx.RegisterModuleType("android_library", AndroidLibraryFactory)
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.TopDown("propagate_rro_enforcement", propagateRROEnforcementMutator).Parallel()
+		ctx.TopDown("propagate_rro_enforcement", propagateRROEnforcementMutator)
 	})
 }
 
@@ -66,6 +65,9 @@
 	// ones.
 	Aapt_include_all_resources *bool
 
+	// list of files to use as assets.
+	Assets []string `android:"path"`
+
 	// list of directories relative to the Blueprints file containing assets.
 	// Defaults to ["assets"] if a directory called assets exists.  Set to []
 	// to disable the default.
@@ -99,29 +101,35 @@
 
 	// true if RRO is enforced for any of the dependent modules
 	RROEnforcedForDependent bool `blueprint:"mutated"`
+
+	// Filter only specified product and ignore other products
+	Filter_product *string `blueprint:"mutated"`
+
+	// Names of aconfig_declarations modules that specify aconfig flags that the module depends on.
+	Flags_packages []string
 }
 
 type aapt struct {
-	aaptSrcJar                     android.Path
-	transitiveAaptRJars            android.Paths
-	transitiveAaptResourcePackages android.Paths
-	exportPackage                  android.Path
-	manifestPath                   android.Path
-	proguardOptionsFile            android.Path
-	rTxt                           android.Path
-	rJar                           android.Path
-	extraAaptPackagesFile          android.Path
-	mergedManifestFile             android.Path
-	noticeFile                     android.OptionalPath
-	assetPackage                   android.OptionalPath
-	isLibrary                      bool
-	defaultManifestVersion         string
-	useEmbeddedNativeLibs          bool
-	useEmbeddedDex                 bool
-	usesNonSdkApis                 bool
-	hasNoCode                      bool
-	LoggingParent                  string
-	resourceFiles                  android.Paths
+	aaptSrcJar                         android.Path
+	transitiveAaptRJars                android.Paths
+	transitiveAaptResourcePackagesFile android.Path
+	exportPackage                      android.Path
+	manifestPath                       android.Path
+	proguardOptionsFile                android.Path
+	rTxt                               android.Path
+	rJar                               android.Path
+	extraAaptPackagesFile              android.Path
+	mergedManifestFile                 android.Path
+	noticeFile                         android.OptionalPath
+	assetPackage                       android.OptionalPath
+	isLibrary                          bool
+	defaultManifestVersion             string
+	useEmbeddedNativeLibs              bool
+	useEmbeddedDex                     bool
+	usesNonSdkApis                     bool
+	hasNoCode                          bool
+	LoggingParent                      string
+	resourceFiles                      android.Paths
 
 	splitNames []string
 	splits     []split
@@ -131,6 +139,10 @@
 	resourcesNodesDepSet *android.DepSet[*resourcesNode]
 	rroDirsDepSet        *android.DepSet[rroDir]
 	manifestsDepSet      *android.DepSet[android.Path]
+
+	manifestValues struct {
+		applicationId string
+	}
 }
 
 type split struct {
@@ -151,8 +163,14 @@
 	}
 }
 
-func (a *aapt) useResourceProcessorBusyBox() bool {
-	return BoolDefault(a.aaptProperties.Use_resource_processor, false)
+func (a *aapt) useResourceProcessorBusyBox(ctx android.BaseModuleContext) bool {
+	return BoolDefault(a.aaptProperties.Use_resource_processor, ctx.Config().UseResourceProcessorByDefault()) &&
+		// TODO(b/331641946): remove this when ResourceProcessorBusyBox supports generating shared libraries.
+		!slices.Contains(a.aaptProperties.Aaptflags, "--shared-lib")
+}
+
+func (a *aapt) filterProduct() string {
+	return String(a.aaptProperties.Filter_product)
 }
 
 func (a *aapt) ExportPackage() android.Path {
@@ -191,7 +209,14 @@
 	// Flags specified in Android.bp
 	linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)
 
+	linkFlags = append(linkFlags, "--enable-compact-entries")
+
 	// Find implicit or explicit asset and resource dirs
+	assets := android.PathsRelativeToModuleSourceDir(android.SourceInput{
+		Context:     ctx,
+		Paths:       a.aaptProperties.Assets,
+		IncludeDirs: false,
+	})
 	assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets")
 	resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res")
 	resourceZips := android.PathsForModuleSrc(ctx, a.aaptProperties.Resource_zips)
@@ -226,6 +251,28 @@
 		assetDirStrings = append(assetDirStrings, filepath.Dir(a.noticeFile.Path().String()))
 		assetDeps = append(assetDeps, a.noticeFile.Path())
 	}
+	if len(assets) > 0 {
+		// aapt2 doesn't support adding individual asset files. Create a temp directory to hold asset
+		// files and pass it to aapt2.
+		tmpAssetDir := android.PathForModuleOut(ctx, "tmp_asset_dir")
+
+		rule := android.NewRuleBuilder(pctx, ctx)
+		rule.Command().
+			Text("rm -rf").Text(tmpAssetDir.String()).
+			Text("&&").
+			Text("mkdir -p").Text(tmpAssetDir.String())
+
+		for _, asset := range assets {
+			output := tmpAssetDir.Join(ctx, asset.Rel())
+			assetDeps = append(assetDeps, output)
+			rule.Command().Text("mkdir -p").Text(filepath.Dir(output.String()))
+			rule.Command().Text("cp").Input(asset).Output(output)
+		}
+
+		rule.Build("tmp_asset_dir", "tmp_asset_dir")
+
+		assetDirStrings = append(assetDirStrings, tmpAssetDir.String())
+	}
 
 	linkFlags = append(linkFlags, "--manifest "+manifestPath.String())
 	linkDeps = append(linkDeps, manifestPath)
@@ -301,23 +348,32 @@
 		CommandDeps: []string{"${config.Zip2ZipCmd}"},
 	})
 
-func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkContext,
-	classLoaderContexts dexpreopt.ClassLoaderContextMap, excludedLibs []string,
-	enforceDefaultTargetSdkVersion bool, extraLinkFlags ...string) {
+type aaptBuildActionOptions struct {
+	sdkContext                     android.SdkContext
+	classLoaderContexts            dexpreopt.ClassLoaderContextMap
+	excludedLibs                   []string
+	enforceDefaultTargetSdkVersion bool
+	forceNonFinalResourceIDs       bool
+	extraLinkFlags                 []string
+	aconfigTextFiles               android.Paths
+	usesLibrary                    *usesLibrary
+}
 
-	staticResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedDeps, libFlags :=
-		aaptLibs(ctx, sdkContext, classLoaderContexts)
+func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptions) {
+
+	staticResourcesNodesDepSet, sharedResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedExportPackages, libFlags :=
+		aaptLibs(ctx, opts.sdkContext, opts.classLoaderContexts, opts.usesLibrary)
 
 	// Exclude any libraries from the supplied list.
-	classLoaderContexts = classLoaderContexts.ExcludeLibs(excludedLibs)
+	opts.classLoaderContexts = opts.classLoaderContexts.ExcludeLibs(opts.excludedLibs)
 
 	// App manifest file
 	manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
 	manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
 
 	manifestPath := ManifestFixer(ctx, manifestSrcPath, ManifestFixerParams{
-		SdkContext:                     sdkContext,
-		ClassLoaderContexts:            classLoaderContexts,
+		SdkContext:                     opts.sdkContext,
+		ClassLoaderContexts:            opts.classLoaderContexts,
 		IsLibrary:                      a.isLibrary,
 		DefaultManifestVersion:         a.defaultManifestVersion,
 		UseEmbeddedNativeLibs:          a.useEmbeddedNativeLibs,
@@ -325,23 +381,24 @@
 		UseEmbeddedDex:                 a.useEmbeddedDex,
 		HasNoCode:                      a.hasNoCode,
 		LoggingParent:                  a.LoggingParent,
-		EnforceDefaultTargetSdkVersion: enforceDefaultTargetSdkVersion,
+		EnforceDefaultTargetSdkVersion: opts.enforceDefaultTargetSdkVersion,
 	})
 
 	staticDeps := transitiveAarDeps(staticResourcesNodesDepSet.ToList())
+	sharedDeps := transitiveAarDeps(sharedResourcesNodesDepSet.ToList())
 
 	// Add additional manifest files to transitive manifests.
 	additionalManifests := android.PathsForModuleSrc(ctx, a.aaptProperties.Additional_manifests)
 	transitiveManifestPaths := append(android.Paths{manifestPath}, additionalManifests...)
-	// TODO(b/288358614): Soong has historically not merged manifests from dependencies of android_library_import
-	// modules.  Merging manifests from dependencies could remove the need for pom2bp to generate the "-nodeps" copies
-	// of androidx libraries, but doing so triggers errors due to errors introduced by existing dependencies of
-	// android_library_import modules.  If this is fixed, staticManifestsDepSet can be dropped completely in favor of
-	// staticResourcesNodesDepSet.manifests()
 	transitiveManifestPaths = append(transitiveManifestPaths, staticManifestsDepSet.ToList()...)
 
 	if len(transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) {
-		a.mergedManifestFile = manifestMerger(ctx, transitiveManifestPaths[0], transitiveManifestPaths[1:], a.isLibrary)
+		manifestMergerParams := ManifestMergerParams{
+			staticLibManifests: transitiveManifestPaths[1:],
+			isLibrary:          a.isLibrary,
+			packageName:        a.manifestValues.applicationId,
+		}
+		a.mergedManifestFile = manifestMerger(ctx, transitiveManifestPaths[0], manifestMergerParams)
 		if !a.isLibrary {
 			// Only use the merged manifest for applications.  For libraries, the transitive closure of manifests
 			// will be propagated to the final application and merged there.  The merged manifest for libraries is
@@ -352,27 +409,24 @@
 		a.mergedManifestFile = manifestPath
 	}
 
-	compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, sdkContext, manifestPath)
+	compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, opts.sdkContext, manifestPath)
 
 	linkFlags = append(linkFlags, libFlags...)
-	linkDeps = append(linkDeps, sharedDeps...)
+	linkDeps = append(linkDeps, sharedExportPackages...)
 	linkDeps = append(linkDeps, staticDeps.resPackages()...)
-	linkFlags = append(linkFlags, extraLinkFlags...)
+	linkFlags = append(linkFlags, opts.extraLinkFlags...)
 	if a.isLibrary {
 		linkFlags = append(linkFlags, "--static-lib")
 	}
+	if opts.forceNonFinalResourceIDs {
+		linkFlags = append(linkFlags, "--non-final-ids")
+	}
 
-	if a.isLibrary && a.useResourceProcessorBusyBox() {
-		// When building an android_library using ResourceProcessorBusyBox the resources are merged into
-		// package-res.apk with --merge-only, but --no-static-lib-packages is not used so that R.txt only
-		// contains resources from this library.
+	linkFlags = append(linkFlags, "--no-static-lib-packages")
+	if a.isLibrary && a.useResourceProcessorBusyBox(ctx) {
+		// When building an android_library using ResourceProcessorBusyBox pass --merge-only to skip resource
+		// references validation until the final app link step when all static libraries are present.
 		linkFlags = append(linkFlags, "--merge-only")
-	} else {
-		// When building and app or when building an android_library without ResourceProcessorBusyBox
-		// --no-static-lib-packages is used to put all the resources into the app.  If ResourceProcessorBusyBox
-		// is used then the app's R.txt will be post-processed along with the R.txt files from dependencies to
-		// sort resources into the right packages in R.class.
-		linkFlags = append(linkFlags, "--no-static-lib-packages")
 	}
 
 	packageRes := android.PathForModuleOut(ctx, "package-res.apk")
@@ -386,7 +440,7 @@
 	var compiledResDirs []android.Paths
 	for _, dir := range resDirs {
 		a.resourceFiles = append(a.resourceFiles, dir.files...)
-		compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths())
+		compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files, compileFlags, a.filterProduct()).Paths())
 	}
 
 	for i, zip := range resZips {
@@ -401,11 +455,16 @@
 	// of transitiveStaticLibs.
 	transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages())
 
-	if a.isLibrary && a.useResourceProcessorBusyBox() {
+	if a.isLibrary && a.useResourceProcessorBusyBox(ctx) {
 		// When building an android_library with ResourceProcessorBusyBox enabled treat static library dependencies
 		// as imports.  The resources from dependencies will not be merged into this module's package-res.apk, and
 		// instead modules depending on this module will reference package-res.apk from all transitive static
 		// dependencies.
+		for _, sharedDep := range sharedDeps {
+			if sharedDep.usedResourceProcessor {
+				transitiveRJars = append(transitiveRJars, sharedDep.rJar)
+			}
+		}
 		for _, staticDep := range staticDeps {
 			linkDeps = append(linkDeps, staticDep.resPackage)
 			linkFlags = append(linkFlags, "-I "+staticDep.resPackage.String())
@@ -440,7 +499,7 @@
 	}
 
 	for _, dir := range overlayDirs {
-		compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths()...)
+		compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files, compileFlags, a.filterProduct()).Paths()...)
 	}
 
 	var splitPackages android.WritablePaths
@@ -458,7 +517,7 @@
 		})
 	}
 
-	if !a.useResourceProcessorBusyBox() {
+	if !a.useResourceProcessorBusyBox(ctx) {
 		// the subdir "android" is required to be filtered by package names
 		srcJar = android.PathForModuleGen(ctx, "android", "R.srcjar")
 	}
@@ -470,7 +529,8 @@
 		transitiveAssets = android.ReverseSliceInPlace(staticDeps.assets())
 	}
 	aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt,
-		linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages)
+		linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages,
+		opts.aconfigTextFiles)
 	// Extract assets from the resource package output so that they can be used later in aapt2link
 	// for modules that depend on this one.
 	if android.PrefixInList(linkFlags, "-A ") {
@@ -484,9 +544,10 @@
 		a.assetPackage = android.OptionalPathForPath(assets)
 	}
 
-	if a.useResourceProcessorBusyBox() {
+	if a.useResourceProcessorBusyBox(ctx) {
 		rJar := android.PathForModuleOut(ctx, "busybox/R.jar")
-		resourceProcessorBusyBoxGenerateBinaryR(ctx, rTxt, a.mergedManifestFile, rJar, staticDeps, a.isLibrary)
+		resourceProcessorBusyBoxGenerateBinaryR(ctx, rTxt, a.mergedManifestFile, rJar, staticDeps, a.isLibrary, a.aaptProperties.Aaptflags,
+			opts.forceNonFinalResourceIDs)
 		aapt2ExtractExtraPackages(ctx, extraPackages, rJar)
 		transitiveRJars = append(transitiveRJars, rJar)
 		a.rJar = rJar
@@ -494,9 +555,20 @@
 		aapt2ExtractExtraPackages(ctx, extraPackages, srcJar)
 	}
 
+	transitiveAaptResourcePackages := staticDeps.resPackages().Strings()
+	transitiveAaptResourcePackages = slices.DeleteFunc(transitiveAaptResourcePackages, func(p string) bool {
+		return p == packageRes.String()
+	})
+	transitiveAaptResourcePackagesFile := android.PathForModuleOut(ctx, "transitive-res-packages")
+	android.WriteFileRule(ctx, transitiveAaptResourcePackagesFile, strings.Join(transitiveAaptResourcePackages, "\n"))
+
+	// Reverse the list of R.jar files so that the current module comes first, and direct dependencies come before
+	// transitive dependencies.
+	transitiveRJars = android.ReversePaths(transitiveRJars)
+
 	a.aaptSrcJar = srcJar
 	a.transitiveAaptRJars = transitiveRJars
-	a.transitiveAaptResourcePackages = staticDeps.resPackages()
+	a.transitiveAaptResourcePackagesFile = transitiveAaptResourcePackagesFile
 	a.exportPackage = packageRes
 	a.manifestPath = manifestPath
 	a.proguardOptionsFile = proguardOptionsFile
@@ -512,7 +584,7 @@
 			rJar:                a.rJar,
 			assets:              a.assetPackage,
 
-			usedResourceProcessor: a.useResourceProcessorBusyBox(),
+			usedResourceProcessor: a.useResourceProcessorBusyBox(ctx),
 		}).
 		Transitive(staticResourcesNodesDepSet).Build()
 	a.rroDirsDepSet = android.NewDepSetBuilder[rroDir](android.TOPOLOGICAL).
@@ -539,7 +611,8 @@
 // using Bazel's ResourceProcessorBusyBox tool, which is faster than compiling the R.java files and
 // supports producing classes for static dependencies that only include resources from that dependency.
 func resourceProcessorBusyBoxGenerateBinaryR(ctx android.ModuleContext, rTxt, manifest android.Path,
-	rJar android.WritablePath, transitiveDeps transitiveAarDeps, isLibrary bool) {
+	rJar android.WritablePath, transitiveDeps transitiveAarDeps, isLibrary bool, aaptFlags []string,
+	forceNonFinalIds bool) {
 
 	var args []string
 	var deps android.Paths
@@ -549,6 +622,9 @@
 		// to ResourceProcessorBusyBox so that it can regenerate R.class files with the final resource IDs for each
 		// package.
 		args, deps = transitiveDeps.resourceProcessorDeps()
+		if forceNonFinalIds {
+			args = append(args, "--finalFields=false")
+		}
 	} else {
 		// When compiling a library don't pass any dependencies as it only needs to generate an R.class file for this
 		// library.  Pass --finalFields=false so that the R.class file contains non-final fields so they don't get
@@ -556,6 +632,17 @@
 		args = append(args, "--finalFields=false")
 	}
 
+	for i, arg := range aaptFlags {
+		const AAPT_CUSTOM_PACKAGE = "--custom-package"
+		if strings.HasPrefix(arg, AAPT_CUSTOM_PACKAGE) {
+			pkg := strings.TrimSpace(strings.TrimPrefix(arg, AAPT_CUSTOM_PACKAGE))
+			if pkg == "" && i+1 < len(aaptFlags) {
+				pkg = aaptFlags[i+1]
+			}
+			args = append(args, "--packageForR "+pkg)
+		}
+	}
+
 	deps = append(deps, rTxt, manifest)
 
 	ctx.Build(pctx, android.BuildParams{
@@ -620,8 +707,9 @@
 }
 
 // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
-func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap) (
-	staticResourcesNodes *android.DepSet[*resourcesNode], staticRRODirs *android.DepSet[rroDir],
+func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext,
+	classLoaderContexts dexpreopt.ClassLoaderContextMap, usesLibrary *usesLibrary) (
+	staticResourcesNodes, sharedResourcesNodes *android.DepSet[*resourcesNode], staticRRODirs *android.DepSet[rroDir],
 	staticManifests *android.DepSet[android.Path], sharedLibs android.Paths, flags []string) {
 
 	if classLoaderContexts == nil {
@@ -635,7 +723,8 @@
 		sharedLibs = append(sharedLibs, sdkDep.jars...)
 	}
 
-	var resourcesNodeDepSets []*android.DepSet[*resourcesNode]
+	var staticResourcesNodeDepSets []*android.DepSet[*resourcesNode]
+	var sharedResourcesNodeDepSets []*android.DepSet[*resourcesNode]
 	rroDirsDepSetBuilder := android.NewDepSetBuilder[rroDir](android.TOPOLOGICAL)
 	manifestsDepSetBuilder := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL)
 
@@ -653,6 +742,7 @@
 			// Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2.
 		case sdkLibTag, libTag:
 			if exportPackage != nil {
+				sharedResourcesNodeDepSets = append(sharedResourcesNodeDepSets, aarDep.ResourcesNodeDepSet())
 				sharedLibs = append(sharedLibs, exportPackage)
 			}
 		case frameworkResTag:
@@ -661,13 +751,16 @@
 			}
 		case staticLibTag:
 			if exportPackage != nil {
-				resourcesNodeDepSets = append(resourcesNodeDepSets, aarDep.ResourcesNodeDepSet())
+				staticResourcesNodeDepSets = append(staticResourcesNodeDepSets, aarDep.ResourcesNodeDepSet())
 				rroDirsDepSetBuilder.Transitive(aarDep.RRODirsDepSet())
 				manifestsDepSetBuilder.Transitive(aarDep.ManifestsDepSet())
 			}
 		}
 
 		addCLCFromDep(ctx, module, classLoaderContexts)
+		if usesLibrary != nil {
+			addMissingOptionalUsesLibsFromDep(ctx, module, usesLibrary)
+		}
 	})
 
 	// AAPT2 overlays are in lowest to highest priority order, the topological order will be reversed later.
@@ -675,9 +768,12 @@
 	// reverse later.
 	// NOTE: this is legacy and probably incorrect behavior, for most other cases (e.g. conflicting classes in
 	// dependencies) the highest priority dependency is listed first, but for resources the highest priority
-	// dependency has to be listed last.
+	// dependency has to be listed last.  This is also inconsistent with the way manifests from the same
+	// transitive dependencies are merged.
 	staticResourcesNodes = android.NewDepSet(android.TOPOLOGICAL, nil,
-		android.ReverseSliceInPlace(resourcesNodeDepSets))
+		android.ReverseSliceInPlace(staticResourcesNodeDepSets))
+	sharedResourcesNodes = android.NewDepSet(android.TOPOLOGICAL, nil,
+		android.ReverseSliceInPlace(sharedResourcesNodeDepSets))
 
 	staticRRODirs = rroDirsDepSetBuilder.Build()
 	staticManifests = manifestsDepSetBuilder.Build()
@@ -690,13 +786,12 @@
 		flags = append(flags, "-I "+sharedLib.String())
 	}
 
-	return staticResourcesNodes, staticRRODirs, staticManifests, sharedLibs, flags
+	return staticResourcesNodes, sharedResourcesNodes, staticRRODirs, staticManifests, sharedLibs, flags
 }
 
 type AndroidLibrary struct {
 	Library
 	aapt
-	android.BazelModuleBase
 
 	androidLibraryProperties androidLibraryProperties
 
@@ -718,26 +813,42 @@
 var _ AndroidLibraryDependency = (*AndroidLibrary)(nil)
 
 func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
+	a.usesLibrary.deps(ctx, false)
 	a.Module.deps(ctx)
 	sdkDep := decodeSdkDep(ctx, android.SdkContext(a))
 	if sdkDep.hasFrameworkLibs() {
 		a.aapt.deps(ctx, sdkDep)
 	}
-	a.usesLibrary.deps(ctx, false)
+
+	for _, aconfig_declaration := range a.aaptProperties.Flags_packages {
+		ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration)
+	}
 }
 
 func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	a.aapt.isLibrary = true
 	a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
-	a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, nil, false)
+	if a.usesLibrary.shouldDisableDexpreopt {
+		a.dexpreopter.disableDexpreopt()
+	}
+	a.aapt.buildActions(ctx,
+		aaptBuildActionOptions{
+			sdkContext:                     android.SdkContext(a),
+			classLoaderContexts:            a.classLoaderContexts,
+			enforceDefaultTargetSdkVersion: false,
+			aconfigTextFiles:               getAconfigFilePaths(ctx),
+			usesLibrary:                    &a.usesLibrary,
+		},
+	)
 
-	a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+	a.hideApexVariantFromMake = !apexInfo.IsForPlatform()
 
-	a.stem = proptools.StringDefault(a.overridableDeviceProperties.Stem, ctx.ModuleName())
+	a.stem = proptools.StringDefault(a.overridableProperties.Stem, ctx.ModuleName())
 
 	ctx.CheckbuildFile(a.aapt.proguardOptionsFile)
 	ctx.CheckbuildFile(a.aapt.exportPackage)
-	if a.useResourceProcessorBusyBox() {
+	if a.useResourceProcessorBusyBox(ctx) {
 		ctx.CheckbuildFile(a.aapt.rJar)
 	} else {
 		ctx.CheckbuildFile(a.aapt.aaptSrcJar)
@@ -750,13 +861,20 @@
 	a.linter.manifest = a.aapt.manifestPath
 	a.linter.resources = a.aapt.resourceFiles
 
-	a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles,
-		a.proguardOptionsFile)
+	proguardSpecInfo := a.collectProguardSpecInfo(ctx)
+	android.SetProvider(ctx, ProguardSpecInfoProvider, proguardSpecInfo)
+	exportedProguardFlagsFiles := proguardSpecInfo.ProguardFlagsFiles.ToList()
+	a.extraProguardFlagsFiles = append(a.extraProguardFlagsFiles, exportedProguardFlagsFiles...)
+	a.extraProguardFlagsFiles = append(a.extraProguardFlagsFiles, a.proguardOptionsFile)
+
+	combinedExportedProguardFlagFile := android.PathForModuleOut(ctx, "export_proguard_flags")
+	writeCombinedProguardFlagsFile(ctx, combinedExportedProguardFlagFile, exportedProguardFlagsFiles)
+	a.combinedExportedProguardFlagsFile = combinedExportedProguardFlagFile
 
 	var extraSrcJars android.Paths
 	var extraCombinedJars android.Paths
 	var extraClasspathJars android.Paths
-	if a.useResourceProcessorBusyBox() {
+	if a.useResourceProcessorBusyBox(ctx) {
 		// When building a library with ResourceProcessorBusyBox enabled ResourceProcessorBusyBox for this
 		// library and each of the transitive static android_library dependencies has already created an
 		// R.class file for the appropriate package.  Add all of those R.class files to the classpath.
@@ -777,31 +895,30 @@
 		ctx.CheckbuildFile(a.aarFile)
 	}
 
-	a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles,
-		android.PathsForModuleSrc(ctx, a.dexProperties.Optimize.Proguard_flags_files)...)
-
-	ctx.VisitDirectDeps(func(m android.Module) {
-		if ctx.OtherModuleDependencyTag(m) == staticLibTag {
-			if lib, ok := m.(LibraryDependency); ok {
-				a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles, lib.ExportedProguardFlagFiles()...)
-			}
-		}
-	})
-	a.exportedProguardFlagFiles = android.FirstUniquePaths(a.exportedProguardFlagFiles)
-
 	prebuiltJniPackages := android.Paths{}
 	ctx.VisitDirectDeps(func(module android.Module) {
-		if info, ok := ctx.OtherModuleProvider(module, JniPackageProvider).(JniPackageInfo); ok {
+		if info, ok := android.OtherModuleProvider(ctx, module, JniPackageProvider); ok {
 			prebuiltJniPackages = append(prebuiltJniPackages, info.JniPackages...)
 		}
 	})
 	if len(prebuiltJniPackages) > 0 {
-		ctx.SetProvider(JniPackageProvider, JniPackageInfo{
+		android.SetProvider(ctx, JniPackageProvider, JniPackageInfo{
 			JniPackages: prebuiltJniPackages,
 		})
 	}
 }
 
+func (a *AndroidLibrary) IDEInfo(dpInfo *android.IdeInfo) {
+	a.Library.IDEInfo(dpInfo)
+	a.aapt.IDEInfo(dpInfo)
+}
+
+func (a *aapt) IDEInfo(dpInfo *android.IdeInfo) {
+	if a.rJar != nil {
+		dpInfo.Jars = append(dpInfo.Jars, a.rJar.String())
+	}
+}
+
 // android_library builds and links sources into a `.jar` file for the device along with Android resources.
 //
 // An android_library has a single variant that produces a `.jar` file containing `.class` files that were
@@ -814,14 +931,14 @@
 	module.Module.addHostAndDeviceProperties()
 	module.AddProperties(
 		&module.aaptProperties,
-		&module.androidLibraryProperties)
+		&module.androidLibraryProperties,
+		&module.sourceProperties)
 
 	module.androidLibraryProperties.BuildAAR = true
 	module.Module.linter.library = true
 
 	android.InitApexModule(module)
 	InitJavaModule(module, android.DeviceSupported)
-	android.InitBazelModule(module)
 	return module
 }
 
@@ -854,13 +971,15 @@
 	// will be passed transitively through android_libraries to an android_app.
 	//TODO(b/241138093) evaluate whether we can have this flag default to true for Bazel conversion
 	Extract_jni *bool
+
+	// If set, overrides the manifest extracted from the AAR with the provided path.
+	Manifest *string `android:"path"`
 }
 
 type AARImport struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
 	android.ApexModuleBase
-	android.BazelModuleBase
 	prebuilt android.Prebuilt
 
 	// Functionality common to Module and Import.
@@ -870,15 +989,17 @@
 
 	properties AARImportProperties
 
-	classpathFile                  android.WritablePath
-	proguardFlags                  android.WritablePath
-	exportPackage                  android.WritablePath
-	transitiveAaptResourcePackages android.Paths
-	extraAaptPackagesFile          android.WritablePath
-	manifest                       android.WritablePath
-	assetsPackage                  android.WritablePath
-	rTxt                           android.WritablePath
-	rJar                           android.WritablePath
+	headerJarFile                      android.WritablePath
+	implementationJarFile              android.WritablePath
+	implementationAndResourcesJarFile  android.WritablePath
+	proguardFlags                      android.WritablePath
+	exportPackage                      android.WritablePath
+	transitiveAaptResourcePackagesFile android.Path
+	extraAaptPackagesFile              android.WritablePath
+	manifest                           android.Path
+	assetsPackage                      android.WritablePath
+	rTxt                               android.WritablePath
+	rJar                               android.WritablePath
 
 	resourcesNodesDepSet *android.DepSet[*resourcesNode]
 	manifestsDepSet      *android.DepSet[android.Path]
@@ -890,6 +1011,12 @@
 
 	sdkVersion    android.SdkSpec
 	minSdkVersion android.ApiLevel
+
+	usesLibrary
+	classLoaderContexts dexpreopt.ClassLoaderContextMap
+
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
 }
 
 var _ android.OutputFileProducer = (*AARImport)(nil)
@@ -900,7 +1027,7 @@
 	case ".aar":
 		return []android.Path{a.aarPath}, nil
 	case "":
-		return []android.Path{a.classpathFile}, nil
+		return []android.Path{a.implementationAndResourcesJarFile}, nil
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
@@ -938,10 +1065,6 @@
 func (a *AARImport) ExportPackage() android.Path {
 	return a.exportPackage
 }
-func (a *AARImport) ExportedProguardFlagFiles() android.Paths {
-	return android.Paths{a.proguardFlags}
-}
-
 func (a *AARImport) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
 	return a.resourcesNodesDepSet
 }
@@ -987,6 +1110,8 @@
 
 	ctx.AddVariationDependencies(nil, libTag, a.properties.Libs...)
 	ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs...)
+
+	a.usesLibrary.deps(ctx, false)
 }
 
 type JniPackageInfo struct {
@@ -995,7 +1120,7 @@
 	JniPackages android.Paths
 }
 
-var JniPackageProvider = blueprint.NewProvider(JniPackageInfo{})
+var JniPackageProvider = blueprint.NewProvider[JniPackageInfo]()
 
 // Unzip an AAR and extract the JNI libs for $archString.
 var extractJNI = pctx.AndroidStaticRule("extractJNI",
@@ -1005,7 +1130,7 @@
 			`jni_files=$$(find $outDir/jni -type f) && ` +
 			// print error message if there are no JNI libs for this arch
 			`[ -n "$$jni_files" ] || (echo "ERROR: no JNI libs found for arch ${archString}" && exit 1) && ` +
-			`${config.SoongZipCmd} -o $out -P 'lib/${archString}' ` +
+			`${config.SoongZipCmd} -o $out -L 0 -P 'lib/${archString}' ` +
 			`-C $outDir/jni/${archString} $$(echo $$jni_files | xargs -n1 printf " -f %s")`,
 		CommandDeps: []string{"${config.SoongZipCmd}"},
 	},
@@ -1032,7 +1157,8 @@
 	a.sdkVersion = a.SdkVersion(ctx)
 	a.minSdkVersion = a.MinSdkVersion(ctx)
 
-	a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+	a.hideApexVariantFromMake = !apexInfo.IsForPlatform()
 
 	aarName := ctx.ModuleName() + ".aar"
 	a.aarPath = android.PathForModuleSrc(ctx, a.properties.Aars[0])
@@ -1043,21 +1169,43 @@
 		TransformJetifier(ctx, a.aarPath.(android.WritablePath), inputFile)
 	}
 
+	jarName := ctx.ModuleName() + ".jar"
 	extractedAARDir := android.PathForModuleOut(ctx, "aar")
-	a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar")
-	a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
-	a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
-	aarRTxt := extractedAARDir.Join(ctx, "R.txt")
+	classpathFile := extractedAARDir.Join(ctx, jarName)
+
+	extractedManifest := extractedAARDir.Join(ctx, "AndroidManifest.xml")
+	providedManifest := android.OptionalPathForModuleSrc(ctx, a.properties.Manifest)
+	if providedManifest.Valid() {
+		a.manifest = providedManifest.Path()
+	} else {
+		a.manifest = extractedManifest
+	}
+
+	a.rTxt = extractedAARDir.Join(ctx, "R.txt")
 	a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip")
+	a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
+	transitiveProguardFlags, transitiveUnconditionalExportedFlags := collectDepProguardSpecInfo(ctx)
+	android.SetProvider(ctx, ProguardSpecInfoProvider, ProguardSpecInfo{
+		ProguardFlagsFiles: android.NewDepSet[android.Path](
+			android.POSTORDER,
+			android.Paths{a.proguardFlags},
+			transitiveProguardFlags,
+		),
+		UnconditionallyExportedProguardFlags: android.NewDepSet[android.Path](
+			android.POSTORDER,
+			nil,
+			transitiveUnconditionalExportedFlags,
+		),
+	})
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        unzipAAR,
 		Input:       a.aarPath,
-		Outputs:     android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage, aarRTxt},
+		Outputs:     android.WritablePaths{classpathFile, a.proguardFlags, extractedManifest, a.assetsPackage, a.rTxt},
 		Description: "unzip AAR",
 		Args: map[string]string{
 			"outDir":             extractedAARDir.String(),
-			"combinedClassesJar": a.classpathFile.String(),
+			"combinedClassesJar": classpathFile.String(),
 			"assetsPackage":      a.assetsPackage.String(),
 		},
 	})
@@ -1071,7 +1219,7 @@
 
 	a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk")
 	proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
-	a.rTxt = android.PathForModuleOut(ctx, "R.txt")
+	aaptRTxt := android.PathForModuleOut(ctx, "R.txt")
 	a.extraAaptPackagesFile = android.PathForModuleOut(ctx, "extra_packages")
 
 	var linkDeps android.Paths
@@ -1080,15 +1228,18 @@
 		"--static-lib",
 		"--merge-only",
 		"--auto-add-overlay",
+		"--no-static-lib-packages",
 	}
 
 	linkFlags = append(linkFlags, "--manifest "+a.manifest.String())
 	linkDeps = append(linkDeps, a.manifest)
 
-	staticResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedLibs, libFlags :=
-		aaptLibs(ctx, android.SdkContext(a), nil)
+	staticResourcesNodesDepSet, sharedResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedLibs, libFlags :=
+		aaptLibs(ctx, android.SdkContext(a), nil, nil)
 
+	_ = sharedResourcesNodesDepSet
 	_ = staticRRODirsDepSet
+
 	staticDeps := transitiveAarDeps(staticResourcesNodesDepSet.ToList())
 
 	linkDeps = append(linkDeps, sharedLibs...)
@@ -1105,11 +1256,11 @@
 	}
 
 	transitiveAssets := android.ReverseSliceInPlace(staticDeps.assets())
-	aapt2Link(ctx, a.exportPackage, nil, proguardOptionsFile, a.rTxt,
-		linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil)
+	aapt2Link(ctx, a.exportPackage, nil, proguardOptionsFile, aaptRTxt,
+		linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil, nil)
 
 	a.rJar = android.PathForModuleOut(ctx, "busybox/R.jar")
-	resourceProcessorBusyBoxGenerateBinaryR(ctx, a.rTxt, a.manifest, a.rJar, nil, true)
+	resourceProcessorBusyBoxGenerateBinaryR(ctx, a.rTxt, a.manifest, a.rJar, nil, true, nil, false)
 
 	aapt2ExtractExtraPackages(ctx, a.extraAaptPackagesFile, a.rJar)
 
@@ -1127,24 +1278,87 @@
 	a.resourcesNodesDepSet = resourcesNodesDepSetBuilder.Build()
 
 	manifestDepSetBuilder := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(a.manifest)
-	// TODO(b/288358614): Soong has historically not merged manifests from dependencies of android_library_import
-	// modules.  Merging manifests from dependencies could remove the need for pom2bp to generate the "-nodeps" copies
-	// of androidx libraries, but doing so triggers errors due to errors introduced by existing dependencies of
-	// android_library_import modules.  If this is fixed, AndroidLibraryDependency.ManifestsDepSet can be dropped
-	// completely in favor of AndroidLibraryDependency.ResourceNodesDepSet.manifest
-	//manifestDepSetBuilder.Transitive(transitiveStaticDeps.manifests)
-	_ = staticManifestsDepSet
+	manifestDepSetBuilder.Transitive(staticManifestsDepSet)
 	a.manifestsDepSet = manifestDepSetBuilder.Build()
 
-	a.transitiveAaptResourcePackages = staticDeps.resPackages()
+	transitiveAaptResourcePackages := staticDeps.resPackages().Strings()
+	transitiveAaptResourcePackages = slices.DeleteFunc(transitiveAaptResourcePackages, func(p string) bool {
+		return p == a.exportPackage.String()
+	})
+	transitiveAaptResourcePackagesFile := android.PathForModuleOut(ctx, "transitive-res-packages")
+	android.WriteFileRule(ctx, transitiveAaptResourcePackagesFile, strings.Join(transitiveAaptResourcePackages, "\n"))
+	a.transitiveAaptResourcePackagesFile = transitiveAaptResourcePackagesFile
 
 	a.collectTransitiveHeaderJars(ctx)
-	ctx.SetProvider(JavaInfoProvider, JavaInfo{
-		HeaderJars:                     android.PathsIfNonNil(a.classpathFile),
+
+	a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+
+	var staticJars android.Paths
+	var staticHeaderJars android.Paths
+	var staticResourceJars android.Paths
+	ctx.VisitDirectDeps(func(module android.Module) {
+		if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
+			tag := ctx.OtherModuleDependencyTag(module)
+			switch tag {
+			case staticLibTag:
+				staticJars = append(staticJars, dep.ImplementationJars...)
+				staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...)
+				staticResourceJars = append(staticResourceJars, dep.ResourceJars...)
+			}
+		}
+		addCLCFromDep(ctx, module, a.classLoaderContexts)
+		addMissingOptionalUsesLibsFromDep(ctx, module, &a.usesLibrary)
+	})
+
+	var implementationJarFile android.OutputPath
+	if len(staticJars) > 0 {
+		combineJars := append(android.Paths{classpathFile}, staticJars...)
+		implementationJarFile = android.PathForModuleOut(ctx, "combined", jarName).OutputPath
+		TransformJarsToJar(ctx, implementationJarFile, "combine", combineJars, android.OptionalPath{}, false, nil, nil)
+	} else {
+		implementationJarFile = classpathFile
+	}
+
+	var resourceJarFile android.Path
+	if len(staticResourceJars) > 1 {
+		combinedJar := android.PathForModuleOut(ctx, "res-combined", jarName)
+		TransformJarsToJar(ctx, combinedJar, "for resources", staticResourceJars, android.OptionalPath{},
+			false, nil, nil)
+		resourceJarFile = combinedJar
+	} else if len(staticResourceJars) == 1 {
+		resourceJarFile = staticResourceJars[0]
+	}
+
+	// merge implementation jar with resources if necessary
+	implementationAndResourcesJar := implementationJarFile
+	if resourceJarFile != nil {
+		jars := android.Paths{resourceJarFile, implementationAndResourcesJar}
+		combinedJar := android.PathForModuleOut(ctx, "withres", jarName).OutputPath
+		TransformJarsToJar(ctx, combinedJar, "for resources", jars, android.OptionalPath{},
+			false, nil, nil)
+		implementationAndResourcesJar = combinedJar
+	}
+
+	a.implementationJarFile = implementationJarFile
+	// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
+	a.implementationAndResourcesJarFile = implementationAndResourcesJar.WithoutRel()
+
+	if len(staticHeaderJars) > 0 {
+		combineJars := append(android.Paths{classpathFile}, staticHeaderJars...)
+		a.headerJarFile = android.PathForModuleOut(ctx, "turbine-combined", jarName)
+		TransformJarsToJar(ctx, a.headerJarFile, "combine header jars", combineJars, android.OptionalPath{}, false, nil, nil)
+	} else {
+		a.headerJarFile = classpathFile
+	}
+
+	android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
+		HeaderJars:                     android.PathsIfNonNil(a.headerJarFile),
+		ResourceJars:                   android.PathsIfNonNil(resourceJarFile),
 		TransitiveLibsHeaderJars:       a.transitiveLibsHeaderJars,
 		TransitiveStaticLibsHeaderJars: a.transitiveStaticLibsHeaderJars,
-		ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile),
-		ImplementationJars:             android.PathsIfNonNil(a.classpathFile),
+		ImplementationAndResourcesJars: android.PathsIfNonNil(a.implementationAndResourcesJarFile),
+		ImplementationJars:             android.PathsIfNonNil(a.implementationJarFile),
+		StubsLinkType:                  Implementation,
 		// TransitiveAconfigFiles: // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
 	})
 
@@ -1167,23 +1381,24 @@
 				},
 			})
 		}
-
-		ctx.SetProvider(JniPackageProvider, JniPackageInfo{
-			JniPackages: a.jniPackages,
-		})
 	}
+
+	android.SetProvider(ctx, JniPackageProvider, JniPackageInfo{
+		JniPackages: a.jniPackages,
+	})
+	android.CollectDependencyAconfigFiles(ctx, &a.mergedAconfigFiles)
 }
 
 func (a *AARImport) HeaderJars() android.Paths {
-	return android.Paths{a.classpathFile}
+	return android.Paths{a.headerJarFile}
 }
 
 func (a *AARImport) ImplementationAndResourcesJars() android.Paths {
-	return android.Paths{a.classpathFile}
+	return android.Paths{a.implementationAndResourcesJarFile}
 }
 
-func (a *AARImport) DexJarBuildPath() android.Path {
-	return nil
+func (a *AARImport) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
+	return OptionalDexJarPath{}
 }
 
 func (a *AARImport) DexJarInstallPath() android.Path {
@@ -1191,9 +1406,11 @@
 }
 
 func (a *AARImport) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap {
-	return nil
+	return a.classLoaderContexts
 }
 
+var _ UsesLibraryDependency = (*AARImport)(nil)
+
 var _ android.ApexModule = (*AARImport)(nil)
 
 // Implements android.ApexModule
@@ -1202,13 +1419,19 @@
 }
 
 // Implements android.ApexModule
-func (g *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
+func (a *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
 	return nil
 }
 
 var _ android.PrebuiltInterface = (*AARImport)(nil)
 
+func (a *AARImport) UsesLibrary() *usesLibrary {
+	return &a.usesLibrary
+}
+
+var _ ModuleWithUsesLibrary = (*AARImport)(nil)
+
 // android_library_import imports an `.aar` file into the build graph as if it was built with android_library.
 //
 // This module is not suitable for installing on a device, but can be used as a `static_libs` dependency of
@@ -1216,144 +1439,13 @@
 func AARImportFactory() android.Module {
 	module := &AARImport{}
 
-	module.AddProperties(&module.properties)
+	module.AddProperties(
+		&module.properties,
+		&module.usesLibrary.usesLibraryProperties,
+	)
 
 	android.InitPrebuiltModule(module, &module.properties.Aars)
 	android.InitApexModule(module)
 	InitJavaModuleMultiTargets(module, android.DeviceSupported)
-	android.InitBazelModule(module)
 	return module
 }
-
-type bazelAapt struct {
-	Manifest       bazel.Label
-	Resource_files bazel.LabelListAttribute
-}
-
-type bazelAndroidLibrary struct {
-	*javaLibraryAttributes
-	*bazelAapt
-}
-
-type bazelAndroidLibraryImport struct {
-	Aar         bazel.Label
-	Deps        bazel.LabelListAttribute
-	Exports     bazel.LabelListAttribute
-	Sdk_version bazel.StringAttribute
-}
-
-func (a *aapt) convertAaptAttrsWithBp2Build(ctx android.TopDownMutatorContext) *bazelAapt {
-	manifest := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
-
-	resourceFiles := bazel.LabelList{
-		Includes: []bazel.Label{},
-	}
-	for _, dir := range android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res") {
-		files := android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir))
-		resourceFiles.Includes = append(resourceFiles.Includes, files...)
-	}
-	return &bazelAapt{
-		android.BazelLabelForModuleSrcSingle(ctx, manifest),
-		bazel.MakeLabelListAttribute(resourceFiles),
-	}
-}
-
-func (a *AARImport) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	aars := android.BazelLabelForModuleSrcExcludes(ctx, a.properties.Aars, []string{})
-	exportableStaticLibs := []string{}
-	// TODO(b/240716882): investigate and handle static_libs deps that are not imports. They are not supported for export by Bazel.
-	for _, depName := range a.properties.Static_libs {
-		if dep, ok := ctx.ModuleFromName(depName); ok {
-			switch dep.(type) {
-			case *AARImport, *Import:
-				exportableStaticLibs = append(exportableStaticLibs, depName)
-			}
-		}
-	}
-	name := android.RemoveOptionalPrebuiltPrefix(a.Name())
-	deps := android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(android.CopyOf(append(a.properties.Static_libs, a.properties.Libs...))))
-	exports := android.BazelLabelForModuleDeps(ctx, android.LastUniqueStrings(exportableStaticLibs))
-
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "aar_import",
-			Bzl_load_location: "//build/bazel/rules/android:aar_import.bzl",
-		},
-		android.CommonAttributes{Name: name},
-		&bazelAndroidLibraryImport{
-			Aar:         aars.Includes[0],
-			Deps:        bazel.MakeLabelListAttribute(deps),
-			Exports:     bazel.MakeLabelListAttribute(exports),
-			Sdk_version: bazel.StringAttribute{Value: a.properties.Sdk_version},
-		},
-	)
-
-	neverlink := true
-	ctx.CreateBazelTargetModule(
-		AndroidLibraryBazelTargetModuleProperties(),
-		android.CommonAttributes{Name: name + "-neverlink"},
-		&bazelAndroidLibrary{
-			javaLibraryAttributes: &javaLibraryAttributes{
-				Neverlink: bazel.BoolAttribute{Value: &neverlink},
-				Exports:   bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}),
-				javaCommonAttributes: &javaCommonAttributes{
-					Sdk_version: bazel.StringAttribute{Value: a.properties.Sdk_version},
-				},
-			},
-		},
-	)
-
-}
-func AndroidLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties {
-	return bazel.BazelTargetModuleProperties{
-		Rule_class:        "android_library",
-		Bzl_load_location: "//build/bazel/rules/android:android_library.bzl",
-	}
-}
-
-func (a *AndroidLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	commonAttrs, bp2buildInfo, supported := a.convertLibraryAttrsBp2Build(ctx)
-	if !supported {
-		return
-	}
-
-	depLabels := bp2buildInfo.DepLabels
-
-	deps := depLabels.Deps
-	if !commonAttrs.Srcs.IsEmpty() {
-		deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them
-	} else if !depLabels.Deps.IsEmpty() {
-		ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.")
-	}
-	name := a.Name()
-	props := AndroidLibraryBazelTargetModuleProperties()
-
-	ctx.CreateBazelTargetModule(
-		props,
-		android.CommonAttributes{Name: name},
-		&bazelAndroidLibrary{
-			&javaLibraryAttributes{
-				javaCommonAttributes: commonAttrs,
-				Deps:                 deps,
-				Exports:              depLabels.StaticDeps,
-			},
-			a.convertAaptAttrsWithBp2Build(ctx),
-		},
-	)
-
-	neverlink := true
-	ctx.CreateBazelTargetModule(
-		props,
-		android.CommonAttributes{Name: name + "-neverlink"},
-		&bazelAndroidLibrary{
-			javaLibraryAttributes: &javaLibraryAttributes{
-				Neverlink: bazel.BoolAttribute{Value: &neverlink},
-				Exports:   bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}),
-				javaCommonAttributes: &javaCommonAttributes{
-					Sdk_version:  bazel.StringAttribute{Value: a.deviceProperties.Sdk_version},
-					Java_version: bazel.StringAttribute{Value: a.properties.Java_version},
-				},
-			},
-		},
-	)
-}
diff --git a/java/aar_test.go b/java/aar_test.go
index 8afa039..d6dbe3c 100644
--- a/java/aar_test.go
+++ b/java/aar_test.go
@@ -52,7 +52,7 @@
 			appMod := ctx.Module(tc.name, "android_common")
 			appTestMod := ctx.ModuleForTests(tc.name, "android_common")
 
-			info, ok := ctx.ModuleProvider(appMod, JniPackageProvider).(JniPackageInfo)
+			info, ok := android.SingletonModuleProvider(ctx, appMod, JniPackageProvider)
 			if !ok {
 				t.Errorf("expected android_library_import to have JniPackageProvider")
 			}
@@ -81,3 +81,96 @@
 		})
 	}
 }
+
+func TestLibraryFlagsPackages(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+	).RunTestWithBp(t, `
+		android_library {
+			name: "foo",
+			srcs: ["a.java"],
+			sdk_version: "current",
+			flags_packages: [
+				"bar",
+				"baz",
+			],
+		}
+		aconfig_declarations {
+			name: "bar",
+			package: "com.example.package.bar",
+			srcs: [
+				"bar.aconfig",
+			],
+		}
+		aconfig_declarations {
+			name: "baz",
+			package: "com.example.package.baz",
+			srcs: [
+				"baz.aconfig",
+			],
+		}
+	`)
+
+	foo := result.ModuleForTests("foo", "android_common")
+
+	// android_library module depends on aconfig_declarations listed in flags_packages
+	android.AssertBoolEquals(t, "foo expected to depend on bar", true,
+		CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "bar"))
+
+	android.AssertBoolEquals(t, "foo expected to depend on baz", true,
+		CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "baz"))
+
+	aapt2LinkRule := foo.Rule("android/soong/java.aapt2Link")
+	linkInFlags := aapt2LinkRule.Args["inFlags"]
+	android.AssertStringDoesContain(t,
+		"aapt2 link command expected to pass feature flags arguments",
+		linkInFlags,
+		"--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt",
+	)
+}
+
+func TestAndroidLibraryOutputFilesRel(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+	).RunTestWithBp(t, `
+		android_library {
+			name: "foo",
+			srcs: ["a.java"],
+			java_resources: ["foo.txt"],
+		}
+
+		android_library_import {
+			name: "bar",
+			aars: ["bar_prebuilt.aar"],
+
+		}
+
+		android_library_import {
+			name: "baz",
+			aars: ["baz_prebuilt.aar"],
+			static_libs: ["foo", "bar"],
+		}
+	`)
+
+	foo := result.ModuleForTests("foo", "android_common")
+	bar := result.ModuleForTests("bar", "android_common")
+	baz := result.ModuleForTests("baz", "android_common")
+
+	fooOutputPath := android.OutputFileForModule(android.PathContext(nil), foo.Module(), "")
+	barOutputPath := android.OutputFileForModule(android.PathContext(nil), bar.Module(), "")
+	bazOutputPath := android.OutputFileForModule(android.PathContext(nil), baz.Module(), "")
+
+	android.AssertPathRelativeToTopEquals(t, "foo output path",
+		"out/soong/.intermediates/foo/android_common/withres/foo.jar", fooOutputPath)
+	android.AssertPathRelativeToTopEquals(t, "bar output path",
+		"out/soong/.intermediates/bar/android_common/aar/bar.jar", barOutputPath)
+	android.AssertPathRelativeToTopEquals(t, "baz output path",
+		"out/soong/.intermediates/baz/android_common/withres/baz.jar", bazOutputPath)
+
+	android.AssertStringEquals(t, "foo relative output path",
+		"foo.jar", fooOutputPath.Rel())
+	android.AssertStringEquals(t, "bar relative output path",
+		"bar.jar", barOutputPath.Rel())
+	android.AssertStringEquals(t, "baz relative output path",
+		"baz.jar", bazOutputPath.Rel())
+}
diff --git a/java/android_manifest.go b/java/android_manifest.go
index f2ebfa6..8599003 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -152,9 +152,10 @@
 	if params.SdkContext != nil {
 		targetSdkVersion := targetSdkVersionForManifestFixer(ctx, params)
 
-		if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
-			targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
-			deps = append(deps, ApiFingerprintPath(ctx))
+		if useApiFingerprint, fingerprintTargetSdkVersion, fingerprintDeps :=
+			UseApiFingerprint(ctx); useApiFingerprint && ctx.ModuleName() != "framework-res" {
+			targetSdkVersion = fingerprintTargetSdkVersion
+			deps = append(deps, fingerprintDeps)
 		}
 
 		args = append(args, "--targetSdkVersion ", targetSdkVersion)
@@ -169,9 +170,10 @@
 			ctx.ModuleErrorf("invalid ReplaceMaxSdkVersionPlaceholder: %s", err)
 		}
 
-		if UseApiFingerprint(ctx) && ctx.ModuleName() != "framework-res" {
-			minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", ApiFingerprintPath(ctx).String())
-			deps = append(deps, ApiFingerprintPath(ctx))
+		if useApiFingerprint, fingerprintMinSdkVersion, fingerprintDeps :=
+			UseApiFingerprint(ctx); useApiFingerprint && ctx.ModuleName() != "framework-res" {
+			minSdkVersion = fingerprintMinSdkVersion
+			deps = append(deps, fingerprintDeps)
 		}
 
 		if err != nil {
@@ -200,13 +202,24 @@
 	return fixedManifest.WithoutRel()
 }
 
-func manifestMerger(ctx android.ModuleContext, manifest android.Path, staticLibManifests android.Paths,
-	isLibrary bool) android.Path {
+type ManifestMergerParams struct {
+	staticLibManifests android.Paths
+	isLibrary          bool
+	packageName        string
+}
 
-	var args string
-	if !isLibrary {
+func manifestMerger(ctx android.ModuleContext, manifest android.Path,
+	params ManifestMergerParams) android.Path {
+
+	var args []string
+	if !params.isLibrary {
 		// Follow Gradle's behavior, only pass --remove-tools-declarations when merging app manifests.
-		args = "--remove-tools-declarations"
+		args = append(args, "--remove-tools-declarations")
+	}
+
+	packageName := params.packageName
+	if packageName != "" {
+		args = append(args, "--property PACKAGE="+packageName)
 	}
 
 	mergedManifest := android.PathForModuleOut(ctx, "manifest_merger", "AndroidManifest.xml")
@@ -214,11 +227,11 @@
 		Rule:        manifestMergerRule,
 		Description: "merge manifest",
 		Input:       manifest,
-		Implicits:   staticLibManifests,
+		Implicits:   params.staticLibManifests,
 		Output:      mergedManifest,
 		Args: map[string]string{
-			"libs": android.JoinWithPrefix(staticLibManifests.Strings(), "--libs "),
-			"args": args,
+			"libs": android.JoinWithPrefix(params.staticLibManifests.Strings(), "--libs "),
+			"args": strings.Join(args, " "),
 		},
 	})
 
diff --git a/java/android_manifest_test.go b/java/android_manifest_test.go
index b12d778..7c91884 100644
--- a/java/android_manifest_test.go
+++ b/java/android_manifest_test.go
@@ -15,8 +15,9 @@
 package java
 
 import (
-	"android/soong/android"
 	"testing"
+
+	"android/soong/android"
 )
 
 func TestManifestMerger(t *testing.T) {
@@ -77,10 +78,7 @@
 		}
 	`
 
-	result := android.GroupFixturePreparers(
-		PrepareForTestWithJavaDefaultModules,
-		PrepareForTestWithOverlayBuildComponents,
-	).RunTestWithBp(t, bp)
+	result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, bp)
 
 	manifestMergerRule := result.ModuleForTests("app", "android_common").Rule("manifestMerger")
 	android.AssertPathRelativeToTopEquals(t, "main manifest",
@@ -94,10 +92,44 @@
 			"out/soong/.intermediates/transitive/android_common/manifest_fixer/AndroidManifest.xml",
 			"transitive/AndroidManifest2.xml",
 			"out/soong/.intermediates/transitive_import/android_common/aar/AndroidManifest.xml",
+			"out/soong/.intermediates/transitive_import_dep/android_common/aar/AndroidManifest.xml",
 			"out/soong/.intermediates/direct_import/android_common/aar/AndroidManifest.xml",
-			// TODO(b/288358614): Soong has historically not merged manifests from dependencies of
-			// android_library_import modules.
-
+			"out/soong/.intermediates/direct_import_dep/android_common/aar/AndroidManifest.xml",
 		},
 		manifestMergerRule.Implicits)
 }
+
+func TestManifestValuesApplicationIdSetsPackageName(t *testing.T) {
+	bp := `
+		android_test {
+			name: "test",
+			sdk_version: "current",
+			srcs: ["app/app.java"],
+			manifest: "test/AndroidManifest.xml",
+			additional_manifests: ["test/AndroidManifest2.xml"],
+			static_libs: ["direct"],
+      test_suites: ["device-tests"],
+      manifest_values:  {
+        applicationId: "new_package_name"
+      },
+		}
+
+		android_library {
+			name: "direct",
+			sdk_version: "current",
+			srcs: ["direct/direct.java"],
+			resource_dirs: ["direct/res"],
+			manifest: "direct/AndroidManifest.xml",
+			additional_manifests: ["direct/AndroidManifest2.xml"],
+		}
+
+	`
+
+	result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, bp)
+
+	manifestMergerRule := result.ModuleForTests("test", "android_common").Rule("manifestMerger")
+	android.AssertStringMatches(t,
+		"manifest merger args",
+		manifestMergerRule.Args["args"],
+		"--property PACKAGE=new_package_name")
+}
diff --git a/java/android_resources.go b/java/android_resources.go
index 8c5908f..038a260 100644
--- a/java/android_resources.go
+++ b/java/android_resources.go
@@ -21,14 +21,6 @@
 	"android/soong/android"
 )
 
-func init() {
-	registerOverlayBuildComponents(android.InitRegistrationContext)
-}
-
-func registerOverlayBuildComponents(ctx android.RegistrationContext) {
-	ctx.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
-}
-
 var androidResourceIgnoreFilenames = []string{
 	".svn",
 	".git",
@@ -84,7 +76,38 @@
 func overlayResourceGlob(ctx android.ModuleContext, a *aapt, dir android.Path) (res []globbedResourceDir,
 	rroDirs []rroDir) {
 
-	overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)
+	overlayData := ctx.Config().Once(overlayDataKey, func() interface{} {
+		var overlayData []overlayGlobResult
+
+		appendOverlayData := func(overlayDirs []string, t overlayType) {
+			for i := range overlayDirs {
+				// Iterate backwards through the list of overlay directories so that the later, lower-priority
+				// directories in the list show up earlier in the command line to aapt2.
+				overlay := overlayDirs[len(overlayDirs)-1-i]
+				var result overlayGlobResult
+				result.dir = overlay
+				result.overlayType = t
+
+				files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), androidResourceIgnoreFilenames)
+				if err != nil {
+					ctx.ModuleErrorf("failed to glob resource dir %q: %s", overlay, err.Error())
+					continue
+				}
+				var paths android.Paths
+				for _, f := range files {
+					if !strings.HasSuffix(f, "/") {
+						paths = append(paths, android.PathForSource(ctx, f))
+					}
+				}
+				result.paths = android.PathsToDirectorySortedPaths(paths)
+				overlayData = append(overlayData, result)
+			}
+		}
+
+		appendOverlayData(ctx.Config().DeviceResourceOverlays(), device)
+		appendOverlayData(ctx.Config().ProductResourceOverlays(), product)
+		return overlayData
+	}).([]overlayGlobResult)
 
 	// Runtime resource overlays (RRO) may be turned on by the product config for some modules
 	rroEnabled := a.IsRROEnforced(ctx)
@@ -110,44 +133,3 @@
 
 	return res, rroDirs
 }
-
-func OverlaySingletonFactory() android.Singleton {
-	return overlaySingleton{}
-}
-
-type overlaySingleton struct{}
-
-func (overlaySingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	var overlayData []overlayGlobResult
-
-	appendOverlayData := func(overlayDirs []string, t overlayType) {
-		for i := range overlayDirs {
-			// Iterate backwards through the list of overlay directories so that the later, lower-priority
-			// directories in the list show up earlier in the command line to aapt2.
-			overlay := overlayDirs[len(overlayDirs)-1-i]
-			var result overlayGlobResult
-			result.dir = overlay
-			result.overlayType = t
-
-			files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), androidResourceIgnoreFilenames)
-			if err != nil {
-				ctx.Errorf("failed to glob resource dir %q: %s", overlay, err.Error())
-				continue
-			}
-			var paths android.Paths
-			for _, f := range files {
-				if !strings.HasSuffix(f, "/") {
-					paths = append(paths, android.PathForSource(ctx, f))
-				}
-			}
-			result.paths = android.PathsToDirectorySortedPaths(paths)
-			overlayData = append(overlayData, result)
-		}
-	}
-
-	appendOverlayData(ctx.Config().DeviceResourceOverlays(), device)
-	appendOverlayData(ctx.Config().ProductResourceOverlays(), product)
-	ctx.Config().Once(overlayDataKey, func() interface{} {
-		return overlayData
-	})
-}
diff --git a/java/androidmk.go b/java/androidmk.go
index 82505e9..a52d439 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -20,6 +20,8 @@
 	"strings"
 
 	"android/soong/android"
+
+	"github.com/google/blueprint/proptools"
 )
 
 func (library *Library) AndroidMkEntriesHostDex() android.AndroidMkEntries {
@@ -79,6 +81,9 @@
 	} else if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) {
 		// Platform variant.  If not available for the platform, we don't need Make module.
 		entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true})
+	} else if proptools.Bool(library.properties.Headers_only) {
+		// If generating headers only then don't expose to Make.
+		entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true})
 	} else {
 		entriesList = append(entriesList, android.AndroidMkEntries{
 			Class:      "JAVA_LIBRARIES",
@@ -123,8 +128,7 @@
 					if library.dexpreopter.configPath != nil {
 						entries.SetPath("LOCAL_SOONG_DEXPREOPT_CONFIG", library.dexpreopter.configPath)
 					}
-
-					entries.SetOptionalPaths("LOCAL_ACONFIG_FILES", library.getTransitiveAconfigFiles().ToList())
+					android.SetAconfigFileMkEntries(&library.ModuleBase, entries, library.mergedAconfigFiles)
 				},
 			},
 		})
@@ -202,24 +206,21 @@
 
 func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries {
 	if prebuilt.hideApexVariantFromMake {
-		// For a library imported from a prebuilt APEX, we don't need a Make module for itself, as we
-		// don't need to install it. However, we need to add its dexpreopt outputs as sub-modules, if it
-		// is preopted.
-		dexpreoptEntries := prebuilt.dexpreopter.AndroidMkEntriesForApex()
-		return append(dexpreoptEntries, android.AndroidMkEntries{Disabled: true})
+		return []android.AndroidMkEntries{}
 	}
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
-		Class:      "JAVA_LIBRARIES",
-		OutputFile: android.OptionalPathForPath(prebuilt.combinedClasspathFile),
-		Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
+		Class:        "JAVA_LIBRARIES",
+		OverrideName: prebuilt.BaseModuleName(),
+		OutputFile:   android.OptionalPathForPath(prebuilt.combinedImplementationFile),
+		Include:      "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 				entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable))
 				if prebuilt.dexJarFile.IsSet() {
 					entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile.Path())
 				}
-				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile)
-				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile)
+				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedHeaderFile)
+				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedImplementationFile)
 				entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String())
 				entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
 				// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
@@ -261,15 +262,15 @@
 	}
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
 		Class:      "JAVA_LIBRARIES",
-		OutputFile: android.OptionalPathForPath(prebuilt.classpathFile),
+		OutputFile: android.OptionalPathForPath(prebuilt.implementationJarFile),
 		Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 				entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
-				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.classpathFile)
-				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.classpathFile)
+				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.headerJarFile)
+				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.implementationJarFile)
 				entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", prebuilt.exportPackage)
-				entries.SetPaths("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", prebuilt.transitiveAaptResourcePackages)
+				entries.SetPath("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", prebuilt.transitiveAaptResourcePackagesFile)
 				entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags)
 				entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", prebuilt.extraAaptPackagesFile)
 				entries.SetPath("LOCAL_FULL_MANIFEST_FILE", prebuilt.manifest)
@@ -301,7 +302,7 @@
 					if len(binary.dexpreopter.builtInstalled) > 0 {
 						entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", binary.dexpreopter.builtInstalled)
 					}
-					entries.SetOptionalPaths("LOCAL_ACONFIG_FILES", binary.getTransitiveAconfigFiles().ToList())
+					android.SetAconfigFileMkEntries(&binary.ModuleBase, entries, binary.mergedAconfigFiles)
 				},
 			},
 			ExtraFooters: []android.AndroidMkExtraFootersFunc{
@@ -338,10 +339,15 @@
 			Disabled: true,
 		}}
 	}
+	var required []string
+	if proptools.Bool(app.appProperties.Generate_product_characteristics_rro) {
+		required = []string{app.productCharacteristicsRROPackageName()}
+	}
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
 		Class:      "APPS",
 		OutputFile: android.OptionalPathForPath(app.outputFile),
 		Include:    "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+		Required:   required,
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 				// App module names can be overridden.
@@ -449,7 +455,7 @@
 				entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", app.linter.reports)
 
 				if app.Name() != "framework-res" {
-					entries.SetOptionalPaths("LOCAL_ACONFIG_FILES", app.getTransitiveAconfigFiles().ToList())
+					android.SetAconfigFileMkEntries(&app.ModuleBase, entries, app.mergedAconfigFiles)
 				}
 			},
 		},
@@ -522,12 +528,12 @@
 		}
 
 		entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.exportPackage)
-		entries.SetPaths("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", a.transitiveAaptResourcePackages)
+		entries.SetPath("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", a.transitiveAaptResourcePackagesFile)
 		entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", a.extraAaptPackagesFile)
 		entries.SetPath("LOCAL_FULL_MANIFEST_FILE", a.mergedManifestFile)
-		entries.AddStrings("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", a.exportedProguardFlagFiles.Strings()...)
+		entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", a.combinedExportedProguardFlagsFile)
 		entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", true)
-		entries.SetOptionalPaths("LOCAL_ACONFIG_FILES", a.getTransitiveAconfigFiles().ToList())
+		android.SetAconfigFileMkEntries(&a.ModuleBase, entries, a.mergedAconfigFiles)
 	})
 
 	return entriesList
@@ -543,8 +549,8 @@
 				if BoolDefault(jd.properties.Installable, true) {
 					entries.SetPath("LOCAL_DROIDDOC_DOC_ZIP", jd.docZip)
 				}
-				if jd.stubsSrcJar != nil {
-					entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", jd.stubsSrcJar)
+				if jd.exportableStubsSrcJar != nil {
+					entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", jd.exportableStubsSrcJar)
 				}
 			},
 		},
@@ -582,7 +588,7 @@
 		outputFile = android.OptionalPathForPath(dstubs.apiFile)
 	}
 	if !outputFile.Valid() {
-		outputFile = android.OptionalPathForPath(dstubs.apiVersionsXml)
+		outputFile = android.OptionalPathForPath(dstubs.everythingArtifacts.apiVersionsXml)
 	}
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
 		Class:      "JAVA_LIBRARIES",
@@ -590,17 +596,17 @@
 		Include:    "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
-				if dstubs.Javadoc.stubsSrcJar != nil {
-					entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", dstubs.Javadoc.stubsSrcJar)
+				if dstubs.Javadoc.exportableStubsSrcJar != nil {
+					entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", dstubs.Javadoc.exportableStubsSrcJar)
 				}
-				if dstubs.apiVersionsXml != nil {
-					entries.SetPath("LOCAL_DROIDDOC_API_VERSIONS_XML", dstubs.apiVersionsXml)
+				if dstubs.everythingArtifacts.apiVersionsXml != nil {
+					entries.SetPath("LOCAL_DROIDDOC_API_VERSIONS_XML", dstubs.exportableArtifacts.apiVersionsXml)
 				}
-				if dstubs.annotationsZip != nil {
-					entries.SetPath("LOCAL_DROIDDOC_ANNOTATIONS_ZIP", dstubs.annotationsZip)
+				if dstubs.everythingArtifacts.annotationsZip != nil {
+					entries.SetPath("LOCAL_DROIDDOC_ANNOTATIONS_ZIP", dstubs.exportableArtifacts.annotationsZip)
 				}
-				if dstubs.metadataZip != nil {
-					entries.SetPath("LOCAL_DROIDDOC_METADATA_ZIP", dstubs.metadataZip)
+				if dstubs.everythingArtifacts.metadataZip != nil {
+					entries.SetPath("LOCAL_DROIDDOC_METADATA_ZIP", dstubs.exportableArtifacts.metadataZip)
 				}
 			},
 		},
@@ -685,9 +691,10 @@
 		return nil
 	}
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
-		Class:      "APPS",
-		OutputFile: android.OptionalPathForPath(a.outputFile),
-		Include:    "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+		Class:        "APPS",
+		OutputFile:   android.OptionalPathForPath(a.outputFile),
+		OverrideName: a.BaseModuleName(), // TODO (spandandas): Add a test
+		Include:      "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 				entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", a.Privileged())
diff --git a/java/app.go b/java/app.go
old mode 100755
new mode 100644
index e277aed..50d1a2f
--- a/java/app.go
+++ b/java/app.go
@@ -22,13 +22,15 @@
 	"path/filepath"
 	"strings"
 
+	"android/soong/testing"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/cc"
 	"android/soong/dexpreopt"
+	"android/soong/genrule"
 	"android/soong/tradefed"
 )
 
@@ -128,6 +130,16 @@
 
 	// Specifies the file that contains the allowlist for this app.
 	Privapp_allowlist *string `android:"path"`
+
+	// If set, create an RRO package which contains only resources having PRODUCT_CHARACTERISTICS
+	// and install the RRO package to /product partition, instead of passing --product argument
+	// to aapt2. Default is false.
+	// Setting this will make this APK identical to all targets, regardless of
+	// PRODUCT_CHARACTERISTICS.
+	Generate_product_characteristics_rro *bool
+
+	ProductCharacteristicsRROPackageName        *string `blueprint:"mutated"`
+	ProductCharacteristicsRROManifestModuleName *string `blueprint:"mutated"`
 }
 
 // android_app properties that can be overridden by override_android_app
@@ -160,7 +172,6 @@
 }
 
 type AndroidApp struct {
-	android.BazelModuleBase
 	Library
 	aapt
 	android.OverridableModuleBase
@@ -200,10 +211,6 @@
 	return Bool(a.properties.Installable)
 }
 
-func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
-	return nil
-}
-
 func (a *AndroidApp) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
 	return a.aapt.resourcesNodesDepSet
 }
@@ -242,13 +249,13 @@
 }
 
 func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
-	a.Module.deps(ctx)
-
 	if String(a.appProperties.Stl) == "c++_shared" && !a.SdkVersion(ctx).Specified() {
 		ctx.PropertyErrorf("stl", "sdk_version must be set in order to use c++_shared")
 	}
 
 	sdkDep := decodeSdkDep(ctx, android.SdkContext(a))
+	a.usesLibrary.deps(ctx, sdkDep.hasFrameworkLibs())
+	a.Module.deps(ctx)
 	if sdkDep.hasFrameworkLibs() {
 		a.aapt.deps(ctx, sdkDep)
 	}
@@ -278,8 +285,9 @@
 		}
 		ctx.AddFarVariationDependencies(variation, jniLibTag, a.appProperties.Jni_libs...)
 	}
-
-	a.usesLibrary.deps(ctx, sdkDep.hasFrameworkLibs())
+	for _, aconfig_declaration := range a.aaptProperties.Flags_packages {
+		ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration)
+	}
 }
 
 func (a *AndroidApp) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) {
@@ -310,7 +318,18 @@
 }
 
 func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	applicationId := a.appTestHelperAppProperties.Manifest_values.ApplicationId
+	if applicationId != nil {
+		if a.overridableAppProperties.Package_name != nil {
+			ctx.PropertyErrorf("manifest_values.applicationId", "property is not supported when property package_name is set.")
+		}
+		a.aapt.manifestValues.applicationId = *applicationId
+	}
 	a.generateAndroidBuildActions(ctx)
+	android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
+		TestOnly: true,
+	})
+
 }
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -319,6 +338,17 @@
 	a.generateJavaUsedByApex(ctx)
 }
 
+func (a *AndroidApp) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
+	defaultMinSdkVersion := a.Module.MinSdkVersion(ctx)
+	if proptools.Bool(a.appProperties.Updatable) {
+		overrideApiLevel := android.MinSdkVersionFromValue(ctx, ctx.DeviceConfig().ApexGlobalMinSdkVersionOverride())
+		if !overrideApiLevel.IsNone() && overrideApiLevel.CompareTo(defaultMinSdkVersion) > 0 {
+			return overrideApiLevel
+		}
+	}
+	return defaultMinSdkVersion
+}
+
 func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
 	if a.Updatable() {
 		if !a.SdkVersion(ctx).Stable() {
@@ -378,7 +408,7 @@
 		ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.MinSdkVersion(ctx), err)
 	}
 
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	return (minSdkVersion.FinalOrFutureInt() >= 23 && Bool(a.appProperties.Use_embedded_native_libs)) ||
 		!apexInfo.IsForPlatform()
 }
@@ -399,11 +429,11 @@
 		return false
 	}
 
-	return shouldUncompressDex(ctx, &a.dexpreopter)
+	return shouldUncompressDex(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), &a.dexpreopter)
 }
 
 func (a *AndroidApp) shouldEmbedJnis(ctx android.BaseModuleContext) bool {
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	return ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) ||
 		!apexInfo.IsForPlatform() || a.appProperties.AlwaysPackageNativeLibs
 }
@@ -425,6 +455,21 @@
 	return proptools.BoolDefault(a.overridableAppProperties.Rename_resources_package, true)
 }
 
+func getAconfigFilePaths(ctx android.ModuleContext) (aconfigTextFilePaths android.Paths) {
+	ctx.VisitDirectDepsWithTag(aconfigDeclarationTag, func(dep android.Module) {
+		if provider, ok := android.OtherModuleProvider(ctx, dep, android.AconfigDeclarationsProviderKey); ok {
+			aconfigTextFilePaths = append(aconfigTextFilePaths, provider.IntermediateDumpOutputPath)
+		} else {
+			ctx.ModuleErrorf("Only aconfig_declarations module type is allowed for "+
+				"flags_packages property, but %s is not aconfig_declarations module type",
+				dep.Name(),
+			)
+		}
+	})
+
+	return aconfigTextFilePaths
+}
+
 func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
 	usePlatformAPI := proptools.Bool(a.Module.deviceProperties.Platform_apis)
 	if ctx.Module().(android.SdkContext).SdkVersion(ctx).Kind == android.SdkModule {
@@ -438,9 +483,11 @@
 	aaptLinkFlags := []string{}
 
 	// Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided.
+	autogenerateRRO := proptools.Bool(a.appProperties.Generate_product_characteristics_rro)
 	hasProduct := android.PrefixInList(a.aaptProperties.Aaptflags, "--product")
-	if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
-		aaptLinkFlags = append(aaptLinkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
+	characteristics := ctx.Config().ProductAAPTCharacteristics()
+	if !autogenerateRRO && !hasProduct && len(characteristics) > 0 && characteristics != "default" {
+		aaptLinkFlags = append(aaptLinkFlags, "--product", characteristics)
 	}
 
 	if !Bool(a.aaptProperties.Aapt_include_all_resources) {
@@ -472,8 +519,21 @@
 	if a.Updatable() {
 		a.aapt.defaultManifestVersion = android.DefaultUpdatableModuleVersion
 	}
-	a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts,
-		a.usesLibraryProperties.Exclude_uses_libs, a.enforceDefaultTargetSdkVersion(), aaptLinkFlags...)
+
+	// Use non final ids if we are doing optimized shrinking and are using R8.
+	nonFinalIds := Bool(a.dexProperties.Optimize.Optimized_shrink_resources) && a.dexer.effectiveOptimizeEnabled()
+	a.aapt.buildActions(ctx,
+		aaptBuildActionOptions{
+			sdkContext:                     android.SdkContext(a),
+			classLoaderContexts:            a.classLoaderContexts,
+			excludedLibs:                   a.usesLibraryProperties.Exclude_uses_libs,
+			enforceDefaultTargetSdkVersion: a.enforceDefaultTargetSdkVersion(),
+			forceNonFinalResourceIDs:       nonFinalIds,
+			extraLinkFlags:                 aaptLinkFlags,
+			aconfigTextFiles:               getAconfigFilePaths(ctx),
+			usesLibrary:                    &a.usesLibrary,
+		},
+	)
 
 	// apps manifests are handled by aapt, don't let Module see them
 	a.properties.Manifest = nil
@@ -482,15 +542,23 @@
 func (a *AndroidApp) proguardBuildActions(ctx android.ModuleContext) {
 	var staticLibProguardFlagFiles android.Paths
 	ctx.VisitDirectDeps(func(m android.Module) {
-		if lib, ok := m.(LibraryDependency); ok && ctx.OtherModuleDependencyTag(m) == staticLibTag {
-			staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, lib.ExportedProguardFlagFiles()...)
+		depProguardInfo, _ := android.OtherModuleProvider(ctx, m, ProguardSpecInfoProvider)
+		staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, depProguardInfo.UnconditionallyExportedProguardFlags.ToList()...)
+		if ctx.OtherModuleDependencyTag(m) == staticLibTag {
+			staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, depProguardInfo.ProguardFlagsFiles.ToList()...)
 		}
 	})
 
 	staticLibProguardFlagFiles = android.FirstUniquePaths(staticLibProguardFlagFiles)
 
-	a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles, staticLibProguardFlagFiles...)
-	a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles, a.proguardOptionsFile)
+	a.Module.extraProguardFlagsFiles = append(a.Module.extraProguardFlagsFiles, staticLibProguardFlagFiles...)
+	if !Bool(a.dexProperties.Optimize.Optimized_shrink_resources) {
+		// When using the optimized shrinking the R8 enqueuer will traverse the xml files that become
+		// live for code references and (transitively) mark these as live.
+		// In this case we explicitly don't wan't the aapt2 generated keep files (which would keep the now
+		// dead code alive)
+		a.Module.extraProguardFlagsFiles = append(a.Module.extraProguardFlagsFiles, a.proguardOptionsFile)
+	}
 }
 
 func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath {
@@ -507,7 +575,7 @@
 	return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
 }
 
-func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
+func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) (android.Path, android.Path) {
 	a.dexpreopter.installPath = a.installPath(ctx)
 	a.dexpreopter.isApp = true
 	if a.dexProperties.Uncompress_dex == nil {
@@ -520,11 +588,19 @@
 	a.dexpreopter.manifestFile = a.mergedManifestFile
 	a.dexpreopter.preventInstall = a.appProperties.PreventInstall
 
+	var packageResources = a.exportPackage
+
 	if ctx.ModuleName() != "framework-res" {
+		if a.dexProperties.resourceShrinkingEnabled() {
+			protoFile := android.PathForModuleOut(ctx, packageResources.Base()+".proto.apk")
+			aapt2Convert(ctx, protoFile, packageResources, "proto")
+			a.dexer.resourcesInput = android.OptionalPathForPath(protoFile)
+		}
+
 		var extraSrcJars android.Paths
 		var extraClasspathJars android.Paths
 		var extraCombinedJars android.Paths
-		if a.useResourceProcessorBusyBox() {
+		if a.useResourceProcessorBusyBox(ctx) {
 			// When building an app with ResourceProcessorBusyBox enabled ResourceProcessorBusyBox has already
 			// created R.class files that provide IDs for resources in busybox/R.jar.  Pass that file in the
 			// classpath when compiling everything else, and add it to the final classes jar.
@@ -538,9 +614,14 @@
 		}
 
 		a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
+		if a.dexProperties.resourceShrinkingEnabled() {
+			binaryResources := android.PathForModuleOut(ctx, packageResources.Base()+".binary.out.apk")
+			aapt2Convert(ctx, binaryResources, a.dexer.resourcesOutput.Path(), "binary")
+			packageResources = binaryResources
+		}
 	}
 
-	return a.dexJarFile.PathOrNil()
+	return a.dexJarFile.PathOrNil(), packageResources
 }
 
 func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, prebuiltJniPackages android.Paths, ctx android.ModuleContext) android.WritablePath {
@@ -675,7 +756,8 @@
 func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
 	var apkDeps android.Paths
 
-	if !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() {
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+	if !apexInfo.IsForPlatform() {
 		a.hideApexVariantFromMake = true
 	}
 
@@ -684,7 +766,7 @@
 
 	// Unlike installApkName, a.stem should respect base module name for override_android_app.
 	// Therefore, use ctx.ModuleName() instead of a.Name().
-	a.stem = proptools.StringDefault(a.overridableDeviceProperties.Stem, ctx.ModuleName())
+	a.stem = proptools.StringDefault(a.overridableProperties.Stem, ctx.ModuleName())
 
 	// Check if the install APK name needs to be overridden.
 	// Both android_app and override_android_app module are expected to possess
@@ -692,7 +774,7 @@
 	// from the base module. Therefore, use a.Name() which represents
 	// the module name for both android_app and override_android_app.
 	a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(
-		proptools.StringDefault(a.overridableDeviceProperties.Stem, a.Name()))
+		proptools.StringDefault(a.overridableProperties.Stem, a.Name()))
 
 	if ctx.ModuleName() == "framework-res" {
 		// framework-res.apk is installed as system/framework/framework-res.apk
@@ -707,6 +789,9 @@
 	a.onDeviceDir = android.InstallPathToOnDevicePath(ctx, a.installDir)
 
 	a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+	if a.usesLibrary.shouldDisableDexpreopt {
+		a.dexpreopter.disableDexpreopt()
+	}
 
 	var noticeAssetPath android.WritablePath
 	if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
@@ -725,22 +810,13 @@
 
 	// Process all building blocks, from AAPT to certificates.
 	a.aaptBuildActions(ctx)
-
 	// The decision to enforce <uses-library> checks is made before adding implicit SDK libraries.
 	a.usesLibrary.freezeEnforceUsesLibraries()
 
-	// Add implicit SDK libraries to <uses-library> list.
-	requiredUsesLibs, optionalUsesLibs := a.classLoaderContexts.UsesLibs()
-	for _, usesLib := range requiredUsesLibs {
-		a.usesLibrary.addLib(usesLib, false)
-	}
-	for _, usesLib := range optionalUsesLibs {
-		a.usesLibrary.addLib(usesLib, true)
-	}
-
 	// Check that the <uses-library> list is coherent with the manifest.
 	if a.usesLibrary.enforceUsesLibraries() {
-		manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest(ctx, a.mergedManifestFile)
+		manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest(
+			ctx, a.mergedManifestFile, &a.classLoaderContexts)
 		apkDeps = append(apkDeps, manifestCheckFile)
 	}
 
@@ -751,7 +827,7 @@
 	a.linter.resources = a.aapt.resourceFiles
 	a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps()
 
-	dexJarFile := a.dexBuildActions(ctx)
+	dexJarFile, packageResources := a.dexBuildActions(ctx)
 
 	jniLibs, prebuiltJniPackages, certificates := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
 	jniJarFile := a.jniBuildActions(jniLibs, prebuiltJniPackages, ctx)
@@ -775,7 +851,7 @@
 	}
 	rotationMinSdkVersion := String(a.overridableAppProperties.RotationMinSdkVersion)
 
-	CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion, Bool(a.dexProperties.Optimize.Shrink_resources))
+	CreateAndSignAppPackage(ctx, packageFile, packageResources, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion)
 	a.outputFile = packageFile
 	if v4SigningRequested {
 		a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
@@ -804,7 +880,7 @@
 		if v4SigningRequested {
 			v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig")
 		}
-		CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion, false)
+		CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion)
 		a.extraOutputFiles = append(a.extraOutputFiles, packageFile)
 		if v4SigningRequested {
 			a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile)
@@ -821,8 +897,6 @@
 		a.privAppAllowlist = android.OptionalPathForPath(allowlist)
 	}
 
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
-
 	// Install the app package.
 	shouldInstallAppPackage := (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() && !a.appProperties.PreventInstall
 	if shouldInstallAppPackage {
@@ -832,7 +906,7 @@
 			ctx.InstallFile(allowlistInstallPath, allowlistInstallFilename, a.privAppAllowlist.Path())
 		}
 
-		var extraInstalledPaths android.Paths
+		var extraInstalledPaths android.InstallPaths
 		for _, extra := range a.extraOutputFiles {
 			installed := ctx.InstallFile(a.installDir, extra.Base(), extra)
 			extraInstalledPaths = append(extraInstalledPaths, installed)
@@ -841,6 +915,13 @@
 	}
 
 	a.buildAppDependencyInfo(ctx)
+
+	providePrebuiltInfo(ctx,
+		prebuiltInfoProps{
+			baseModuleName: a.BaseModuleName(),
+			isPrebuilt:     false,
+		},
+	)
 }
 
 type appDepsInterface interface {
@@ -853,15 +934,39 @@
 	shouldCollectRecursiveNativeDeps bool,
 	checkNativeSdkVersion bool) ([]jniLib, android.Paths, []Certificate) {
 
-	var jniLibs []jniLib
-	var prebuiltJniPackages android.Paths
-	var certificates []Certificate
-	seenModulePaths := make(map[string]bool)
-
 	if checkNativeSdkVersion {
 		checkNativeSdkVersion = app.SdkVersion(ctx).Specified() &&
 			app.SdkVersion(ctx).Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx)
 	}
+	jniLib, prebuiltJniPackages := collectJniDeps(ctx, shouldCollectRecursiveNativeDeps,
+		checkNativeSdkVersion, func(dep cc.LinkableInterface) bool {
+			return !dep.IsNdk(ctx.Config()) && !dep.IsStubs()
+		})
+
+	var certificates []Certificate
+
+	ctx.VisitDirectDeps(func(module android.Module) {
+		otherName := ctx.OtherModuleName(module)
+		tag := ctx.OtherModuleDependencyTag(module)
+
+		if tag == certificateTag {
+			if dep, ok := module.(*AndroidAppCertificate); ok {
+				certificates = append(certificates, dep.Certificate)
+			} else {
+				ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", otherName)
+			}
+		}
+	})
+	return jniLib, prebuiltJniPackages, certificates
+}
+
+func collectJniDeps(ctx android.ModuleContext,
+	shouldCollectRecursiveNativeDeps bool,
+	checkNativeSdkVersion bool,
+	filter func(cc.LinkableInterface) bool) ([]jniLib, android.Paths) {
+	var jniLibs []jniLib
+	var prebuiltJniPackages android.Paths
+	seenModulePaths := make(map[string]bool)
 
 	ctx.WalkDeps(func(module android.Module, parent android.Module) bool {
 		otherName := ctx.OtherModuleName(module)
@@ -869,7 +974,7 @@
 
 		if IsJniDepTag(tag) || cc.IsSharedDepTag(tag) {
 			if dep, ok := module.(cc.LinkableInterface); ok {
-				if dep.IsNdk(ctx.Config()) || dep.IsStubs() {
+				if filter != nil && !filter(dep) {
 					return false
 				}
 
@@ -906,22 +1011,14 @@
 			return shouldCollectRecursiveNativeDeps
 		}
 
-		if info, ok := ctx.OtherModuleProvider(module, JniPackageProvider).(JniPackageInfo); ok {
+		if info, ok := android.OtherModuleProvider(ctx, module, JniPackageProvider); ok {
 			prebuiltJniPackages = append(prebuiltJniPackages, info.JniPackages...)
 		}
 
-		if tag == certificateTag {
-			if dep, ok := module.(*AndroidAppCertificate); ok {
-				certificates = append(certificates, dep.Certificate)
-			} else {
-				ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", otherName)
-			}
-		}
-
 		return false
 	})
 
-	return jniLibs, prebuiltJniPackages, certificates
+	return jniLibs, prebuiltJniPackages
 }
 
 func (a *AndroidApp) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) {
@@ -1029,8 +1126,12 @@
 		if a.rJar != nil {
 			return []android.Path{a.rJar}, nil
 		}
+	case ".apk":
+		return []android.Path{a.outputFile}, nil
 	case ".export-package.apk":
 		return []android.Path{a.exportPackage}, nil
+	case ".manifest.xml":
+		return []android.Path{a.aapt.manifestPath}, nil
 	}
 	return a.Library.OutputFiles(tag)
 }
@@ -1039,7 +1140,7 @@
 	return Bool(a.appProperties.Privileged)
 }
 
-func (a *AndroidApp) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
+func (a *AndroidApp) IsNativeCoverageNeeded(ctx android.IncomingTransitionContext) bool {
 	return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
 }
 
@@ -1055,12 +1156,26 @@
 
 var _ cc.Coverage = (*AndroidApp)(nil)
 
+func (a *AndroidApp) IDEInfo(dpInfo *android.IdeInfo) {
+	a.Library.IDEInfo(dpInfo)
+	a.aapt.IDEInfo(dpInfo)
+}
+
+func (a *AndroidApp) productCharacteristicsRROPackageName() string {
+	return proptools.String(a.appProperties.ProductCharacteristicsRROPackageName)
+}
+
+func (a *AndroidApp) productCharacteristicsRROManifestModuleName() string {
+	return proptools.String(a.appProperties.ProductCharacteristicsRROManifestModuleName)
+}
+
 // android_app compiles sources and Android resources into an Android application package `.apk` file.
 func AndroidAppFactory() android.Module {
 	module := &AndroidApp{}
 
 	module.Module.dexProperties.Optimize.EnabledByDefault = true
 	module.Module.dexProperties.Optimize.Shrink = proptools.BoolPtr(true)
+	module.Module.dexProperties.Optimize.Proguard_compatibility = proptools.BoolPtr(false)
 
 	module.Module.properties.Instrument = true
 	module.Module.properties.Supports_static_instrumentation = true
@@ -1070,7 +1185,8 @@
 	module.AddProperties(
 		&module.aaptProperties,
 		&module.appProperties,
-		&module.overridableAppProperties)
+		&module.overridableAppProperties,
+		&module.Library.sourceProperties)
 
 	module.usesLibrary.enforce = true
 
@@ -1078,11 +1194,67 @@
 	android.InitDefaultableModule(module)
 	android.InitOverridableModule(module, &module.overridableAppProperties.Overrides)
 	android.InitApexModule(module)
-	android.InitBazelModule(module)
+
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		a := ctx.Module().(*AndroidApp)
+
+		characteristics := ctx.Config().ProductAAPTCharacteristics()
+		if characteristics == "default" || characteristics == "" {
+			module.appProperties.Generate_product_characteristics_rro = nil
+			// no need to create RRO
+			return
+		}
+
+		if !proptools.Bool(module.appProperties.Generate_product_characteristics_rro) {
+			return
+		}
+
+		rroPackageName := a.Name() + "__" + strings.ReplaceAll(characteristics, ",", "_") + "__auto_generated_characteristics_rro"
+		rroManifestName := rroPackageName + "_manifest"
+
+		a.appProperties.ProductCharacteristicsRROPackageName = proptools.StringPtr(rroPackageName)
+		a.appProperties.ProductCharacteristicsRROManifestModuleName = proptools.StringPtr(rroManifestName)
+
+		rroManifestProperties := struct {
+			Name  *string
+			Tools []string
+			Out   []string
+			Srcs  []string
+			Cmd   *string
+		}{
+			Name:  proptools.StringPtr(rroManifestName),
+			Tools: []string{"characteristics_rro_generator", "aapt2"},
+			Out:   []string{"AndroidManifest.xml"},
+			Srcs:  []string{":" + a.Name() + "{.apk}"},
+			Cmd:   proptools.StringPtr("$(location characteristics_rro_generator) $$($(location aapt2) dump packagename $(in)) $(out)"),
+		}
+		ctx.CreateModule(genrule.GenRuleFactory, &rroManifestProperties)
+
+		rroProperties := struct {
+			Name           *string
+			Filter_product *string
+			Aaptflags      []string
+			Manifest       *string
+			Resource_dirs  []string
+		}{
+			Name:           proptools.StringPtr(rroPackageName),
+			Filter_product: proptools.StringPtr(characteristics),
+			Aaptflags:      []string{"--auto-add-overlay"},
+			Manifest:       proptools.StringPtr(":" + rroManifestName),
+			Resource_dirs:  a.aaptProperties.Resource_dirs,
+		}
+		ctx.CreateModule(RuntimeResourceOverlayFactory, &rroProperties)
+	})
 
 	return module
 }
 
+// A dictionary of values to be overridden in the manifest.
+type Manifest_values struct {
+	// Overrides the value of package_name in the manifest
+	ApplicationId *string
+}
+
 type appTestProperties struct {
 	// The name of the android_app module that the tests will run against.
 	Instrumentation_for *string
@@ -1092,6 +1264,8 @@
 
 	// If specified, the mainline module package name in the test config is overwritten by it.
 	Mainline_package_name *string
+
+	Manifest_values Manifest_values
 }
 
 type AndroidTest struct {
@@ -1134,6 +1308,13 @@
 			a.additionalAaptFlags = append(a.additionalAaptFlags, "--rename-instrumentation-target-package "+manifestPackageName)
 		}
 	}
+	applicationId := a.appTestProperties.Manifest_values.ApplicationId
+	if applicationId != nil {
+		if a.overridableAppProperties.Package_name != nil {
+			ctx.PropertyErrorf("manifest_values.applicationId", "property is not supported when property package_name is set.")
+		}
+		a.aapt.manifestValues.applicationId = *applicationId
+	}
 	a.generateAndroidBuildActions(ctx)
 
 	for _, module := range a.testProperties.Test_mainline_modules {
@@ -1145,6 +1326,20 @@
 	a.testConfig = a.FixTestConfig(ctx, testConfig)
 	a.extraTestConfigs = android.PathsForModuleSrc(ctx, a.testProperties.Test_options.Extra_test_configs)
 	a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
+	android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+	android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{
+		InstalledFiles:          a.data,
+		OutputFile:              a.OutputFile(),
+		TestConfig:              a.testConfig,
+		HostRequiredModuleNames: a.HostRequiredModuleNames(),
+		TestSuites:              a.testProperties.Test_suites,
+		IsHost:                  false,
+	})
+	android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
+		TestOnly:       true,
+		TopLevelTarget: true,
+	})
+
 }
 
 func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig android.Path) android.Path {
@@ -1221,6 +1416,7 @@
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
 	android.InitOverridableModule(module, &module.overridableAppProperties.Overrides)
+
 	return module
 }
 
@@ -1236,6 +1432,8 @@
 
 	// Install the test into a folder named for the module in all test suites.
 	Per_testcase_directory *bool
+
+	Manifest_values Manifest_values
 }
 
 type AndroidTestHelperApp struct {
@@ -1278,7 +1476,6 @@
 
 type AndroidAppCertificate struct {
 	android.ModuleBase
-	android.BazelModuleBase
 
 	properties  AndroidAppCertificateProperties
 	Certificate Certificate
@@ -1295,7 +1492,6 @@
 	module := &AndroidAppCertificate{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidModule(module)
-	android.InitBazelModule(module)
 	return module
 }
 
@@ -1322,7 +1518,7 @@
 func OverrideAndroidAppModuleFactory() android.Module {
 	m := &OverrideAndroidApp{}
 	m.AddProperties(
-		&OverridableDeviceProperties{},
+		&OverridableProperties{},
 		&overridableAppProperties{},
 	)
 
@@ -1336,9 +1532,13 @@
 	android.OverrideModuleBase
 }
 
-func (i *OverrideAndroidTest) GenerateAndroidBuildActions(_ android.ModuleContext) {
+func (i *OverrideAndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	// All the overrides happen in the base module.
 	// TODO(jungjw): Check the base module type.
+	android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
+		TestOnly:       true,
+		TopLevelTarget: true,
+	})
 }
 
 // override_android_test is used to create an android_app module based on another android_test by overriding
@@ -1386,6 +1586,9 @@
 	// provide the android.test.base statically and use jarjar to rename them so they do not collide
 	// with the classes provided by the android.test.base library.
 	Exclude_uses_libs []string
+
+	// The module names of optional uses-library libraries that are missing from the source tree.
+	Missing_optional_uses_libs []string `blueprint:"mutated"`
 }
 
 // usesLibrary provides properties and helper functions for AndroidApp and AndroidAppImport to verify that the
@@ -1397,22 +1600,16 @@
 
 	// Whether to enforce verify_uses_library check.
 	enforce bool
-}
 
-func (u *usesLibrary) addLib(lib string, optional bool) {
-	if !android.InList(lib, u.usesLibraryProperties.Uses_libs) && !android.InList(lib, u.usesLibraryProperties.Optional_uses_libs) {
-		if optional {
-			u.usesLibraryProperties.Optional_uses_libs = append(u.usesLibraryProperties.Optional_uses_libs, lib)
-		} else {
-			u.usesLibraryProperties.Uses_libs = append(u.usesLibraryProperties.Uses_libs, lib)
-		}
-	}
+	// Whether dexpreopt should be disabled
+	shouldDisableDexpreopt bool
 }
 
 func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, addCompatDeps bool) {
 	if !ctx.Config().UnbundledBuild() || ctx.Config().UnbundledBuildImage() {
 		ctx.AddVariationDependencies(nil, usesLibReqTag, u.usesLibraryProperties.Uses_libs...)
-		ctx.AddVariationDependencies(nil, usesLibOptTag, u.presentOptionalUsesLibs(ctx)...)
+		presentOptionalUsesLibs := u.presentOptionalUsesLibs(ctx)
+		ctx.AddVariationDependencies(nil, usesLibOptTag, presentOptionalUsesLibs...)
 		// Only add these extra dependencies if the module is an app that depends on framework
 		// libs. This avoids creating a cyclic dependency:
 		//     e.g. framework-res -> org.apache.http.legacy -> ... -> framework-res.
@@ -1423,6 +1620,8 @@
 			ctx.AddVariationDependencies(nil, usesLibCompat28OptTag, dexpreopt.OptionalCompatUsesLibs28...)
 			ctx.AddVariationDependencies(nil, usesLibCompat30OptTag, dexpreopt.OptionalCompatUsesLibs30...)
 		}
+		_, diff, _ := android.ListSetDifference(u.usesLibraryProperties.Optional_uses_libs, presentOptionalUsesLibs)
+		u.usesLibraryProperties.Missing_optional_uses_libs = diff
 	} else {
 		ctx.AddVariationDependencies(nil, r8LibraryJarTag, u.usesLibraryProperties.Uses_libs...)
 		ctx.AddVariationDependencies(nil, r8LibraryJarTag, u.presentOptionalUsesLibs(ctx)...)
@@ -1441,15 +1640,6 @@
 	return optionalUsesLibs
 }
 
-// Helper function to replace string in a list.
-func replaceInList(list []string, oldstr, newstr string) {
-	for i, str := range list {
-		if str == oldstr {
-			list[i] = newstr
-		}
-	}
-}
-
 // Returns a map of module names of shared library dependencies to the paths to their dex jars on
 // host and on device.
 func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext) dexpreopt.ClassLoaderContextMap {
@@ -1478,18 +1668,22 @@
 			}
 		}
 
+		// Skip java_sdk_library dependencies that provide stubs, but not an implementation.
+		// This will be restricted to optional_uses_libs
+		if sdklib, ok := m.(SdkLibraryDependency); ok {
+			if tag == usesLibOptTag && sdklib.DexJarBuildPath(ctx).PathOrNil() == nil {
+				u.shouldDisableDexpreopt = true
+				return
+			}
+		}
+
 		if lib, ok := m.(UsesLibraryDependency); ok {
 			libName := dep
 			if ulib, ok := m.(ProvidesUsesLib); ok && ulib.ProvidesUsesLib() != nil {
 				libName = *ulib.ProvidesUsesLib()
-				// Replace module name with library name in `uses_libs`/`optional_uses_libs` in
-				// order to pass verify_uses_libraries check (which compares these properties
-				// against library names written in the manifest).
-				replaceInList(u.usesLibraryProperties.Uses_libs, dep, libName)
-				replaceInList(u.usesLibraryProperties.Optional_uses_libs, dep, libName)
 			}
 			clcMap.AddContext(ctx, tag.sdkVersion, libName, tag.optional,
-				lib.DexJarBuildPath().PathOrNil(), lib.DexJarInstallPath(),
+				lib.DexJarBuildPath(ctx).PathOrNil(), lib.DexJarInstallPath(),
 				lib.ClassLoaderContexts())
 		} else if ctx.Config().AllowMissingDependencies() {
 			ctx.AddMissingDependencies([]string{dep})
@@ -1520,7 +1714,7 @@
 // an APK with the manifest embedded in it (manifest_check will know which one it is by the file
 // extension: APKs are supposed to end with '.apk').
 func (u *usesLibrary) verifyUsesLibraries(ctx android.ModuleContext, inputFile android.Path,
-	outputFile android.WritablePath) android.Path {
+	outputFile android.WritablePath, classLoaderContexts *dexpreopt.ClassLoaderContextMap) android.Path {
 
 	statusFile := dexpreopt.UsesLibrariesStatusFile(ctx)
 
@@ -1529,7 +1723,7 @@
 	// non-linux build platforms where dexpreopt is generally disabled (the check may fail due to
 	// various unrelated reasons, such as a failure to get manifest from an APK).
 	global := dexpreopt.GetGlobalConfig(ctx)
-	if global.DisablePreopt || global.OnlyPreoptBootImageAndSystemServer {
+	if global.DisablePreopt || global.OnlyPreoptArtBootImage {
 		return inputFile
 	}
 
@@ -1548,156 +1742,37 @@
 		cmd.Flag("--enforce-uses-libraries-relax")
 	}
 
-	for _, lib := range u.usesLibraryProperties.Uses_libs {
+	requiredUsesLibs, optionalUsesLibs := classLoaderContexts.UsesLibs()
+	for _, lib := range requiredUsesLibs {
 		cmd.FlagWithArg("--uses-library ", lib)
 	}
-
-	for _, lib := range u.usesLibraryProperties.Optional_uses_libs {
+	for _, lib := range optionalUsesLibs {
 		cmd.FlagWithArg("--optional-uses-library ", lib)
 	}
 
+	// Also add missing optional uses libs, as the manifest check expects them.
+	// Note that what we add here are the module names of those missing libs, not library names, while
+	// the manifest check actually expects library names. However, the case where a library is missing
+	// and the module name != the library name is too rare for us to handle.
+	for _, lib := range u.usesLibraryProperties.Missing_optional_uses_libs {
+		cmd.FlagWithArg("--missing-optional-uses-library ", lib)
+	}
+
 	rule.Build("verify_uses_libraries", "verify <uses-library>")
 	return outputFile
 }
 
 // verifyUsesLibrariesManifest checks the <uses-library> tags in an AndroidManifest.xml against
 // the build system and returns the path to a copy of the manifest.
-func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path {
+func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path,
+	classLoaderContexts *dexpreopt.ClassLoaderContextMap) android.Path {
 	outputFile := android.PathForModuleOut(ctx, "manifest_check", "AndroidManifest.xml")
-	return u.verifyUsesLibraries(ctx, manifest, outputFile)
+	return u.verifyUsesLibraries(ctx, manifest, outputFile, classLoaderContexts)
 }
 
 // verifyUsesLibrariesAPK checks the <uses-library> tags in the manifest of an APK against the build
 // system and returns the path to a copy of the APK.
-func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) {
-	u.verifyUsesLibraries(ctx, apk, nil) // for APKs manifest_check does not write output file
-}
-
-// For Bazel / bp2build
-
-type bazelAndroidAppCertificateAttributes struct {
-	Certificate string
-}
-
-func (m *AndroidAppCertificate) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	androidAppCertificateBp2Build(ctx, m)
-}
-
-func androidAppCertificateBp2Build(ctx android.TopDownMutatorContext, module *AndroidAppCertificate) {
-	var certificate string
-	if module.properties.Certificate != nil {
-		certificate = *module.properties.Certificate
-	}
-
-	attrs := &bazelAndroidAppCertificateAttributes{
-		Certificate: certificate,
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "android_app_certificate",
-		Bzl_load_location: "//build/bazel/rules/android:android_app_certificate.bzl",
-	}
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
-}
-
-type manifestValueAttribute struct {
-	MinSdkVersion    *string
-	MaxSdkVersion    *string
-	TargetSdkVersion *string
-}
-
-type bazelAndroidAppAttributes struct {
-	*javaCommonAttributes
-	*bazelAapt
-	Deps             bazel.LabelListAttribute
-	Custom_package   *string
-	Certificate      bazel.LabelAttribute
-	Certificate_name bazel.StringAttribute
-	Manifest_values  *manifestValueAttribute
-}
-
-// ConvertWithBp2build is used to convert android_app to Bazel.
-func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	commonAttrs, bp2BuildInfo, supported := a.convertLibraryAttrsBp2Build(ctx)
-	if !supported {
-		return
-	}
-	depLabels := bp2BuildInfo.DepLabels
-
-	deps := depLabels.Deps
-	deps.Append(depLabels.StaticDeps)
-
-	aapt := a.convertAaptAttrsWithBp2Build(ctx)
-
-	certificate, certificateName := android.BazelStringOrLabelFromProp(ctx, a.overridableAppProperties.Certificate)
-
-	manifestValues := &manifestValueAttribute{}
-	// TODO(b/274474008 ): Directly convert deviceProperties.Min_sdk_version in bp2build
-	// MinSdkVersion(ctx) calls SdkVersion(ctx) if no value for min_sdk_version is set
-	minSdkVersion := a.MinSdkVersion(ctx)
-	if !minSdkVersion.IsPreview() && !minSdkVersion.IsInvalid() {
-		if minSdkStr, err := minSdkVersion.EffectiveVersionString(ctx); err == nil {
-			manifestValues.MinSdkVersion = &minSdkStr
-		}
-	}
-
-	maxSdkVersion := a.MaxSdkVersion(ctx)
-	if !maxSdkVersion.IsPreview() && !maxSdkVersion.IsInvalid() {
-		if maxSdkStr, err := maxSdkVersion.EffectiveVersionString(ctx); err == nil {
-			manifestValues.MaxSdkVersion = &maxSdkStr
-		}
-	}
-
-	targetSdkVersion := a.TargetSdkVersion(ctx)
-	if !targetSdkVersion.IsPreview() && !targetSdkVersion.IsInvalid() {
-		if targetSdkStr, err := targetSdkVersion.EffectiveVersionString(ctx); err == nil {
-			manifestValues.TargetSdkVersion = &targetSdkStr
-		}
-	}
-
-	appAttrs := &bazelAndroidAppAttributes{
-		// TODO(b/209576404): handle package name override by product variable PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES
-		Custom_package:   a.overridableAppProperties.Package_name,
-		Certificate:      certificate,
-		Certificate_name: certificateName,
-		Manifest_values:  manifestValues,
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "android_binary",
-		Bzl_load_location: "//build/bazel/rules/android:android_binary.bzl",
-	}
-
-	if !bp2BuildInfo.hasKotlin {
-		appAttrs.javaCommonAttributes = commonAttrs
-		appAttrs.bazelAapt = aapt
-		appAttrs.Deps = deps
-	} else {
-		ktName := a.Name() + "_kt"
-		ctx.CreateBazelTargetModule(
-			AndroidLibraryBazelTargetModuleProperties(),
-			android.CommonAttributes{Name: ktName},
-			&bazelAndroidLibrary{
-				javaLibraryAttributes: &javaLibraryAttributes{
-					javaCommonAttributes: commonAttrs,
-					Deps:                 deps,
-				},
-				bazelAapt: aapt,
-			},
-		)
-
-		appAttrs.bazelAapt = &bazelAapt{Manifest: aapt.Manifest}
-		appAttrs.Deps = bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + ktName})
-		appAttrs.javaCommonAttributes = &javaCommonAttributes{
-			Sdk_version: commonAttrs.Sdk_version,
-		}
-	}
-
-	ctx.CreateBazelTargetModule(
-		props,
-		android.CommonAttributes{Name: a.Name(), SkipData: proptools.BoolPtr(true)},
-		appAttrs,
-	)
-
+func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path,
+	classLoaderContexts *dexpreopt.ClassLoaderContextMap) {
+	u.verifyUsesLibraries(ctx, apk, nil, classLoaderContexts) // for APKs manifest_check does not write output file
 }
diff --git a/java/app_builder.go b/java/app_builder.go
index d397ff7..943ce31 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -52,7 +52,7 @@
 	})
 
 func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
-	packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string, shrinkResources bool) {
+	packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string) {
 
 	unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk"
 	unsignedApk := android.PathForModuleOut(ctx, unsignedApkName)
@@ -71,12 +71,6 @@
 		Output:    unsignedApk,
 		Implicits: deps,
 	})
-
-	if shrinkResources {
-		shrunkenApk := android.PathForModuleOut(ctx, "resource-shrunken", unsignedApk.Base())
-		ShrinkResources(ctx, unsignedApk, shrunkenApk)
-		unsignedApk = shrunkenApk
-	}
 	SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile, rotationMinSdkVersion)
 }
 
diff --git a/java/app_import.go b/java/app_import.go
index ad1765e..bb07c42 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -19,6 +19,7 @@
 import (
 	"fmt"
 	"reflect"
+	"strings"
 
 	"github.com/google/blueprint"
 
@@ -51,27 +52,11 @@
 		Description: "Uncompress dex files",
 	})
 
-	checkDexLibsAreUncompressedRule = pctx.AndroidStaticRule("check-dex-libs-are-uncompressed", blueprint.RuleParams{
-		// grep -v ' stor ' will search for lines that don't have ' stor '. stor means the file is stored uncompressed
-		Command: "if (zipinfo $in '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then " +
-			"echo $in: Contains compressed JNI libraries and/or dex files >&2;" +
-			"exit 1; " +
-			"else " +
-			"touch $out; " +
-			"fi",
-		Description: "Check for compressed JNI libs or dex files",
-	})
-
-	checkJniLibsAreUncompressedRule = pctx.AndroidStaticRule("check-jni-libs-are-uncompressed", blueprint.RuleParams{
-		// grep -v ' stor ' will search for lines that don't have ' stor '. stor means the file is stored uncompressed
-		Command: "if (zipinfo $in 'lib/*.so' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then " +
-			"echo $in: Contains compressed JNI libraries >&2;" +
-			"exit 1; " +
-			"else " +
-			"touch $out; " +
-			"fi",
-		Description: "Check for compressed JNI libs or dex files",
-	})
+	checkPresignedApkRule = pctx.AndroidStaticRule("check-presigned-apk", blueprint.RuleParams{
+		Command:     "build/soong/scripts/check_prebuilt_presigned_apk.py --aapt2 ${config.Aapt2Cmd} --zipalign ${config.ZipAlign} $extraArgs $in $out",
+		CommandDeps: []string{"build/soong/scripts/check_prebuilt_presigned_apk.py", "${config.Aapt2Cmd}", "${config.ZipAlign}"},
+		Description: "Check presigned apk",
+	}, "extraArgs")
 )
 
 func RegisterAppImportBuildComponents(ctx android.RegistrationContext) {
@@ -85,9 +70,10 @@
 	android.ApexModuleBase
 	prebuilt android.Prebuilt
 
-	properties   AndroidAppImportProperties
-	dpiVariants  interface{}
-	archVariants interface{}
+	properties       AndroidAppImportProperties
+	dpiVariants      interface{}
+	archVariants     interface{}
+	arch_dpiVariants interface{}
 
 	outputFile  android.Path
 	certificate Certificate
@@ -101,6 +87,9 @@
 	hideApexVariantFromMake bool
 
 	provenanceMetaDataFile android.OutputPath
+
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
 }
 
 type AndroidAppImportProperties struct {
@@ -156,6 +145,16 @@
 	// Whether or not to skip checking the preprocessed apk for proper alignment and uncompressed
 	// JNI libs and dex files. Default is false
 	Skip_preprocessed_apk_checks *bool
+
+	// Name of the source soong module that gets shadowed by this prebuilt
+	// If unspecified, follows the naming convention that the source module of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_module_name *string
+
+	// Path to the .prebuilt_info file of the prebuilt app.
+	// In case of mainline modules, the .prebuilt_info file contains the build_id that was used
+	// to generate the prebuilt.
+	Prebuilt_info *string `android:"path"`
 }
 
 func (a *AndroidAppImport) IsInstallable() bool {
@@ -163,10 +162,12 @@
 }
 
 // Updates properties with variant-specific values.
-func (a *AndroidAppImport) processVariants(ctx android.LoadHookContext) {
+// This happens as a DefaultableHook instead of a LoadHook because we want to run it after
+// soong config variables are applied.
+func (a *AndroidAppImport) processVariants(ctx android.DefaultableHookContext) {
 	config := ctx.Config()
+	dpiProps := reflect.ValueOf(a.dpiVariants).Elem().FieldByName(DpiGroupName)
 
-	dpiProps := reflect.ValueOf(a.dpiVariants).Elem().FieldByName("Dpi_variants")
 	// Try DPI variant matches in the reverse-priority order so that the highest priority match
 	// overwrites everything else.
 	// TODO(jungjw): Can we optimize this by making it priority order?
@@ -176,11 +177,27 @@
 	if config.ProductAAPTPreferredConfig() != "" {
 		MergePropertiesFromVariant(ctx, &a.properties, dpiProps, config.ProductAAPTPreferredConfig())
 	}
-
-	archProps := reflect.ValueOf(a.archVariants).Elem().FieldByName("Arch")
+	archProps := reflect.ValueOf(a.archVariants).Elem().FieldByName(ArchGroupName)
 	archType := ctx.Config().AndroidFirstDeviceTarget.Arch.ArchType
 	MergePropertiesFromVariant(ctx, &a.properties, archProps, archType.Name)
 
+	// Process "arch" includes "dpi_variants"
+	archStructPtr := reflect.ValueOf(a.arch_dpiVariants).Elem().FieldByName(ArchGroupName)
+	if archStruct := archStructPtr.Elem(); archStruct.IsValid() {
+		archPartPropsPtr := archStruct.FieldByName(proptools.FieldNameForProperty(archType.Name))
+		if archPartProps := archPartPropsPtr.Elem(); archPartProps.IsValid() {
+			archDpiPropsPtr := archPartProps.FieldByName(DpiGroupName)
+			if archDpiProps := archDpiPropsPtr.Elem(); archDpiProps.IsValid() {
+				for i := len(config.ProductAAPTPrebuiltDPI()) - 1; i >= 0; i-- {
+					MergePropertiesFromVariant(ctx, &a.properties, archDpiProps, config.ProductAAPTPrebuiltDPI()[i])
+				}
+				if config.ProductAAPTPreferredConfig() != "" {
+					MergePropertiesFromVariant(ctx, &a.properties, archDpiProps, config.ProductAAPTPreferredConfig())
+				}
+			}
+		}
+	}
+
 	if String(a.properties.Apk) == "" {
 		// Disable this module since the apk property is still empty after processing all matching
 		// variants. This likely means there is no matching variant, and the default variant doesn't
@@ -256,7 +273,7 @@
 		return ctx.Config().UncompressPrivAppDex()
 	}
 
-	return shouldUncompressDex(ctx, &a.dexpreopter)
+	return shouldUncompressDex(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), &a.dexpreopter)
 }
 
 func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -267,16 +284,28 @@
 	return a.BaseModuleName()
 }
 
+func (a *AndroidAppImport) BaseModuleName() string {
+	return proptools.StringDefault(a.properties.Source_module_name, a.ModuleBase.Name())
+}
+
 func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext) {
 	if a.Name() == "prebuilt_framework-res" {
 		ctx.ModuleErrorf("prebuilt_framework-res found. This used to have special handling in soong, but was removed due to prebuilt_framework-res no longer existing. This check is to ensure it doesn't come back without readding the special handling.")
 	}
 
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	if !apexInfo.IsForPlatform() {
 		a.hideApexVariantFromMake = true
 	}
 
+	if Bool(a.properties.Preprocessed) {
+		if a.properties.Presigned != nil && !*a.properties.Presigned {
+			ctx.ModuleErrorf("Setting preprocessed: true implies presigned: true, so you cannot set presigned to false")
+		}
+		t := true
+		a.properties.Presigned = &t
+	}
+
 	numCertPropsSet := 0
 	if String(a.properties.Certificate) != "" {
 		numCertPropsSet++
@@ -288,11 +317,9 @@
 		numCertPropsSet++
 	}
 	if numCertPropsSet != 1 {
-		ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set")
+		ctx.ModuleErrorf("One and only one of certficate, presigned (implied by preprocessed), and default_dev_cert properties must be set")
 	}
 
-	_, _, certificates := collectAppDeps(ctx, a, false, false)
-
 	// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
 	// TODO: LOCAL_PACKAGE_SPLITS
 
@@ -323,12 +350,15 @@
 
 	a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries()
 	a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
-
-	if a.usesLibrary.enforceUsesLibraries() {
-		a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
+	if a.usesLibrary.shouldDisableDexpreopt {
+		a.dexpreopter.disableDexpreopt()
 	}
 
-	a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
+	if a.usesLibrary.enforceUsesLibraries() {
+		a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk, &a.dexpreopter.classLoaderContexts)
+	}
+
+	a.dexpreopter.dexpreopt(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), jnisUncompressed)
 	if a.dexpreopter.uncompressedDex {
 		dexUncompressed := android.PathForModuleOut(ctx, "dex-uncompressed", ctx.ModuleName()+".apk")
 		ctx.Build(pctx, android.BuildParams{
@@ -346,25 +376,20 @@
 	// Sign or align the package if package has not been preprocessed
 
 	if proptools.Bool(a.properties.Preprocessed) {
-		var output android.WritablePath
-		if !proptools.Bool(a.properties.Skip_preprocessed_apk_checks) {
-			output = android.PathForModuleOut(ctx, "validated-prebuilt", apkFilename)
-			a.validatePreprocessedApk(ctx, srcApk, output)
-		} else {
-			// If using the input APK unmodified, still make a copy of it so that the output filename has the
-			// right basename.
-			output = android.PathForModuleOut(ctx, apkFilename)
-			ctx.Build(pctx, android.BuildParams{
-				Rule:   android.Cp,
-				Input:  srcApk,
-				Output: output,
-			})
-		}
+		validationStamp := a.validatePresignedApk(ctx, srcApk)
+		output := android.PathForModuleOut(ctx, apkFilename)
+		ctx.Build(pctx, android.BuildParams{
+			Rule:       android.Cp,
+			Input:      srcApk,
+			Output:     output,
+			Validation: validationStamp,
+		})
 		a.outputFile = output
 		a.certificate = PresignedCertificate
 	} else if !Bool(a.properties.Presigned) {
 		// If the certificate property is empty at this point, default_dev_cert must be set to true.
 		// Which makes processMainCert's behavior for the empty cert string WAI.
+		_, _, certificates := collectAppDeps(ctx, a, false, false)
 		a.certificate, certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
 		signed := android.PathForModuleOut(ctx, "signed", apkFilename)
 		var lineageFile android.Path
@@ -377,8 +402,9 @@
 		SignAppPackage(ctx, signed, jnisUncompressed, certificates, nil, lineageFile, rotationMinSdkVersion)
 		a.outputFile = signed
 	} else {
+		validationStamp := a.validatePresignedApk(ctx, srcApk)
 		alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
-		TransformZipAlign(ctx, alignedApk, jnisUncompressed)
+		TransformZipAlign(ctx, alignedApk, jnisUncompressed, []android.Path{validationStamp})
 		a.outputFile = alignedApk
 		a.certificate = PresignedCertificate
 	}
@@ -390,46 +416,41 @@
 		artifactPath := android.PathForModuleSrc(ctx, *a.properties.Apk)
 		a.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, artifactPath, a.installPath)
 	}
+	android.CollectDependencyAconfigFiles(ctx, &a.mergedAconfigFiles)
+
+	providePrebuiltInfo(ctx,
+		prebuiltInfoProps{
+			baseModuleName: a.BaseModuleName(),
+			isPrebuilt:     true,
+			prebuiltInfo:   a.properties.Prebuilt_info,
+		},
+	)
 
 	// TODO: androidmk converter jni libs
 }
 
-func (a *AndroidAppImport) validatePreprocessedApk(ctx android.ModuleContext, srcApk android.Path, dstApk android.WritablePath) {
-	var validations android.Paths
-
-	alignmentStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "alignment.stamp")
-	ctx.Build(pctx, android.BuildParams{
-		Rule:   checkZipAlignment,
-		Input:  srcApk,
-		Output: alignmentStamp,
-	})
-
-	validations = append(validations, alignmentStamp)
-	jniCompressionStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "jni_compression.stamp")
-	ctx.Build(pctx, android.BuildParams{
-		Rule:   checkJniLibsAreUncompressedRule,
-		Input:  srcApk,
-		Output: jniCompressionStamp,
-	})
-	validations = append(validations, jniCompressionStamp)
-
+func (a *AndroidAppImport) validatePresignedApk(ctx android.ModuleContext, srcApk android.Path) android.Path {
+	stamp := android.PathForModuleOut(ctx, "validated-prebuilt", "check.stamp")
+	var extraArgs []string
 	if a.Privileged() {
-		// It's ok for non-privileged apps to have compressed dex files, see go/gms-uncompressed-jni-slides
-		dexCompressionStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "dex_compression.stamp")
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   checkDexLibsAreUncompressedRule,
-			Input:  srcApk,
-			Output: dexCompressionStamp,
-		})
-		validations = append(validations, dexCompressionStamp)
+		extraArgs = append(extraArgs, "--privileged")
+	}
+	if proptools.Bool(a.properties.Skip_preprocessed_apk_checks) {
+		extraArgs = append(extraArgs, "--skip-preprocessed-apk-checks")
+	}
+	if proptools.Bool(a.properties.Preprocessed) {
+		extraArgs = append(extraArgs, "--preprocessed")
 	}
 
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        android.Cp,
-		Input:       srcApk,
-		Output:      dstApk,
-		Validations: validations,
+		Rule:   checkPresignedApkRule,
+		Input:  srcApk,
+		Output: stamp,
+		Args: map[string]string{
+			"extraArgs": strings.Join(extraArgs, " "),
+		},
 	})
+	return stamp
 }
 
 func (a *AndroidAppImport) Prebuilt() *android.Prebuilt {
@@ -469,18 +490,25 @@
 	return android.OptionalPath{}
 }
 
+const (
+	ArchGroupName = "Arch"
+	DpiGroupName  = "Dpi_variants"
+)
+
 var dpiVariantGroupType reflect.Type
 var archVariantGroupType reflect.Type
+var archdpiVariantGroupType reflect.Type
 var supportedDpis = []string{"ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"}
 
 func initAndroidAppImportVariantGroupTypes() {
-	dpiVariantGroupType = createVariantGroupType(supportedDpis, "Dpi_variants")
+	dpiVariantGroupType = createVariantGroupType(supportedDpis, DpiGroupName)
 
 	archNames := make([]string, len(android.ArchTypeList()))
 	for i, archType := range android.ArchTypeList() {
 		archNames[i] = archType.Name
 	}
-	archVariantGroupType = createVariantGroupType(archNames, "Arch")
+	archVariantGroupType = createVariantGroupType(archNames, ArchGroupName)
+	archdpiVariantGroupType = createArchDpiVariantGroupType(archNames, supportedDpis)
 }
 
 // Populates all variant struct properties at creation time.
@@ -490,6 +518,9 @@
 
 	a.archVariants = reflect.New(archVariantGroupType).Interface()
 	a.AddProperties(a.archVariants)
+
+	a.arch_dpiVariants = reflect.New(archdpiVariantGroupType).Interface()
+	a.AddProperties(a.arch_dpiVariants)
 }
 
 func (a *AndroidAppImport) Privileged() bool {
@@ -544,6 +575,48 @@
 	})
 }
 
+func createArchDpiVariantGroupType(archNames []string, dpiNames []string) reflect.Type {
+	props := reflect.TypeOf((*AndroidAppImportProperties)(nil))
+
+	dpiVariantFields := make([]reflect.StructField, len(dpiNames))
+	for i, variant_dpi := range dpiNames {
+		dpiVariantFields[i] = reflect.StructField{
+			Name: proptools.FieldNameForProperty(variant_dpi),
+			Type: props,
+		}
+	}
+	dpiVariantGroupStruct := reflect.StructOf(dpiVariantFields)
+	dpi_struct := reflect.StructOf([]reflect.StructField{
+		{
+			Name: DpiGroupName,
+			Type: reflect.PointerTo(dpiVariantGroupStruct),
+		},
+	})
+
+	archVariantFields := make([]reflect.StructField, len(archNames))
+	for i, variant_arch := range archNames {
+		archVariantFields[i] = reflect.StructField{
+			Name: proptools.FieldNameForProperty(variant_arch),
+			Type: reflect.PointerTo(dpi_struct),
+		}
+	}
+	archVariantGroupStruct := reflect.StructOf(archVariantFields)
+
+	return_struct := reflect.StructOf([]reflect.StructField{
+		{
+			Name: ArchGroupName,
+			Type: reflect.PointerTo(archVariantGroupStruct),
+		},
+	})
+	return return_struct
+}
+
+func (a *AndroidAppImport) UsesLibrary() *usesLibrary {
+	return &a.usesLibrary
+}
+
+var _ ModuleWithUsesLibrary = (*AndroidAppImport)(nil)
+
 // android_app_import imports a prebuilt apk with additional processing specified in the module.
 // DPI-specific apk source files can be specified using dpi_variants. Example:
 //
@@ -566,7 +639,7 @@
 	module.AddProperties(&module.dexpreoptProperties)
 	module.AddProperties(&module.usesLibrary.usesLibraryProperties)
 	module.populateAllVariantStructs()
-	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+	module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
 		module.processVariants(ctx)
 	})
 
@@ -617,7 +690,7 @@
 	module.AddProperties(&module.dexpreoptProperties)
 	module.AddProperties(&module.testProperties)
 	module.populateAllVariantStructs()
-	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+	module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
 		module.processVariants(ctx)
 	})
 
diff --git a/java/app_import_test.go b/java/app_import_test.go
index bb8fab9..5de50e7 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -40,8 +40,8 @@
 	variant := ctx.ModuleForTests("foo", "android_common")
 
 	// Check dexpreopt outputs.
-	if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
-		variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+	if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil ||
+		variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule == nil {
 		t.Errorf("can't find dexpreopt outputs")
 	}
 
@@ -74,8 +74,8 @@
 	variant := ctx.ModuleForTests("foo", "android_common")
 
 	// Check dexpreopt outputs. They shouldn't exist.
-	if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule != nil ||
-		variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule != nil {
+	if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule != nil ||
+		variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule != nil {
 		t.Errorf("dexpreopt shouldn't have run.")
 	}
 
@@ -101,8 +101,8 @@
 	variant := ctx.ModuleForTests("foo", "android_common")
 
 	// Check dexpreopt outputs.
-	if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
-		variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+	if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil ||
+		variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule == nil {
 		t.Errorf("can't find dexpreopt outputs")
 	}
 	// Make sure signing was skipped and aligning was done.
@@ -210,8 +210,8 @@
 	variant := ctx.ModuleForTests("foo", "android_common")
 
 	// Check dexpreopt outputs.
-	if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
-		variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
+	if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil ||
+		variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule == nil {
 		t.Errorf("can't find dexpreopt outputs")
 	}
 
@@ -411,6 +411,27 @@
 			installPath:  "/system/app/foo/foo.apk",
 		},
 		{
+			name: "matching arch without default",
+			bp: `
+				android_app_import {
+					name: "foo",
+					apk: "prebuilts/apk/app.apk",
+					arch: {
+						arm64: {
+							apk: "prebuilts/apk/app_arm64.apk",
+						},
+					},
+					presigned: true,
+					dex_preopt: {
+						enabled: true,
+					},
+				}
+			`,
+			expected:     "verify_uses_libraries/apk/app_arm64.apk",
+			artifactPath: "prebuilts/apk/app_arm64.apk",
+			installPath:  "/system/app/foo/foo.apk",
+		},
+		{
 			name: "no matching arch",
 			bp: `
 				android_app_import {
@@ -451,29 +472,137 @@
 			artifactPath: "prebuilts/apk/app_arm.apk",
 			installPath:  "/system/app/foo/foo.apk",
 		},
+		{
+			name: "matching arch and dpi_variants",
+			bp: `
+				android_app_import {
+					name: "foo",
+					apk: "prebuilts/apk/app.apk",
+					arch: {
+						arm64: {
+							apk: "prebuilts/apk/app_arm64.apk",
+							dpi_variants: {
+								mdpi: {
+									apk: "prebuilts/apk/app_arm64_mdpi.apk",
+								},
+								xhdpi: {
+									apk: "prebuilts/apk/app_arm64_xhdpi.apk",
+								},
+							},
+						},
+					},
+					presigned: true,
+					dex_preopt: {
+						enabled: true,
+					},
+				}
+			`,
+			expected:     "verify_uses_libraries/apk/app_arm64_xhdpi.apk",
+			artifactPath: "prebuilts/apk/app_arm64_xhdpi.apk",
+			installPath:  "/system/app/foo/foo.apk",
+		},
 	}
 
 	for _, test := range testCases {
-		ctx, _ := testJava(t, test.bp)
+		t.Run(test.name, func(t *testing.T) {
+			ctx, _ := testJava(t, test.bp)
 
-		variant := ctx.ModuleForTests("foo", "android_common")
-		if test.expected == "" {
-			if variant.Module().Enabled() {
-				t.Error("module should have been disabled, but wasn't")
+			variant := ctx.ModuleForTests("foo", "android_common")
+			if test.expected == "" {
+				if variant.Module().Enabled() {
+					t.Error("module should have been disabled, but wasn't")
+				}
+				rule := variant.MaybeRule("genProvenanceMetaData")
+				android.AssertDeepEquals(t, "Provenance metadata is not empty", android.TestingBuildParams{}, rule)
+				return
 			}
-			rule := variant.MaybeRule("genProvenanceMetaData")
-			android.AssertDeepEquals(t, "Provenance metadata is not empty", android.TestingBuildParams{}, rule)
-			continue
-		}
-		input := variant.Output("jnis-uncompressed/foo.apk").Input.String()
-		if strings.HasSuffix(input, test.expected) {
-			t.Errorf("wrong src apk, expected: %q got: %q", test.expected, input)
-		}
-		rule := variant.Rule("genProvenanceMetaData")
-		android.AssertStringEquals(t, "Invalid input", test.artifactPath, rule.Inputs[0].String())
-		android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String())
-		android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"])
-		android.AssertStringEquals(t, "Invalid args", test.installPath, rule.Args["install_path"])
+			input := variant.Output("jnis-uncompressed/foo.apk").Input.String()
+			if strings.HasSuffix(input, test.expected) {
+				t.Errorf("wrong src apk, expected: %q got: %q", test.expected, input)
+			}
+			rule := variant.Rule("genProvenanceMetaData")
+			android.AssertStringEquals(t, "Invalid input", test.artifactPath, rule.Inputs[0].String())
+			android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String())
+			android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"])
+			android.AssertStringEquals(t, "Invalid args", test.installPath, rule.Args["install_path"])
+		})
+	}
+}
+
+func TestAndroidAppImport_SoongConfigVariables(t *testing.T) {
+	testCases := []struct {
+		name         string
+		bp           string
+		expected     string
+		artifactPath string
+		metaDataPath string
+		installPath  string
+	}{
+		{
+			name: "matching arch",
+			bp: `
+				soong_config_module_type {
+					name: "my_android_app_import",
+					module_type: "android_app_import",
+					config_namespace: "my_namespace",
+					value_variables: ["my_apk_var"],
+					properties: ["apk"],
+				}
+				soong_config_value_variable {
+					name: "my_apk_var",
+				}
+				my_android_app_import {
+					name: "foo",
+					soong_config_variables: {
+						my_apk_var: {
+							apk: "prebuilts/apk/%s.apk",
+						},
+					},
+					presigned: true,
+					dex_preopt: {
+						enabled: true,
+					},
+				}
+			`,
+			expected:     "verify_uses_libraries/apk/name_from_soong_config.apk",
+			artifactPath: "prebuilts/apk/name_from_soong_config.apk",
+			installPath:  "/system/app/foo/foo.apk",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			ctx := android.GroupFixturePreparers(
+				prepareForJavaTest,
+				android.PrepareForTestWithSoongConfigModuleBuildComponents,
+				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+					variables.VendorVars = map[string]map[string]string{
+						"my_namespace": {
+							"my_apk_var": "name_from_soong_config",
+						},
+					}
+				}),
+			).RunTestWithBp(t, test.bp).TestContext
+
+			variant := ctx.ModuleForTests("foo", "android_common")
+			if test.expected == "" {
+				if variant.Module().Enabled() {
+					t.Error("module should have been disabled, but wasn't")
+				}
+				rule := variant.MaybeRule("genProvenanceMetaData")
+				android.AssertDeepEquals(t, "Provenance metadata is not empty", android.TestingBuildParams{}, rule)
+				return
+			}
+			input := variant.Output("jnis-uncompressed/foo.apk").Input.String()
+			if strings.HasSuffix(input, test.expected) {
+				t.Errorf("wrong src apk, expected: %q got: %q", test.expected, input)
+			}
+			rule := variant.Rule("genProvenanceMetaData")
+			android.AssertStringEquals(t, "Invalid input", test.artifactPath, rule.Inputs[0].String())
+			android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String())
+			android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"])
+			android.AssertStringEquals(t, "Invalid args", test.installPath, rule.Args["install_path"])
+		})
 	}
 }
 
@@ -629,31 +758,21 @@
 			presigned: true,
 			preprocessed: true,
 		}
-
-		android_test_import {
-			name: "foo_cert",
-			apk: "prebuilts/apk/app.apk",
-			certificate: "cert/new_cert",
-			preprocessed: true,
-		}
 		`)
 
-	testModules := []string{"foo", "foo_cert"}
-	for _, m := range testModules {
-		apkName := m + ".apk"
-		variant := ctx.ModuleForTests(m, "android_common")
-		jniRule := variant.Output("jnis-uncompressed/" + apkName).BuildParams.Rule.String()
-		if jniRule != android.Cp.String() {
-			t.Errorf("Unexpected JNI uncompress rule: " + jniRule)
-		}
+	apkName := "foo.apk"
+	variant := ctx.ModuleForTests("foo", "android_common")
+	jniRule := variant.Output("jnis-uncompressed/" + apkName).BuildParams.Rule.String()
+	if jniRule != android.Cp.String() {
+		t.Errorf("Unexpected JNI uncompress rule: " + jniRule)
+	}
 
-		// Make sure signing and aligning were skipped.
-		if variant.MaybeOutput("signed/"+apkName).Rule != nil {
-			t.Errorf("signing rule shouldn't be included for preprocessed.")
-		}
-		if variant.MaybeOutput("zip-aligned/"+apkName).Rule != nil {
-			t.Errorf("aligning rule shouldn't be for preprocessed")
-		}
+	// Make sure signing and aligning were skipped.
+	if variant.MaybeOutput("signed/"+apkName).Rule != nil {
+		t.Errorf("signing rule shouldn't be included for preprocessed.")
+	}
+	if variant.MaybeOutput("zip-aligned/"+apkName).Rule != nil {
+		t.Errorf("aligning rule shouldn't be for preprocessed")
 	}
 }
 
@@ -669,14 +788,19 @@
 
 	apkName := "foo.apk"
 	variant := ctx.ModuleForTests("foo", "android_common")
-	outputBuildParams := variant.Output("validated-prebuilt/" + apkName).BuildParams
+	outputBuildParams := variant.Output(apkName).BuildParams
 	if outputBuildParams.Rule.String() != android.Cp.String() {
 		t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String())
 	}
 
 	// Make sure compression and aligning were validated.
-	if len(outputBuildParams.Validations) != 2 {
-		t.Errorf("Expected compression/alignment validation rules, found %d validations", len(outputBuildParams.Validations))
+	if outputBuildParams.Validation == nil {
+		t.Errorf("Expected validation rule, but was not found")
+	}
+
+	validationBuildParams := variant.Output("validated-prebuilt/check.stamp").BuildParams
+	if validationBuildParams.Rule.String() != checkPresignedApkRule.String() {
+		t.Errorf("Unexpected validation rule: " + validationBuildParams.Rule.String())
 	}
 }
 
diff --git a/java/app_set.go b/java/app_set.go
index d2d3b06..33d3ade 100644
--- a/java/app_set.go
+++ b/java/app_set.go
@@ -48,6 +48,11 @@
 	// Names of modules to be overridden. Listed modules can only be other apps
 	//	(in Make or Soong).
 	Overrides []string
+
+	// Path to the .prebuilt_info file of the prebuilt app.
+	// In case of mainline modules, the .prebuilt_info file contains the build_id that was used
+	// to generate the prebuilt.
+	Prebuilt_info *string `android:"path"`
 }
 
 type AndroidAppSet struct {
@@ -117,6 +122,27 @@
 	return result
 }
 
+type prebuiltInfoProps struct {
+	baseModuleName string
+	isPrebuilt     bool
+	prebuiltInfo   *string
+}
+
+// Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file
+// with information about whether source or prebuilt of an apex was used during the build.
+func providePrebuiltInfo(ctx android.ModuleContext, p prebuiltInfoProps) {
+	info := android.PrebuiltInfo{
+		Name:        p.baseModuleName,
+		Is_prebuilt: p.isPrebuilt,
+	}
+	// If Prebuilt_info information is available in the soong module definition, add it to prebuilt_info.json.
+	if p.prebuiltInfo != nil {
+		prebuiltInfoFile := android.PathForModuleSrc(ctx, *p.prebuiltInfo)
+		info.Prebuilt_info_file_path = prebuiltInfoFile.String()
+	}
+	android.SetProvider(ctx, android.PrebuiltInfoProvider, info)
+}
+
 func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip")
 	as.primaryOutput = android.PathForModuleOut(ctx, as.BaseModuleName()+".apk")
@@ -157,6 +183,15 @@
 		installDir = android.PathForModuleInstall(ctx, "app", as.BaseModuleName())
 	}
 	ctx.InstallFileWithExtraFilesZip(installDir, as.BaseModuleName()+".apk", as.primaryOutput, as.packedOutput)
+
+	providePrebuiltInfo(ctx,
+		prebuiltInfoProps{
+			baseModuleName: as.BaseModuleName(),
+			isPrebuilt:     true,
+			prebuiltInfo:   as.properties.Prebuilt_info,
+		},
+	)
+
 }
 
 func (as *AndroidAppSet) InstallBypassMake() bool { return true }
diff --git a/java/app_test.go b/java/app_test.go
index 8474ea7..eab40e7 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -558,7 +558,6 @@
 		t.Run(testCase.name, func(t *testing.T) {
 			result := android.GroupFixturePreparers(
 				PrepareForTestWithJavaDefaultModules,
-				PrepareForTestWithOverlayBuildComponents,
 				fs.AddToFixture(),
 			).RunTestWithBp(t, fmt.Sprintf(bp, testCase.prop))
 
@@ -608,6 +607,15 @@
 				asset_dirs: ["assets_b"],
 			}
 
+			android_library {
+				name: "lib5",
+				sdk_version: "current",
+				assets: [
+					"path/to/asset_file_1",
+					"path/to/asset_file_2",
+				],
+			}
+
 			android_library_import {
 				name: "import",
 				sdk_version: "current",
@@ -616,9 +624,11 @@
 		`
 
 	testCases := []struct {
-		name          string
-		assetFlag     string
-		assetPackages []string
+		name               string
+		assetFlag          string
+		assetPackages      []string
+		tmpAssetDirInputs  []string
+		tmpAssetDirOutputs []string
 	}{
 		{
 			name: "foo",
@@ -644,6 +654,18 @@
 			name:      "lib4",
 			assetFlag: "-A assets_b",
 		},
+		{
+			name:      "lib5",
+			assetFlag: "-A out/soong/.intermediates/lib5/android_common/tmp_asset_dir",
+			tmpAssetDirInputs: []string{
+				"path/to/asset_file_1",
+				"path/to/asset_file_2",
+			},
+			tmpAssetDirOutputs: []string{
+				"out/soong/.intermediates/lib5/android_common/tmp_asset_dir/path/to/asset_file_1",
+				"out/soong/.intermediates/lib5/android_common/tmp_asset_dir/path/to/asset_file_2",
+			},
+		},
 	}
 	ctx := testApp(t, bp)
 
@@ -671,6 +693,14 @@
 				mergeAssets := m.Output("package-res.apk")
 				android.AssertPathsRelativeToTopEquals(t, "mergeAssets inputs", test.assetPackages, mergeAssets.Inputs)
 			}
+
+			if len(test.tmpAssetDirInputs) > 0 {
+				rule := m.Rule("tmp_asset_dir")
+				inputs := rule.Implicits
+				outputs := append(android.WritablePaths{rule.Output}, rule.ImplicitOutputs...).Paths()
+				android.AssertPathsRelativeToTopEquals(t, "tmp_asset_dir inputs", test.tmpAssetDirInputs, inputs)
+				android.AssertPathsRelativeToTopEquals(t, "tmp_asset_dir outputs", test.tmpAssetDirOutputs, outputs)
+			}
 		})
 	}
 }
@@ -722,10 +752,13 @@
 
 func TestAndroidResourceProcessor(t *testing.T) {
 	testCases := []struct {
-		name                string
-		appUsesRP           bool
-		directLibUsesRP     bool
-		transitiveLibUsesRP bool
+		name                            string
+		appUsesRP                       bool
+		directLibUsesRP                 bool
+		transitiveLibUsesRP             bool
+		sharedLibUsesRP                 bool
+		sharedTransitiveStaticLibUsesRP bool
+		sharedTransitiveSharedLibUsesRP bool
 
 		dontVerifyApp bool
 		appResources  []string
@@ -760,6 +793,14 @@
 		transitiveImportResources  []string
 		transitiveImportOverlays   []string
 		transitiveImportImports    []string
+
+		dontVerifyShared bool
+		sharedResources  []string
+		sharedOverlays   []string
+		sharedImports    []string
+		sharedSrcJars    []string
+		sharedClasspath  []string
+		sharedCombined   []string
 	}{
 		{
 			// Test with all modules set to use_resource_processor: false (except android_library_import modules,
@@ -779,17 +820,21 @@
 				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
 				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
 			},
-			appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			appImports: []string{
+				"out/soong/.intermediates/shared/android_common/package-res.apk",
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+			},
 			appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"},
 			appClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar",
 			},
 			appCombined: []string{
 				"out/soong/.intermediates/app/android_common/javac/app.jar",
 				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar",
 			},
 
 			directResources: nil,
@@ -804,12 +849,12 @@
 			directClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
 				"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/turbine-combined/transitive_import.jar",
 			},
 			directCombined: []string{
 				"out/soong/.intermediates/direct/android_common/javac/direct.jar",
 				"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/combined/transitive_import.jar",
 			},
 
 			transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
@@ -819,6 +864,26 @@
 			transitiveClasspath: []string{"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar"},
 			transitiveCombined:  nil,
 
+			sharedResources: nil,
+			sharedOverlays: []string{
+				"out/soong/.intermediates/shared_transitive_static/android_common/package-res.apk",
+				"out/soong/.intermediates/shared/android_common/aapt2/shared/res/values_strings.arsc.flat",
+			},
+			sharedImports: []string{
+				"out/soong/.intermediates/shared_transitive_shared/android_common/package-res.apk",
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+			},
+			sharedSrcJars: []string{"out/soong/.intermediates/shared/android_common/gen/android/R.srcjar"},
+			sharedClasspath: []string{
+				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/shared_transitive_shared/android_common/turbine-combined/shared_transitive_shared.jar",
+				"out/soong/.intermediates/shared_transitive_static/android_common/turbine-combined/shared_transitive_static.jar",
+			},
+			sharedCombined: []string{
+				"out/soong/.intermediates/shared/android_common/javac/shared.jar",
+				"out/soong/.intermediates/shared_transitive_static/android_common/javac/shared_transitive_static.jar",
+			},
+
 			directImportResources: nil,
 			directImportOverlays:  []string{"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata"},
 			directImportImports: []string{
@@ -835,10 +900,13 @@
 		},
 		{
 			// Test with all modules set to use_resource_processor: true.
-			name:                "resource_processor",
-			appUsesRP:           true,
-			directLibUsesRP:     true,
-			transitiveLibUsesRP: true,
+			name:                            "resource_processor",
+			appUsesRP:                       true,
+			directLibUsesRP:                 true,
+			transitiveLibUsesRP:             true,
+			sharedLibUsesRP:                 true,
+			sharedTransitiveSharedLibUsesRP: true,
+			sharedTransitiveStaticLibUsesRP: true,
 
 			appResources: nil,
 			appOverlays: []string{
@@ -850,19 +918,23 @@
 				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
 				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
 			},
-			appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			appImports: []string{
+				"out/soong/.intermediates/shared/android_common/package-res.apk",
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+			},
 			appSrcJars: nil,
 			appClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
 				"out/soong/.intermediates/app/android_common/busybox/R.jar",
+				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar",
 			},
 			appCombined: []string{
-				"out/soong/.intermediates/app/android_common/busybox/R.jar",
 				"out/soong/.intermediates/app/android_common/javac/app.jar",
+				"out/soong/.intermediates/app/android_common/busybox/R.jar",
 				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar",
 			},
 
 			directResources: nil,
@@ -876,17 +948,17 @@
 			directSrcJars: nil,
 			directClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
-				"out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
-				"out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
-				"out/soong/.intermediates/transitive/android_common/busybox/R.jar",
 				"out/soong/.intermediates/direct/android_common/busybox/R.jar",
+				"out/soong/.intermediates/transitive/android_common/busybox/R.jar",
+				"out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
+				"out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
 				"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/turbine-combined/transitive_import.jar",
 			},
 			directCombined: []string{
 				"out/soong/.intermediates/direct/android_common/javac/direct.jar",
 				"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/combined/transitive_import.jar",
 			},
 
 			transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
@@ -899,6 +971,27 @@
 			},
 			transitiveCombined: nil,
 
+			sharedResources: nil,
+			sharedOverlays:  []string{"out/soong/.intermediates/shared/android_common/aapt2/shared/res/values_strings.arsc.flat"},
+			sharedImports: []string{
+				"out/soong/.intermediates/shared_transitive_shared/android_common/package-res.apk",
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+				"out/soong/.intermediates/shared_transitive_static/android_common/package-res.apk",
+			},
+			sharedSrcJars: nil,
+			sharedClasspath: []string{
+				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/shared/android_common/busybox/R.jar",
+				"out/soong/.intermediates/shared_transitive_static/android_common/busybox/R.jar",
+				"out/soong/.intermediates/shared_transitive_shared/android_common/busybox/R.jar",
+				"out/soong/.intermediates/shared_transitive_shared/android_common/turbine-combined/shared_transitive_shared.jar",
+				"out/soong/.intermediates/shared_transitive_static/android_common/turbine-combined/shared_transitive_static.jar",
+			},
+			sharedCombined: []string{
+				"out/soong/.intermediates/shared/android_common/javac/shared.jar",
+				"out/soong/.intermediates/shared_transitive_static/android_common/javac/shared_transitive_static.jar",
+			},
+
 			directImportResources: nil,
 			directImportOverlays:  []string{"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata"},
 			directImportImports: []string{
@@ -930,24 +1023,29 @@
 				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
 				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
 			},
-			appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			appImports: []string{
+				"out/soong/.intermediates/shared/android_common/package-res.apk",
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+			},
 			appSrcJars: nil,
 			appClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
 				// R.jar has to come before direct.jar
 				"out/soong/.intermediates/app/android_common/busybox/R.jar",
+				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar",
 			},
 			appCombined: []string{
-				"out/soong/.intermediates/app/android_common/busybox/R.jar",
 				"out/soong/.intermediates/app/android_common/javac/app.jar",
+				"out/soong/.intermediates/app/android_common/busybox/R.jar",
 				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar",
 			},
 
 			dontVerifyDirect:           true,
 			dontVerifyTransitive:       true,
+			dontVerifyShared:           true,
 			dontVerifyDirectImport:     true,
 			dontVerifyTransitiveImport: true,
 		},
@@ -968,17 +1066,21 @@
 				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
 				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
 			},
-			appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			appImports: []string{
+				"out/soong/.intermediates/shared/android_common/package-res.apk",
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+			},
 			appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"},
 			appClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar",
 			},
 			appCombined: []string{
 				"out/soong/.intermediates/app/android_common/javac/app.jar",
 				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar",
 			},
 
 			directResources: nil,
@@ -992,19 +1094,20 @@
 			directSrcJars: nil,
 			directClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
-				"out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
-				"out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
 				"out/soong/.intermediates/direct/android_common/busybox/R.jar",
+				"out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
+				"out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
 				"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/turbine-combined/transitive_import.jar",
 			},
 			directCombined: []string{
 				"out/soong/.intermediates/direct/android_common/javac/direct.jar",
 				"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/combined/transitive_import.jar",
 			},
 
 			dontVerifyTransitive:       true,
+			dontVerifyShared:           true,
 			dontVerifyDirectImport:     true,
 			dontVerifyTransitiveImport: true,
 		},
@@ -1025,17 +1128,21 @@
 				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
 				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
 			},
-			appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			appImports: []string{
+				"out/soong/.intermediates/shared/android_common/package-res.apk",
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+			},
 			appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"},
 			appClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar",
 			},
 			appCombined: []string{
 				"out/soong/.intermediates/app/android_common/javac/app.jar",
 				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
-				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar",
 			},
 
 			directResources: nil,
@@ -1050,12 +1157,12 @@
 			directClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
 				"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/turbine-combined/transitive_import.jar",
 			},
 			directCombined: []string{
 				"out/soong/.intermediates/direct/android_common/javac/direct.jar",
 				"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
-				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+				"out/soong/.intermediates/transitive_import/android_common/combined/transitive_import.jar",
 			},
 
 			transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
@@ -1068,6 +1175,7 @@
 			},
 			transitiveCombined: nil,
 
+			dontVerifyShared:           true,
 			dontVerifyDirectImport:     true,
 			dontVerifyTransitiveImport: true,
 		},
@@ -1082,6 +1190,7 @@
 					srcs: ["app/app.java"],
 					resource_dirs: ["app/res"],
 					manifest: "app/AndroidManifest.xml",
+					libs: ["shared"],
 					static_libs: ["direct", "direct_import"],
 					use_resource_processor: %v,
 				}
@@ -1105,6 +1214,35 @@
 					use_resource_processor: %v,
 				}
 
+				android_library {
+					name: "shared",
+					sdk_version: "current",
+					srcs: ["shared/shared.java"],
+					resource_dirs: ["shared/res"],
+					manifest: "shared/AndroidManifest.xml",
+					use_resource_processor: %v,
+					libs: ["shared_transitive_shared"],
+					static_libs: ["shared_transitive_static"],
+				}
+
+				android_library {
+					name: "shared_transitive_shared",
+					sdk_version: "current",
+					srcs: ["shared_transitive_shared/shared_transitive_shared.java"],
+					resource_dirs: ["shared_transitive_shared/res"],
+					manifest: "shared_transitive_shared/AndroidManifest.xml",
+					use_resource_processor: %v,
+				}
+
+				android_library {
+					name: "shared_transitive_static",
+					sdk_version: "current",
+					srcs: ["shared_transitive_static/shared.java"],
+					resource_dirs: ["shared_transitive_static/res"],
+					manifest: "shared_transitive_static/AndroidManifest.xml",
+					use_resource_processor: %v,
+				}
+
 				android_library_import {
 					name: "direct_import",
 					sdk_version: "current",
@@ -1130,17 +1268,20 @@
 					sdk_version: "current",
 					aars: ["transitive_import_dep.aar"],
 				}
-			`, testCase.appUsesRP, testCase.directLibUsesRP, testCase.transitiveLibUsesRP)
+			`, testCase.appUsesRP, testCase.directLibUsesRP, testCase.transitiveLibUsesRP,
+				testCase.sharedLibUsesRP, testCase.sharedTransitiveSharedLibUsesRP, testCase.sharedTransitiveStaticLibUsesRP)
 
 			fs := android.MockFS{
-				"app/res/values/strings.xml":        nil,
-				"direct/res/values/strings.xml":     nil,
-				"transitive/res/values/strings.xml": nil,
+				"app/res/values/strings.xml":                      nil,
+				"direct/res/values/strings.xml":                   nil,
+				"transitive/res/values/strings.xml":               nil,
+				"shared/res/values/strings.xml":                   nil,
+				"shared_transitive_static/res/values/strings.xml": nil,
+				"shared_transitive_shared/res/values/strings.xml": nil,
 			}
 
 			result := android.GroupFixturePreparers(
 				PrepareForTestWithJavaDefaultModules,
-				PrepareForTestWithOverlayBuildComponents,
 				fs.AddToFixture(),
 			).RunTestWithBp(t, bp)
 
@@ -1182,6 +1323,7 @@
 			app := getAaptInfo("app")
 			direct := getAaptInfo("direct")
 			transitive := getAaptInfo("transitive")
+			shared := getAaptInfo("shared")
 			directImport := getAaptInfo("direct_import")
 			transitiveImport := getAaptInfo("transitive_import")
 
@@ -1212,6 +1354,15 @@
 				android.AssertPathsRelativeToTopEquals(t, "transitive combined", testCase.transitiveCombined, transitive.combined)
 			}
 
+			if !testCase.dontVerifyShared {
+				android.AssertPathsRelativeToTopEquals(t, "shared resources", testCase.sharedResources, shared.resources)
+				android.AssertPathsRelativeToTopEquals(t, "shared overlays", testCase.sharedOverlays, shared.overlays)
+				android.AssertPathsRelativeToTopEquals(t, "shared imports", testCase.sharedImports, shared.imports)
+				android.AssertPathsRelativeToTopEquals(t, "shared srcjars", testCase.sharedSrcJars, shared.srcJars)
+				android.AssertPathsRelativeToTopEquals(t, "shared classpath", testCase.sharedClasspath, shared.classpath)
+				android.AssertPathsRelativeToTopEquals(t, "shared combined", testCase.sharedCombined, shared.combined)
+			}
+
 			if !testCase.dontVerifyDirectImport {
 				android.AssertPathsRelativeToTopEquals(t, "direct_import resources", testCase.directImportResources, directImport.resources)
 				android.AssertPathsRelativeToTopEquals(t, "direct_import overlays", testCase.directImportOverlays, directImport.overlays)
@@ -1413,7 +1564,6 @@
 		t.Run(testCase.name, func(t *testing.T) {
 			result := android.GroupFixturePreparers(
 				PrepareForTestWithJavaDefaultModules,
-				PrepareForTestWithOverlayBuildComponents,
 				fs.AddToFixture(),
 				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 					variables.DeviceResourceOverlays = deviceResourceOverlays
@@ -1959,7 +2109,7 @@
 		Output("libjni.so").Output.String()
 	sdkJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").
 		Output("libjni.so").Output.String()
-	vendorJNI := ctx.ModuleForTests("libvendorjni", "android_arm64_armv8-a_shared").
+	vendorJNI := ctx.ModuleForTests("libvendorjni", "android_vendor_arm64_armv8-a_shared").
 		Output("libvendorjni.so").Output.String()
 
 	for _, test := range testCases {
@@ -3094,7 +3244,10 @@
 			name: "static-y",
 			srcs: ["a.java"],
 			uses_libs: ["runtime-required-y"],
-			optional_uses_libs: ["runtime-optional-y"],
+			optional_uses_libs: [
+				"runtime-optional-y",
+				"missing-lib-a",
+			],
 			sdk_version: "current",
 		}
 
@@ -3130,7 +3283,7 @@
 			sdk_version: "current",
 			optional_uses_libs: [
 				"bar",
-				"baz",
+				"missing-lib-b",
 			],
 		}
 
@@ -3145,7 +3298,7 @@
 			],
 			optional_uses_libs: [
 				"bar",
-				"baz",
+				"missing-lib-b",
 			],
 		}
 	`
@@ -3167,10 +3320,10 @@
 	// propagated from dependencies.
 	actualManifestFixerArgs := app.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
 	expectManifestFixerArgs := `--extract-native-libs=true ` +
-		`--uses-library qux ` +
-		`--uses-library quuz ` +
 		`--uses-library foo ` +
 		`--uses-library com.non.sdk.lib ` +
+		`--uses-library qux ` +
+		`--uses-library quuz ` +
 		`--uses-library runtime-library ` +
 		`--uses-library runtime-required-x ` +
 		`--uses-library runtime-required-y ` +
@@ -3189,9 +3342,10 @@
 		`--uses-library runtime-required-x ` +
 		`--uses-library runtime-required-y ` +
 		`--optional-uses-library bar ` +
-		`--optional-uses-library baz ` +
 		`--optional-uses-library runtime-optional-x ` +
-		`--optional-uses-library runtime-optional-y `
+		`--optional-uses-library runtime-optional-y ` +
+		`--missing-optional-uses-library missing-lib-b ` +
+		`--missing-optional-uses-library missing-lib-a`
 	android.AssertStringDoesContain(t, "verify cmd args", verifyCmd, verifyArgs)
 
 	// Test that all libraries are verified for an APK (library order matters).
@@ -3200,14 +3354,14 @@
 		`--uses-library com.non.sdk.lib ` +
 		`--uses-library android.test.runner ` +
 		`--optional-uses-library bar ` +
-		`--optional-uses-library baz `
+		`--missing-optional-uses-library missing-lib-b `
 	android.AssertStringDoesContain(t, "verify apk cmd args", verifyApkCmd, verifyApkArgs)
 
 	// Test that necessary args are passed for constructing CLC in Ninja phase.
 	cmd := app.Rule("dexpreopt").RuleParams.Command
 	android.AssertStringDoesContain(t, "dexpreopt app cmd context", cmd, "--context-json=")
 	android.AssertStringDoesContain(t, "dexpreopt app cmd product_packages", cmd,
-		"--product-packages=out/soong/.intermediates/app/android_common/dexpreopt/product_packages.txt")
+		"--product-packages=out/soong/.intermediates/app/android_common/dexpreopt/app/product_packages.txt")
 }
 
 func TestDexpreoptBcp(t *testing.T) {
@@ -3475,7 +3629,10 @@
 		android_app {
 			name: "foo",
 			sdk_version: "current",
-			static_libs: ["lib1"],
+			static_libs: [
+				"lib1",
+				"lib3",
+			],
 		}
 
 		android_library {
@@ -3483,22 +3640,49 @@
 			sdk_version: "current",
 			optimize: {
 				proguard_flags_files: ["lib1proguard.cfg"],
+			},
+			static_libs: ["lib2"],
+		}
+
+		android_library {
+			name: "lib2",
+			sdk_version: "current",
+			optimize: {
+				proguard_flags_files: ["lib2proguard.cfg"],
 			}
 		}
+
+		android_library_import {
+			name: "lib3",
+			sdk_version: "current",
+			aars: ["lib3.aar"],
+			static_libs: ["lib4"],
+		}
+
+		android_library {
+			name: "lib4",
+			sdk_version: "current",
+			optimize: {
+				proguard_flags_files: ["lib4proguard.cfg"],
+			}
+		}
+
+
 	`)
 
 	m := ctx.ModuleForTests("foo", "android_common")
-	hasLib1Proguard := false
-	for _, s := range m.Rule("java.r8").Implicits.Strings() {
-		if s == "lib1proguard.cfg" {
-			hasLib1Proguard = true
-			break
-		}
-	}
+	r8 := m.Rule("java.r8")
+	implicits := r8.Implicits.RelativeToTop().Strings()
+	android.AssertStringListContains(t, "r8 implicits", implicits, "lib1proguard.cfg")
+	android.AssertStringListContains(t, "r8 implicits", implicits, "lib2proguard.cfg")
+	android.AssertStringListContains(t, "r8 implicits", implicits, "lib4proguard.cfg")
+	android.AssertStringListContains(t, "r8 implicits", implicits, "out/soong/.intermediates/lib3/android_common/aar/proguard.txt")
 
-	if !hasLib1Proguard {
-		t.Errorf("App does not use library proguard config")
-	}
+	flags := r8.Args["r8Flags"]
+	android.AssertStringDoesContain(t, "r8 flags", flags, "-include lib1proguard.cfg")
+	android.AssertStringDoesContain(t, "r8 flags", flags, "-include lib2proguard.cfg")
+	android.AssertStringDoesContain(t, "r8 flags", flags, "-include lib4proguard.cfg")
+	android.AssertStringDoesContain(t, "r8 flags", flags, "-include out/soong/.intermediates/lib3/android_common/aar/proguard.txt")
 }
 
 func TestTargetSdkVersionManifestFixer(t *testing.T) {
@@ -4137,3 +4321,172 @@
 		"\\S+soong/.intermediates/foo/android_common_bar/privapp_allowlist_com.google.android.foo.xml:\\S+/target/product/test_device/system/etc/permissions/bar.xml",
 	)
 }
+
+func TestApexGlobalMinSdkVersionOverride(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.ApexGlobalMinSdkVersionOverride = proptools.StringPtr("Tiramisu")
+		}),
+	).RunTestWithBp(t, `
+		android_app {
+			name: "com.android.bar",
+			srcs: ["a.java"],
+			sdk_version: "current",
+		}
+		android_app {
+			name: "com.android.foo",
+			srcs: ["a.java"],
+			sdk_version: "current",
+			min_sdk_version: "S",
+			updatable: true,
+		}
+		override_android_app {
+			name: "com.android.go.foo",
+			base: "com.android.foo",
+		}
+	`)
+	foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer")
+	fooOverride := result.ModuleForTests("com.android.foo", "android_common_com.android.go.foo").Rule("manifestFixer")
+	bar := result.ModuleForTests("com.android.bar", "android_common").Rule("manifestFixer")
+
+	android.AssertStringDoesContain(t,
+		"expected manifest fixer to set com.android.bar minSdkVersion to S",
+		bar.BuildParams.Args["args"],
+		"--minSdkVersion  S",
+	)
+	android.AssertStringDoesContain(t,
+		"com.android.foo: expected manifest fixer to set minSdkVersion to T",
+		foo.BuildParams.Args["args"],
+		"--minSdkVersion  T",
+	)
+	android.AssertStringDoesContain(t,
+		"com.android.go.foo: expected manifest fixer to set minSdkVersion to T",
+		fooOverride.BuildParams.Args["args"],
+		"--minSdkVersion  T",
+	)
+
+}
+
+func TestAppFlagsPackages(t *testing.T) {
+	ctx := testApp(t, `
+		android_app {
+			name: "foo",
+			srcs: ["a.java"],
+			sdk_version: "current",
+			flags_packages: [
+				"bar",
+				"baz",
+			],
+		}
+		aconfig_declarations {
+			name: "bar",
+			package: "com.example.package.bar",
+			srcs: [
+				"bar.aconfig",
+			],
+		}
+		aconfig_declarations {
+			name: "baz",
+			package: "com.example.package.baz",
+			srcs: [
+				"baz.aconfig",
+			],
+		}
+	`)
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+
+	// android_app module depends on aconfig_declarations listed in flags_packages
+	android.AssertBoolEquals(t, "foo expected to depend on bar", true,
+		CheckModuleHasDependency(t, ctx, "foo", "android_common", "bar"))
+
+	android.AssertBoolEquals(t, "foo expected to depend on baz", true,
+		CheckModuleHasDependency(t, ctx, "foo", "android_common", "baz"))
+
+	aapt2LinkRule := foo.Rule("android/soong/java.aapt2Link")
+	linkInFlags := aapt2LinkRule.Args["inFlags"]
+	android.AssertStringDoesContain(t,
+		"aapt2 link command expected to pass feature flags arguments",
+		linkInFlags,
+		"--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt",
+	)
+}
+
+// Test that dexpreopt is disabled if an optional_uses_libs exists, but does not provide an implementation.
+func TestNoDexpreoptOptionalUsesLibDoesNotHaveImpl(t *testing.T) {
+	bp := `
+		java_sdk_library_import {
+			name: "sdklib_noimpl",
+			public: {
+				jars: ["stub.jar"],
+			},
+		}
+		android_app {
+			name: "app",
+			srcs: ["a.java"],
+			sdk_version: "current",
+			optional_uses_libs: [
+				"sdklib_noimpl",
+			],
+		}
+	`
+	result := prepareForJavaTest.RunTestWithBp(t, bp)
+	dexpreopt := result.ModuleForTests("app", "android_common").MaybeRule("dexpreopt").Rule
+	android.AssertBoolEquals(t, "dexpreopt should be disabled if optional_uses_libs does not have an implementation", true, dexpreopt == nil)
+}
+
+func TestTestOnlyApp(t *testing.T) {
+	t.Parallel()
+	ctx := android.GroupFixturePreparers(
+		prepareForJavaTest,
+	).RunTestWithBp(t, `
+                // These should be test-only
+                android_test {
+                        name: "android-test",
+                }
+                android_test_helper_app {
+                        name: "helper-app",
+                }
+                override_android_test {
+                        name: "override-test",
+                        base: "android-app",
+                }
+                // And these should not be
+		android_app {
+			name: "android-app",
+                        srcs: ["b.java"],
+			sdk_version: "current",
+		}
+	`)
+
+	expectedTestOnly := []string{
+		"android-test",
+		"helper-app",
+		"override-test",
+	}
+
+	expectedTopLevel := []string{
+		"android-test",
+		"override-test",
+	}
+
+	assertTestOnlyAndTopLevel(t, ctx, expectedTestOnly, expectedTopLevel)
+}
+
+func TestAppStem(t *testing.T) {
+	ctx := testApp(t, `
+				android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					stem: "foo-new",
+					sdk_version: "current",
+				}`)
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+
+	outputs := fmt.Sprint(foo.AllOutputs())
+	if !strings.Contains(outputs, "foo-new.apk") {
+		t.Errorf("Module output does not contain expected apk %s", "foo-new.apk")
+	}
+}
diff --git a/java/base.go b/java/base.go
index f5eb01c..938ac5e 100644
--- a/java/base.go
+++ b/java/base.go
@@ -17,11 +17,12 @@
 import (
 	"fmt"
 	"path/filepath"
+	"reflect"
+	"slices"
 	"strconv"
 	"strings"
 
-	"android/soong/ui/metrics/bp2build_metrics_proto"
-
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 	"github.com/google/blueprint/proptools"
 
@@ -90,6 +91,9 @@
 	// if not blank, run jarjar using the specified rules file
 	Jarjar_rules *string `android:"path,arch_variant"`
 
+	// if not blank, used as prefix to generate repackage rule
+	Jarjar_prefix *string
+
 	// If not blank, set the java version passed to javac as -source and -target
 	Java_version *string
 
@@ -134,7 +138,7 @@
 	// supported at compile time. It should only be needed to compile tests in
 	// packages that exist in libcore and which are inconvenient to move
 	// elsewhere.
-	Patch_module *string `android:"arch_variant"`
+	Patch_module *string
 
 	Jacoco struct {
 		// List of classes to include for instrumentation with jacoco to collect coverage
@@ -192,6 +196,25 @@
 
 	// Additional srcJars tacked in by GeneratedJavaLibraryModule
 	Generated_srcjars []android.Path `android:"mutated"`
+
+	// intermediate aconfig cache file tacked in by GeneratedJavaLibraryModule
+	Aconfig_Cache_files []android.Path `android:"mutated"`
+
+	// If true, then only the headers are built and not the implementation jar.
+	Headers_only *bool
+
+	// A list of files or dependencies to make available to the build sandbox. This is
+	// useful if source files are symlinks, the targets of the symlinks must be listed here.
+	// Note that currently not all actions implemented by android_apps are sandboxed, so you
+	// may only see this being necessary in lint builds.
+	Compile_data []string `android:"path"`
+
+	// Property signifying whether the module compiles stubs or not.
+	// Should be set to true when srcs of this module are stub files.
+	// This property does not need to be set to true when the module depends on
+	// the stubs via libs, but should be set to true when the module depends on
+	// the stubs via static libs.
+	Is_stubs_module *bool
 }
 
 // Properties that are specific to device modules. Host module factories should not add these when
@@ -282,8 +305,8 @@
 	HiddenAPIFlagFileProperties
 }
 
-// Device properties that can be overridden by overriding module (e.g. override_android_app)
-type OverridableDeviceProperties struct {
+// Properties that can be overridden by overriding module (e.g. override_android_app)
+type OverridableProperties struct {
 	// set the name of the output. If not set, `name` is used.
 	// To override a module with this property set, overriding module might need to set this as well.
 	// Otherwise, both the overridden and the overriding modules will have the same output name, which
@@ -403,7 +426,6 @@
 	android.ModuleBase
 	android.DefaultableModuleBase
 	android.ApexModuleBase
-	android.BazelModuleBase
 
 	// Functionality common to Module and Import.
 	embeddableInModuleAndImport
@@ -412,12 +434,15 @@
 	protoProperties  android.ProtoProperties
 	deviceProperties DeviceProperties
 
-	overridableDeviceProperties OverridableDeviceProperties
+	overridableProperties OverridableProperties
+	sourceProperties      android.SourceProperties
 
 	// jar file containing header classes including static library dependencies, suitable for
 	// inserting into the bootclasspath/classpath of another compile
 	headerJarFile android.Path
 
+	repackagedHeaderJarFile android.Path
+
 	// jar file containing implementation classes including static library dependencies but no
 	// resources
 	implementationJarFile android.Path
@@ -429,6 +454,9 @@
 	srcJarArgs []string
 	srcJarDeps android.Paths
 
+	// the source files of this module and all its static dependencies
+	transitiveSrcFiles *android.DepSet[android.Path]
+
 	// jar file containing implementation classes and resources including static library
 	// dependencies
 	implementationAndResourcesJar android.Path
@@ -479,6 +507,9 @@
 	// expanded Jarjar_rules
 	expandJarjarRules android.Path
 
+	// jarjar rule for inherited jarjar rules
+	repackageJarjarRules android.Path
+
 	// Extra files generated by the module type to be added as java resources.
 	extraResources android.Paths
 
@@ -491,9 +522,6 @@
 	// list of the xref extraction files
 	kytheFiles android.Paths
 
-	// Collect the module directory for IDE info in java/jdeps.go.
-	modulePaths []string
-
 	hideApexVariantFromMake bool
 
 	sdkVersion    android.SdkSpec
@@ -509,13 +537,19 @@
 	// or the module should override Stem().
 	stem string
 
-	// Aconfig "cache files" that went directly into this module.  Transitive ones are
-	// tracked via JavaInfo.TransitiveAconfigFiles
-	// TODO: Extract to something standalone to propagate tags via GeneratedJavaLibraryModule
-	aconfigIntermediates android.Paths
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
 
-	// Aconfig files for all transitive deps.  Also exposed via JavaInfo
-	transitiveAconfigFiles *android.DepSet[android.Path]
+	// Values that will be set in the JarJarProvider data for jarjar repackaging,
+	// and merged with our dependencies' rules.
+	jarjarRenameRules map[string]string
+
+	stubsLinkType StubsLinkType
+
+	// Paths to the aconfig intermediate cache files that are provided by the
+	// java_aconfig_library or java_library modules that are statically linked
+	// to this module. Does not contain cache files from all transitive dependencies.
+	aconfigCacheFiles android.Paths
 }
 
 func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
@@ -574,9 +608,21 @@
 	}
 }
 
+func (j *Module) checkHeadersOnly(ctx android.ModuleContext) {
+	if _, ok := ctx.Module().(android.SdkContext); ok {
+		headersOnly := proptools.Bool(j.properties.Headers_only)
+		installable := proptools.Bool(j.properties.Installable)
+
+		if headersOnly && installable {
+			ctx.PropertyErrorf("headers_only", "This module has conflicting settings. headers_only is true which, which means this module doesn't generate an implementation jar. However installable is set to true.")
+		}
+	}
+}
+
 func (j *Module) addHostProperties() {
 	j.AddProperties(
 		&j.properties,
+		&j.overridableProperties,
 		&j.protoProperties,
 		&j.usesLibraryProperties,
 	)
@@ -586,7 +632,6 @@
 	j.addHostProperties()
 	j.AddProperties(
 		&j.deviceProperties,
-		&j.overridableDeviceProperties,
 		&j.dexer.dexProperties,
 		&j.dexpreoptProperties,
 		&j.linter.properties,
@@ -604,7 +649,7 @@
 	// Populate with package rules from the properties.
 	hiddenAPIInfo.extractPackageRulesFromProperties(&j.deviceProperties.HiddenAPIPackageProperties)
 
-	ctx.SetProvider(hiddenAPIPropertyInfoProvider, hiddenAPIInfo)
+	android.SetProvider(ctx, hiddenAPIPropertyInfoProvider, hiddenAPIInfo)
 }
 
 func (j *Module) OutputFiles(tag string) (android.Paths, error) {
@@ -622,6 +667,13 @@
 			return android.Paths{j.dexer.proguardDictionary.Path()}, nil
 		}
 		return nil, fmt.Errorf("%q was requested, but no output file was found.", tag)
+	case ".generated_srcjars":
+		return j.properties.Generated_srcjars, nil
+	case ".lint":
+		if j.linter.outputs.xml != nil {
+			return android.Paths{j.linter.outputs.xml}, nil
+		}
+		return nil, fmt.Errorf("%q was requested, but no output file was found.", tag)
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
@@ -664,7 +716,7 @@
 	// Force enable the instrumentation for java code that is built for APEXes ...
 	// except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent
 	// doesn't make sense) or framework libraries (e.g. libraries found in the InstrumentFrameworkModules list) unless EMMA_INSTRUMENT_FRAMEWORK is true.
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	isJacocoAgent := ctx.ModuleName() == "jacocoagent"
 	if j.DirectlyInAnyApex() && !isJacocoAgent && !apexInfo.IsForPlatform() {
 		if !inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
@@ -695,6 +747,10 @@
 	return j.SdkVersion(ctx).ApiLevel
 }
 
+func (j *Module) GetDeviceProperties() *DeviceProperties {
+	return &j.deviceProperties
+}
+
 func (j *Module) MaxSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
 	if j.deviceProperties.Max_sdk_version != nil {
 		return android.ApiLevelFrom(ctx, *j.deviceProperties.Max_sdk_version)
@@ -754,7 +810,7 @@
 	// Add dependency on libraries that provide additional hidden api annotations.
 	ctx.AddVariationDependencies(nil, hiddenApiAnnotationsTag, j.properties.Hiddenapi_additional_annotations...)
 
-	if ctx.DeviceConfig().VndkVersion() != "" && ctx.Config().EnforceInterPartitionJavaSdkLibrary() {
+	if ctx.Config().EnforceInterPartitionJavaSdkLibrary() {
 		// Require java_sdk_library at inter-partition java dependency to ensure stable
 		// interface between partitions. If inter-partition java_library dependency is detected,
 		// raise build error because java_library doesn't have a stable interface.
@@ -787,9 +843,11 @@
 		if dep != nil {
 			if component, ok := dep.(SdkLibraryComponentDependency); ok {
 				if lib := component.OptionalSdkLibraryImplementation(); lib != nil {
-					// Add library as optional if it's one of the optional compatibility libs.
+					// Add library as optional if it's one of the optional compatibility libs or it's
+					// explicitly listed in the optional_uses_libs property.
 					tag := usesLibReqTag
-					if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) {
+					if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) ||
+						android.InList(*lib, j.usesLibrary.usesLibraryProperties.Optional_uses_libs) {
 						tag = usesLibOptTag
 					}
 					ctx.AddVariationDependencies(nil, tag, *lib)
@@ -986,8 +1044,16 @@
 	ctx android.ModuleContext, flags javaBuilderFlags, srcFiles android.Paths) javaBuilderFlags {
 	// javac flags.
 	javacFlags := j.properties.Javacflags
+	var needsDebugInfo bool
 
-	if ctx.Config().MinimizeJavaDebugInfo() && !ctx.Host() {
+	needsDebugInfo = false
+	for _, flag := range javacFlags {
+		if strings.HasPrefix(flag, "-g") {
+			needsDebugInfo = true
+		}
+	}
+
+	if ctx.Config().MinimizeJavaDebugInfo() && !ctx.Host() && !needsDebugInfo {
 		// For non-host binaries, override the -g flag passed globally to remove
 		// local variable debug info to reduce disk and memory usage.
 		javacFlags = append(javacFlags, "-g:source,lines")
@@ -996,44 +1062,18 @@
 
 	if flags.javaVersion.usesJavaModules() {
 		javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
+	} else if len(j.properties.Openjdk9.Javacflags) > 0 {
+		// java version defaults higher than openjdk 9, these conditionals should no longer be necessary
+		ctx.PropertyErrorf("openjdk9.javacflags", "JDK version defaults to higher than 9")
+	}
 
+	if flags.javaVersion.usesJavaModules() {
 		if j.properties.Patch_module != nil {
 			// Manually specify build directory in case it is not under the repo root.
 			// (javac doesn't seem to expand into symbolic links when searching for patch-module targets, so
 			// just adding a symlink under the root doesn't help.)
 			patchPaths := []string{".", ctx.Config().SoongOutDir()}
 
-			// b/150878007
-			//
-			// Workaround to support *Bazel-executed* JDK9 javac in Bazel's
-			// execution root for --patch-module. If this javac command line is
-			// invoked within Bazel's execution root working directory, the top
-			// level directories (e.g. libcore/, tools/, frameworks/) are all
-			// symlinks. JDK9 javac does not traverse into symlinks, which causes
-			// --patch-module to fail source file lookups when invoked in the
-			// execution root.
-			//
-			// Short of patching javac or enumerating *all* directories as possible
-			// input dirs, manually add the top level dir of the source files to be
-			// compiled.
-			topLevelDirs := map[string]bool{}
-			for _, srcFilePath := range srcFiles {
-				srcFileParts := strings.Split(srcFilePath.String(), "/")
-				// Ignore source files that are already in the top level directory
-				// as well as generated files in the out directory. The out
-				// directory may be an absolute path, which means srcFileParts[0] is the
-				// empty string, so check that as well. Note that "out" in Bazel's execution
-				// root is *not* a symlink, which doesn't cause problems for --patch-modules
-				// anyway, so it's fine to not apply this workaround for generated
-				// source files.
-				if len(srcFileParts) > 1 &&
-					srcFileParts[0] != "" &&
-					srcFileParts[0] != "out" {
-					topLevelDirs[srcFileParts[0]] = true
-				}
-			}
-			patchPaths = append(patchPaths, android.SortedKeys(topLevelDirs)...)
-
 			classPath := flags.classpath.FormJavaClassPath("")
 			if classPath != "" {
 				patchPaths = append(patchPaths, classPath)
@@ -1061,11 +1101,24 @@
 
 }
 
-func (module *Module) addGeneratedSrcJars(path android.Path) {
-	module.properties.Generated_srcjars = append(module.properties.Generated_srcjars, path)
+func (j *Module) addGeneratedSrcJars(path android.Path) {
+	j.properties.Generated_srcjars = append(j.properties.Generated_srcjars, path)
 }
 
 func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars android.Paths) {
+
+	// Auto-propagating jarjar rules
+	jarjarProviderData := j.collectJarJarRules(ctx)
+	if jarjarProviderData != nil {
+		android.SetProvider(ctx, JarJarProvider, *jarjarProviderData)
+		text := getJarJarRuleText(jarjarProviderData)
+		if text != "" {
+			ruleTextFile := android.PathForModuleOut(ctx, "repackaged-jarjar", "repackaging.txt")
+			android.WriteFileRule(ctx, ruleTextFile, text)
+			j.repackageJarjarRules = ruleTextFile
+		}
+	}
+
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
 
 	deps := j.collectDeps(ctx)
@@ -1073,6 +1126,9 @@
 
 	if flags.javaVersion.usesJavaModules() {
 		j.properties.Srcs = append(j.properties.Srcs, j.properties.Openjdk9.Srcs...)
+	} else if len(j.properties.Openjdk9.Javacflags) > 0 {
+		// java version defaults higher than openjdk 9, these conditionals should no longer be necessary
+		ctx.PropertyErrorf("openjdk9.srcs", "JDK version defaults to higher than 9")
 	}
 
 	srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
@@ -1133,6 +1189,7 @@
 	uniqueSrcFiles = append(uniqueSrcFiles, uniqueJavaFiles...)
 	uniqueSrcFiles = append(uniqueSrcFiles, uniqueKtFiles...)
 	j.uniqueSrcFiles = uniqueSrcFiles
+	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: uniqueSrcFiles.Strings()})
 
 	// We don't currently run annotation processors in turbine, which means we can't use turbine
 	// generated header jars when an annotation processor that generates API is enabled.  One
@@ -1151,6 +1208,40 @@
 	// final R classes from the app.
 	flags.classpath = append(android.CopyOf(extraClasspathJars), flags.classpath...)
 
+	j.aconfigCacheFiles = append(deps.aconfigProtoFiles, j.properties.Aconfig_Cache_files...)
+
+	// If compiling headers then compile them and skip the rest
+	if proptools.Bool(j.properties.Headers_only) {
+		if srcFiles.HasExt(".kt") {
+			ctx.ModuleErrorf("Compiling headers_only with .kt not supported")
+		}
+		if ctx.Config().IsEnvFalse("TURBINE_ENABLED") || disableTurbine {
+			ctx.ModuleErrorf("headers_only is enabled but Turbine is disabled.")
+		}
+
+		_, j.headerJarFile, _ =
+			j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName,
+				extraCombinedJars)
+		if ctx.Failed() {
+			return
+		}
+
+		android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
+			HeaderJars:                          android.PathsIfNonNil(j.headerJarFile),
+			TransitiveLibsHeaderJars:            j.transitiveLibsHeaderJars,
+			TransitiveStaticLibsHeaderJars:      j.transitiveStaticLibsHeaderJars,
+			AidlIncludeDirs:                     j.exportAidlIncludeDirs,
+			ExportedPlugins:                     j.exportedPluginJars,
+			ExportedPluginClasses:               j.exportedPluginClasses,
+			ExportedPluginDisableTurbine:        j.exportedDisableTurbine,
+			StubsLinkType:                       j.stubsLinkType,
+			AconfigIntermediateCacheOutputPaths: deps.aconfigProtoFiles,
+		})
+
+		j.outputFile = j.headerJarFile
+		return
+	}
+
 	if srcFiles.HasExt(".kt") {
 		// When using kotlin sources turbine is used to generate annotation processor sources,
 		// including for annotation processors that generate API, so we can use turbine for
@@ -1211,10 +1302,12 @@
 			return
 		}
 
+		kotlinJarPath := j.repackageFlagsIfNecessary(ctx, kotlinJar.OutputPath, jarName, "kotlinc")
+
 		// Make javac rule depend on the kotlinc rule
 		flags.classpath = append(classpath{kotlinHeaderJar}, flags.classpath...)
 
-		kotlinJars = append(kotlinJars, kotlinJar)
+		kotlinJars = append(kotlinJars, kotlinJarPath)
 		kotlinHeaderJars = append(kotlinHeaderJars, kotlinHeaderJar)
 
 		// Jar kotlin classes into the final jar after javac
@@ -1229,7 +1322,7 @@
 		}
 	}
 
-	jars := append(android.Paths(nil), kotlinJars...)
+	jars := slices.Clone(kotlinJars)
 
 	j.compiledSrcJars = srcJars
 
@@ -1244,8 +1337,8 @@
 			// allow for the use of annotation processors that do function correctly
 			// with sharding enabled. See: b/77284273.
 		}
-		extraJars := append(android.CopyOf(extraCombinedJars), kotlinHeaderJars...)
-		headerJarFileWithoutDepsOrJarjar, j.headerJarFile =
+		extraJars := append(slices.Clone(kotlinHeaderJars), extraCombinedJars...)
+		headerJarFileWithoutDepsOrJarjar, j.headerJarFile, j.repackagedHeaderJarFile =
 			j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
 		if ctx.Failed() {
 			return
@@ -1294,16 +1387,26 @@
 				for idx, shardSrc := range shardSrcs {
 					classes := j.compileJavaClasses(ctx, jarName, idx, shardSrc,
 						nil, flags, extraJarDeps)
+					classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(idx))
 					jars = append(jars, classes)
 				}
 			}
+			// Assume approximately 5 sources per srcjar.
+			// For framework-minus-apex in AOSP at the time this was written, there are 266 srcjars, with a mean
+			// of 5.8 sources per srcjar, but a median of 1, a standard deviation of 10, and a max of 48 source files.
 			if len(srcJars) > 0 {
-				classes := j.compileJavaClasses(ctx, jarName, len(shardSrcs),
-					nil, srcJars, flags, extraJarDeps)
-				jars = append(jars, classes)
+				startIdx := len(shardSrcs)
+				shardSrcJarsList := android.ShardPaths(srcJars, shardSize/5)
+				for idx, shardSrcJars := range shardSrcJarsList {
+					classes := j.compileJavaClasses(ctx, jarName, startIdx+idx,
+						nil, shardSrcJars, flags, extraJarDeps)
+					classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(startIdx+idx))
+					jars = append(jars, classes)
+				}
 			}
 		} else {
 			classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, extraJarDeps)
+			classes = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac")
 			jars = append(jars, classes)
 		}
 		if ctx.Failed() {
@@ -1311,6 +1414,8 @@
 		}
 	}
 
+	jars = append(jars, extraCombinedJars...)
+
 	j.srcJarArgs, j.srcJarDeps = resourcePathsToJarArgs(srcFiles), srcFiles
 
 	var includeSrcJar android.WritablePath
@@ -1397,8 +1502,6 @@
 		jars = append(jars, servicesJar)
 	}
 
-	jars = append(android.CopyOf(extraCombinedJars), jars...)
-
 	// Combine the classes built from sources, any manifests, and any static libraries into
 	// classes.jar. If there is only one input jar this step will be skipped.
 	var outputFile android.OutputPath
@@ -1524,7 +1627,7 @@
 
 	// Enable dex compilation for the APEX variants, unless it is disabled explicitly
 	compileDex := j.dexProperties.Compile_dex
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	if j.DirectlyInAnyApex() && !apexInfo.IsForPlatform() {
 		if compileDex == nil {
 			compileDex = proptools.BoolPtr(true)
@@ -1537,7 +1640,7 @@
 	if ctx.Device() && (Bool(j.properties.Installable) || Bool(compileDex)) {
 		if j.hasCode(ctx) {
 			if j.shouldInstrumentStatic(ctx) {
-				j.dexer.extraProguardFlagFiles = append(j.dexer.extraProguardFlagFiles,
+				j.dexer.extraProguardFlagsFiles = append(j.dexer.extraProguardFlagsFiles,
 					android.PathForSource(ctx, "build/make/core/proguard.jacoco.flags"))
 			}
 			// Dex compilation
@@ -1562,7 +1665,7 @@
 					false, nil, nil)
 				if *j.dexProperties.Uncompress_dex {
 					combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName).OutputPath
-					TransformZipAlign(ctx, combinedAlignedJar, combinedJar)
+					TransformZipAlign(ctx, combinedAlignedJar, combinedJar, nil)
 					dexOutputFile = combinedAlignedJar
 				} else {
 					dexOutputFile = combinedJar
@@ -1579,7 +1682,7 @@
 			j.dexJarFile = makeDexJarPathFromPath(dexOutputFile)
 
 			// Dexpreopting
-			j.dexpreopt(ctx, dexOutputFile)
+			j.dexpreopt(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), dexOutputFile)
 
 			outputFile = dexOutputFile
 		} else {
@@ -1597,30 +1700,11 @@
 	}
 
 	if ctx.Device() {
-		lintSDKVersion := func(apiLevel android.ApiLevel) int {
+		lintSDKVersion := func(apiLevel android.ApiLevel) android.ApiLevel {
 			if !apiLevel.IsPreview() {
-				return apiLevel.FinalInt()
+				return apiLevel
 			} else {
-				// When running metalava, we pass --version-codename. When that value
-				// is not REL, metalava will add 1 to the --current-version argument.
-				// On old branches, PLATFORM_SDK_VERSION is the latest version (for that
-				// branch) and the codename is REL, except potentially on the most
-				// recent non-master branch. On that branch, it goes through two other
-				// phases before it gets to the phase previously described:
-				//  - PLATFORM_SDK_VERSION has not been updated yet, and the codename
-				//    is not rel. This happens for most of the internal branch's life
-				//    while the branch has been cut but is still under active development.
-				//  - PLATFORM_SDK_VERSION has been set, but the codename is still not
-				//    REL. This happens briefly during the release process. During this
-				//    state the code to add --current-version is commented out, and then
-				//    that commenting out is reverted after the codename is set to REL.
-				// On the master branch, the PLATFORM_SDK_VERSION always represents a
-				// prior version and the codename is always non-REL.
-				//
-				// We need to add one here to match metalava adding 1. Technically
-				// this means that in the state described in the second bullet point
-				// above, this number is 1 higher than it should be.
-				return ctx.Config().PlatformSdkVersion().FinalInt() + 1
+				return ctx.Config().DefaultAppTargetSdk(ctx)
 			}
 		}
 
@@ -1635,31 +1719,37 @@
 		j.linter.compileSdkKind = j.SdkVersion(ctx).Kind
 		j.linter.javaLanguageLevel = flags.javaVersion.String()
 		j.linter.kotlinLanguageLevel = "1.3"
+		j.linter.compile_data = android.PathsForModuleSrc(ctx, j.properties.Compile_data)
 		if !apexInfo.IsForPlatform() && ctx.Config().UnbundledBuildApps() {
 			j.linter.buildModuleReportZip = true
 		}
 		j.linter.lint(ctx)
 	}
 
+	j.collectTransitiveSrcFiles(ctx, srcFiles)
+
 	ctx.CheckbuildFile(outputFile)
 
-	j.collectTransitiveAconfigFiles(ctx)
+	android.CollectDependencyAconfigFiles(ctx, &j.mergedAconfigFiles)
 
-	ctx.SetProvider(JavaInfoProvider, JavaInfo{
-		HeaderJars:                     android.PathsIfNonNil(j.headerJarFile),
-		TransitiveLibsHeaderJars:       j.transitiveLibsHeaderJars,
-		TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
-		ImplementationAndResourcesJars: android.PathsIfNonNil(j.implementationAndResourcesJar),
-		ImplementationJars:             android.PathsIfNonNil(j.implementationJarFile),
-		ResourceJars:                   android.PathsIfNonNil(j.resourceJar),
-		AidlIncludeDirs:                j.exportAidlIncludeDirs,
-		SrcJarArgs:                     j.srcJarArgs,
-		SrcJarDeps:                     j.srcJarDeps,
-		ExportedPlugins:                j.exportedPluginJars,
-		ExportedPluginClasses:          j.exportedPluginClasses,
-		ExportedPluginDisableTurbine:   j.exportedDisableTurbine,
-		JacocoReportClassesFile:        j.jacocoReportClassesFile,
-		TransitiveAconfigFiles:         j.transitiveAconfigFiles,
+	android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
+		HeaderJars:                          android.PathsIfNonNil(j.headerJarFile),
+		RepackagedHeaderJars:                android.PathsIfNonNil(j.repackagedHeaderJarFile),
+		TransitiveLibsHeaderJars:            j.transitiveLibsHeaderJars,
+		TransitiveStaticLibsHeaderJars:      j.transitiveStaticLibsHeaderJars,
+		ImplementationAndResourcesJars:      android.PathsIfNonNil(j.implementationAndResourcesJar),
+		ImplementationJars:                  android.PathsIfNonNil(j.implementationJarFile),
+		ResourceJars:                        android.PathsIfNonNil(j.resourceJar),
+		AidlIncludeDirs:                     j.exportAidlIncludeDirs,
+		SrcJarArgs:                          j.srcJarArgs,
+		SrcJarDeps:                          j.srcJarDeps,
+		TransitiveSrcFiles:                  j.transitiveSrcFiles,
+		ExportedPlugins:                     j.exportedPluginJars,
+		ExportedPluginClasses:               j.exportedPluginClasses,
+		ExportedPluginDisableTurbine:        j.exportedDisableTurbine,
+		JacocoReportClassesFile:             j.jacocoReportClassesFile,
+		StubsLinkType:                       j.stubsLinkType,
+		AconfigIntermediateCacheOutputPaths: j.aconfigCacheFiles,
 	})
 
 	// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
@@ -1670,6 +1760,52 @@
 	return android.InList("androidx.compose.runtime_runtime", j.properties.Static_libs)
 }
 
+func collectDepProguardSpecInfo(ctx android.ModuleContext) (transitiveProguardFlags, transitiveUnconditionalExportedFlags []*android.DepSet[android.Path]) {
+	ctx.VisitDirectDeps(func(m android.Module) {
+		depProguardInfo, _ := android.OtherModuleProvider(ctx, m, ProguardSpecInfoProvider)
+		depTag := ctx.OtherModuleDependencyTag(m)
+
+		if depProguardInfo.UnconditionallyExportedProguardFlags != nil {
+			transitiveUnconditionalExportedFlags = append(transitiveUnconditionalExportedFlags, depProguardInfo.UnconditionallyExportedProguardFlags)
+			transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.UnconditionallyExportedProguardFlags)
+		}
+
+		if depTag == staticLibTag && depProguardInfo.ProguardFlagsFiles != nil {
+			transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.ProguardFlagsFiles)
+		}
+	})
+
+	return transitiveProguardFlags, transitiveUnconditionalExportedFlags
+}
+
+func (j *Module) collectProguardSpecInfo(ctx android.ModuleContext) ProguardSpecInfo {
+	transitiveProguardFlags, transitiveUnconditionalExportedFlags := collectDepProguardSpecInfo(ctx)
+
+	directUnconditionalExportedFlags := android.Paths{}
+	proguardFlagsForThisModule := android.PathsForModuleSrc(ctx, j.dexProperties.Optimize.Proguard_flags_files)
+	exportUnconditionally := proptools.Bool(j.dexProperties.Optimize.Export_proguard_flags_files)
+	if exportUnconditionally {
+		// if we explicitly export, then our unconditional exports are the same as our transitive flags
+		transitiveUnconditionalExportedFlags = transitiveProguardFlags
+		directUnconditionalExportedFlags = proguardFlagsForThisModule
+	}
+
+	return ProguardSpecInfo{
+		Export_proguard_flags_files: exportUnconditionally,
+		ProguardFlagsFiles: android.NewDepSet[android.Path](
+			android.POSTORDER,
+			proguardFlagsForThisModule,
+			transitiveProguardFlags,
+		),
+		UnconditionallyExportedProguardFlags: android.NewDepSet[android.Path](
+			android.POSTORDER,
+			directUnconditionalExportedFlags,
+			transitiveUnconditionalExportedFlags,
+		),
+	}
+
+}
+
 // Returns a copy of the supplied flags, but with all the errorprone-related
 // fields copied to the regular build's fields.
 func enableErrorproneFlags(flags javaBuilderFlags) javaBuilderFlags {
@@ -1739,7 +1875,7 @@
 
 func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths,
 	deps deps, flags javaBuilderFlags, jarName string,
-	extraJars android.Paths) (headerJar, jarjarAndDepsHeaderJar android.Path) {
+	extraJars android.Paths) (headerJar, jarjarAndDepsHeaderJar, jarjarAndDepsRepackagedHeaderJar android.Path) {
 
 	var jars android.Paths
 	if len(srcFiles) > 0 || len(srcJars) > 0 {
@@ -1747,7 +1883,7 @@
 		turbineJar := android.PathForModuleOut(ctx, "turbine", jarName)
 		TransformJavaToHeaderClasses(ctx, turbineJar, srcFiles, srcJars, flags)
 		if ctx.Failed() {
-			return nil, nil
+			return nil, nil, nil
 		}
 		jars = append(jars, turbineJar)
 		headerJar = turbineJar
@@ -1772,11 +1908,22 @@
 		TransformJarJar(ctx, jarjarFile, jarjarAndDepsHeaderJar, j.expandJarjarRules)
 		jarjarAndDepsHeaderJar = jarjarFile
 		if ctx.Failed() {
-			return nil, nil
+			return nil, nil, nil
 		}
 	}
 
-	return headerJar, jarjarAndDepsHeaderJar
+	if j.repackageJarjarRules != nil {
+		repackagedJarjarFile := android.PathForModuleOut(ctx, "repackaged-turbine-jarjar", jarName)
+		TransformJarJar(ctx, repackagedJarjarFile, jarjarAndDepsHeaderJar, j.repackageJarjarRules)
+		jarjarAndDepsRepackagedHeaderJar = repackagedJarjarFile
+		if ctx.Failed() {
+			return nil, nil, nil
+		}
+	} else {
+		jarjarAndDepsRepackagedHeaderJar = jarjarAndDepsHeaderJar
+	}
+
+	return headerJar, jarjarAndDepsHeaderJar, jarjarAndDepsRepackagedHeaderJar
 }
 
 func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
@@ -1818,20 +1965,23 @@
 			return
 		}
 
-		dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
-		if dep.TransitiveLibsHeaderJars != nil {
-			transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJars)
-		}
-		if dep.TransitiveStaticLibsHeaderJars != nil {
-			transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJars)
-		}
-
+		dep, _ := android.OtherModuleProvider(ctx, module, JavaInfoProvider)
 		tag := ctx.OtherModuleDependencyTag(module)
 		_, isUsesLibDep := tag.(usesLibraryDependencyTag)
 		if tag == libTag || tag == r8LibraryJarTag || isUsesLibDep {
 			directLibs = append(directLibs, dep.HeaderJars...)
 		} else if tag == staticLibTag {
 			directStaticLibs = append(directStaticLibs, dep.HeaderJars...)
+		} else {
+			// Don't propagate transitive libs for other kinds of dependencies.
+			return
+		}
+
+		if dep.TransitiveLibsHeaderJars != nil {
+			transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJars)
+		}
+		if dep.TransitiveStaticLibsHeaderJars != nil {
+			transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJars)
 		}
 	})
 	j.transitiveLibsHeaderJars = android.NewDepSet(android.POSTORDER, directLibs, transitiveLibs)
@@ -1852,7 +2002,7 @@
 	return android.Paths{j.implementationJarFile}
 }
 
-func (j *Module) DexJarBuildPath() OptionalDexJarPath {
+func (j *Module) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
 	return j.dexJarFile
 }
 
@@ -1885,7 +2035,6 @@
 	if j.expandJarjarRules != nil {
 		dpInfo.Jarjar_rules = append(dpInfo.Jarjar_rules, j.expandJarjarRules.String())
 	}
-	dpInfo.Paths = append(dpInfo.Paths, j.modulePaths...)
 	dpInfo.Static_libs = append(dpInfo.Static_libs, j.properties.Static_libs...)
 	dpInfo.Libs = append(dpInfo.Libs, j.properties.Libs...)
 	dpInfo.SrcJars = append(dpInfo.SrcJars, j.annoSrcJars.Strings()...)
@@ -1936,36 +2085,23 @@
 	return j.jacocoReportClassesFile
 }
 
-func (j *Module) IsInstallable() bool {
-	return Bool(j.properties.Installable)
-}
-
-func (j *Module) collectTransitiveAconfigFiles(ctx android.ModuleContext) {
-	// Aconfig files from this module
-	mine := j.aconfigIntermediates
-
-	// Aconfig files from transitive dependencies
-	fromDeps := []*android.DepSet[android.Path]{}
+func (j *Module) collectTransitiveSrcFiles(ctx android.ModuleContext, mine android.Paths) {
+	var fromDeps []*android.DepSet[android.Path]
 	ctx.VisitDirectDeps(func(module android.Module) {
-		dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
-		if dep.TransitiveAconfigFiles != nil {
-			fromDeps = append(fromDeps, dep.TransitiveAconfigFiles)
+		tag := ctx.OtherModuleDependencyTag(module)
+		if tag == staticLibTag {
+			depInfo, _ := android.OtherModuleProvider(ctx, module, JavaInfoProvider)
+			if depInfo.TransitiveSrcFiles != nil {
+				fromDeps = append(fromDeps, depInfo.TransitiveSrcFiles)
+			}
 		}
 	})
 
-	// DepSet containing aconfig files myself and from dependencies
-	j.transitiveAconfigFiles = android.NewDepSet(android.POSTORDER, mine, fromDeps)
+	j.transitiveSrcFiles = android.NewDepSet(android.POSTORDER, mine, fromDeps)
 }
 
-func (j *Module) AddAconfigIntermediate(path android.Path) {
-	j.aconfigIntermediates = append(j.aconfigIntermediates, path)
-}
-
-func (j *Module) getTransitiveAconfigFiles() *android.DepSet[android.Path] {
-	if j.transitiveAconfigFiles == nil {
-		panic(fmt.Errorf("java.Moduile: getTransitiveAconfigFiles called before collectTransitiveAconfigFiles module=%s", j.Name()))
-	}
-	return j.transitiveAconfigFiles
+func (j *Module) IsInstallable() bool {
+	return Bool(j.properties.Installable)
 }
 
 type sdkLinkType int
@@ -2126,15 +2262,14 @@
 			case staticLibTag:
 				ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
 			}
-		} else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
-			dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
-			if sdkLinkType != javaPlatform &&
-				ctx.OtherModuleHasProvider(module, SyspropPublicStubInfoProvider) {
-				// dep is a sysprop implementation library, but this module is not linking against
-				// the platform, so it gets the sysprop public stubs library instead.  Replace
-				// dep with the JavaInfo from the SyspropPublicStubInfoProvider.
-				syspropDep := ctx.OtherModuleProvider(module, SyspropPublicStubInfoProvider).(SyspropPublicStubInfo)
-				dep = syspropDep.JavaInfo
+		} else if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
+			if sdkLinkType != javaPlatform {
+				if syspropDep, ok := android.OtherModuleProvider(ctx, module, SyspropPublicStubInfoProvider); ok {
+					// dep is a sysprop implementation library, but this module is not linking against
+					// the platform, so it gets the sysprop public stubs library instead.  Replace
+					// dep with the JavaInfo from the SyspropPublicStubInfoProvider.
+					dep = syspropDep.JavaInfo
+				}
 			}
 			switch tag {
 			case bootClasspathTag:
@@ -2145,6 +2280,10 @@
 				}
 				deps.classpath = append(deps.classpath, dep.HeaderJars...)
 				deps.dexClasspath = append(deps.dexClasspath, dep.HeaderJars...)
+				if len(dep.RepackagedHeaderJars) == 1 && !slices.Contains(dep.HeaderJars, dep.RepackagedHeaderJars[0]) {
+					deps.classpath = append(deps.classpath, dep.RepackagedHeaderJars...)
+					deps.dexClasspath = append(deps.dexClasspath, dep.RepackagedHeaderJars...)
+				}
 				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
 				addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...)
 				deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
@@ -2164,6 +2303,7 @@
 				// annotation processor that generates API is incompatible with the turbine
 				// optimization.
 				deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
+				deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...)
 			case pluginTag:
 				if plugin, ok := module.(*Plugin); ok {
 					if plugin.pluginProperties.Processor_class != nil {
@@ -2206,7 +2346,7 @@
 			case syspropPublicStubDepTag:
 				// This is a sysprop implementation library, forward the JavaInfoProvider from
 				// the corresponding sysprop public stub library as SyspropPublicStubInfoProvider.
-				ctx.SetProvider(SyspropPublicStubInfoProvider, SyspropPublicStubInfo{
+				android.SetProvider(ctx, SyspropPublicStubInfoProvider, SyspropPublicStubInfo{
 					JavaInfo: dep,
 				})
 			}
@@ -2222,6 +2362,11 @@
 				deps.staticJars = append(deps.staticJars, dep.Srcs()...)
 				deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...)
 			}
+		} else if dep, ok := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider); ok {
+			switch tag {
+			case staticLibTag:
+				deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...)
+			}
 		} else {
 			switch tag {
 			case bootClasspathTag:
@@ -2244,11 +2389,320 @@
 		}
 
 		addCLCFromDep(ctx, module, j.classLoaderContexts)
+		addMissingOptionalUsesLibsFromDep(ctx, module, &j.usesLibrary)
 	})
 
 	return deps
 }
 
+// Provider for jarjar renaming rules.
+//
+// Modules can set their jarjar renaming rules with addJarJarRenameRule, and those renamings will be
+// passed to all rdeps.  The typical way that these renamings will NOT be inherited is when a module
+// links against stubs -- these are not passed through stubs. The classes will remain unrenamed on
+// classes until a module with jarjar_prefix is reached, and all as yet unrenamed classes will then
+// be renamed from that module.
+// TODO: Add another property to suppress the forwarding of
+type DependencyUse int
+
+const (
+	RenameUseInvalid DependencyUse = iota
+	RenameUseInclude
+	RenameUseExclude
+)
+
+type RenameUseElement struct {
+	DepName   string
+	RenameUse DependencyUse
+	Why       string // token for determining where in the logic the decision was made.
+}
+
+type JarJarProviderData struct {
+	// Mapping of class names: original --> renamed.  If the value is "", the class will be
+	// renamed by the next rdep that has the jarjar_prefix attribute (or this module if it has
+	// attribute). Rdeps of that module will inherit the renaming.
+	Rename    map[string]string
+	RenameUse []RenameUseElement
+}
+
+func (this JarJarProviderData) GetDebugString() string {
+	result := ""
+	for _, k := range android.SortedKeys(this.Rename) {
+		v := this.Rename[k]
+		if strings.Contains(k, "android.companion.virtual.flags.FakeFeatureFlagsImpl") {
+			result += k + "--&gt;" + v + ";"
+		}
+	}
+	return result
+}
+
+var JarJarProvider = blueprint.NewProvider[JarJarProviderData]()
+
+var overridableJarJarPrefix = "com.android.internal.hidden_from_bootclasspath"
+
+func init() {
+	android.SetJarJarPrefixHandler(mergeJarJarPrefixes)
+}
+
+// BaseJarJarProviderData contains information that will propagate across dependencies regardless of
+// whether they are java modules or not.
+type BaseJarJarProviderData struct {
+	JarJarProviderData JarJarProviderData
+}
+
+func (this BaseJarJarProviderData) GetDebugString() string {
+	return this.JarJarProviderData.GetDebugString()
+}
+
+var BaseJarJarProvider = blueprint.NewProvider[BaseJarJarProviderData]()
+
+// mergeJarJarPrefixes is called immediately before module.GenerateAndroidBuildActions is called.
+// Since there won't be a JarJarProvider, we create the BaseJarJarProvider if any of our deps have
+// either JarJarProvider or BaseJarJarProvider.
+func mergeJarJarPrefixes(ctx android.ModuleContext) {
+	mod := ctx.Module()
+	// Explicitly avoid propagating into some module types.
+	switch reflect.TypeOf(mod).String() {
+	case "*java.Droidstubs":
+		return
+	}
+	jarJarData := collectDirectDepsProviders(ctx)
+	if jarJarData != nil {
+		providerData := BaseJarJarProviderData{
+			JarJarProviderData: *jarJarData,
+		}
+		android.SetProvider(ctx, BaseJarJarProvider, providerData)
+	}
+
+}
+
+// Add a jarjar renaming rule to this module, to be inherited to all dependent modules.
+func (module *Module) addJarJarRenameRule(original string, renamed string) {
+	if module.jarjarRenameRules == nil {
+		module.jarjarRenameRules = make(map[string]string)
+	}
+	module.jarjarRenameRules[original] = renamed
+}
+
+func collectDirectDepsProviders(ctx android.ModuleContext) (result *JarJarProviderData) {
+	// Gather repackage information from deps
+	// If the dep jas a JarJarProvider, it is used.  Otherwise, any BaseJarJarProvider is used.
+
+	module := ctx.Module()
+	moduleName := module.Name()
+
+	ctx.VisitDirectDepsIgnoreBlueprint(func(m android.Module) {
+		tag := ctx.OtherModuleDependencyTag(m)
+		// This logic mirrors that in (*Module).collectDeps above.  There are several places
+		// where we explicitly return RenameUseExclude, even though it is the default, to
+		// indicate that it has been verified to be the case.
+		//
+		// Note well: there are probably cases that are getting to the unconditional return
+		// and are therefore wrong.
+		shouldIncludeRenames := func() (DependencyUse, string) {
+			if moduleName == m.Name() {
+				return RenameUseInclude, "name" // If we have the same module name, include the renames.
+			}
+			if sc, ok := module.(android.SdkContext); ok {
+				if ctx.Device() {
+					sdkDep := decodeSdkDep(ctx, sc)
+					if !sdkDep.invalidVersion && sdkDep.useFiles {
+						return RenameUseExclude, "useFiles"
+					}
+				}
+			}
+			if IsJniDepTag(tag) || tag == certificateTag || tag == proguardRaiseTag {
+				return RenameUseExclude, "tags"
+			}
+			if _, ok := m.(SdkLibraryDependency); ok {
+				switch tag {
+				case sdkLibTag, libTag:
+					return RenameUseExclude, "sdklibdep" // matches collectDeps()
+				}
+				return RenameUseInvalid, "sdklibdep" // dep is not used in collectDeps()
+			} else if ji, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok {
+				switch ji.StubsLinkType {
+				case Stubs:
+					return RenameUseExclude, "info"
+				case Implementation:
+					return RenameUseInclude, "info"
+				default:
+					//fmt.Printf("LJ: %v -> %v StubsLinkType unknown\n", module, m)
+					// Fall through to the heuristic logic.
+				}
+				switch reflect.TypeOf(m).String() {
+				case "*java.GeneratedJavaLibraryModule":
+					// Probably a java_aconfig_library module.
+					// TODO: make this check better.
+					return RenameUseInclude, "reflect"
+				}
+				switch tag {
+				case bootClasspathTag:
+					return RenameUseExclude, "tagswitch"
+				case sdkLibTag, libTag, instrumentationForTag:
+					return RenameUseInclude, "tagswitch"
+				case java9LibTag:
+					return RenameUseExclude, "tagswitch"
+				case staticLibTag:
+					return RenameUseInclude, "tagswitch"
+				case pluginTag:
+					return RenameUseInclude, "tagswitch"
+				case errorpronePluginTag:
+					return RenameUseInclude, "tagswitch"
+				case exportedPluginTag:
+					return RenameUseInclude, "tagswitch"
+				case kotlinStdlibTag, kotlinAnnotationsTag:
+					return RenameUseExclude, "tagswitch"
+				case kotlinPluginTag:
+					return RenameUseInclude, "tagswitch"
+				default:
+					return RenameUseExclude, "tagswitch"
+				}
+			} else if _, ok := m.(android.SourceFileProducer); ok {
+				switch tag {
+				case sdkLibTag, libTag, staticLibTag:
+					return RenameUseInclude, "srcfile"
+				default:
+					return RenameUseExclude, "srcfile"
+				}
+			} else if _, ok := android.OtherModuleProvider(ctx, m, android.CodegenInfoProvider); ok {
+				return RenameUseInclude, "aconfig_declarations_group"
+			} else {
+				switch tag {
+				case bootClasspathTag:
+					return RenameUseExclude, "else"
+				case systemModulesTag:
+					return RenameUseInclude, "else"
+				}
+			}
+			// If we got here, choose the safer option, which may lead to a build failure, rather
+			// than runtime failures on the device.
+			return RenameUseExclude, "end"
+		}
+
+		if result == nil {
+			result = &JarJarProviderData{
+				Rename:    make(map[string]string),
+				RenameUse: make([]RenameUseElement, 0),
+			}
+		}
+		how, why := shouldIncludeRenames()
+		result.RenameUse = append(result.RenameUse, RenameUseElement{DepName: m.Name(), RenameUse: how, Why: why})
+		if how != RenameUseInclude {
+			// Nothing to merge.
+			return
+		}
+
+		merge := func(theirs *JarJarProviderData) {
+			for orig, renamed := range theirs.Rename {
+				if preexisting, exists := (*result).Rename[orig]; !exists || preexisting == "" {
+					result.Rename[orig] = renamed
+				} else if preexisting != "" && renamed != "" && preexisting != renamed {
+					if strings.HasPrefix(preexisting, overridableJarJarPrefix) {
+						result.Rename[orig] = renamed
+					} else if !strings.HasPrefix(renamed, overridableJarJarPrefix) {
+						ctx.ModuleErrorf("1. Conflicting jarjar rules inherited for class: %s (%s and %s)", orig, renamed, preexisting, ctx.ModuleName(), m.Name())
+						continue
+					}
+				}
+			}
+		}
+		if theirs, ok := android.OtherModuleProvider(ctx, m, JarJarProvider); ok {
+			merge(&theirs)
+		} else if theirs, ok := android.OtherModuleProvider(ctx, m, BaseJarJarProvider); ok {
+			// TODO: if every java.Module should have a JarJarProvider, and we find only the
+			// BaseJarJarProvider, then there is a bug.  Consider seeing if m can be cast
+			// to java.Module.
+			merge(&theirs.JarJarProviderData)
+		}
+	})
+	return
+}
+
+func (this Module) GetDebugString() string {
+	return "sdk_version=" + proptools.String(this.deviceProperties.Sdk_version)
+}
+
+// Merge the jarjar rules we inherit from our dependencies, any that have been added directly to
+// us, and if it's been set, apply the jarjar_prefix property to rename them.
+func (module *Module) collectJarJarRules(ctx android.ModuleContext) *JarJarProviderData {
+	// Gather repackage information from deps
+	result := collectDirectDepsProviders(ctx)
+
+	// Update that with entries we've stored for ourself
+	for orig, renamed := range module.jarjarRenameRules {
+		if result == nil {
+			result = &JarJarProviderData{
+				Rename: make(map[string]string),
+			}
+		}
+		if renamed != "" {
+			if preexisting, exists := (*result).Rename[orig]; exists && preexisting != renamed {
+				ctx.ModuleErrorf("Conflicting jarjar rules inherited for class: %s (%s and %s)", orig, renamed, preexisting)
+				continue
+			}
+		}
+		(*result).Rename[orig] = renamed
+	}
+
+	// If there are no renamings, then jarjar_prefix does nothing, so skip the extra work.
+	if result == nil {
+		return nil
+	}
+
+	// If they've given us a jarjar_prefix property, then we will use that to rename any classes
+	// that have not yet been renamed.
+	prefix := proptools.String(module.properties.Jarjar_prefix)
+	if prefix != "" {
+		if prefix[0] == '.' {
+			ctx.PropertyErrorf("jarjar_prefix", "jarjar_prefix can not start with '.'")
+			return nil
+		}
+		if prefix[len(prefix)-1] == '.' {
+			ctx.PropertyErrorf("jarjar_prefix", "jarjar_prefix can not end with '.'")
+			return nil
+		}
+
+		var updated map[string]string
+		for orig, renamed := range (*result).Rename {
+			if renamed == "" {
+				if updated == nil {
+					updated = make(map[string]string)
+				}
+				updated[orig] = prefix + "." + orig
+			}
+		}
+		for orig, renamed := range updated {
+			(*result).Rename[orig] = renamed
+		}
+	}
+
+	return result
+}
+
+// Get the jarjar rule text for a given provider for the fully resolved rules. Classes that map
+// to "" won't be in this list because they shouldn't be renamed yet.
+func getJarJarRuleText(provider *JarJarProviderData) string {
+	result := ""
+	for _, orig := range android.SortedKeys(provider.Rename) {
+		renamed := provider.Rename[orig]
+		if renamed != "" {
+			result += "rule " + orig + " " + renamed + "\n"
+		}
+	}
+	return result
+}
+
+// Repackage the flags if the jarjar rule txt for the flags is generated
+func (j *Module) repackageFlagsIfNecessary(ctx android.ModuleContext, infile android.WritablePath, jarName, info string) android.WritablePath {
+	if j.repackageJarjarRules == nil {
+		return infile
+	}
+	repackagedJarjarFile := android.PathForModuleOut(ctx, "repackaged-jarjar", info+jarName)
+	TransformJarJar(ctx, repackagedJarjarFile, infile, j.repackageJarjarRules)
+	return repackagedJarjarFile
+}
+
 func addPlugins(deps *deps, pluginJars android.Paths, pluginClasses ...string) {
 	deps.processorPath = append(deps.processorPath, pluginJars...)
 	deps.processorClasses = append(deps.processorClasses, pluginClasses...)
@@ -2270,21 +2724,12 @@
 
 var _ ModuleWithStem = (*Module)(nil)
 
-func (j *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	switch ctx.ModuleType() {
-	case "java_library", "java_library_host", "java_library_static", "tradefed_java_library_host":
-		if lib, ok := ctx.Module().(*Library); ok {
-			javaLibraryBp2Build(ctx, lib)
-		}
-	case "java_binary_host":
-		if binary, ok := ctx.Module().(*Binary); ok {
-			javaBinaryHostBp2Build(ctx, binary)
-		}
-	case "java_test_host":
-		if testHost, ok := ctx.Module().(*TestHost); ok {
-			javaTestHostBp2Build(ctx, testHost)
-		}
-	default:
-		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
-	}
+type ModuleWithUsesLibrary interface {
+	UsesLibrary() *usesLibrary
 }
+
+func (j *Module) UsesLibrary() *usesLibrary {
+	return &j.usesLibrary
+}
+
+var _ ModuleWithUsesLibrary = (*Module)(nil)
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index dcc2dec..cc3da76 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -23,6 +23,7 @@
 
 	"android/soong/android"
 	"android/soong/dexpreopt"
+	"android/soong/testing"
 
 	"github.com/google/blueprint/proptools"
 
@@ -76,7 +77,7 @@
 		return javaSdkLibrarySdkMemberType
 	}
 
-	return javaBootLibsSdkMemberType
+	return JavaBootLibsSdkMemberType
 }
 
 func (b bootclasspathFragmentContentDependencyTag) ExportMember() bool {
@@ -228,6 +229,7 @@
 
 type BootclasspathFragmentModule struct {
 	android.ModuleBase
+	android.DefaultableModuleBase
 	android.ApexModuleBase
 	ClasspathFragmentBase
 
@@ -238,11 +240,9 @@
 
 	sourceOnlyProperties SourceOnlyBootclasspathProperties
 
-	// Collect the module directory for IDE info in java/jdeps.go.
-	modulePaths []string
-
 	// Path to the boot image profile.
-	profilePath android.WritablePath
+	profilePath    android.WritablePath
+	profilePathErr error
 }
 
 // commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt
@@ -268,6 +268,7 @@
 	android.InitApexModule(m)
 	initClasspathFragment(m, BOOTCLASSPATH)
 	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(m)
 
 	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
 		// If code coverage has been enabled for the framework then append the properties with
@@ -354,7 +355,7 @@
 	}
 }
 
-var BootclasspathFragmentApexContentInfoProvider = blueprint.NewProvider(BootclasspathFragmentApexContentInfo{})
+var BootclasspathFragmentApexContentInfoProvider = blueprint.NewProvider[BootclasspathFragmentApexContentInfo]()
 
 // BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the
 // apex contents.
@@ -386,6 +387,10 @@
 	}
 }
 
+func (i BootclasspathFragmentApexContentInfo) DexBootJarPathMap() bootDexJarByModule {
+	return i.contentModuleDexJarPaths
+}
+
 func (i BootclasspathFragmentApexContentInfo) ProfilePathOnHost() android.Path {
 	return i.profilePathOnHost
 }
@@ -396,6 +401,11 @@
 
 func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
 	tag := ctx.OtherModuleDependencyTag(dep)
+
+	// If the module is a default module, do not check the tag
+	if _, ok := dep.(*Defaults); ok {
+		return true
+	}
 	if IsBootclasspathFragmentContentDepTag(tag) {
 		// Boot image contents are automatically added to apex.
 		return true
@@ -471,9 +481,6 @@
 	// Generate classpaths.proto config
 	b.generateClasspathProtoBuildActions(ctx)
 
-	// Collect the module directory for IDE info in java/jdeps.go.
-	b.modulePaths = append(b.modulePaths, ctx.ModuleDir())
-
 	// Gather the bootclasspath fragment's contents.
 	var contents []android.Module
 	ctx.VisitDirectDeps(func(module android.Module) {
@@ -505,6 +512,7 @@
 	if ctx.Module() != ctx.FinalModule() {
 		b.HideFromMake()
 	}
+	android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 // getProfileProviderApex returns the name of the apex that provides a boot image profile, or an
@@ -516,7 +524,7 @@
 	}
 
 	// Bootclasspath fragment modules that are for the platform do not produce boot related files.
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	for _, apex := range apexInfo.InApexVariants {
 		if isProfileProviderApex(ctx, apex) {
 			return apex
@@ -537,11 +545,11 @@
 
 	if profile != nil {
 		info.profilePathOnHost = profile
-		info.profileInstallPathInApex = profileInstallPathInApex
+		info.profileInstallPathInApex = ProfileInstallPathInApex
 	}
 
 	// Make the apex content info available for other modules.
-	ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info)
+	android.SetProvider(ctx, BootclasspathFragmentApexContentInfoProvider, info)
 }
 
 // generateClasspathProtoBuildActions generates all required build actions for classpath.proto config
@@ -582,7 +590,7 @@
 		// So ignore it even if it is not in PRODUCT_APEX_BOOT_JARS.
 		// TODO(b/202896428): Add better way to handle this.
 		_, unknown = android.RemoveFromList("android.car-module", unknown)
-		if len(unknown) > 0 {
+		if isActiveModule(ctx.Module()) && len(unknown) > 0 {
 			ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_APEX_BOOT_JARS", unknown)
 		}
 	}
@@ -627,26 +635,11 @@
 	hiddenAPIInfo.HiddenAPIFlagOutput = output.HiddenAPIFlagOutput
 
 	//  Provide it for use by other modules.
-	ctx.SetProvider(HiddenAPIInfoProvider, hiddenAPIInfo)
+	android.SetProvider(ctx, HiddenAPIInfoProvider, hiddenAPIInfo)
 
 	return output
 }
 
-// retrieveLegacyEncodedBootDexFiles attempts to retrieve the legacy encoded boot dex jar files.
-func retrieveLegacyEncodedBootDexFiles(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
-	// If the current bootclasspath_fragment is the active module or a source module then retrieve the
-	// encoded dex files, otherwise return an empty map.
-	//
-	// An inactive (i.e. not preferred) bootclasspath_fragment needs to retrieve the encoded dex jars
-	// as they are still needed by an apex. An inactive prebuilt_bootclasspath_fragment does not need
-	// to do so and may not yet have access to dex boot jars from a prebuilt_apex/apex_set.
-	if isActiveModule(ctx.Module()) || !android.IsModulePrebuilt(ctx.Module()) {
-		return extractEncodedDexJarsFromModules(ctx, contents)
-	} else {
-		return nil
-	}
-}
-
 // createHiddenAPIFlagInput creates a HiddenAPIFlagInput struct and initializes it with information derived
 // from the properties on this module and its dependencies.
 func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) HiddenAPIFlagInput {
@@ -763,7 +756,7 @@
 	}
 
 	// Make the information available for the sdk snapshot.
-	ctx.SetProvider(HiddenAPIInfoForSdkProvider, HiddenAPIInfoForSdk{
+	android.SetProvider(ctx, HiddenAPIInfoForSdkProvider, HiddenAPIInfoForSdk{
 		FlagFilesByCategory: flagFilesByCategory,
 		HiddenAPIFlagOutput: flagOutput,
 	})
@@ -782,7 +775,7 @@
 	dexLocations := make([]string, 0, len(contents))
 	for _, module := range contents {
 		dexPaths = append(dexPaths, modules[module.Name()])
-		dexLocations = append(dexLocations, filepath.Join("/", "apex", apex, "javalib", module.Name() + ".jar"))
+		dexLocations = append(dexLocations, filepath.Join("/", "apex", apex, "javalib", module.Name()+".jar"))
 	}
 
 	// Build a profile for the modules in this fragment.
@@ -816,7 +809,6 @@
 // Collect information for opening IDE project files in java/jdeps.go.
 func (b *BootclasspathFragmentModule) IDEInfo(dpInfo *android.IdeInfo) {
 	dpInfo.Deps = append(dpInfo.Deps, b.properties.Contents...)
-	dpInfo.Paths = append(dpInfo.Paths, b.modulePaths...)
 }
 
 type bootclasspathFragmentMemberType struct {
@@ -896,7 +888,7 @@
 
 	// Get the hidden API information from the module.
 	mctx := ctx.SdkModuleContext()
-	hiddenAPIInfo := mctx.OtherModuleProvider(module, HiddenAPIInfoForSdkProvider).(HiddenAPIInfoForSdk)
+	hiddenAPIInfo, _ := android.OtherModuleProvider(mctx, module, HiddenAPIInfoForSdkProvider)
 	b.Flag_files_by_category = hiddenAPIInfo.FlagFilesByCategory
 
 	// Copy all the generated file paths.
@@ -957,7 +949,7 @@
 					builder.CopyToSnapshot(p, dest)
 					dests = append(dests, dest)
 				}
-				hiddenAPISet.AddProperty(category.PropertyName, dests)
+				hiddenAPISet.AddProperty(category.PropertyName(), dests)
 			}
 		}
 	}
@@ -1053,10 +1045,6 @@
 		return android.PathForModuleSrc(ctx, *src)
 	}
 
-	// Retrieve the dex files directly from the content modules. They in turn should retrieve the
-	// encoded dex jars from the prebuilt .apex files.
-	encodedBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, contents)
-
 	output := HiddenAPIOutput{
 		HiddenAPIFlagOutput: HiddenAPIFlagOutput{
 			AnnotationFlagsPath:   pathForSrc("hidden_api.annotation_flags", module.prebuiltProperties.Hidden_api.Annotation_flags),
@@ -1067,8 +1055,6 @@
 			StubFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Stub_flags, nil),
 			AllFlagsPath:  pathForOptionalSrc(module.prebuiltProperties.Hidden_api.All_flags, nil),
 		},
-
-		EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
 	}
 
 	// TODO: Temporarily fallback to stub_flags/all_flags properties until prebuilts have been updated.
@@ -1085,15 +1071,21 @@
 		return nil
 	}
 
-	di := android.FindDeapexerProviderForModule(ctx)
-	if di == nil {
+	di, err := android.FindDeapexerProviderForModule(ctx)
+	if err != nil {
+		// An error was found, possibly due to multiple apexes in the tree that export this library
+		// Defer the error till a client tries to call getProfilePath
+		module.profilePathErr = err
 		return nil // An error has been reported by FindDeapexerProviderForModule.
 	}
 
-	return di.PrebuiltExportPath(profileInstallPathInApex)
+	return di.PrebuiltExportPath(ProfileInstallPathInApex)
 }
 
 func (b *PrebuiltBootclasspathFragmentModule) getProfilePath() android.Path {
+	if b.profilePathErr != nil {
+		panic(b.profilePathErr.Error())
+	}
 	return b.profilePath
 }
 
@@ -1107,12 +1099,16 @@
 func (module *PrebuiltBootclasspathFragmentModule) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string {
 	for _, apex := range module.ApexProperties.Apex_available {
 		if isProfileProviderApex(ctx, apex) {
-			return []string{profileInstallPathInApex}
+			return []string{ProfileInstallPathInApex}
 		}
 	}
 	return nil
 }
 
+func (module *PrebuiltBootclasspathFragmentModule) UseProfileGuidedDexpreopt() bool {
+	return false
+}
+
 var _ android.RequiredFilesFromPrebuiltApex = (*PrebuiltBootclasspathFragmentModule)(nil)
 
 func prebuiltBootclasspathFragmentFactory() android.Module {
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 888caad..8bc0a7e 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -222,6 +222,11 @@
 		PrepareForTestWithJavaSdkLibraryFiles,
 		FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary", "mycoreplatform"),
 		FixtureConfigureApexBootJars("someapex:mysdklibrary"),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
 	).RunTestWithBp(t, `
 		bootclasspath_fragment {
 			name: "myfragment",
@@ -272,16 +277,16 @@
 	`)
 
 	fragment := result.Module("myfragment", "android_common")
-	info := result.ModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
+	info, _ := android.SingletonModuleProvider(result, fragment, HiddenAPIInfoProvider)
 
 	stubsJar := "out/soong/.intermediates/mystublib/android_common/dex/mystublib.jar"
 
 	// Stubs jars for mysdklibrary
-	publicStubsJar := "out/soong/.intermediates/mysdklibrary.stubs/android_common/dex/mysdklibrary.stubs.jar"
-	systemStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.system/android_common/dex/mysdklibrary.stubs.system.jar"
+	publicStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.exportable/android_common/dex/mysdklibrary.stubs.exportable.jar"
+	systemStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.exportable.system/android_common/dex/mysdklibrary.stubs.exportable.system.jar"
 
 	// Stubs jars for myothersdklibrary
-	otherPublicStubsJar := "out/soong/.intermediates/myothersdklibrary.stubs/android_common/dex/myothersdklibrary.stubs.jar"
+	otherPublicStubsJar := "out/soong/.intermediates/myothersdklibrary.stubs.exportable/android_common/dex/myothersdklibrary.stubs.exportable.jar"
 
 	// Check that SdkPublic uses public stubs for all sdk libraries.
 	android.AssertPathsRelativeToTopEquals(t, "public dex stubs jar", []string{otherPublicStubsJar, publicStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(PublicHiddenAPIScope))
@@ -316,6 +321,60 @@
 	android.AssertPathsRelativeToTopEquals(t, "widest dex stubs jar", expectedWidestPaths, info.TransitiveStubDexJarsByScope.StubDexJarsForWidestAPIScope())
 }
 
+func TestFromTextWidestApiScope(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForTestWithBootclasspathFragment,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.SetBuildFromTextStub(true)
+		}),
+		FixtureWithLastReleaseApis("mysdklibrary", "android-non-updatable"),
+		FixtureConfigureApexBootJars("someapex:mysdklibrary"),
+	).RunTestWithBp(t, `
+		bootclasspath_fragment {
+			name: "myfragment",
+			contents: ["mysdklibrary"],
+			additional_stubs: [
+				"android-non-updatable",
+			],
+			hidden_api: {
+				split_packages: ["*"],
+			},
+		}
+		java_sdk_library {
+			name: "mysdklibrary",
+			srcs: ["a.java"],
+			shared_library: false,
+			public: {enabled: true},
+			system: {enabled: true},
+		}
+		java_sdk_library {
+			name: "android-non-updatable",
+			srcs: ["b.java"],
+			compile_dex: true,
+			public: {
+				enabled: true,
+			},
+			system: {
+				enabled: true,
+			},
+			test: {
+				enabled: true,
+			},
+			module_lib: {
+				enabled: true,
+			},
+		}
+	`)
+
+	fragment := result.ModuleForTests("myfragment", "android_common")
+	dependencyStubDexFlag := "--dependency-stub-dex=out/soong/.intermediates/default/java/android-non-updatable.stubs.test_module_lib/android_common/dex/android-non-updatable.stubs.test_module_lib.jar"
+	stubFlagsCommand := fragment.Output("modular-hiddenapi/stub-flags.csv").RuleParams.Command
+	android.AssertStringDoesContain(t,
+		"Stub flags generating command does not include the expected dependency stub dex file",
+		stubFlagsCommand, dependencyStubDexFlag)
+}
+
 func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForTestWithBootclasspathFragment,
@@ -402,16 +461,16 @@
 
 	// Make sure that the library exports hidden API properties for use by the bootclasspath_fragment.
 	library := result.Module("mynewlibrary", "android_common")
-	info := result.ModuleProvider(library, hiddenAPIPropertyInfoProvider).(HiddenAPIPropertyInfo)
+	info, _ := android.SingletonModuleProvider(result, library, hiddenAPIPropertyInfoProvider)
 	android.AssertArrayString(t, "split packages", []string{"sdklibrary", "newlibrary"}, info.SplitPackages)
 	android.AssertArrayString(t, "package prefixes", []string{"newlibrary.all.mine"}, info.PackagePrefixes)
 	android.AssertArrayString(t, "single packages", []string{"newlibrary.mine"}, info.SinglePackages)
 	for _, c := range HiddenAPIFlagFileCategories {
 		expectedMaxTargetQPaths := []string(nil)
-		if c.PropertyName == "max_target_q" {
+		if c.PropertyName() == "max_target_q" {
 			expectedMaxTargetQPaths = []string{"my-new-max-target-q.txt"}
 		}
-		android.AssertPathsRelativeToTopEquals(t, c.PropertyName, expectedMaxTargetQPaths, info.FlagFilesByCategory[c])
+		android.AssertPathsRelativeToTopEquals(t, c.PropertyName(), expectedMaxTargetQPaths, info.FlagFilesByCategory[c])
 	}
 
 	// Make sure that the signature-patterns.csv is passed all the appropriate package properties
diff --git a/java/builder.go b/java/builder.go
index debf49a..5d84d0b 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -120,6 +120,8 @@
 				`--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED ` +
 				`--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED ` +
 				`--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED ` +
+				`--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED ` +
+				`--add-exports=jdk.internal.opt/jdk.internal.opt=ALL-UNNAMED ` +
 				`-jar ${config.JavaKytheExtractorJar} ` +
 				`${config.JavacHeapFlags} ${config.CommonJdkFlags} ` +
 				`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
@@ -212,6 +214,14 @@
 			CommandDeps: []string{"${config.MergeZipsCmd}"},
 		},
 		"jarArgs")
+	combineJarRsp = pctx.AndroidStaticRule("combineJarRsp",
+		blueprint.RuleParams{
+			Command:        `${config.MergeZipsCmd} --ignore-duplicates -j $jarArgs $out @$out.rsp`,
+			CommandDeps:    []string{"${config.MergeZipsCmd}"},
+			Rspfile:        "$out.rsp",
+			RspfileContent: "$in",
+		},
+		"jarArgs")
 
 	jarjar = pctx.AndroidStaticRule("jarjar",
 		blueprint.RuleParams{
@@ -259,29 +269,45 @@
 		},
 	)
 
-	checkZipAlignment = pctx.AndroidStaticRule("checkzipalign",
-		blueprint.RuleParams{
-			Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " +
-				"echo $in: Improper package alignment >&2; " +
-				"exit 1; " +
-				"else " +
-				"touch $out; " +
-				"fi",
-			CommandDeps: []string{"${config.ZipAlign}"},
-			Description: "Check zip alignment",
-		},
-	)
-
 	convertImplementationJarToHeaderJarRule = pctx.AndroidStaticRule("convertImplementationJarToHeaderJar",
 		blueprint.RuleParams{
 			Command:     `${config.Zip2ZipCmd} -i ${in} -o ${out} -x 'META-INF/services/**/*'`,
 			CommandDeps: []string{"${config.Zip2ZipCmd}"},
 		})
+
+	writeCombinedProguardFlagsFileRule = pctx.AndroidStaticRule("writeCombinedProguardFlagsFileRule",
+		blueprint.RuleParams{
+			Command: `rm -f $out && ` +
+				`for f in $in; do ` +
+				` echo  && ` +
+				` echo "# including $$f" && ` +
+				` cat $$f; ` +
+				`done > $out`,
+		})
+
+	gatherReleasedFlaggedApisRule = pctx.AndroidStaticRule("gatherReleasedFlaggedApisRule",
+		blueprint.RuleParams{
+			Command: `${aconfig} dump-cache --dedup --format='{fully_qualified_name}={state:bool}' ` +
+				`--out ${out} ` +
+				`${flags_path} ` +
+				`${filter_args} `,
+			CommandDeps: []string{"${aconfig}"},
+			Description: "aconfig_bool",
+		}, "flags_path", "filter_args")
+
+	generateMetalavaRevertAnnotationsRule = pctx.AndroidStaticRule("generateMetalavaRevertAnnotationsRule",
+		blueprint.RuleParams{
+			Command:     `${keep-flagged-apis} ${in} > ${out}`,
+			CommandDeps: []string{"${keep-flagged-apis}"},
+		})
 )
 
 func init() {
 	pctx.Import("android/soong/android")
 	pctx.Import("android/soong/java/config")
+
+	pctx.HostBinToolVariable("aconfig", "aconfig")
+	pctx.HostBinToolVariable("keep-flagged-apis", "keep-flagged-apis")
 }
 
 type javaBuilderFlags struct {
@@ -402,7 +428,7 @@
 		})
 }
 
-func turbineFlags(ctx android.ModuleContext, flags javaBuilderFlags) (string, android.Paths) {
+func turbineFlags(ctx android.ModuleContext, flags javaBuilderFlags, dir string) (string, android.Paths) {
 	var deps android.Paths
 
 	classpath := flags.classpath
@@ -427,13 +453,21 @@
 	deps = append(deps, classpath...)
 	turbineFlags := bootClasspath + " " + classpath.FormTurbineClassPath("--classpath ")
 
+	const flagsLimit = 32 * 1024
+	if len(turbineFlags) > flagsLimit {
+		flagsRspFile := android.PathForModuleOut(ctx, dir, "turbine-flags.rsp")
+		android.WriteFileRule(ctx, flagsRspFile, turbineFlags)
+		turbineFlags = "@" + flagsRspFile.String()
+		deps = append(deps, flagsRspFile)
+	}
+
 	return turbineFlags, deps
 }
 
 func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android.WritablePath,
 	srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
 
-	turbineFlags, deps := turbineFlags(ctx, flags)
+	turbineFlags, deps := turbineFlags(ctx, flags, "turbine")
 
 	deps = append(deps, srcJars...)
 
@@ -465,7 +499,7 @@
 func TurbineApt(ctx android.ModuleContext, outputSrcJar, outputResJar android.WritablePath,
 	srcFiles, srcJars android.Paths, flags javaBuilderFlags) {
 
-	turbineFlags, deps := turbineFlags(ctx, flags)
+	turbineFlags, deps := turbineFlags(ctx, flags, "kapt")
 
 	deps = append(deps, srcJars...)
 
@@ -518,14 +552,14 @@
 
 	deps = append(deps, srcJars...)
 
-	classpath := flags.classpath
+	javacClasspath := flags.classpath
 
 	var bootClasspath string
 	if flags.javaVersion.usesJavaModules() {
 		var systemModuleDeps android.Paths
 		bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device())
 		deps = append(deps, systemModuleDeps...)
-		classpath = append(flags.java9Classpath, classpath...)
+		javacClasspath = append(flags.java9Classpath, javacClasspath...)
 	} else {
 		deps = append(deps, flags.bootClasspath...)
 		if len(flags.bootClasspath) == 0 && ctx.Device() {
@@ -537,7 +571,19 @@
 		}
 	}
 
-	deps = append(deps, classpath...)
+	classpathArg := javacClasspath.FormJavaClassPath("-classpath")
+
+	// Keep the command line under the MAX_ARG_STRLEN limit by putting the classpath argument into an rsp file
+	// if it is too long.
+	const classpathLimit = 64 * 1024
+	if len(classpathArg) > classpathLimit {
+		classpathRspFile := outputFile.ReplaceExtension(ctx, "classpath")
+		android.WriteFileRule(ctx, classpathRspFile, classpathArg)
+		deps = append(deps, classpathRspFile)
+		classpathArg = "@" + classpathRspFile.String()
+	}
+
+	deps = append(deps, javacClasspath...)
 	deps = append(deps, flags.processorPath...)
 
 	processor := "-proc:none"
@@ -568,7 +614,7 @@
 		Args: map[string]string{
 			"javacFlags":    flags.javacFlags,
 			"bootClasspath": bootClasspath,
-			"classpath":     classpath.FormJavaClassPath("-classpath"),
+			"classpath":     classpathArg,
 			"processorpath": flags.processorPath.FormJavaClassPath("-processorpath"),
 			"processor":     processor,
 			"srcJars":       strings.Join(srcJars.Strings(), " "),
@@ -627,8 +673,23 @@
 		jarArgs = append(jarArgs, "-D")
 	}
 
+	rule := combineJar
+	// Keep the command line under the MAX_ARG_STRLEN limit by putting the list of jars into an rsp file
+	// if it is too long.
+	const jarsLengthLimit = 64 * 1024
+	jarsLength := 0
+	for i, jar := range jars {
+		if i != 0 {
+			jarsLength += 1
+		}
+		jarsLength += len(jar.String())
+	}
+	if jarsLength > jarsLengthLimit {
+		rule = combineJarRsp
+	}
+
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        combineJar,
+		Rule:        rule,
 		Description: desc,
 		Output:      outputFile,
 		Inputs:      jars,
@@ -689,12 +750,22 @@
 	android.WriteFileRule(ctx, outputFile, "Main-Class: "+mainClass+"\n")
 }
 
-func TransformZipAlign(ctx android.ModuleContext, outputFile android.WritablePath, inputFile android.Path) {
+func TransformZipAlign(ctx android.ModuleContext, outputFile android.WritablePath, inputFile android.Path, validations android.Paths) {
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        zipalign,
 		Description: "align",
 		Input:       inputFile,
 		Output:      outputFile,
+		Validations: validations,
+	})
+}
+
+func writeCombinedProguardFlagsFile(ctx android.ModuleContext, outputFile android.WritablePath, files android.Paths) {
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        writeCombinedProguardFlagsFileRule,
+		Description: "write combined proguard flags file",
+		Inputs:      files,
+		Output:      outputFile,
 	})
 }
 
diff --git a/java/classpath_element.go b/java/classpath_element.go
index 4962916..abbcae7 100644
--- a/java/classpath_element.go
+++ b/java/classpath_element.go
@@ -21,7 +21,6 @@
 	"strings"
 
 	"android/soong/android"
-	"github.com/google/blueprint"
 )
 
 // Supports constructing a list of ClasspathElement from a set of fragments and modules.
@@ -72,8 +71,7 @@
 
 // ClasspathElementContext defines the context methods needed by CreateClasspathElements
 type ClasspathElementContext interface {
-	OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool
-	OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{}
+	android.OtherModuleProviderContext
 	ModuleErrorf(fmt string, args ...interface{})
 }
 
@@ -123,12 +121,12 @@
 	// associated with a particular apex.
 	apexToFragment := map[string]android.Module{}
 	for _, fragment := range fragments {
-		if !ctx.OtherModuleHasProvider(fragment, android.ApexInfoProvider) {
+		apexInfo, ok := android.OtherModuleProvider(ctx, fragment, android.ApexInfoProvider)
+		if !ok {
 			ctx.ModuleErrorf("fragment %s is not part of an apex", fragment)
 			continue
 		}
 
-		apexInfo := ctx.OtherModuleProvider(fragment, android.ApexInfoProvider).(android.ApexInfo)
 		for _, apex := range apexInfo.InApexVariants {
 			if existing, ok := apexToFragment[apex]; ok {
 				ctx.ModuleErrorf("apex %s has multiple fragments, %s and %s", apex, fragment, existing)
@@ -146,8 +144,7 @@
 	// Iterate over the libraries to construct the ClasspathElements list.
 	for _, library := range libraries {
 		var element ClasspathElement
-		if ctx.OtherModuleHasProvider(library, android.ApexInfoProvider) {
-			apexInfo := ctx.OtherModuleProvider(library, android.ApexInfoProvider).(android.ApexInfo)
+		if apexInfo, ok := android.OtherModuleProvider(ctx, library, android.ApexInfoProvider); ok {
 
 			var fragment android.Module
 
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index bc9de50..0ebab4d 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -103,8 +103,8 @@
 func gatherPossibleApexModuleNamesAndStems(ctx android.ModuleContext, contents []string, tag blueprint.DependencyTag) []string {
 	set := map[string]struct{}{}
 	for _, name := range contents {
-		dep := ctx.GetDirectDepWithTag(name, tag)
-		set[name] = struct{}{}
+		dep, _ := ctx.GetDirectDepWithTag(name, tag).(android.Module)
+		set[ModuleStemForDeapexing(dep)] = struct{}{}
 		if m, ok := dep.(ModuleWithStem); ok {
 			set[m.Stem()] = struct{}{}
 		} else {
@@ -178,7 +178,7 @@
 		ClasspathFragmentProtoInstallDir: c.installDirPath,
 		ClasspathFragmentProtoOutput:     c.outputFilepath,
 	}
-	ctx.SetProvider(ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
+	android.SetProvider(ctx, ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
 }
 
 func writeClasspathsTextproto(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
@@ -211,7 +211,7 @@
 	}}
 }
 
-var ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider(ClasspathFragmentProtoContentInfo{})
+var ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider[ClasspathFragmentProtoContentInfo]()
 
 type ClasspathFragmentProtoContentInfo struct {
 	// Whether the classpaths.proto config is generated for the fragment.
diff --git a/java/code_metadata_test.go b/java/code_metadata_test.go
new file mode 100644
index 0000000..0ef348a
--- /dev/null
+++ b/java/code_metadata_test.go
@@ -0,0 +1,114 @@
+package java
+
+import (
+	"strings"
+	"testing"
+
+	"android/soong/android"
+	soongTesting "android/soong/testing"
+	"android/soong/testing/code_metadata_internal_proto"
+	"google.golang.org/protobuf/proto"
+)
+
+func TestCodeMetadata(t *testing.T) {
+	bp := `code_metadata {
+		name: "module-name",
+		teamId: "12345",
+		code: [
+			"foo",
+		]
+	}
+
+	java_sdk_library {
+		name: "foo",
+		srcs: ["a.java"],
+	}`
+	result := runCodeMetadataTest(t, android.FixtureExpectsNoErrors, bp)
+
+	module := result.ModuleForTests("module-name", "")
+
+	// Check that the provider has the right contents
+	data, _ := android.SingletonModuleProvider(result, module.Module(), soongTesting.CodeMetadataProviderKey)
+	if !strings.HasSuffix(
+		data.IntermediatePath.String(), "/intermediateCodeMetadata.pb",
+	) {
+		t.Errorf(
+			"Missing intermediates path in provider: %s",
+			data.IntermediatePath.String(),
+		)
+	}
+
+	metadata := android.ContentFromFileRuleForTests(t, result.TestContext,
+		module.Output(data.IntermediatePath.String()))
+
+	metadataList := make([]*code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership, 0, 2)
+	teamId := "12345"
+	bpFilePath := "Android.bp"
+	targetName := "foo"
+	srcFile := []string{"a.java"}
+	expectedMetadataProto := code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership{
+		TrendyTeamId: &teamId,
+		TargetName:   &targetName,
+		Path:         &bpFilePath,
+		SourceFiles:  srcFile,
+	}
+	metadataList = append(metadataList, &expectedMetadataProto)
+
+	CodeMetadataMetadata := code_metadata_internal_proto.CodeMetadataInternal{TargetOwnershipList: metadataList}
+	protoData, _ := proto.Marshal(&CodeMetadataMetadata)
+	expectedMetadata := string(protoData)
+
+	if metadata != expectedMetadata {
+		t.Errorf(
+			"Retrieved metadata: %s is not equal to expectedMetadata: %s", metadata,
+			expectedMetadata,
+		)
+	}
+
+	// Tests for all_test_spec singleton.
+	singleton := result.SingletonForTests("all_code_metadata")
+	rule := singleton.Rule("all_code_metadata_rule")
+	prebuiltOs := result.Config.PrebuiltOS()
+	expectedCmd := "out/soong/host/" + prebuiltOs + "/bin/metadata -rule code_metadata -inputFile out/soong/all_code_metadata_paths.rsp -outputFile out/soong/ownership/all_code_metadata.pb"
+	expectedOutputFile := "out/soong/ownership/all_code_metadata.pb"
+	expectedInputFile := "out/soong/.intermediates/module-name/intermediateCodeMetadata.pb"
+	if !strings.Contains(
+		strings.TrimSpace(rule.Output.String()),
+		expectedOutputFile,
+	) {
+		t.Errorf(
+			"Retrieved singletonOutputFile: %s is not equal to expectedSingletonOutputFile: %s",
+			rule.Output.String(), expectedOutputFile,
+		)
+	}
+
+	if !strings.Contains(
+		strings.TrimSpace(rule.Inputs[0].String()),
+		expectedInputFile,
+	) {
+		t.Errorf(
+			"Retrieved singletonInputFile: %s is not equal to expectedSingletonInputFile: %s",
+			rule.Inputs[0].String(), expectedInputFile,
+		)
+	}
+
+	if !strings.Contains(
+		strings.TrimSpace(rule.RuleParams.Command),
+		expectedCmd,
+	) {
+		t.Errorf(
+			"Retrieved cmd: %s doesn't contain expectedCmd: %s",
+			rule.RuleParams.Command, expectedCmd,
+		)
+	}
+}
+func runCodeMetadataTest(
+	t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
+) *android.TestResult {
+	return android.GroupFixturePreparers(
+		soongTesting.PrepareForTestWithTestingBuildComponents, prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles, FixtureWithLastReleaseApis("foo"),
+	).
+		ExtendWithErrorHandler(errorHandler).
+		RunTestWithBp(t, bp)
+}
diff --git a/java/config/Android.bp b/java/config/Android.bp
index 194e2c6..bfe83ab 100644
--- a/java/config/Android.bp
+++ b/java/config/Android.bp
@@ -12,6 +12,7 @@
     ],
     srcs: [
         "config.go",
+        "droidstubs.go",
         "error_prone.go",
         "kotlin.go",
         "makevars.go",
diff --git a/java/config/config.go b/java/config/config.go
index 83c27d3..2bb50f6 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -26,8 +26,7 @@
 )
 
 var (
-	pctx         = android.NewPackageContext("android/soong/java/config")
-	exportedVars = android.NewExportedVariables(pctx)
+	pctx = android.NewPackageContext("android/soong/java/config")
 
 	LegacyCorePlatformBootclasspathLibraries = []string{"legacy.core.platform.api.stubs", "core-lambda-stubs"}
 	LegacyCorePlatformSystemModules          = "legacy-core-platform-api-stubs-system-modules"
@@ -79,32 +78,30 @@
 func init() {
 	pctx.Import("github.com/google/blueprint/bootstrap")
 
-	exportedVars.ExportStringStaticVariable("JavacHeapSize", "4096M")
-	exportedVars.ExportStringStaticVariable("JavacHeapFlags", "-J-Xmx${JavacHeapSize}")
+	pctx.StaticVariable("JavacHeapSize", "4096M")
+	pctx.StaticVariable("JavacHeapFlags", "-J-Xmx${JavacHeapSize}")
 
 	// ErrorProne can use significantly more memory than javac alone, give it a higher heap
 	// size (b/221480398).
-	exportedVars.ExportStringStaticVariable("ErrorProneHeapSize", "8192M")
-	exportedVars.ExportStringStaticVariable("ErrorProneHeapFlags", "-J-Xmx${ErrorProneHeapSize}")
+	pctx.StaticVariable("ErrorProneHeapSize", "8192M")
+	pctx.StaticVariable("ErrorProneHeapFlags", "-J-Xmx${ErrorProneHeapSize}")
 
 	// D8 invocations are shorter lived, so we restrict their JIT tiering relative to R8.
 	// Note that the `-JXX` prefix syntax is specific to the R8/D8 invocation wrappers.
-	exportedVars.ExportStringListStaticVariable("D8Flags", append([]string{
+	pctx.StaticVariable("D8Flags", strings.Join(append([]string{
 		"-JXmx4096M",
 		"-JXX:+TieredCompilation",
 		"-JXX:TieredStopAtLevel=1",
 		"-JDcom.android.tools.r8.emitRecordAnnotationsInDex",
 		"-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex",
-		"-JDcom.android.tools.r8.emitRecordAnnotationsExInDex",
-	}, dexerJavaVmFlagsList...))
-	exportedVars.ExportStringListStaticVariable("R8Flags", append([]string{
+	}, dexerJavaVmFlagsList...), " "))
+	pctx.StaticVariable("R8Flags", strings.Join(append([]string{
 		"-JXmx4096M",
 		"-JDcom.android.tools.r8.emitRecordAnnotationsInDex",
 		"-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex",
-		"-JDcom.android.tools.r8.emitRecordAnnotationsExInDex",
-	}, dexerJavaVmFlagsList...))
+	}, dexerJavaVmFlagsList...), " "))
 
-	exportedVars.ExportStringListStaticVariable("CommonJdkFlags", []string{
+	pctx.StaticVariable("CommonJdkFlags", strings.Join([]string{
 		`-Xmaxerrs 9999999`,
 		`-encoding UTF-8`,
 		`-sourcepath ""`,
@@ -118,10 +115,10 @@
 
 		// b/65004097: prevent using java.lang.invoke.StringConcatFactory when using -target 1.9
 		`-XDstringConcat=inline`,
-	})
+	}, " "))
 
-	exportedVars.ExportStringListStaticVariable("JavaVmFlags", javaVmFlagsList)
-	exportedVars.ExportStringListStaticVariable("JavacVmFlags", javacVmFlagsList)
+	pctx.StaticVariable("JavaVmFlags", strings.Join(javaVmFlagsList, " "))
+	pctx.StaticVariable("JavacVmFlags", strings.Join(javacVmFlagsList, " "))
 
 	pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS)
 
@@ -133,7 +130,7 @@
 		if override := ctx.Config().Getenv("OVERRIDE_JLINK_VERSION_NUMBER"); override != "" {
 			return override
 		}
-		return "17"
+		return "21"
 	})
 
 	pctx.SourcePathVariable("JavaToolchain", "${JavaHome}/bin")
@@ -216,10 +213,6 @@
 	hostJNIToolVariableWithSdkToolsPrebuilt("SignapkJniLibrary", "libconscrypt_openjdk_jni")
 }
 
-func BazelJavaToolchainVars(config android.Config) string {
-	return android.BazelToolchainVars(config, exportedVars)
-}
-
 func hostBinToolVariableWithSdkToolsPrebuilt(name, tool string) {
 	pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
 		if ctx.Config().AlwaysUsePrebuiltSdks() {
diff --git a/java/config/droidstubs.go b/java/config/droidstubs.go
new file mode 100644
index 0000000..04a3f96
--- /dev/null
+++ b/java/config/droidstubs.go
@@ -0,0 +1,64 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package config
+
+import "strings"
+
+var (
+	metalavaFlags = []string{
+		"--color",
+		"--quiet",
+		"--format=v2",
+		"--repeat-errors-max 10",
+		"--hide UnresolvedImport",
+
+		// Force metalava to ignore classes on the classpath when an API file contains missing classes.
+		// See b/285140653 for more information.
+		"--api-class-resolution api",
+
+		// Force metalava to sort overloaded methods by their order in the source code.
+		// See b/285312164 for more information.
+		// And add concrete overrides of abstract methods, see b/299366704 for more
+		// information.
+		"--format-defaults overloaded-method-order=source,add-additional-overrides=yes",
+	}
+
+	MetalavaFlags = strings.Join(metalavaFlags, " ")
+
+	metalavaAnnotationsFlags = []string{
+		"--include-annotations",
+		"--exclude-annotation androidx.annotation.RequiresApi",
+	}
+
+	MetalavaAnnotationsFlags = strings.Join(metalavaAnnotationsFlags, " ")
+
+	metalavaAnnotationsWarningsFlags = []string{
+		// TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
+		"--hide HiddenTypedefConstant",
+		"--hide SuperfluousPrefix",
+	}
+
+	MetalavaAnnotationsWarningsFlags = strings.Join(metalavaAnnotationsWarningsFlags, " ")
+)
+
+const (
+	MetalavaAddOpens = "-J--add-opens=java.base/java.util=ALL-UNNAMED"
+)
+
+func init() {
+	pctx.StaticVariable("MetalavaAnnotationsFlags", strings.Join(metalavaAnnotationsFlags, " "))
+
+	pctx.StaticVariable("MetalavaAnnotationWarningsFlags", strings.Join(metalavaAnnotationsWarningsFlags, " "))
+}
diff --git a/java/config/error_prone.go b/java/config/error_prone.go
index 5f853c8..767164f 100644
--- a/java/config/error_prone.go
+++ b/java/config/error_prone.go
@@ -15,6 +15,7 @@
 package config
 
 import (
+	"android/soong/android"
 	"strings"
 )
 
@@ -29,23 +30,23 @@
 )
 
 // Wrapper that grabs value of val late so it can be initialized by a later module's init function
-func errorProneVar(val *[]string, sep string) func() string {
-	return func() string {
+func errorProneVar(val *[]string, sep string) func(android.PackageVarContext) string {
+	return func(android.PackageVarContext) string {
 		return strings.Join(*val, sep)
 	}
 }
 
 func init() {
-	exportedVars.ExportVariableFuncVariable("ErrorProneClasspath", errorProneVar(&ErrorProneClasspath, ":"))
-	exportedVars.ExportVariableFuncVariable("ErrorProneChecksError", errorProneVar(&ErrorProneChecksError, " "))
-	exportedVars.ExportVariableFuncVariable("ErrorProneChecksWarning", errorProneVar(&ErrorProneChecksWarning, " "))
-	exportedVars.ExportVariableFuncVariable("ErrorProneChecksDefaultDisabled", errorProneVar(&ErrorProneChecksDefaultDisabled, " "))
-	exportedVars.ExportVariableFuncVariable("ErrorProneChecksOff", errorProneVar(&ErrorProneChecksOff, " "))
-	exportedVars.ExportVariableFuncVariable("ErrorProneFlags", errorProneVar(&ErrorProneFlags, " "))
-	exportedVars.ExportStringListStaticVariable("ErrorProneChecks", []string{
+	pctx.VariableFunc("ErrorProneClasspath", errorProneVar(&ErrorProneClasspath, ":"))
+	pctx.VariableFunc("ErrorProneChecksError", errorProneVar(&ErrorProneChecksError, " "))
+	pctx.VariableFunc("ErrorProneChecksWarning", errorProneVar(&ErrorProneChecksWarning, " "))
+	pctx.VariableFunc("ErrorProneChecksDefaultDisabled", errorProneVar(&ErrorProneChecksDefaultDisabled, " "))
+	pctx.VariableFunc("ErrorProneChecksOff", errorProneVar(&ErrorProneChecksOff, " "))
+	pctx.VariableFunc("ErrorProneFlags", errorProneVar(&ErrorProneFlags, " "))
+	pctx.StaticVariable("ErrorProneChecks", strings.Join([]string{
 		"${ErrorProneChecksOff}",
 		"${ErrorProneChecksError}",
 		"${ErrorProneChecksWarning}",
 		"${ErrorProneChecksDefaultDisabled}",
-	})
+	}, " "))
 }
diff --git a/java/config/kotlin.go b/java/config/kotlin.go
index fc63f4d..e5e187c 100644
--- a/java/config/kotlin.go
+++ b/java/config/kotlin.go
@@ -49,8 +49,5 @@
 		"-J--add-opens=java.base/java.util=ALL-UNNAMED", // https://youtrack.jetbrains.com/issue/KT-43704
 	}, " "))
 
-	pctx.StaticVariable("KotlincGlobalFlags", strings.Join([]string{
-		// b/222162908: prevent kotlinc from reading /tmp/build.txt
-		"-Didea.plugins.compatible.build=999.SNAPSHOT",
-	}, " "))
+	pctx.StaticVariable("KotlincGlobalFlags", strings.Join([]string{}, " "))
 }
diff --git a/java/config/makevars.go b/java/config/makevars.go
index 4e09195..649b6c5 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -34,8 +34,6 @@
 
 	ctx.Strict("ANDROID_JAVA_HOME", "${JavaHome}")
 	ctx.Strict("ANDROID_JAVA8_HOME", "prebuilts/jdk/jdk8/${hostPrebuiltTag}")
-	ctx.Strict("ANDROID_JAVA9_HOME", "prebuilts/jdk/jdk9/${hostPrebuiltTag}")
-	ctx.Strict("ANDROID_JAVA11_HOME", "prebuilts/jdk/jdk11/${hostPrebuiltTag}")
 	ctx.Strict("ANDROID_JAVA_TOOLCHAIN", "${JavaToolchain}")
 	ctx.Strict("JAVA", "${JavaCmd} ${JavaVmFlags}")
 	ctx.Strict("JAVAC", "${JavacCmd} ${JavacVmFlags}")
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index de9a82d..ab72e8b 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -38,9 +38,6 @@
     visibility: ["//visibility:public"],
     sdk_version: "none",
     system_modules: "none",
-    dist: {
-        targets: dist_targets,
-    },
 }
 
 java_library {
@@ -55,6 +52,21 @@
     ],
 }
 
+java_api_library {
+    name: "core.current.stubs.from-text",
+    api_surface: "core",
+    api_contributions: [
+        "art.module.public.api.stubs.source.api.contribution",
+        "conscrypt.module.public.api.stubs.source.api.contribution",
+        "i18n.module.public.api.stubs.source.api.contribution",
+    ],
+    libs: [
+        "stub-annotations",
+    ],
+    enable_validation: false,
+    stubs_type: "everything",
+}
+
 java_library {
     name: "core.current.stubs",
     defaults: [
@@ -75,6 +87,32 @@
     },
 }
 
+java_library {
+    name: "core.current.stubs.exportable.from-source",
+    defaults: [
+        "core.current.stubs.defaults",
+    ],
+    static_libs: [
+        "art.module.public.api.stubs.exportable",
+        "conscrypt.module.public.api.stubs.exportable",
+        "i18n.module.public.api.stubs.exportable",
+    ],
+    dist: {
+        targets: dist_targets,
+        dest: "core.current.stubs.jar",
+    },
+}
+
+java_library {
+    name: "core.current.stubs.exportable",
+    defaults: [
+        "core.current.stubs.defaults",
+    ],
+    static_libs: [
+        "core.current.stubs.exportable.from-source",
+    ],
+}
+
 // Distributed with the SDK for turning into system modules to compile apps
 // against.
 //
@@ -153,7 +191,6 @@
     system_modules: "none",
 }
 
-
 // A stubs target containing the parts of the public SDK & @SystemApi(MODULE_LIBRARIES) API
 // provided by the core libraries.
 //
@@ -194,6 +231,27 @@
     ],
 }
 
+java_api_library {
+    name: "core.module_lib.stubs.from-text",
+    api_surface: "module-lib",
+    api_contributions: [
+        "art.module.public.api.stubs.source.api.contribution",
+        "art.module.public.api.stubs.source.system.api.contribution",
+        "art.module.public.api.stubs.source.module_lib.api.contribution",
+
+        // Add the module-lib correspondence when Conscrypt or i18N module
+        // provides @SystemApi(MODULE_LIBRARIES). Currently, assume that only ART module provides
+        // @SystemApi(MODULE_LIBRARIES).
+        "conscrypt.module.public.api.stubs.source.api.contribution",
+        "i18n.module.public.api.stubs.source.api.contribution",
+    ],
+    libs: [
+        "stub-annotations",
+    ],
+    visibility: ["//visibility:private"],
+    stubs_type: "everything",
+}
+
 // Produces a dist file that is used by the
 // prebuilts/sdk/update_prebuilts.py script to update the prebuilts/sdk
 // directory.
@@ -266,6 +324,46 @@
 }
 
 java_library {
+    name: "legacy.core.platform.api.stubs.exportable.from-source",
+    visibility: core_platform_visibility,
+    defaults: [
+        "core.platform.api.stubs.defaults",
+    ],
+    static_libs: [
+        "art.module.public.api.stubs.exportable.module_lib",
+        "conscrypt.module.platform.api.stubs.exportable",
+        "legacy.i18n.module.platform.api.stubs.exportable",
+    ],
+}
+
+java_defaults {
+    name: "android_core_platform_stubs_current_contributions",
+    api_surface: "core_platform",
+    api_contributions: [
+        "art.module.public.api.stubs.source.api.contribution",
+        "art.module.public.api.stubs.source.system.api.contribution",
+        "art.module.public.api.stubs.source.module_lib.api.contribution",
+        "conscrypt.module.platform.api.stubs.source.api.contribution",
+        "i18n.module.public.api.stubs.source.api.contribution",
+    ],
+}
+
+java_api_library {
+    name: "legacy.core.platform.api.stubs.from-text",
+    api_surface: "core_platform",
+    defaults: [
+        "android_core_platform_stubs_current_contributions",
+    ],
+    api_contributions: [
+        "legacy.i18n.module.platform.api.stubs.source.api.contribution",
+    ],
+    libs: [
+        "stub-annotations",
+    ],
+    stubs_type: "everything",
+}
+
+java_library {
     name: "legacy.core.platform.api.stubs",
     visibility: core_platform_visibility,
     defaults: [
@@ -286,6 +384,17 @@
     },
 }
 
+java_library {
+    name: "legacy.core.platform.api.stubs.exportable",
+    visibility: core_platform_visibility,
+    defaults: [
+        "core.platform.api.stubs.defaults",
+    ],
+    static_libs: [
+        "legacy.core.platform.api.stubs.exportable.from-source",
+    ],
+}
+
 java_defaults {
     name: "core.platform.api.stubs.defaults",
     hostdex: true,
@@ -328,6 +437,21 @@
     ],
 }
 
+java_api_library {
+    name: "stable.core.platform.api.stubs.from-text",
+    api_surface: "core_platform",
+    defaults: [
+        "android_core_platform_stubs_current_contributions",
+    ],
+    api_contributions: [
+        "stable.i18n.module.platform.api.stubs.source.api.contribution",
+    ],
+    libs: [
+        "stub-annotations",
+    ],
+    stubs_type: "everything",
+}
+
 java_library {
     name: "stable.core.platform.api.stubs",
     visibility: core_platform_visibility,
@@ -451,7 +575,3 @@
         "art-module-intra-core-api-stubs-system-modules-lib",
     ],
 }
-
-build = [
-    "TxtStubLibraries.bp",
-]
diff --git a/java/core-libraries/TxtStubLibraries.bp b/java/core-libraries/TxtStubLibraries.bp
deleted file mode 100644
index c46f8b8..0000000
--- a/java/core-libraries/TxtStubLibraries.bp
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (C) 2023 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// This file contains java_system_modules provided by the SDK.
-// These system modules transitively depend on core stub libraries generated from .txt files.
-
-// Same as core-public-stubs-system-modules, but the stubs are generated from .txt files
-java_system_modules {
-    name: "core-public-stubs-system-modules.from-text",
-    visibility: ["//visibility:public"],
-    libs: [
-        "core-current-stubs-for-system-modules-no-annotations.from-text",
-    ],
-}
-
-java_library {
-    name: "core-current-stubs-for-system-modules-no-annotations.from-text",
-    visibility: ["//visibility:private"],
-    defaults: [
-        "system-modules-no-annotations",
-    ],
-    static_libs: [
-        "core.current.stubs.from-text",
-        "core-lambda-stubs.from-text",
-    ],
-}
-
-// Same as core-module-lib-stubs-system-modules, but the stubs are generated from .txt files
-java_system_modules {
-    name: "core-module-lib-stubs-system-modules.from-text",
-    visibility: ["//visibility:public"],
-    libs: [
-        "core-module-lib-stubs-for-system-modules-no-annotations.from-text",
-    ],
-}
-
-java_library {
-    name: "core-module-lib-stubs-for-system-modules-no-annotations.from-text",
-    visibility: ["//visibility:private"],
-    defaults: [
-        "system-modules-no-annotations",
-    ],
-    static_libs: [
-        "core.module_lib.stubs.from-text",
-        "core-lambda-stubs.from-text",
-    ],
-}
-
-java_api_library {
-    name: "core.module_lib.stubs.from-text",
-    api_surface: "module-lib",
-    api_contributions: [
-        "art.module.public.api.stubs.source.api.contribution",
-        "art.module.public.api.stubs.source.system.api.contribution",
-        "art.module.public.api.stubs.source.module_lib.api.contribution",
-
-        // Add the module-lib correspondence when Conscrypt or i18N module
-        // provides @SystemApi(MODULE_LIBRARIES). Currently, assume that only ART module provides
-        // @SystemApi(MODULE_LIBRARIES).
-        "conscrypt.module.public.api.stubs.source.api.contribution",
-        "i18n.module.public.api.stubs.source.api.contribution",
-    ],
-    libs: [
-        "stub-annotations",
-    ],
-    visibility: ["//visibility:private"],
-}
-
-// Same as legacy-core-platform-api-stubs-system-modules, but the stubs are generated from .txt files
-java_system_modules {
-    name: "legacy-core-platform-api-stubs-system-modules.from-text",
-    visibility: core_platform_visibility,
-    libs: [
-        "legacy.core.platform.api.no.annotations.stubs.from-text",
-        "core-lambda-stubs.from-text",
-    ],
-}
-
-java_library {
-    name: "legacy.core.platform.api.no.annotations.stubs.from-text",
-    visibility: core_platform_visibility,
-    defaults: [
-        "system-modules-no-annotations",
-    ],
-    hostdex: true,
-    compile_dex: true,
-
-    static_libs: [
-        "legacy.core.platform.api.stubs.from-text",
-    ],
-    patch_module: "java.base",
-}
-
-// Same as stable-core-platform-api-stubs-system-modules, but the stubs are generated from .txt files
-java_system_modules {
-    name: "stable-core-platform-api-stubs-system-modules.from-text",
-    visibility: core_platform_visibility,
-    libs: [
-        "stable.core.platform.api.no.annotations.stubs.from-text",
-        "core-lambda-stubs.from-text",
-    ],
-}
-
-java_library {
-    name: "stable.core.platform.api.no.annotations.stubs.from-text",
-    visibility: core_platform_visibility,
-    defaults: [
-        "system-modules-no-annotations",
-    ],
-    hostdex: true,
-    compile_dex: true,
-
-    static_libs: [
-        "stable.core.platform.api.stubs.from-text",
-    ],
-    patch_module: "java.base",
-}
-
-java_api_library {
-    name: "core-lambda-stubs.from-text",
-    api_surface: "toolchain",
-    api_contributions: [
-        "art.module.toolchain.api.api.contribution",
-    ],
-    libs: [
-        // LambdaMetaFactory depends on CallSite etc. which is part of the Core API surface
-        "core.current.stubs.from-text",
-    ],
-}
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 5460dc9..3f8735c 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -19,16 +19,12 @@
 	"io"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/dexpreopt"
-
-	"github.com/google/blueprint/proptools"
 )
 
 type DeviceHostConverter struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
-	android.BazelModuleBase
 
 	properties DeviceHostConverterProperties
 
@@ -80,7 +76,6 @@
 	module.AddProperties(&module.properties)
 
 	InitJavaModule(module, android.DeviceSupported)
-	android.InitBazelModule(module)
 	return module
 }
 
@@ -102,8 +97,7 @@
 	}
 
 	ctx.VisitDirectDepsWithTag(deviceHostConverterDepTag, func(m android.Module) {
-		if ctx.OtherModuleHasProvider(m, JavaInfoProvider) {
-			dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo)
+		if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok {
 			d.headerJars = append(d.headerJars, dep.HeaderJars...)
 			d.implementationJars = append(d.implementationJars, dep.ImplementationJars...)
 			d.implementationAndResourceJars = append(d.implementationAndResourceJars, dep.ImplementationAndResourcesJars...)
@@ -136,13 +130,14 @@
 		d.combinedHeaderJar = d.headerJars[0]
 	}
 
-	ctx.SetProvider(JavaInfoProvider, JavaInfo{
+	android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
 		HeaderJars:                     d.headerJars,
 		ImplementationAndResourcesJars: d.implementationAndResourceJars,
 		ImplementationJars:             d.implementationJars,
 		ResourceJars:                   d.resourceJars,
 		SrcJarArgs:                     d.srcJarArgs,
 		SrcJarDeps:                     d.srcJarDeps,
+		StubsLinkType:                  Implementation,
 		// TODO: Not sure if aconfig flags that have been moved between device and host variants
 		// make sense.
 	})
@@ -157,7 +152,7 @@
 	return d.implementationAndResourceJars
 }
 
-func (d *DeviceHostConverter) DexJarBuildPath() android.Path {
+func (d *DeviceHostConverter) DexJarBuildPath(ctx android.ModuleErrorfContext) android.Path {
 	return nil
 }
 
@@ -193,32 +188,3 @@
 		},
 	}
 }
-
-type bazelDeviceHostConverterAttributes struct {
-	Exports bazel.LabelListAttribute
-}
-
-func (d *DeviceHostConverter) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        "java_host_for_device",
-			Bzl_load_location: "//build/bazel/rules/java:host_for_device.bzl",
-		},
-		android.CommonAttributes{Name: d.Name()},
-		&bazelDeviceHostConverterAttributes{
-			Exports: bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, d.properties.Libs)),
-		},
-	)
-	neverLinkAttrs := &javaLibraryAttributes{
-		Exports:   bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + d.Name()}),
-		Neverlink: bazel.BoolAttribute{Value: proptools.BoolPtr(true)},
-		javaCommonAttributes: &javaCommonAttributes{
-			Sdk_version: bazel.StringAttribute{Value: proptools.StringPtr("none")},
-		},
-	}
-	ctx.CreateBazelTargetModule(
-		javaLibraryBazelTargetModuleProperties(),
-		android.CommonAttributes{Name: d.Name() + "-neverlink"},
-		neverLinkAttrs)
-
-}
diff --git a/java/device_host_converter_test.go b/java/device_host_converter_test.go
index 3413da0..6ccc5c1 100644
--- a/java/device_host_converter_test.go
+++ b/java/device_host_converter_test.go
@@ -16,7 +16,7 @@
 
 import (
 	"android/soong/android"
-	"reflect"
+	"slices"
 	"strings"
 	"testing"
 )
@@ -84,7 +84,7 @@
 		deviceImportCombined.Output,
 	}
 
-	if !reflect.DeepEqual(combined.Inputs, expectedInputs) {
+	if !slices.Equal(combined.Inputs.Strings(), expectedInputs.Strings()) {
 		t.Errorf("expected host_module combined inputs:\n%q\ngot:\n%q",
 			expectedInputs, combined.Inputs)
 	}
@@ -95,7 +95,7 @@
 		deviceRes.Output,
 	}
 
-	if !reflect.DeepEqual(resCombined.Inputs, expectedInputs) {
+	if !slices.Equal(resCombined.Inputs.Strings(), expectedInputs.Strings()) {
 		t.Errorf("expected host_module res combined inputs:\n%q\ngot:\n%q",
 			expectedInputs, resCombined.Inputs)
 	}
@@ -165,7 +165,7 @@
 		hostImportCombined.Output,
 	}
 
-	if !reflect.DeepEqual(combined.Inputs, expectedInputs) {
+	if !slices.Equal(combined.Inputs.Strings(), expectedInputs.Strings()) {
 		t.Errorf("expected device_module combined inputs:\n%q\ngot:\n%q",
 			expectedInputs, combined.Inputs)
 	}
@@ -176,7 +176,7 @@
 		hostRes.Output,
 	}
 
-	if !reflect.DeepEqual(resCombined.Inputs, expectedInputs) {
+	if !slices.Equal(resCombined.Inputs.Strings(), expectedInputs.Strings()) {
 		t.Errorf("expected device_module res combined inputs:\n%q\ngot:\n%q",
 			expectedInputs, resCombined.Inputs)
 	}
diff --git a/java/dex.go b/java/dex.go
index 7e7da00..6caaa7f 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -45,8 +45,8 @@
 		// Whether to continue building even if warnings are emitted.  Defaults to true.
 		Ignore_warnings *bool
 
-		// If true, runs R8 in Proguard compatibility mode (default).
-		// Otherwise, runs R8 in full mode.
+		// If true, runs R8 in Proguard compatibility mode, otherwise runs R8 in full mode.
+		// Defaults to false for apps, true for libraries and tests.
 		Proguard_compatibility *bool
 
 		// If true, optimize for size by removing unused code.  Defaults to true for apps,
@@ -66,11 +66,21 @@
 		// If true, optimize for size by removing unused resources. Defaults to false.
 		Shrink_resources *bool
 
+		// If true, use optimized resource shrinking in R8, overriding the
+		// Shrink_resources setting. Defaults to false.
+		// Optimized shrinking means that R8 will trace and treeshake resources together with code
+		// and apply additional optimizations. This implies non final fields in the R classes.
+		Optimized_shrink_resources *bool
+
 		// Flags to pass to proguard.
 		Proguard_flags []string
 
 		// Specifies the locations of files containing proguard flags.
 		Proguard_flags_files []string `android:"path"`
+
+		// If true, transitive reverse dependencies of this module will have this
+		// module's proguard spec appended to their optimization action
+		Export_proguard_flags_files *bool
 	}
 
 	// Keep the data uncompressed. We always need uncompressed dex for execution,
@@ -87,10 +97,12 @@
 	dexProperties DexProperties
 
 	// list of extra proguard flag files
-	extraProguardFlagFiles android.Paths
-	proguardDictionary     android.OptionalPath
-	proguardConfiguration  android.OptionalPath
-	proguardUsageZip       android.OptionalPath
+	extraProguardFlagsFiles android.Paths
+	proguardDictionary      android.OptionalPath
+	proguardConfiguration   android.OptionalPath
+	proguardUsageZip        android.OptionalPath
+	resourcesInput          android.OptionalPath
+	resourcesOutput         android.OptionalPath
 
 	providesTransitiveHeaderJars
 }
@@ -99,17 +111,19 @@
 	return BoolDefault(d.dexProperties.Optimize.Enabled, d.dexProperties.Optimize.EnabledByDefault)
 }
 
+func (d *DexProperties) resourceShrinkingEnabled() bool {
+	return BoolDefault(d.Optimize.Optimized_shrink_resources, Bool(d.Optimize.Shrink_resources))
+}
+
 var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8",
 	blueprint.RuleParams{
 		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
-			`mkdir -p $$(dirname $tmpJar) && ` +
-			`${config.Zip2ZipCmd} -i $in -o $tmpJar -x '**/*.dex' && ` +
-			`$d8Template${config.D8Cmd} ${config.D8Flags} --output $outDir $d8Flags $tmpJar && ` +
+			`$d8Template${config.D8Cmd} ${config.D8Flags} $d8Flags --output $outDir --no-dex-input-jar $in && ` +
 			`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
-			`${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in`,
+			`${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in && ` +
+			`rm -f "$outDir/classes*.dex" "$outDir/classes.dex.jar"`,
 		CommandDeps: []string{
 			"${config.D8Cmd}",
-			"${config.Zip2ZipCmd}",
 			"${config.SoongZipCmd}",
 			"${config.MergeZipsCmd}",
 		},
@@ -128,32 +142,29 @@
 			ExecStrategy: "${config.RED8ExecStrategy}",
 			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
 		},
-	}, []string{"outDir", "d8Flags", "zipFlags", "tmpJar", "mergeZipsFlags"}, nil)
+	}, []string{"outDir", "d8Flags", "zipFlags", "mergeZipsFlags"}, nil)
 
 var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8",
 	blueprint.RuleParams{
 		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
 			`rm -f "$outDict" && rm -f "$outConfig" && rm -rf "${outUsageDir}" && ` +
 			`mkdir -p $$(dirname ${outUsage}) && ` +
-			`mkdir -p $$(dirname $tmpJar) && ` +
-			`${config.Zip2ZipCmd} -i $in -o $tmpJar -x '**/*.dex' && ` +
-			`$r8Template${config.R8Cmd} ${config.R8Flags} -injars $tmpJar --output $outDir ` +
+			`$r8Template${config.R8Cmd} ${config.R8Flags} $r8Flags -injars $in --output $outDir ` +
 			`--no-data-resources ` +
 			`-printmapping ${outDict} ` +
 			`-printconfiguration ${outConfig} ` +
 			`-printusage ${outUsage} ` +
-			`--deps-file ${out}.d ` +
-			`$r8Flags && ` +
+			`--deps-file ${out}.d && ` +
 			`touch "${outDict}" "${outConfig}" "${outUsage}" && ` +
 			`${config.SoongZipCmd} -o ${outUsageZip} -C ${outUsageDir} -f ${outUsage} && ` +
 			`rm -rf ${outUsageDir} && ` +
 			`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
-			`${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in`,
+			`${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in && ` +
+			`rm -f "$outDir/classes*.dex" "$outDir/classes.dex.jar"`,
 		Depfile: "${out}.d",
 		Deps:    blueprint.DepsGCC,
 		CommandDeps: []string{
 			"${config.R8Cmd}",
-			"${config.Zip2ZipCmd}",
 			"${config.SoongZipCmd}",
 			"${config.MergeZipsCmd}",
 		},
@@ -161,7 +172,7 @@
 		"$r8Template": &remoteexec.REParams{
 			Labels:          map[string]string{"type": "compile", "compiler": "r8"},
 			Inputs:          []string{"$implicits", "${config.R8Jar}"},
-			OutputFiles:     []string{"${outUsage}", "${outConfig}", "${outDict}"},
+			OutputFiles:     []string{"${outUsage}", "${outConfig}", "${outDict}", "${resourcesOutput}"},
 			ExecStrategy:    "${config.RER8ExecStrategy}",
 			ToolchainInputs: []string{"${config.JavaCmd}"},
 			Platform:        map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
@@ -181,7 +192,7 @@
 			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
 		},
 	}, []string{"outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir",
-		"r8Flags", "zipFlags", "tmpJar", "mergeZipsFlags"}, []string{"implicits"})
+		"r8Flags", "zipFlags", "mergeZipsFlags", "resourcesOutput"}, []string{"implicits"})
 
 func (d *dexer) dexCommonFlags(ctx android.ModuleContext,
 	dexParams *compileDexParams) (flags []string, deps android.Paths) {
@@ -213,8 +224,9 @@
 	// Note: Targets with a min SDK kind of core_platform (e.g., framework.jar) or unspecified (e.g.,
 	// services.jar), are not classified as stable, which is WAI.
 	// TODO(b/232073181): Expand to additional min SDK cases after validation.
+	var addAndroidPlatformBuildFlag = false
 	if !dexParams.sdkVersion.Stable() {
-		flags = append(flags, "--android-platform-build")
+		addAndroidPlatformBuildFlag = true
 	}
 
 	effectiveVersion, err := dexParams.minSdkVersion.EffectiveVersion(ctx)
@@ -222,7 +234,18 @@
 		ctx.PropertyErrorf("min_sdk_version", "%s", err)
 	}
 
-	flags = append(flags, "--min-api "+strconv.Itoa(effectiveVersion.FinalOrFutureInt()))
+	// If the specified SDK level is 10000, then configure the compiler to use the
+	// current platform SDK level and to compile the build as a platform build.
+	var minApiFlagValue = effectiveVersion.FinalOrFutureInt()
+	if minApiFlagValue == 10000 {
+		minApiFlagValue = ctx.Config().PlatformSdkVersion().FinalInt()
+		addAndroidPlatformBuildFlag = true
+	}
+	flags = append(flags, "--min-api "+strconv.Itoa(minApiFlagValue))
+
+	if addAndroidPlatformBuildFlag {
+		flags = append(flags, "--android-platform-build")
+	}
 	return flags, deps
 }
 
@@ -248,8 +271,8 @@
 	// See b/20667396
 	var proguardRaiseDeps classpath
 	ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(m android.Module) {
-		dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo)
-		proguardRaiseDeps = append(proguardRaiseDeps, dep.HeaderJars...)
+		dep, _ := android.OtherModuleProvider(ctx, m, JavaInfoProvider)
+		proguardRaiseDeps = append(proguardRaiseDeps, dep.RepackagedHeaderJars...)
 	})
 
 	r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars"))
@@ -283,11 +306,13 @@
 		android.PathForSource(ctx, "build/make/core/proguard.flags"),
 	}
 
-	flagFiles = append(flagFiles, d.extraProguardFlagFiles...)
+	flagFiles = append(flagFiles, d.extraProguardFlagsFiles...)
 	// TODO(ccross): static android library proguard files
 
 	flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, opt.Proguard_flags_files)...)
 
+	flagFiles = android.FirstUniquePaths(flagFiles)
+
 	r8Flags = append(r8Flags, android.JoinWithPrefix(flagFiles.Strings(), "-include "))
 	r8Deps = append(r8Deps, flagFiles...)
 
@@ -299,15 +324,14 @@
 
 	if BoolDefault(opt.Proguard_compatibility, true) {
 		r8Flags = append(r8Flags, "--force-proguard-compatibility")
-	} else {
+	}
+
+	if Bool(opt.Optimize) || Bool(opt.Obfuscate) {
 		// TODO(b/213833843): Allow configuration of the prefix via a build variable.
 		var sourceFilePrefix = "go/retraceme "
 		var sourceFileTemplate = "\"" + sourceFilePrefix + "%MAP_ID\""
-		// TODO(b/200967150): Also tag the source file in compat builds.
-		if Bool(opt.Optimize) || Bool(opt.Obfuscate) {
-			r8Flags = append(r8Flags, "--map-id-template", "%MAP_HASH")
-			r8Flags = append(r8Flags, "--source-file-template", sourceFileTemplate)
-		}
+		r8Flags = append(r8Flags, "--map-id-template", "%MAP_HASH")
+		r8Flags = append(r8Flags, "--source-file-template", sourceFileTemplate)
 	}
 
 	// TODO(ccross): Don't shrink app instrumentation tests by default.
@@ -337,6 +361,16 @@
 		r8Flags = append(r8Flags, "-ignorewarnings")
 	}
 
+	// resourcesInput is empty when we don't use resource shrinking, if on, pass these to R8
+	if d.resourcesInput.Valid() {
+		r8Flags = append(r8Flags, "--resource-input", d.resourcesInput.Path().String())
+		r8Deps = append(r8Deps, d.resourcesInput.Path())
+		r8Flags = append(r8Flags, "--resource-output", d.resourcesOutput.Path().String())
+		if Bool(opt.Optimized_shrink_resources) {
+			r8Flags = append(r8Flags, "--optimized-resource-shrinking")
+		}
+	}
+
 	return r8Flags, r8Deps
 }
 
@@ -353,7 +387,6 @@
 	// Compile classes.jar into classes.dex and then javalib.jar
 	javalibJar := android.PathForModuleOut(ctx, "dex", dexParams.jarName).OutputPath
 	outDir := android.PathForModuleOut(ctx, "dex")
-	tmpJar := android.PathForModuleOut(ctx, "withres-withoutdex", dexParams.jarName)
 
 	zipFlags := "--ignore_missing_files"
 	if proptools.Bool(d.dexProperties.Uncompress_dex) {
@@ -379,6 +412,8 @@
 			android.ModuleNameWithPossibleOverride(ctx), "unused.txt")
 		proguardUsageZip := android.PathForModuleOut(ctx, "proguard_usage.zip")
 		d.proguardUsageZip = android.OptionalPathForPath(proguardUsageZip)
+		resourcesOutput := android.PathForModuleOut(ctx, "package-res-shrunken.apk")
+		d.resourcesOutput = android.OptionalPathForPath(resourcesOutput)
 		r8Flags, r8Deps := d.r8Flags(ctx, dexParams.flags)
 		r8Deps = append(r8Deps, commonDeps...)
 		rule := r8
@@ -391,24 +426,28 @@
 			"outUsage":       proguardUsage.String(),
 			"outUsageZip":    proguardUsageZip.String(),
 			"outDir":         outDir.String(),
-			"tmpJar":         tmpJar.String(),
 			"mergeZipsFlags": mergeZipsFlags,
 		}
 		if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") {
 			rule = r8RE
 			args["implicits"] = strings.Join(r8Deps.Strings(), ",")
 		}
+		implicitOutputs := android.WritablePaths{
+			proguardDictionary,
+			proguardUsageZip,
+			proguardConfiguration}
+		if d.resourcesInput.Valid() {
+			implicitOutputs = append(implicitOutputs, resourcesOutput)
+			args["resourcesOutput"] = resourcesOutput.String()
+		}
 		ctx.Build(pctx, android.BuildParams{
-			Rule:        rule,
-			Description: "r8",
-			Output:      javalibJar,
-			ImplicitOutputs: android.WritablePaths{
-				proguardDictionary,
-				proguardUsageZip,
-				proguardConfiguration},
-			Input:     dexParams.classesJar,
-			Implicits: r8Deps,
-			Args:      args,
+			Rule:            rule,
+			Description:     "r8",
+			Output:          javalibJar,
+			ImplicitOutputs: implicitOutputs,
+			Input:           dexParams.classesJar,
+			Implicits:       r8Deps,
+			Args:            args,
 		})
 	} else {
 		d8Flags, d8Deps := d8Flags(dexParams.flags)
@@ -427,14 +466,13 @@
 				"d8Flags":        strings.Join(append(commonFlags, d8Flags...), " "),
 				"zipFlags":       zipFlags,
 				"outDir":         outDir.String(),
-				"tmpJar":         tmpJar.String(),
 				"mergeZipsFlags": mergeZipsFlags,
 			},
 		})
 	}
 	if proptools.Bool(d.dexProperties.Uncompress_dex) {
 		alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", dexParams.jarName).OutputPath
-		TransformZipAlign(ctx, alignedJavalibJar, javalibJar)
+		TransformZipAlign(ctx, alignedJavalibJar, javalibJar, nil)
 		javalibJar = alignedJavalibJar
 	}
 
diff --git a/java/dex_test.go b/java/dex_test.go
index 2ba3831..1ecdae0 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"fmt"
 	"testing"
 
 	"android/soong/android"
@@ -327,7 +328,7 @@
 		fooD8.Args["d8Flags"], staticLibHeader.String())
 }
 
-func TestProguardFlagsInheritance(t *testing.T) {
+func TestProguardFlagsInheritanceStatic(t *testing.T) {
 	result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
 		android_app {
 			name: "app",
@@ -380,3 +381,284 @@
 	android.AssertStringDoesContain(t, "expected tertiary_lib's proguard flags from inherited dep",
 		appR8.Args["r8Flags"], "tertiary.flags")
 }
+
+func TestProguardFlagsInheritance(t *testing.T) {
+	directDepFlagsFileName := "direct_dep.flags"
+	transitiveDepFlagsFileName := "transitive_dep.flags"
+
+	topLevelModules := []struct {
+		name       string
+		definition string
+	}{
+		{
+			name: "android_app",
+			definition: `
+				android_app {
+					name: "app",
+					static_libs: ["androidlib"], // this must be static_libs to initate dexing
+					platform_apis: true,
+				}
+			`,
+		},
+		{
+			name: "android_library",
+			definition: `
+				android_library {
+					name: "app",
+					static_libs: ["androidlib"], // this must be static_libs to initate dexing
+					installable: true,
+					optimize: {
+						enabled: true,
+						shrink: true,
+					},
+				}
+			`,
+		},
+		{
+			name: "java_library",
+			definition: `
+				java_library {
+					name: "app",
+					static_libs: ["androidlib"], // this must be static_libs to initate dexing
+					srcs: ["Foo.java"],
+					installable: true,
+					optimize: {
+						enabled: true,
+						shrink: true,
+					},
+				}
+			`,
+		},
+	}
+
+	bp := `
+		android_library {
+			name: "androidlib",
+			static_libs: ["app_dep"],
+		}
+
+		java_library {
+			name: "app_dep",
+			%s: ["dep"],
+		}
+
+		java_library {
+			name: "dep",
+			%s: ["transitive_dep"],
+			optimize: {
+				proguard_flags_files: ["direct_dep.flags"],
+				export_proguard_flags_files: %v,
+			},
+		}
+
+		java_library {
+			name: "transitive_dep",
+			optimize: {
+				proguard_flags_files: ["transitive_dep.flags"],
+				export_proguard_flags_files: %v,
+			},
+		}
+	`
+
+	testcases := []struct {
+		name                           string
+		depType                        string
+		depExportsFlagsFiles           bool
+		transitiveDepType              string
+		transitiveDepExportsFlagsFiles bool
+		expectedFlagsFiles             []string
+	}{
+		{
+			name:                           "libs_export_libs_export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_export_libs_export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_no-export_static_export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_no-export_static_export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_export_libs_no-export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName},
+		},
+		{
+			name:                           "static_export_libs_no-export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName},
+		},
+		{
+			name:                           "libs_no-export_static_no-export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{},
+		},
+		{
+			name:                           "static_no-export_static_no-export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_no-export_libs_export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_no-export_libs_export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_export_static_export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_export_static_export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_no-export_libs_no-export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{},
+		},
+		{
+			name:                           "static_no-export_libs_no-export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName},
+		},
+		{
+			name:                           "libs_export_static_no-export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_export_static_no-export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+	}
+
+	for _, topLevelModuleDef := range topLevelModules {
+		for _, tc := range testcases {
+			t.Run(topLevelModuleDef.name+"-"+tc.name, func(t *testing.T) {
+				result := android.GroupFixturePreparers(
+					PrepareForTestWithJavaDefaultModules,
+					android.FixtureMergeMockFs(android.MockFS{
+						directDepFlagsFileName:     nil,
+						transitiveDepFlagsFileName: nil,
+					}),
+				).RunTestWithBp(t,
+					topLevelModuleDef.definition+
+						fmt.Sprintf(
+							bp,
+							tc.depType,
+							tc.transitiveDepType,
+							tc.depExportsFlagsFiles,
+							tc.transitiveDepExportsFlagsFiles,
+						),
+				)
+				appR8 := result.ModuleForTests("app", "android_common").Rule("r8")
+
+				shouldHaveDepFlags := android.InList(directDepFlagsFileName, tc.expectedFlagsFiles)
+				if shouldHaveDepFlags {
+					android.AssertStringDoesContain(t, "expected deps's proguard flags",
+						appR8.Args["r8Flags"], directDepFlagsFileName)
+				} else {
+					android.AssertStringDoesNotContain(t, "app did not expect deps's proguard flags",
+						appR8.Args["r8Flags"], directDepFlagsFileName)
+				}
+
+				shouldHaveTransitiveDepFlags := android.InList(transitiveDepFlagsFileName, tc.expectedFlagsFiles)
+				if shouldHaveTransitiveDepFlags {
+					android.AssertStringDoesContain(t, "expected transitive deps's proguard flags",
+						appR8.Args["r8Flags"], transitiveDepFlagsFileName)
+				} else {
+					android.AssertStringDoesNotContain(t, "app did not expect transitive deps's proguard flags",
+						appR8.Args["r8Flags"], transitiveDepFlagsFileName)
+				}
+			})
+		}
+	}
+}
+
+func TestProguardFlagsInheritanceAppImport(t *testing.T) {
+	bp := `
+		android_app {
+			name: "app",
+			static_libs: ["aarimport"], // this must be static_libs to initate dexing
+			platform_apis: true,
+		}
+
+		android_library_import {
+			name: "aarimport",
+			aars: ["import.aar"],
+		}
+	`
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+	).RunTestWithBp(t, bp)
+
+	appR8 := result.ModuleForTests("app", "android_common").Rule("r8")
+	android.AssertStringDoesContain(t, "expected aarimports's proguard flags",
+		appR8.Args["r8Flags"], "proguard.txt")
+}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 998730e..25e95db 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -29,7 +29,7 @@
 	IsInstallable() bool
 
 	// True if dexpreopt is disabled for the java module.
-	dexpreoptDisabled(ctx android.BaseModuleContext) bool
+	dexpreoptDisabled(ctx android.BaseModuleContext, libraryName string) bool
 
 	// If the java module is to be installed into an APEX, this list contains information about the
 	// dexpreopt outputs to be installed on devices. Note that these dexpreopt outputs are installed
@@ -79,22 +79,34 @@
 func (install dexpreopterInstall) ToMakeEntries() android.AndroidMkEntries {
 	return android.AndroidMkEntries{
 		Class:      "ETC",
-		SubName:    install.SubModuleName(),
 		OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+				entries.SetString("LOCAL_MODULE", install.FullModuleName())
 				entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String())
 				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
 				entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
+				// Unset LOCAL_SOONG_INSTALLED_MODULE so that this does not default to the primary .apex file
+				// Without this, installation of the dexpreopt artifacts get skipped
+				entries.SetString("LOCAL_SOONG_INSTALLED_MODULE", "")
 			},
 		},
 	}
 }
 
+type Dexpreopter struct {
+	dexpreopter
+}
+
 type dexpreopter struct {
 	dexpreoptProperties       DexpreoptProperties
 	importDexpreoptProperties ImportDexpreoptProperties
 
+	// If true, the dexpreopt rules will not be generated
+	// Unlike Dex_preopt.Enabled which is user-facing,
+	// shouldDisableDexpreopt is a mutated propery.
+	shouldDisableDexpreopt bool
+
 	installPath         android.InstallPath
 	uncompressedDex     bool
 	isSDKLibrary        bool
@@ -166,24 +178,45 @@
 }
 
 func isApexVariant(ctx android.BaseModuleContext) bool {
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	return !apexInfo.IsForPlatform()
 }
 
 func forPrebuiltApex(ctx android.BaseModuleContext) bool {
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	return apexInfo.ForPrebuiltApex
 }
 
-func moduleName(ctx android.BaseModuleContext) string {
-	// Remove the "prebuilt_" prefix if the module is from a prebuilt because the prefix is not
-	// expected by dexpreopter.
-	return android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName())
+// For apex variant of modules, this returns true on the source variant if the prebuilt apex
+// has been selected using apex_contributions.
+// The prebuilt apex will be responsible for generating the dexpreopt rules of the deapexed java lib.
+func disableSourceApexVariant(ctx android.BaseModuleContext) bool {
+	if !isApexVariant(ctx) {
+		return false // platform variant
+	}
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+	psi := android.PrebuiltSelectionInfoMap{}
+	ctx.VisitDirectDepsWithTag(android.PrebuiltDepTag, func(am android.Module) {
+		psi, _ = android.OtherModuleProvider(ctx, am, android.PrebuiltSelectionInfoProvider)
+	})
+	// Find the apex variant for this module
+	_, apexVariantsWithoutTestApexes, _ := android.ListSetDifference(apexInfo.InApexVariants, apexInfo.TestApexes)
+	disableSource := false
+	// find the selected apexes
+	for _, apexVariant := range apexVariantsWithoutTestApexes {
+		for _, selected := range psi.GetSelectedModulesForApiDomain(apexVariant) {
+			// If the apex_contribution for this api domain contains a prebuilt apex, disable the source variant
+			if strings.HasPrefix(selected, "prebuilt_com.google.android") {
+				disableSource = true
+			}
+		}
+	}
+	return disableSource
 }
 
 // Returns whether dexpreopt is applicable to the module.
 // When it returns true, neither profile nor dexpreopt artifacts will be generated.
-func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
+func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext, libName string) bool {
 	if !ctx.Device() {
 		return true
 	}
@@ -196,6 +229,10 @@
 		return true
 	}
 
+	if d.shouldDisableDexpreopt {
+		return true
+	}
+
 	// If the module is from a prebuilt APEX, it shouldn't be installable, but it can still be
 	// dexpreopted.
 	if !ctx.Module().(DexpreopterInterface).IsInstallable() && !forPrebuiltApex(ctx) {
@@ -206,11 +243,20 @@
 		return true
 	}
 
+	if _, isApex := android.ModuleProvider(ctx, android.ApexBundleInfoProvider); isApex {
+		// dexpreopt rules for system server jars can be generated in the ModuleCtx of prebuilt apexes
+		return false
+	}
+
 	global := dexpreopt.GetGlobalConfig(ctx)
 
-	isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
-	if isApexVariant(ctx) {
-		// Don't preopt APEX variant module unless the module is an APEX system server jar.
+	// Use the libName argument to determine if the library being dexpreopt'd is a system server jar
+	// ctx.ModuleName() is not safe. In case of prebuilt apexes, the dexpreopt rules of system server jars
+	// are created in the ctx object of the top-level prebuilt apex.
+	isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(libName)
+
+	if _, isApex := android.ModuleProvider(ctx, android.ApexBundleInfoProvider); isApex || isApexVariant(ctx) {
+		// dexpreopt rules for system server jars can be generated in the ModuleCtx of prebuilt apexes
 		if !isApexSystemServerJar {
 			return true
 		}
@@ -227,14 +273,20 @@
 }
 
 func dexpreoptToolDepsMutator(ctx android.BottomUpMutatorContext) {
-	if d, ok := ctx.Module().(DexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) || !dexpreopt.IsDex2oatNeeded(ctx) {
+	if _, isApex := android.ModuleProvider(ctx, android.ApexBundleInfoProvider); isApex && dexpreopt.IsDex2oatNeeded(ctx) {
+		// prebuilt apexes can genererate rules to dexpreopt deapexed jars
+		// Add a dex2oat dep aggressively on _every_ apex module
+		dexpreopt.RegisterToolDeps(ctx)
+		return
+	}
+	if d, ok := ctx.Module().(DexpreopterInterface); !ok || d.dexpreoptDisabled(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName())) || !dexpreopt.IsDex2oatNeeded(ctx) {
 		return
 	}
 	dexpreopt.RegisterToolDeps(ctx)
 }
 
-func (d *dexpreopter) odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool {
-	return dexpreopt.OdexOnSystemOtherByName(moduleName(ctx), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx))
+func (d *dexpreopter) odexOnSystemOther(ctx android.ModuleContext, libName string, installPath android.InstallPath) bool {
+	return dexpreopt.OdexOnSystemOtherByName(libName, android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx))
 }
 
 // Returns the install path of the dex jar of a module.
@@ -245,20 +297,42 @@
 // This function is on a best-effort basis. It cannot handle the case where an APEX jar is not a
 // system server jar, which is fine because we currently only preopt system server jars for APEXes.
 func (d *dexpreopter) getInstallPath(
-	ctx android.ModuleContext, defaultInstallPath android.InstallPath) android.InstallPath {
+	ctx android.ModuleContext, libName string, defaultInstallPath android.InstallPath) android.InstallPath {
 	global := dexpreopt.GetGlobalConfig(ctx)
-	if global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx)) {
-		dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, moduleName(ctx))
+	if global.AllApexSystemServerJars(ctx).ContainsJar(libName) {
+		dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, libName)
 		return android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexLocation, "/"))
 	}
-	if !d.dexpreoptDisabled(ctx) && isApexVariant(ctx) &&
+	if !d.dexpreoptDisabled(ctx, libName) && isApexVariant(ctx) &&
 		filepath.Base(defaultInstallPath.PartitionDir()) != "apex" {
 		ctx.ModuleErrorf("unable to get the install path of the dex jar for dexpreopt")
 	}
 	return defaultInstallPath
 }
 
-func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.WritablePath) {
+// DexpreoptPrebuiltApexSystemServerJars generates the dexpreopt artifacts from a jar file that has been deapexed from a prebuilt apex
+func (d *Dexpreopter) DexpreoptPrebuiltApexSystemServerJars(ctx android.ModuleContext, libraryName string, di *android.DeapexerInfo) {
+	// A single prebuilt apex can have multiple apex system jars
+	// initialize the output path for this dex jar
+	dc := dexpreopt.GetGlobalConfig(ctx)
+	d.installPath = android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexpreopt.GetSystemServerDexLocation(ctx, dc, libraryName), "/"))
+	// generate the rules for creating the .odex and .vdex files for this system server jar
+	dexJarFile := di.PrebuiltExportPath(ApexRootRelativePathToJavaLib(libraryName))
+
+	d.inputProfilePathOnHost = nil // reset: TODO(spandandas): Make dexpreopter stateless
+	if android.InList(libraryName, di.GetDexpreoptProfileGuidedExportedModuleNames()) {
+		// Set the profile path to guide optimization
+		prof := di.PrebuiltExportPath(ApexRootRelativePathToJavaLib(libraryName) + ".prof")
+		if prof == nil {
+			ctx.ModuleErrorf("Could not find a .prof file in this prebuilt apex")
+		}
+		d.inputProfilePathOnHost = prof
+	}
+
+	d.dexpreopt(ctx, libraryName, dexJarFile)
+}
+
+func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJarFile android.WritablePath) {
 	global := dexpreopt.GetGlobalConfig(ctx)
 
 	// TODO(b/148690468): The check on d.installPath is to bail out in cases where
@@ -271,7 +345,7 @@
 
 	dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
 
-	providesUsesLib := moduleName(ctx)
+	providesUsesLib := libName
 	if ulib, ok := ctx.Module().(ProvidesUsesLib); ok {
 		name := ulib.ProvidesUsesLib()
 		if name != nil {
@@ -281,11 +355,11 @@
 
 	// If it is test, make config files regardless of its dexpreopt setting.
 	// The config files are required for apps defined in make which depend on the lib.
-	if d.isTest && d.dexpreoptDisabled(ctx) {
+	if d.isTest && d.dexpreoptDisabled(ctx, libName) {
 		return
 	}
 
-	isSystemServerJar := global.AllSystemServerJars(ctx).ContainsJar(moduleName(ctx))
+	isSystemServerJar := global.AllSystemServerJars(ctx).ContainsJar(libName)
 
 	bootImage := defaultBootImageConfig(ctx)
 	// When `global.PreoptWithUpdatableBcp` is true, `bcpForDexpreopt` below includes the mainline
@@ -304,7 +378,7 @@
 				targets = append(targets, target)
 			}
 		}
-		if isSystemServerJar && moduleName(ctx) != "com.android.location.provider" {
+		if isSystemServerJar && libName != "com.android.location.provider" {
 			// If the module is a system server jar, only preopt for the primary arch because the jar can
 			// only be loaded by system server. "com.android.location.provider" is a special case because
 			// it's also used by apps as a shared library.
@@ -327,6 +401,7 @@
 	var profileClassListing android.OptionalPath
 	var profileBootListing android.OptionalPath
 	profileIsTextListing := false
+
 	if d.inputProfilePathOnHost != nil {
 		profileClassListing = android.OptionalPathForPath(d.inputProfilePathOnHost)
 	} else if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) && !forPrebuiltApex(ctx) {
@@ -340,17 +415,21 @@
 			profileIsTextListing = true
 		} else if global.ProfileDir != "" {
 			profileClassListing = android.ExistentPathForSource(ctx,
-				global.ProfileDir, moduleName(ctx)+".prof")
+				global.ProfileDir, libName+".prof")
 		}
 	}
 
 	d.dexpreoptProperties.Dex_preopt_result.Profile_guided = profileClassListing.Valid()
 
+	// A single apex can have multiple system server jars
+	// Use the dexJar to create a unique scope for each
+	dexJarStem := strings.TrimSuffix(dexJarFile.Base(), dexJarFile.Ext())
+
 	// Full dexpreopt config, used to create dexpreopt build rules.
 	dexpreoptConfig := &dexpreopt.ModuleConfig{
-		Name:            moduleName(ctx),
+		Name:            libName,
 		DexLocation:     dexLocation,
-		BuildPath:       android.PathForModuleOut(ctx, "dexpreopt", moduleName(ctx)+".jar").OutputPath,
+		BuildPath:       android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, libName+".jar").OutputPath,
 		DexPath:         dexJarFile,
 		ManifestPath:    android.OptionalPathForPath(d.manifestFile),
 		UncompressedDex: d.uncompressedDex,
@@ -374,18 +453,16 @@
 		PreoptBootClassPathDexFiles:     dexFiles.Paths(),
 		PreoptBootClassPathDexLocations: dexLocations,
 
-		PreoptExtractedApk: false,
-
 		NoCreateAppImage:    !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true),
 		ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false),
 
 		PresignedPrebuilt: d.isPresignedPrebuilt,
 	}
 
-	d.configPath = android.PathForModuleOut(ctx, "dexpreopt", "dexpreopt.config")
+	d.configPath = android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, "dexpreopt.config")
 	dexpreopt.WriteModuleConfig(ctx, dexpreoptConfig, d.configPath)
 
-	if d.dexpreoptDisabled(ctx) {
+	if d.dexpreoptDisabled(ctx, libName) {
 		return
 	}
 
@@ -396,7 +473,7 @@
 	// dependencies to create a per-app list, and use `rsync --checksum` to prevent the file's mtime
 	// from being changed if the contents don't change. This avoids unnecessary dexpreopt reruns.
 	productPackages := android.PathForModuleInPartitionInstall(ctx, "", "product_packages.txt")
-	appProductPackages := android.PathForModuleOut(ctx, "dexpreopt", "product_packages.txt")
+	appProductPackages := android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, "product_packages.txt")
 	appProductPackagesStaging := appProductPackages.ReplaceExtension(ctx, "txt.tmp")
 	clcNames, _ := dexpreopt.ComputeClassLoaderContextDependencies(dexpreoptConfig.ClassLoaderContexts)
 	sort.Strings(clcNames) // The order needs to be deterministic.
@@ -418,18 +495,24 @@
 		Text("rsync --checksum").
 		Input(appProductPackagesStaging).
 		Output(appProductPackages)
-	productPackagesRule.Restat().Build("product_packages", "dexpreopt product_packages")
+	productPackagesRule.Restat().Build("product_packages."+dexJarStem, "dexpreopt product_packages")
 
+	// Prebuilts are active, do not copy the dexpreopt'd source javalib to out/soong/system_server_dexjars
+	// The javalib from the deapexed prebuilt will be copied to this location.
+	// TODO (b/331665856): Implement a principled solution for this.
+	copyApexSystemServerJarDex := !disableSourceApexVariant(ctx)
 	dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
-		ctx, globalSoong, global, dexpreoptConfig, appProductPackages)
+		ctx, globalSoong, global, dexpreoptConfig, appProductPackages, copyApexSystemServerJarDex)
 	if err != nil {
 		ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
 		return
 	}
 
-	dexpreoptRule.Build("dexpreopt", "dexpreopt")
+	dexpreoptRule.Build("dexpreopt"+"."+dexJarStem, "dexpreopt")
 
-	isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
+	// The current ctx might be of a deapexer module created by a prebuilt apex
+	// Use the path of the dex file to determine the library name
+	isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(dexJarStem)
 
 	for _, install := range dexpreoptRule.Installs() {
 		// Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
@@ -454,7 +537,7 @@
 				// The installs will be handled by Make as sub-modules of the java library.
 				d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
 					name:                arch + "-" + installBase,
-					moduleName:          moduleName(ctx),
+					moduleName:          libName,
 					outputPathOnHost:    install.From,
 					installDirOnDevice:  installPath,
 					installFileOnDevice: installBase,
@@ -485,3 +568,7 @@
 func (d *dexpreopter) OutputProfilePathOnHost() android.Path {
 	return d.outputProfilePathOnHost
 }
+
+func (d *dexpreopter) disableDexpreopt() {
+	d.shouldDisableDexpreopt = true
+}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 003f2de..f7e3cb9 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -21,6 +21,7 @@
 	"android/soong/android"
 	"android/soong/dexpreopt"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -224,8 +225,9 @@
 }
 
 var (
-	dexpreoptBootJarDepTag  = bootclasspathDependencyTag{name: "dexpreopt-boot-jar"}
-	dexBootJarsFragmentsKey = android.NewOnceKey("dexBootJarsFragments")
+	dexpreoptBootJarDepTag          = bootclasspathDependencyTag{name: "dexpreopt-boot-jar"}
+	dexBootJarsFragmentsKey         = android.NewOnceKey("dexBootJarsFragments")
+	apexContributionsMetadataDepTag = dependencyTag{name: "all_apex_contributions"}
 )
 
 func init() {
@@ -236,8 +238,7 @@
 //
 // WARNING: All fields in this struct should be initialized in the genBootImageConfigs function.
 // Failure to do so can lead to data races if there is no synchronization enforced ordering between
-// the writer and the reader. Fields which break this rule are marked as deprecated and should be
-// removed and replaced with something else, e.g. providers.
+// the writer and the reader.
 type bootImageConfig struct {
 	// If this image is an extension, the image that it extends.
 	extends *bootImageConfig
@@ -277,16 +278,6 @@
 	// File path to a zip archive with all image files (or nil, if not needed).
 	zip android.WritablePath
 
-	// Rules which should be used in make to install the outputs.
-	//
-	// Deprecated: Not initialized correctly, see struct comment.
-	profileInstalls android.RuleBuilderInstalls
-
-	// Path to the license metadata file for the module that built the profile.
-	//
-	// Deprecated: Not initialized correctly, see struct comment.
-	profileLicenseMetadataFile android.OptionalPath
-
 	// Target-dependent fields.
 	variants []*bootImageVariant
 
@@ -502,6 +493,11 @@
 	dexpreoptConfigForMake android.WritablePath
 }
 
+func (dbj *dexpreoptBootJars) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// Create a dependency on all_apex_contributions to determine the selected mainline module
+	ctx.AddDependency(ctx.Module(), apexContributionsMetadataDepTag, "all_apex_contributions")
+}
+
 func DexpreoptBootJarsMutator(ctx android.BottomUpMutatorContext) {
 	if _, ok := ctx.Module().(*dexpreoptBootJars); !ok {
 		return
@@ -520,6 +516,14 @@
 		}
 		// For accessing the boot jars.
 		addDependenciesOntoBootImageModules(ctx, config.modules, dexpreoptBootJarDepTag)
+		// Create a dependency on the apex selected using RELEASE_APEX_CONTRIBUTIONS_*
+		// TODO: b/308174306 - Remove the direct depedendency edge to the java_library (source/prebuilt) once all mainline modules
+		// have been flagged using RELEASE_APEX_CONTRIBUTIONS_*
+		apexes := []string{}
+		for i := 0; i < config.modules.Len(); i++ {
+			apexes = append(apexes, config.modules.Apex(i))
+		}
+		addDependenciesOntoSelectedBootImageApexes(ctx, android.FirstUniqueStrings(apexes)...)
 	}
 
 	if ctx.OtherModuleExists("platform-bootclasspath") {
@@ -532,6 +536,28 @@
 	}
 }
 
+// Create a dependency from dex_bootjars to the specific apexes selected using all_apex_contributions
+// This dependency will be used to get the path to the deapexed dex boot jars and profile (via a provider)
+func addDependenciesOntoSelectedBootImageApexes(ctx android.BottomUpMutatorContext, apexes ...string) {
+	psi := android.PrebuiltSelectionInfoMap{}
+	ctx.VisitDirectDepsWithTag(apexContributionsMetadataDepTag, func(am android.Module) {
+		if info, exists := android.OtherModuleProvider(ctx, am, android.PrebuiltSelectionInfoProvider); exists {
+			psi = info
+		}
+	})
+	for _, apex := range apexes {
+		for _, selected := range psi.GetSelectedModulesForApiDomain(apex) {
+			// We need to add a dep on only the apex listed in `contents` of the selected apex_contributions module
+			// This is not available in a structured format in `apex_contributions`, so this hack adds a dep on all `contents`
+			// (some modules like art.module.public.api do not have an apex variation since it is a pure stub module that does not get installed)
+			apexVariationOfSelected := append(ctx.Target().Variations(), blueprint.Variation{Mutator: "apex", Variation: apex})
+			if ctx.OtherModuleDependencyVariantExists(apexVariationOfSelected, selected) {
+				ctx.AddFarVariationDependencies(apexVariationOfSelected, dexpreoptBootJarDepTag, selected)
+			}
+		}
+	}
+}
+
 func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android.Module {
 	return ctx.Config().Once(dexBootJarsFragmentsKey, func() interface{} {
 		fragments := make(map[string]android.Module)
@@ -544,7 +570,7 @@
 				return true
 			}
 			if tag == bootclasspathFragmentDepTag {
-				apexInfo := ctx.OtherModuleProvider(child, android.ApexInfoProvider).(android.ApexInfo)
+				apexInfo, _ := android.OtherModuleProvider(ctx, child, android.ApexInfoProvider)
 				for _, apex := range apexInfo.InApexVariants {
 					fragments[apex] = child
 				}
@@ -565,6 +591,7 @@
 	imageConfigs := genBootImageConfigs(ctx)
 	d.defaultBootImage = defaultBootImageConfig(ctx)
 	d.otherImages = make([]*bootImageConfig, 0, len(imageConfigs)-1)
+	var profileInstalls android.RuleBuilderInstalls
 	for _, name := range getImageNames() {
 		config := imageConfigs[name]
 		if config != d.defaultBootImage {
@@ -573,16 +600,25 @@
 		if !config.isEnabled(ctx) {
 			continue
 		}
-		generateBootImage(ctx, config)
+		installs := generateBootImage(ctx, config)
+		profileInstalls = append(profileInstalls, installs...)
 		if config == d.defaultBootImage {
-			bootFrameworkProfileRule(ctx, config)
+			_, installs := bootFrameworkProfileRule(ctx, config)
+			profileInstalls = append(profileInstalls, installs...)
 		}
 	}
+	if len(profileInstalls) > 0 {
+		android.SetProvider(ctx, profileInstallInfoProvider, profileInstallInfo{
+			profileInstalls:            profileInstalls,
+			profileLicenseMetadataFile: android.OptionalPathForPath(ctx.LicenseMetadataFile()),
+		})
+	}
 }
 
 // GenerateSingletonBuildActions generates build rules for the dexpreopt config for Make.
 func (d *dexpreoptBootJars) GenerateSingletonBuildActions(ctx android.SingletonContext) {
-	d.dexpreoptConfigForMake = android.PathForOutput(ctx, getDexpreoptDirName(ctx), "dexpreopt.config")
+	d.dexpreoptConfigForMake =
+		android.PathForOutput(ctx, dexpreopt.GetDexpreoptDirName(ctx), "dexpreopt.config")
 	writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
 }
 
@@ -598,7 +634,7 @@
 	return true
 }
 
-func generateBootImage(ctx android.ModuleContext, imageConfig *bootImageConfig) {
+func generateBootImage(ctx android.ModuleContext, imageConfig *bootImageConfig) android.RuleBuilderInstalls {
 	apexJarModulePairs := getModulesForImage(ctx, imageConfig)
 
 	// Copy module dex jars to their predefined locations.
@@ -607,11 +643,12 @@
 
 	// Build a profile for the image config from the profile at the default path. The profile will
 	// then be used along with profiles imported from APEXes to build the boot image.
-	profile := bootImageProfileRule(ctx, imageConfig)
+	profile, profileInstalls := bootImageProfileRule(ctx, imageConfig)
 
 	// If dexpreopt of boot image jars should be skipped, stop after generating a profile.
-	if SkipDexpreoptBootJars(ctx) {
-		return
+	global := dexpreopt.GetGlobalConfig(ctx)
+	if SkipDexpreoptBootJars(ctx) || (global.OnlyPreoptArtBootImage && imageConfig.name != "art") {
+		return profileInstalls
 	}
 
 	// Build boot image files for the android variants.
@@ -625,10 +662,12 @@
 
 	// Create a `dump-oat-<image-name>` rule that runs `oatdump` for debugging purposes.
 	dumpOatRules(ctx, imageConfig)
+
+	return profileInstalls
 }
 
 type apexJarModulePair struct {
-	apex string
+	apex      string
 	jarModule android.Module
 }
 
@@ -640,7 +679,7 @@
 			name := android.RemoveOptionalPrebuiltPrefix(module.Name())
 			if name == imageConfig.modules.Jar(i) {
 				modules = append(modules, apexJarModulePair{
-					apex: imageConfig.modules.Apex(i),
+					apex:      imageConfig.modules.Apex(i),
 					jarModule: module,
 				})
 				found = true
@@ -661,38 +700,75 @@
 // extractEncodedDexJarsFromModulesOrBootclasspathFragments gets the hidden API encoded dex jars for
 // the given modules.
 func extractEncodedDexJarsFromModulesOrBootclasspathFragments(ctx android.ModuleContext, apexJarModulePairs []apexJarModulePair) bootDexJarByModule {
+	apexNameToApexExportInfoMap := getApexNameToApexExportsInfoMap(ctx)
 	encodedDexJarsByModuleName := bootDexJarByModule{}
 	for _, pair := range apexJarModulePairs {
-		var path android.Path
-		if android.IsConfiguredJarForPlatform(pair.apex) || android.IsModulePrebuilt(pair.jarModule) {
-			// This gives us the dex jar with the hidden API flags encoded from the monolithic hidden API
-			// files or the dex jar extracted from a prebuilt APEX. We can't use this for a boot jar for
-			// a source APEX because there is no guarantee that it is the same as the jar packed into the
-			// APEX. In practice, they are the same when we are building from a full source tree, but they
-			// are different when we are building from a thin manifest (e.g., master-art), where there is
-			// no monolithic hidden API files at all.
-			path = retrieveEncodedBootDexJarFromModule(ctx, pair.jarModule)
-		} else {
-			// Use exactly the same jar that is packed into the APEX.
-			fragment := getBootclasspathFragmentByApex(ctx, pair.apex)
-			if fragment == nil {
-				ctx.ModuleErrorf("Boot jar '%[1]s' is from APEX '%[2]s', but a bootclasspath_fragment for "+
-					"APEX '%[2]s' doesn't exist or is not added as a dependency of dex_bootjars",
-					pair.jarModule.Name(),
-					pair.apex)
-			}
-			bootclasspathFragmentInfo := ctx.OtherModuleProvider(fragment, BootclasspathFragmentApexContentInfoProvider).(BootclasspathFragmentApexContentInfo)
-			jar, err := bootclasspathFragmentInfo.DexBootJarPathForContentModule(pair.jarModule)
-			if err != nil {
-				ctx.ModuleErrorf("%s", err)
-			}
-			path = jar
-		}
-		encodedDexJarsByModuleName.addPath(pair.jarModule, path)
+		dexJarPath := getDexJarForApex(ctx, pair, apexNameToApexExportInfoMap)
+		encodedDexJarsByModuleName.addPath(pair.jarModule, dexJarPath)
 	}
 	return encodedDexJarsByModuleName
 }
 
+type apexNameToApexExportsInfoMap map[string]android.ApexExportsInfo
+
+// javaLibraryPathOnHost returns the path to the java library which is exported by the apex for hiddenapi and dexpreopt and a boolean indicating whether the java library exists
+// For prebuilt apexes, this is created by deapexing the prebuilt apex
+func (m *apexNameToApexExportsInfoMap) javaLibraryDexPathOnHost(ctx android.ModuleContext, apex string, javalib string) (android.Path, bool) {
+	if info, exists := (*m)[apex]; exists {
+		if dex, exists := info.LibraryNameToDexJarPathOnHost[javalib]; exists {
+			return dex, true
+		} else {
+			ctx.ModuleErrorf("Apex %s does not provide a dex boot jar for library %s\n", apex, javalib)
+		}
+	}
+	// An apex entry could not be found. Return false.
+	// TODO: b/308174306 - When all the mainline modules have been flagged, make this a hard error
+	return nil, false
+}
+
+// Returns the stem of an artifact inside a prebuilt apex
+func ModuleStemForDeapexing(m android.Module) string {
+	bmn, _ := m.(interface{ BaseModuleName() string })
+	return bmn.BaseModuleName()
+}
+
+// Returns the java libraries exported by the apex for hiddenapi and dexpreopt
+// This information can come from two mechanisms
+// 1. New: Direct deps to _selected_ apexes. The apexes return a ApexExportsInfo
+// 2. Legacy: An edge to java_library or java_import (java_sdk_library) module. For prebuilt apexes, this serves as a hook and is populated by deapexers of prebuilt apxes
+// TODO: b/308174306 - Once all mainline modules have been flagged, drop (2)
+func getDexJarForApex(ctx android.ModuleContext, pair apexJarModulePair, apexNameToApexExportsInfoMap apexNameToApexExportsInfoMap) android.Path {
+	if dex, found := apexNameToApexExportsInfoMap.javaLibraryDexPathOnHost(ctx, pair.apex, ModuleStemForDeapexing(pair.jarModule)); found {
+		return dex
+	}
+	// TODO: b/308174306 - Remove the legacy mechanism
+	if android.IsConfiguredJarForPlatform(pair.apex) || android.IsModulePrebuilt(pair.jarModule) {
+		// This gives us the dex jar with the hidden API flags encoded from the monolithic hidden API
+		// files or the dex jar extracted from a prebuilt APEX. We can't use this for a boot jar for
+		// a source APEX because there is no guarantee that it is the same as the jar packed into the
+		// APEX. In practice, they are the same when we are building from a full source tree, but they
+		// are different when we are building from a thin manifest (e.g., master-art), where there is
+		// no monolithic hidden API files at all.
+		return retrieveEncodedBootDexJarFromModule(ctx, pair.jarModule)
+	} else {
+		// Use exactly the same jar that is packed into the APEX.
+		fragment := getBootclasspathFragmentByApex(ctx, pair.apex)
+		if fragment == nil {
+			ctx.ModuleErrorf("Boot jar '%[1]s' is from APEX '%[2]s', but a bootclasspath_fragment for "+
+				"APEX '%[2]s' doesn't exist or is not added as a dependency of dex_bootjars",
+				pair.jarModule.Name(),
+				pair.apex)
+		}
+		bootclasspathFragmentInfo, _ := android.OtherModuleProvider(ctx, fragment, BootclasspathFragmentApexContentInfoProvider)
+		jar, err := bootclasspathFragmentInfo.DexBootJarPathForContentModule(pair.jarModule)
+		if err != nil {
+			ctx.ModuleErrorf("%s", err)
+		}
+		return jar
+	}
+	return nil
+}
+
 // copyBootJarsToPredefinedLocations generates commands that will copy boot jars to predefined
 // paths in the global config.
 func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, srcBootDexJarsByModule bootDexJarByModule, dstBootJarsByModule map[string]android.WritablePath) {
@@ -822,6 +898,37 @@
 	config *bootImageVariant
 }
 
+// Returns the profile file for an apex
+// This information can come from two mechanisms
+// 1. New: Direct deps to _selected_ apexes. The apexes return a BootclasspathFragmentApexContentInfo
+// 2. Legacy: An edge to bootclasspath_fragment module. For prebuilt apexes, this serves as a hook and is populated by deapexers of prebuilt apxes
+// TODO: b/308174306 - Once all mainline modules have been flagged, drop (2)
+func getProfilePathForApex(ctx android.ModuleContext, apexName string, apexNameToBcpInfoMap map[string]android.ApexExportsInfo) android.Path {
+	if info, exists := apexNameToBcpInfoMap[apexName]; exists {
+		return info.ProfilePathOnHost
+	}
+	// TODO: b/308174306 - Remove the legacy mechanism
+	fragment := getBootclasspathFragmentByApex(ctx, apexName)
+	if fragment == nil {
+		ctx.ModuleErrorf("Boot image config imports profile from '%[2]s', but a "+
+			"bootclasspath_fragment for APEX '%[2]s' doesn't exist or is not added as a "+
+			"dependency of dex_bootjars",
+			apexName)
+		return nil
+	}
+	return fragment.(commonBootclasspathFragment).getProfilePath()
+}
+
+func getApexNameToApexExportsInfoMap(ctx android.ModuleContext) apexNameToApexExportsInfoMap {
+	apexNameToApexExportsInfoMap := apexNameToApexExportsInfoMap{}
+	ctx.VisitDirectDepsWithTag(dexpreoptBootJarDepTag, func(am android.Module) {
+		if info, exists := android.OtherModuleProvider(ctx, am, android.ApexExportsInfoProvider); exists {
+			apexNameToApexExportsInfoMap[info.ApexName] = info
+		}
+	})
+	return apexNameToApexExportsInfoMap
+}
+
 // Generate boot image build rules for a specific target.
 func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, profile android.Path) bootImageVariantOutputs {
 
@@ -864,6 +971,8 @@
 
 	invocationPath := outputPath.ReplaceExtension(ctx, "invocation")
 
+	apexNameToApexExportsInfoMap := getApexNameToApexExportsInfoMap(ctx)
+
 	cmd.Tool(globalSoong.Dex2oat).
 		Flag("--avoid-storing-invocation").
 		FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath).
@@ -876,16 +985,7 @@
 		}
 
 		for _, apex := range image.profileImports {
-			fragment := getBootclasspathFragmentByApex(ctx, apex)
-			if fragment == nil {
-				ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but a "+
-					"bootclasspath_fragment for APEX '%[2]s' doesn't exist or is not added as a "+
-					"dependency of dex_bootjars",
-					image.name,
-					apex)
-				return bootImageVariantOutputs{}
-			}
-			importedProfile := fragment.(commonBootclasspathFragment).getProfilePath()
+			importedProfile := getProfilePathForApex(ctx, apex, apexNameToApexExportsInfoMap)
 			if importedProfile == nil {
 				ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but '%[2]s' "+
 					"doesn't provide a profile",
@@ -973,8 +1073,8 @@
 		cmd.FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch])
 	}
 
-	if global.EnableUffdGc && image.target.Os == android.Android {
-		cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
+	if image.target.Os == android.Android {
+		cmd.Text("$(cat").Input(globalSoong.UffdGcFlag).Text(")")
 	}
 
 	if global.BootFlags != "" {
@@ -1084,9 +1184,19 @@
 	return profile
 }
 
-func bootImageProfileRule(ctx android.ModuleContext, image *bootImageConfig) android.WritablePath {
+type profileInstallInfo struct {
+	// Rules which should be used in make to install the outputs.
+	profileInstalls android.RuleBuilderInstalls
+
+	// Path to the license metadata file for the module that built the profile.
+	profileLicenseMetadataFile android.OptionalPath
+}
+
+var profileInstallInfoProvider = blueprint.NewProvider[profileInstallInfo]()
+
+func bootImageProfileRule(ctx android.ModuleContext, image *bootImageConfig) (android.WritablePath, android.RuleBuilderInstalls) {
 	if !image.isProfileGuided() {
-		return nil
+		return nil, nil
 	}
 
 	profile := bootImageProfileRuleCommon(ctx, image.name, image.dexPathsDeps.Paths(), image.getAnyAndroidVariant().dexLocationsDeps)
@@ -1094,21 +1204,19 @@
 	if image == defaultBootImageConfig(ctx) {
 		rule := android.NewRuleBuilder(pctx, ctx)
 		rule.Install(profile, "/system/etc/boot-image.prof")
-		image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
-		image.profileLicenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile())
+		return profile, rule.Installs()
 	}
-
-	return profile
+	return profile, nil
 }
 
 // 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 {
+func bootFrameworkProfileRule(ctx android.ModuleContext, image *bootImageConfig) (android.WritablePath, android.RuleBuilderInstalls) {
 	globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
 	global := dexpreopt.GetGlobalConfig(ctx)
 
 	if global.DisableGenerateProfile || ctx.Config().UnbundledBuild() {
-		return nil
+		return nil, nil
 	}
 
 	defaultProfile := "frameworks/base/config/boot-profile.txt"
@@ -1128,16 +1236,13 @@
 
 	rule.Install(profile, "/system/etc/boot-image.bprof")
 	rule.Build("bootFrameworkProfile", "profile boot framework jars")
-	image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
-	image.profileLicenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile())
-
-	return profile
+	return profile, rule.Installs()
 }
 
 func dumpOatRules(ctx android.ModuleContext, image *bootImageConfig) {
 	var allPhonies android.Paths
 	name := image.name
-	global := dexpreopt.GetGlobalConfig(ctx)
+	globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
 	for _, image := range image.variants {
 		arch := image.target.Arch.ArchType
 		suffix := arch.String()
@@ -1149,6 +1254,7 @@
 		output := android.PathForOutput(ctx, name+"."+suffix+".oatdump.txt")
 		rule := android.NewRuleBuilder(pctx, ctx)
 		imageLocationsOnHost, _ := image.imageLocations()
+
 		cmd := rule.Command().
 			BuiltTool("oatdump").
 			FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
@@ -1156,8 +1262,8 @@
 			FlagWithArg("--image=", strings.Join(imageLocationsOnHost, ":")).Implicits(image.imagesDeps.Paths()).
 			FlagWithOutput("--output=", output).
 			FlagWithArg("--instruction-set=", arch.String())
-		if global.EnableUffdGc && image.target.Os == android.Android {
-			cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
+		if image.target.Os == android.Android {
+			cmd.Text("$(cat").Input(globalSoong.UffdGcFlag).Text(")")
 		}
 		rule.Build("dump-oat-"+name+"-"+suffix, "dump oat "+name+" "+arch.String())
 
@@ -1178,7 +1284,7 @@
 		Rule:        android.Phony,
 		Output:      phony,
 		Inputs:      allPhonies,
-		Description: "dump-oat-"+name,
+		Description: "dump-oat-" + name,
 	})
 }
 
@@ -1199,9 +1305,11 @@
 
 	image := d.defaultBootImage
 	if image != nil {
-		ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String())
-		if image.profileLicenseMetadataFile.Valid() {
-			ctx.Strict("DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA", image.profileLicenseMetadataFile.String())
+		if profileInstallInfo, ok := android.SingletonModuleProvider(ctx, d, profileInstallInfoProvider); ok {
+			ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", profileInstallInfo.profileInstalls.String())
+			if profileInstallInfo.profileLicenseMetadataFile.Valid() {
+				ctx.Strict("DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA", profileInstallInfo.profileLicenseMetadataFile.String())
+			}
 		}
 
 		if SkipDexpreoptBootJars(ctx) {
diff --git a/java/dexpreopt_check.go b/java/dexpreopt_check.go
index 7499481..33be603 100644
--- a/java/dexpreopt_check.go
+++ b/java/dexpreopt_check.go
@@ -68,7 +68,7 @@
 
 	// The check should be skipped on unbundled builds because system server jars are not preopted on
 	// unbundled builds since the artifacts are installed into the system image, not the APEXes.
-	if global.DisablePreopt || len(targets) == 0 || ctx.Config().UnbundledBuild() {
+	if global.DisablePreopt || global.OnlyPreoptArtBootImage || len(targets) == 0 || ctx.Config().UnbundledBuild() {
 		return
 	}
 
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 0f4bd9b..dc0973c 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -45,7 +45,7 @@
 	frameworkBootImageName   = "boot"
 	mainlineBootImageName    = "mainline"
 	bootImageStem            = "boot"
-	profileInstallPathInApex = "etc/boot-image.prof"
+	ProfileInstallPathInApex = "etc/boot-image.prof"
 )
 
 // getImageNames returns an ordered list of image names. The order doesn't matter but needs to be
@@ -115,7 +115,7 @@
 func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
 	return ctx.Config().Once(bootImageConfigKey, func() interface{} {
 		targets := dexpreoptTargets(ctx)
-		deviceDir := android.PathForOutput(ctx, getDexpreoptDirName(ctx))
+		deviceDir := android.PathForOutput(ctx, dexpreopt.GetDexpreoptDirName(ctx))
 
 		configs := genBootImageConfigRaw(ctx)
 
@@ -210,57 +210,18 @@
 	return false
 }
 
-// Apex boot config allows to access build/install paths of apex boot jars without going
-// through the usual trouble of registering dependencies on those modules and extracting build paths
-// from those dependencies.
-type apexBootConfig struct {
-	// A list of apex boot jars.
-	modules android.ConfiguredJarList
-
-	// A list of predefined build paths to apex boot jars. They are configured very early,
-	// before the modules for these jars are processed and the actual paths are generated, and
-	// later on a singleton adds commands to copy actual jars to the predefined paths.
-	dexPaths android.WritablePaths
-
-	// Map from module name (without prebuilt_ prefix) to the predefined build path.
-	dexPathsByModule map[string]android.WritablePath
-
-	// A list of dex locations (a.k.a. on-device paths) to the boot jars.
-	dexLocations []string
-}
-
-var updatableBootConfigKey = android.NewOnceKey("apexBootConfig")
-
-// Returns apex boot config.
-func GetApexBootConfig(ctx android.PathContext) apexBootConfig {
-	return ctx.Config().Once(updatableBootConfigKey, func() interface{} {
-		apexBootJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
-		dir := android.PathForOutput(ctx, getDexpreoptDirName(ctx), "apex_bootjars")
-		dexPaths := apexBootJars.BuildPaths(ctx, dir)
-		dexPathsByModuleName := apexBootJars.BuildPathsByModule(ctx, dir)
-
-		dexLocations := apexBootJars.DevicePaths(ctx.Config(), android.Android)
-
-		return apexBootConfig{apexBootJars, dexPaths, dexPathsByModuleName, dexLocations}
-	}).(apexBootConfig)
-}
-
 // Returns a list of paths and a list of locations for the boot jars used in dexpreopt (to be
 // passed in -Xbootclasspath and -Xbootclasspath-locations arguments for dex2oat).
 func bcpForDexpreopt(ctx android.PathContext, withUpdatable bool) (android.WritablePaths, []string) {
-	// Non-updatable boot jars (they are used both in the boot image and in dexpreopt).
 	bootImage := defaultBootImageConfig(ctx)
+	if withUpdatable {
+		bootImage = mainlineBootImageConfig(ctx)
+	}
+
 	dexPaths := bootImage.dexPathsDeps
 	// The dex locations for all Android variants are identical.
 	dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps
 
-	if withUpdatable {
-		// Apex boot jars (they are used only in dexpreopt, but not in the boot image).
-		apexBootConfig := GetApexBootConfig(ctx)
-		dexPaths = append(dexPaths, apexBootConfig.dexPaths...)
-		dexLocations = append(dexLocations, apexBootConfig.dexLocations...)
-	}
-
 	return dexPaths, dexLocations
 }
 
@@ -273,12 +234,3 @@
 func dexpreoptConfigMakevars(ctx android.MakeVarsContext) {
 	ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules.CopyOfApexJarPairs(), ":"))
 }
-
-func getDexpreoptDirName(ctx android.PathContext) string {
-	prefix := "dexpreopt_"
-	targets := ctx.Config().Targets[android.Android]
-	if len(targets) > 0 {
-		return prefix+targets[0].Arch.ArchType.String()
-	}
-	return prefix+"unknown_target"
-}
diff --git a/java/dexpreopt_config_testing.go b/java/dexpreopt_config_testing.go
index 176c251..104829f 100644
--- a/java/dexpreopt_config_testing.go
+++ b/java/dexpreopt_config_testing.go
@@ -77,7 +77,7 @@
 
 func PrepareApexBootJarModule(apexName string, moduleName string) android.FixturePreparer {
 	moduleSourceDir := fmt.Sprintf("packages/modules/%s", apexName)
-	fragmentName := apexName+"-bootclasspath-fragment"
+	fragmentName := apexName + "-bootclasspath-fragment"
 	imageNameProp := ""
 	if apexName == "com.android.art" {
 		fragmentName = "art-bootclasspath-fragment"
@@ -523,7 +523,7 @@
 		},
 	}
 
-	checkBootImageConfig(t, imageConfig, mutated, expected)
+	checkBootImageConfig(t, result, imageConfig, mutated, expected)
 }
 
 // getFrameworkImageConfig gets the framework bootImageConfig that was created during the test.
@@ -904,7 +904,7 @@
 		profileLicenseMetadataFile: expectedLicenseMetadataFile,
 	}
 
-	checkBootImageConfig(t, imageConfig, mutated, expected)
+	checkBootImageConfig(t, result, imageConfig, mutated, expected)
 }
 
 // getMainlineImageConfig gets the framework bootImageConfig that was created during the test.
@@ -1183,7 +1183,7 @@
 		profileLicenseMetadataFile: expectedLicenseMetadataFile,
 	}
 
-	checkBootImageConfig(t, imageConfig, false, expected)
+	checkBootImageConfig(t, result, imageConfig, false, expected)
 }
 
 // clearMutatedFields clears fields in the expectedConfig that correspond to fields in the
@@ -1211,19 +1211,19 @@
 // zero value so that they will match the unmodified values in the boot image.
 //
 // It runs the checks in an image specific subtest of the current test.
-func checkBootImageConfig(t *testing.T, imageConfig *bootImageConfig, mutated bool, expected *expectedConfig) {
+func checkBootImageConfig(t *testing.T, result *android.TestResult, imageConfig *bootImageConfig, mutated bool, expected *expectedConfig) {
 	if !mutated {
 		clearMutatedFields(expected)
 	}
 
 	t.Run(imageConfig.name, func(t *testing.T) {
-		nestedCheckBootImageConfig(t, imageConfig, expected)
+		nestedCheckBootImageConfig(t, result, imageConfig, mutated, expected)
 	})
 }
 
 // nestedCheckBootImageConfig does the work of comparing the image against the expected values and
 // is run in an image specific subtest.
-func nestedCheckBootImageConfig(t *testing.T, imageConfig *bootImageConfig, expected *expectedConfig) {
+func nestedCheckBootImageConfig(t *testing.T, result *android.TestResult, imageConfig *bootImageConfig, mutated bool, expected *expectedConfig) {
 	android.AssertStringEquals(t, "name", expected.name, imageConfig.name)
 	android.AssertStringEquals(t, "stem", expected.stem, imageConfig.stem)
 	android.AssertPathRelativeToTopEquals(t, "dir", expected.dir, imageConfig.dir)
@@ -1234,8 +1234,13 @@
 	android.AssertPathsRelativeToTopEquals(t, "dexPathsDeps", expected.dexPathsDeps, imageConfig.dexPathsDeps.Paths())
 	// dexPathsByModule is just a different representation of the other information in the config.
 	android.AssertPathRelativeToTopEquals(t, "zip", expected.zip, imageConfig.zip)
-	assertInstallsEqual(t, "profileInstalls", expected.profileInstalls, imageConfig.profileInstalls)
-	android.AssertStringEquals(t, "profileLicenseMetadataFile", expected.profileLicenseMetadataFile, imageConfig.profileLicenseMetadataFile.RelativeToTop().String())
+
+	if !mutated {
+		dexBootJarModule := result.ModuleForTests("dex_bootjars", "android_common")
+		profileInstallInfo, _ := android.SingletonModuleProvider(result, dexBootJarModule.Module(), profileInstallInfoProvider)
+		assertInstallsEqual(t, "profileInstalls", expected.profileInstalls, profileInstallInfo.profileInstalls)
+		android.AssertStringEquals(t, "profileLicenseMetadataFile", expected.profileLicenseMetadataFile, profileInstallInfo.profileLicenseMetadataFile.RelativeToTop().String())
+	}
 
 	android.AssertIntEquals(t, "variant count", 4, len(imageConfig.variants))
 	for i, variant := range imageConfig.variants {
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index fedd564..73e33f4 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -410,7 +410,7 @@
 	verifyEntries(t,
 		"entriesList[0]",
 		"service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
-		"/dexpreopt/oat/arm64/javalib.odex",
+		"/dexpreopt/service-foo/oat/arm64/javalib.odex",
 		"/system/framework/oat/arm64",
 		"apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
 		entriesList[0])
@@ -418,7 +418,7 @@
 	verifyEntries(t,
 		"entriesList[1]",
 		"service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
-		"/dexpreopt/oat/arm64/javalib.vdex",
+		"/dexpreopt/service-foo/oat/arm64/javalib.vdex",
 		"/system/framework/oat/arm64",
 		"apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
 		entriesList[1])
@@ -459,7 +459,7 @@
 	ctx := result.TestContext
 	dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeRule("dexpreopt")
 
-	expected := []string{"out/soong/.intermediates/foo/android_common/dexpreopt/profile.prof"}
+	expected := []string{"out/soong/.intermediates/foo/android_common/dexpreopt/foo/profile.prof"}
 
 	android.AssertArrayString(t, "outputs", expected, dexpreopt.AllOutputs())
 }
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 3ba3065..176779e 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -135,6 +135,9 @@
 	// At some point, this might be improved to show more warnings.
 	Todo_file *string `android:"path"`
 
+	// A file containing a baseline for allowed lint errors.
+	Lint_baseline *string `android:"path"`
+
 	// directory under current module source that provide additional resources (images).
 	Resourcesdir *string
 
@@ -179,6 +182,17 @@
 
 func apiCheckEnabled(ctx android.ModuleContext, apiToCheck ApiToCheck, apiVersionTag string) bool {
 	if ctx.Config().IsEnvTrue("WITHOUT_CHECK_API") {
+		if ctx.Config().BuildFromTextStub() {
+			ctx.ModuleErrorf("Generating stubs from api signature files is not available " +
+				"with WITHOUT_CHECK_API=true, as sync between the source Java files and the " +
+				"api signature files is not guaranteed.\n" +
+				"In order to utilize WITHOUT_CHECK_API, generate stubs from the source Java " +
+				"files with BUILD_FROM_SOURCE_STUB=true.\n" +
+				"However, the usage of WITHOUT_CHECK_API is not preferred as the incremental " +
+				"build is slower when generating stubs from the source Java files.\n" +
+				"Consider updating the api signature files and generating the stubs from " +
+				"them instead.")
+		}
 		return false
 	} else if String(apiToCheck.Api_file) != "" && String(apiToCheck.Removed_api_file) != "" {
 		return true
@@ -205,6 +219,8 @@
 
 	docZip      android.WritablePath
 	stubsSrcJar android.WritablePath
+
+	exportableStubsSrcJar android.WritablePath
 }
 
 func (j *Javadoc) OutputFiles(tag string) (android.Paths, error) {
@@ -299,7 +315,7 @@
 	}
 
 	flags = append(flags, android.JoinWithPrefix(aidlIncludes.Strings(), "-I"))
-	flags = append(flags, "-I"+android.PathForModuleSrc(ctx).String())
+	flags = append(flags, "-I"+ctx.ModuleDir())
 	if src := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "src"); src.Valid() {
 		flags = append(flags, "-I"+src.String())
 	}
@@ -360,8 +376,7 @@
 
 		switch tag {
 		case bootClasspathTag:
-			if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
-				dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+			if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
 				deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars...)
 			} else if sm, ok := module.(SystemModulesProvider); ok {
 				// A system modules dependency has been added to the bootclasspath
@@ -373,19 +388,19 @@
 		case libTag, sdkLibTag:
 			if dep, ok := module.(SdkLibraryDependency); ok {
 				deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion(ctx))...)
-			} else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
-				dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+			} else if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
 				deps.classpath = append(deps.classpath, dep.HeaderJars...)
 				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
+				deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...)
 			} else if dep, ok := module.(android.SourceFileProducer); ok {
 				checkProducesJars(ctx, dep)
 				deps.classpath = append(deps.classpath, dep.Srcs()...)
 			} else {
 				ctx.ModuleErrorf("depends on non-java module %q", otherName)
 			}
+
 		case java9LibTag:
-			if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
-				dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+			if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
 				deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...)
 			} else {
 				ctx.ModuleErrorf("depends on non-java module %q", otherName)
@@ -397,6 +412,18 @@
 			sm := module.(SystemModulesProvider)
 			outputDir, outputDeps := sm.OutputDirAndDeps()
 			deps.systemModules = &systemModules{outputDir, outputDeps}
+		case aconfigDeclarationTag:
+			if dep, ok := android.OtherModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey); ok {
+				deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPath)
+			} else if dep, ok := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider); ok {
+				deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...)
+			} else {
+				ctx.ModuleErrorf("Only aconfig_declarations and aconfig_declarations_group "+
+					"module type is allowed for flags_packages property, but %s is neither "+
+					"of these supported module types",
+					module.Name(),
+				)
+			}
 		}
 	})
 	// do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
@@ -404,6 +431,19 @@
 	srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
 	j.implicits = append(j.implicits, srcFiles...)
 
+	// Module can depend on a java_aconfig_library module using the ":module_name{.tag}" syntax.
+	// Find the corresponding aconfig_declarations module name for such case.
+	for _, src := range j.properties.Srcs {
+		if moduleName, tag := android.SrcIsModuleWithTag(src); moduleName != "" {
+			otherModule := android.GetModuleFromPathDep(ctx, moduleName, tag)
+			if otherModule != nil {
+				if dep, ok := android.OtherModuleProvider(ctx, otherModule, android.CodegenInfoProvider); ok {
+					deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...)
+				}
+			}
+		}
+	}
+
 	filterByPackage := func(srcs []android.Path, filterPackages []string) []android.Path {
 		if filterPackages == nil {
 			return srcs
@@ -664,6 +704,10 @@
 			ImplicitOutput(android.PathForModuleOut(ctx, String(d.properties.Todo_file)))
 	}
 
+	if String(d.properties.Lint_baseline) != "" {
+		cmd.FlagWithInput("-lintbaseline ", android.PathForModuleSrc(ctx, String(d.properties.Lint_baseline)))
+	}
+
 	if String(d.properties.Resourcesdir) != "" {
 		// TODO: should we add files under resourcesDir to the implicits? It seems that
 		// resourcesDir is one sub dir of htmlDir
diff --git a/java/droidstubs.go b/java/droidstubs.go
index f05ef1f..08caf91 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -18,13 +18,11 @@
 	"fmt"
 	"path/filepath"
 	"regexp"
-	"sort"
 	"strings"
 
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/java/config"
 	"android/soong/remoteexec"
 )
@@ -32,6 +30,41 @@
 // The values allowed for Droidstubs' Api_levels_sdk_type
 var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib", "system-server"}
 
+type StubsType int
+
+const (
+	Everything StubsType = iota
+	Runtime
+	Exportable
+	Unavailable
+)
+
+func (s StubsType) String() string {
+	switch s {
+	case Everything:
+		return "everything"
+	case Runtime:
+		return "runtime"
+	case Exportable:
+		return "exportable"
+	default:
+		return ""
+	}
+}
+
+func StringToStubsType(s string) StubsType {
+	switch strings.ToLower(s) {
+	case Everything.String():
+		return Everything
+	case Runtime.String():
+		return Runtime
+	case Exportable.String():
+		return Exportable
+	default:
+		return Unavailable
+	}
+}
+
 func init() {
 	RegisterStubsBuildComponents(android.InitRegistrationContext)
 }
@@ -45,14 +78,22 @@
 	ctx.RegisterModuleType("prebuilt_stubs_sources", PrebuiltStubsSourcesFactory)
 }
 
+type stubsArtifacts struct {
+	nullabilityWarningsFile android.WritablePath
+	annotationsZip          android.WritablePath
+	apiVersionsXml          android.WritablePath
+	metadataZip             android.WritablePath
+	metadataDir             android.WritablePath
+}
+
 // Droidstubs
 type Droidstubs struct {
 	Javadoc
+	embeddableInModuleAndImport
 
-	properties              DroidstubsProperties
-	apiFile                 android.Path
-	removedApiFile          android.Path
-	nullabilityWarningsFile android.WritablePath
+	properties     DroidstubsProperties
+	apiFile        android.Path
+	removedApiFile android.Path
 
 	checkCurrentApiTimestamp      android.WritablePath
 	updateCurrentApiTimestamp     android.WritablePath
@@ -62,11 +103,14 @@
 
 	checkNullabilityWarningsTimestamp android.WritablePath
 
-	annotationsZip android.WritablePath
-	apiVersionsXml android.WritablePath
+	everythingArtifacts stubsArtifacts
+	exportableArtifacts stubsArtifacts
 
-	metadataZip android.WritablePath
-	metadataDir android.WritablePath
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
+
+	exportableApiFile        android.WritablePath
+	exportableRemovedApiFile android.WritablePath
 }
 
 type DroidstubsProperties struct {
@@ -123,7 +167,7 @@
 	Generate_stubs *bool
 
 	// if set to true, provides a hint to the build system that this rule uses a lot of memory,
-	// whicih can be used for scheduling purposes
+	// which can be used for scheduling purposes
 	High_mem *bool
 
 	// if set to true, Metalava will allow framework SDK to contain API levels annotations.
@@ -152,26 +196,64 @@
 	// API surface of this module. If set, the module contributes to an API surface.
 	// For the full list of available API surfaces, refer to soong/android/sdk_version.go
 	Api_surface *string
+
+	// a list of aconfig_declarations module names that the stubs generated in this module
+	// depend on.
+	Aconfig_declarations []string
 }
 
 // Used by xsd_config
 type ApiFilePath interface {
-	ApiFilePath() android.Path
+	ApiFilePath(StubsType) (android.Path, error)
 }
 
 type ApiStubsSrcProvider interface {
-	StubsSrcJar() android.Path
+	StubsSrcJar(StubsType) (android.Path, error)
 }
 
 // Provider of information about API stubs, used by java_sdk_library.
 type ApiStubsProvider interface {
-	AnnotationsZip() android.Path
+	AnnotationsZip(StubsType) (android.Path, error)
 	ApiFilePath
-	RemovedApiFilePath() android.Path
+	RemovedApiFilePath(StubsType) (android.Path, error)
 
 	ApiStubsSrcProvider
 }
 
+type currentApiTimestampProvider interface {
+	CurrentApiTimestamp() android.Path
+}
+
+type annotationFlagsParams struct {
+	migratingNullability    bool
+	validatingNullability   bool
+	nullabilityWarningsFile android.WritablePath
+	annotationsZip          android.WritablePath
+}
+type stubsCommandParams struct {
+	srcJarDir               android.ModuleOutPath
+	stubsDir                android.OptionalPath
+	stubsSrcJar             android.WritablePath
+	metadataZip             android.WritablePath
+	metadataDir             android.WritablePath
+	apiVersionsXml          android.WritablePath
+	nullabilityWarningsFile android.WritablePath
+	annotationsZip          android.WritablePath
+	stubConfig              stubsCommandConfigParams
+}
+type stubsCommandConfigParams struct {
+	stubsType             StubsType
+	javaVersion           javaVersion
+	deps                  deps
+	checkApi              bool
+	generateStubs         bool
+	doApiLint             bool
+	doCheckReleased       bool
+	writeSdkValues        bool
+	migratingNullability  bool
+	validatingNullability bool
+}
+
 // droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
 // documented, filtering out hidden classes and methods.  The resulting .java files are intended to be passed to
 // a droiddoc module to generate documentation.
@@ -180,6 +262,7 @@
 
 	module.AddProperties(&module.properties,
 		&module.Javadoc.properties)
+	module.initModuleAndImport(module)
 
 	InitDroiddocModule(module, android.HostAndDeviceSupported)
 
@@ -203,46 +286,160 @@
 	return module
 }
 
+func getStubsTypeAndTag(tag string) (StubsType, string, error) {
+	if len(tag) == 0 {
+		return Everything, "", nil
+	}
+	if tag[0] != '.' {
+		return Unavailable, "", fmt.Errorf("tag must begin with \".\"")
+	}
+
+	stubsType := Everything
+	// Check if the tag has a stubs type prefix (e.g. ".exportable")
+	for st := Everything; st <= Exportable; st++ {
+		if strings.HasPrefix(tag, "."+st.String()) {
+			stubsType = st
+		}
+	}
+
+	return stubsType, strings.TrimPrefix(tag, "."+stubsType.String()), nil
+}
+
+// Droidstubs' tag supports specifying with the stubs type.
+// While supporting the pre-existing tags, it also supports tags with
+// the stubs type prefix. Some examples are shown below:
+// {.annotations.zip} - pre-existing behavior. Returns the path to the
+// annotation zip.
+// {.exportable} - Returns the path to the exportable stubs src jar.
+// {.exportable.annotations.zip} - Returns the path to the exportable
+// annotations zip file.
+// {.runtime.api_versions.xml} - Runtime stubs does not generate api versions
+// xml file. For unsupported combinations, the default everything output file
+// is returned.
 func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
-	switch tag {
+	stubsType, prefixRemovedTag, err := getStubsTypeAndTag(tag)
+	if err != nil {
+		return nil, err
+	}
+	switch prefixRemovedTag {
 	case "":
-		return android.Paths{d.stubsSrcJar}, nil
+		stubsSrcJar, err := d.StubsSrcJar(stubsType)
+		return android.Paths{stubsSrcJar}, err
 	case ".docs.zip":
-		return android.Paths{d.docZip}, nil
+		docZip, err := d.DocZip(stubsType)
+		return android.Paths{docZip}, err
 	case ".api.txt", android.DefaultDistTag:
 		// This is the default dist path for dist properties that have no tag property.
-		return android.Paths{d.apiFile}, nil
+		apiFilePath, err := d.ApiFilePath(stubsType)
+		return android.Paths{apiFilePath}, err
 	case ".removed-api.txt":
-		return android.Paths{d.removedApiFile}, nil
+		removedApiFilePath, err := d.RemovedApiFilePath(stubsType)
+		return android.Paths{removedApiFilePath}, err
 	case ".annotations.zip":
-		return android.Paths{d.annotationsZip}, nil
+		annotationsZip, err := d.AnnotationsZip(stubsType)
+		return android.Paths{annotationsZip}, err
 	case ".api_versions.xml":
-		return android.Paths{d.apiVersionsXml}, nil
+		apiVersionsXmlFilePath, err := d.ApiVersionsXmlFilePath(stubsType)
+		return android.Paths{apiVersionsXmlFilePath}, err
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
 }
 
-func (d *Droidstubs) AnnotationsZip() android.Path {
-	return d.annotationsZip
+func (d *Droidstubs) AnnotationsZip(stubsType StubsType) (ret android.Path, err error) {
+	switch stubsType {
+	case Everything:
+		ret, err = d.everythingArtifacts.annotationsZip, nil
+	case Exportable:
+		ret, err = d.exportableArtifacts.annotationsZip, nil
+	default:
+		ret, err = nil, fmt.Errorf("annotations zip not supported for the stub type %s", stubsType.String())
+	}
+	return ret, err
 }
 
-func (d *Droidstubs) ApiFilePath() android.Path {
-	return d.apiFile
+func (d *Droidstubs) ApiFilePath(stubsType StubsType) (ret android.Path, err error) {
+	switch stubsType {
+	case Everything:
+		ret, err = d.apiFile, nil
+	case Exportable:
+		ret, err = d.exportableApiFile, nil
+	default:
+		ret, err = nil, fmt.Errorf("api file path not supported for the stub type %s", stubsType.String())
+	}
+	if ret == nil && err == nil {
+		err = fmt.Errorf("api file is null for the stub type %s", stubsType.String())
+	}
+	return ret, err
 }
 
-func (d *Droidstubs) RemovedApiFilePath() android.Path {
-	return d.removedApiFile
+func (d *Droidstubs) ApiVersionsXmlFilePath(stubsType StubsType) (ret android.Path, err error) {
+	switch stubsType {
+	case Everything:
+		ret, err = d.everythingArtifacts.apiVersionsXml, nil
+	case Exportable:
+		ret, err = d.exportableArtifacts.apiVersionsXml, nil
+	default:
+		ret, err = nil, fmt.Errorf("api versions xml file path not supported for the stub type %s", stubsType.String())
+	}
+	if ret == nil && err == nil {
+		err = fmt.Errorf("api versions xml file is null for the stub type %s", stubsType.String())
+	}
+	return ret, err
 }
 
-func (d *Droidstubs) StubsSrcJar() android.Path {
-	return d.stubsSrcJar
+func (d *Droidstubs) DocZip(stubsType StubsType) (ret android.Path, err error) {
+	switch stubsType {
+	case Everything:
+		ret, err = d.docZip, nil
+	default:
+		ret, err = nil, fmt.Errorf("docs zip not supported for the stub type %s", stubsType.String())
+	}
+	if ret == nil && err == nil {
+		err = fmt.Errorf("docs zip is null for the stub type %s", stubsType.String())
+	}
+	return ret, err
+}
+
+func (d *Droidstubs) RemovedApiFilePath(stubsType StubsType) (ret android.Path, err error) {
+	switch stubsType {
+	case Everything:
+		ret, err = d.removedApiFile, nil
+	case Exportable:
+		ret, err = d.exportableRemovedApiFile, nil
+	default:
+		ret, err = nil, fmt.Errorf("removed api file path not supported for the stub type %s", stubsType.String())
+	}
+	if ret == nil && err == nil {
+		err = fmt.Errorf("removed api file is null for the stub type %s", stubsType.String())
+	}
+	return ret, err
+}
+
+func (d *Droidstubs) StubsSrcJar(stubsType StubsType) (ret android.Path, err error) {
+	switch stubsType {
+	case Everything:
+		ret, err = d.stubsSrcJar, nil
+	case Exportable:
+		ret, err = d.exportableStubsSrcJar, nil
+	default:
+		ret, err = nil, fmt.Errorf("stubs srcjar not supported for the stub type %s", stubsType.String())
+	}
+	if ret == nil && err == nil {
+		err = fmt.Errorf("stubs srcjar is null for the stub type %s", stubsType.String())
+	}
+	return ret, err
+}
+
+func (d *Droidstubs) CurrentApiTimestamp() android.Path {
+	return d.checkCurrentApiTimestamp
 }
 
 var metalavaMergeAnnotationsDirTag = dependencyTag{name: "metalava-merge-annotations-dir"}
 var metalavaMergeInclusionAnnotationsDirTag = dependencyTag{name: "metalava-merge-inclusion-annotations-dir"}
 var metalavaAPILevelsAnnotationsDirTag = dependencyTag{name: "metalava-api-levels-annotations-dir"}
 var metalavaAPILevelsModuleTag = dependencyTag{name: "metalava-api-levels-module-tag"}
+var metalavaCurrentApiTimestampTag = dependencyTag{name: "metalava-current-api-timestamp-tag"}
 
 func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) {
 	d.Javadoc.addDeps(ctx)
@@ -265,39 +462,57 @@
 		}
 	}
 
+	if len(d.properties.Aconfig_declarations) != 0 {
+		for _, aconfigDeclarationModuleName := range d.properties.Aconfig_declarations {
+			ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfigDeclarationModuleName)
+		}
+	}
+
 	if d.properties.Api_levels_module != nil {
 		ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module))
 	}
 }
 
-func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath) {
-	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
-		apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
-		String(d.properties.Api_filename) != "" {
-		filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
-		uncheckedApiFile := android.PathForModuleOut(ctx, "metalava", filename)
-		cmd.FlagWithOutput("--api ", uncheckedApiFile)
-		d.apiFile = uncheckedApiFile
+func (d *Droidstubs) sdkValuesFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, metadataDir android.WritablePath) {
+	cmd.FlagWithArg("--sdk-values ", metadataDir.String())
+}
+
+func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.OptionalPath, stubsType StubsType, checkApi bool) {
+
+	apiFileName := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
+	uncheckedApiFile := android.PathForModuleOut(ctx, stubsType.String(), apiFileName)
+	cmd.FlagWithOutput("--api ", uncheckedApiFile)
+	if checkApi || String(d.properties.Api_filename) != "" {
+		if stubsType == Everything {
+			d.apiFile = uncheckedApiFile
+		} else if stubsType == Exportable {
+			d.exportableApiFile = uncheckedApiFile
+		}
 	} else if sourceApiFile := proptools.String(d.properties.Check_api.Current.Api_file); sourceApiFile != "" {
-		// If check api is disabled then make the source file available for export.
-		d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
+		if stubsType == Everything {
+			// If check api is disabled then make the source file available for export.
+			d.apiFile = android.PathForModuleSrc(ctx, sourceApiFile)
+		} else if stubsType == Exportable {
+			d.exportableApiFile = uncheckedApiFile
+		}
 	}
 
-	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
-		apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
-		String(d.properties.Removed_api_filename) != "" {
-		filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
-		uncheckedRemovedFile := android.PathForModuleOut(ctx, "metalava", filename)
-		cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
-		d.removedApiFile = uncheckedRemovedFile
+	removedApiFileName := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
+	uncheckedRemovedFile := android.PathForModuleOut(ctx, stubsType.String(), removedApiFileName)
+	cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
+	if checkApi || String(d.properties.Removed_api_filename) != "" {
+		if stubsType == Everything {
+			d.removedApiFile = uncheckedRemovedFile
+		} else if stubsType == Exportable {
+			d.exportableRemovedApiFile = uncheckedRemovedFile
+		}
 	} else if sourceRemovedApiFile := proptools.String(d.properties.Check_api.Current.Removed_api_file); sourceRemovedApiFile != "" {
-		// If check api is disabled then make the source removed api file available for export.
-		d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
-	}
-
-	if Bool(d.properties.Write_sdk_values) {
-		d.metadataDir = android.PathForModuleOut(ctx, "metalava", "metadata")
-		cmd.FlagWithArg("--sdk-values ", d.metadataDir.String())
+		if stubsType == Everything {
+			// If check api is disabled then make the source removed api file available for export.
+			d.removedApiFile = android.PathForModuleSrc(ctx, sourceRemovedApiFile)
+		} else if stubsType == Exportable {
+			d.exportableRemovedApiFile = uncheckedRemovedFile
+		}
 	}
 
 	if stubsDir.Valid() {
@@ -312,46 +527,30 @@
 	}
 }
 
-func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
+func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, params annotationFlagsParams) {
 	if Bool(d.properties.Annotations_enabled) {
-		cmd.Flag("--include-annotations")
+		cmd.Flag(config.MetalavaAnnotationsFlags)
 
-		cmd.FlagWithArg("--exclude-annotation ", "androidx.annotation.RequiresApi")
-
-		validatingNullability :=
-			strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
-				String(d.properties.Validate_nullability_from_list) != ""
-
-		migratingNullability := String(d.properties.Previous_api) != ""
-		if migratingNullability {
-			previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
-			cmd.FlagWithInput("--migrate-nullness ", previousApi)
+		if params.migratingNullability {
+			previousApiFiles := android.PathsForModuleSrc(ctx, []string{String(d.properties.Previous_api)})
+			cmd.FlagForEachInput("--migrate-nullness ", previousApiFiles)
 		}
 
 		if s := String(d.properties.Validate_nullability_from_list); s != "" {
 			cmd.FlagWithInput("--validate-nullability-from-list ", android.PathForModuleSrc(ctx, s))
 		}
 
-		if validatingNullability {
-			d.nullabilityWarningsFile = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_nullability_warnings.txt")
-			cmd.FlagWithOutput("--nullability-warnings-txt ", d.nullabilityWarningsFile)
+		if params.validatingNullability {
+			cmd.FlagWithOutput("--nullability-warnings-txt ", params.nullabilityWarningsFile)
 		}
 
-		d.annotationsZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"_annotations.zip")
-		cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
+		cmd.FlagWithOutput("--extract-annotations ", params.annotationsZip)
 
 		if len(d.properties.Merge_annotations_dirs) != 0 {
 			d.mergeAnnoDirFlags(ctx, cmd)
 		}
 
-		// TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
-		cmd.FlagWithArg("--hide ", "HiddenTypedefConstant").
-			FlagWithArg("--hide ", "SuperfluousPrefix").
-			FlagWithArg("--hide ", "AnnotationExtraction").
-			// b/222738070
-			FlagWithArg("--hide ", "BannedThrow").
-			// b/223382732
-			FlagWithArg("--hide ", "ChangedDefault")
+		cmd.Flag(config.MetalavaAnnotationsWarningsFlags)
 	}
 }
 
@@ -377,15 +576,21 @@
 	})
 }
 
-func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
+func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, apiVersionsXml android.WritablePath) {
 	var apiVersions android.Path
 	if proptools.Bool(d.properties.Api_levels_annotations_enabled) {
-		d.apiLevelsGenerationFlags(ctx, cmd)
-		apiVersions = d.apiVersionsXml
+		d.apiLevelsGenerationFlags(ctx, cmd, stubsType, apiVersionsXml)
+		apiVersions = apiVersionsXml
 	} else {
 		ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) {
 			if s, ok := m.(*Droidstubs); ok {
-				apiVersions = s.apiVersionsXml
+				if stubsType == Everything {
+					apiVersions = s.everythingArtifacts.apiVersionsXml
+				} else if stubsType == Exportable {
+					apiVersions = s.exportableArtifacts.apiVersionsXml
+				} else {
+					ctx.ModuleErrorf("%s stubs type does not generate api-versions.xml file", stubsType.String())
+				}
 			} else {
 				ctx.PropertyErrorf("api_levels_module",
 					"module %q is not a droidstubs module", ctx.OtherModuleName(m))
@@ -399,22 +604,46 @@
 	}
 }
 
-func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
+func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, apiVersionsXml android.WritablePath) {
 	if len(d.properties.Api_levels_annotations_dirs) == 0 {
 		ctx.PropertyErrorf("api_levels_annotations_dirs",
 			"has to be non-empty if api levels annotations was enabled!")
 	}
 
-	d.apiVersionsXml = android.PathForModuleOut(ctx, "metalava", "api-versions.xml")
-	cmd.FlagWithOutput("--generate-api-levels ", d.apiVersionsXml)
+	cmd.FlagWithOutput("--generate-api-levels ", apiVersionsXml)
 
 	filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar")
 
+	// TODO: Avoid the duplication of API surfaces, reuse apiScope.
+	// Add all relevant --android-jar-pattern patterns for Metalava.
+	// When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
+	// an actual file present on disk (in the order the patterns were passed). For system APIs for
+	// privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
+	// for older releases. Similarly, module-lib falls back to system API.
+	var sdkDirs []string
+	switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") {
+	case "system-server":
+		sdkDirs = []string{"system-server", "module-lib", "system", "public"}
+	case "module-lib":
+		sdkDirs = []string{"module-lib", "system", "public"}
+	case "system":
+		sdkDirs = []string{"system", "public"}
+	case "public":
+		sdkDirs = []string{"public"}
+	default:
+		ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes)
+		return
+	}
+
+	// Use the first item in the sdkDirs array as that is the sdk type for the target API levels
+	// being generated but has the advantage over `Api_levels_sdk_type` as it has been validated.
+	extensionsPattern := fmt.Sprintf(`/extensions/[0-9]+/%s/.*\.jar`, sdkDirs[0])
+
 	var dirs []string
 	var extensions_dir string
 	ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) {
 		if t, ok := m.(*ExportedDroiddocDir); ok {
-			extRegex := regexp.MustCompile(t.dir.String() + `/extensions/[0-9]+/public/.*\.jar`)
+			extRegex := regexp.MustCompile(t.dir.String() + extensionsPattern)
 
 			// Grab the first extensions_dir and we find while scanning ExportedDroiddocDir.deps;
 			// ideally this should be read from prebuiltApis.properties.Extensions_*
@@ -446,26 +675,6 @@
 		}
 	})
 
-	// Add all relevant --android-jar-pattern patterns for Metalava.
-	// When parsing a stub jar for a specific version, Metalava picks the first pattern that defines
-	// an actual file present on disk (in the order the patterns were passed). For system APIs for
-	// privileged apps that are only defined since API level 21 (Lollipop), fallback to public stubs
-	// for older releases. Similarly, module-lib falls back to system API.
-	var sdkDirs []string
-	switch proptools.StringDefault(d.properties.Api_levels_sdk_type, "public") {
-	case "system-server":
-		sdkDirs = []string{"system-server", "module-lib", "system", "public"}
-	case "module-lib":
-		sdkDirs = []string{"module-lib", "system", "public"}
-	case "system":
-		sdkDirs = []string{"system", "public"}
-	case "public":
-		sdkDirs = []string{"public"}
-	default:
-		ctx.PropertyErrorf("api_levels_sdk_type", "needs to be one of %v", allowedApiLevelSdkTypes)
-		return
-	}
-
 	for _, sdkDir := range sdkDirs {
 		for _, dir := range dirs {
 			cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, filename))
@@ -483,12 +692,29 @@
 	}
 }
 
+func (d *Droidstubs) apiCompatibilityFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType) {
+	if len(d.Javadoc.properties.Out) > 0 {
+		ctx.PropertyErrorf("out", "out property may not be combined with check_api")
+	}
+
+	apiFiles := android.PathsForModuleSrc(ctx, []string{String(d.properties.Check_api.Last_released.Api_file)})
+	removedApiFiles := android.PathsForModuleSrc(ctx, []string{String(d.properties.Check_api.Last_released.Removed_api_file)})
+
+	cmd.FlagForEachInput("--check-compatibility:api:released ", apiFiles)
+	cmd.FlagForEachInput("--check-compatibility:removed:released ", removedApiFiles)
+
+	baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
+	if baselineFile.Valid() {
+		cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path())
+	}
+}
+
 func metalavaUseRbe(ctx android.ModuleContext) bool {
 	return ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA")
 }
 
-func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths,
-	srcJarList android.Path, bootclasspath, classpath classpath, homeDir android.WritablePath) *android.RuleBuilderCommand {
+func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths,
+	srcJarList android.Path, homeDir android.WritablePath, params stubsCommandConfigParams) *android.RuleBuilderCommand {
 	rule.Command().Text("rm -rf").Flag(homeDir.String())
 	rule.Command().Text("mkdir -p").Flag(homeDir.String())
 
@@ -498,93 +724,137 @@
 	if metalavaUseRbe(ctx) {
 		rule.Remoteable(android.RemoteRuleSupports{RBE: true})
 		execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
+		compare := ctx.Config().IsEnvTrue("RBE_METALAVA_COMPARE")
+		remoteUpdateCache := !ctx.Config().IsEnvFalse("RBE_METALAVA_REMOTE_UPDATE_CACHE")
 		labels := map[string]string{"type": "tool", "name": "metalava"}
 		// TODO: metalava pool rejects these jobs
 		pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
 		rule.Rewrapper(&remoteexec.REParams{
-			Labels:          labels,
-			ExecStrategy:    execStrategy,
-			ToolchainInputs: []string{config.JavaCmd(ctx).String()},
-			Platform:        map[string]string{remoteexec.PoolKey: pool},
+			Labels:              labels,
+			ExecStrategy:        execStrategy,
+			ToolchainInputs:     []string{config.JavaCmd(ctx).String()},
+			Platform:            map[string]string{remoteexec.PoolKey: pool},
+			Compare:             compare,
+			NumLocalRuns:        1,
+			NumRemoteRuns:       1,
+			NoRemoteUpdateCache: !remoteUpdateCache,
 		})
 	}
 
 	cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
 		Flag(config.JavacVmFlags).
-		Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
-		FlagWithArg("--java-source ", javaVersion.String()).
-		FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
+		Flag(config.MetalavaAddOpens).
+		FlagWithArg("--java-source ", params.javaVersion.String()).
+		FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, fmt.Sprintf("%s.metalava.rsp", params.stubsType.String())), srcs).
 		FlagWithInput("@", srcJarList)
 
 	// Metalava does not differentiate between bootclasspath and classpath and has not done so for
 	// years, so it is unlikely to change any time soon.
-	combinedPaths := append(([]android.Path)(nil), bootclasspath.Paths()...)
-	combinedPaths = append(combinedPaths, classpath.Paths()...)
+	combinedPaths := append(([]android.Path)(nil), params.deps.bootClasspath.Paths()...)
+	combinedPaths = append(combinedPaths, params.deps.classpath.Paths()...)
 	if len(combinedPaths) > 0 {
 		cmd.FlagWithInputList("--classpath ", combinedPaths, ":")
 	}
 
-	cmd.Flag("--color").
-		Flag("--quiet").
-		Flag("--format=v2").
-		FlagWithArg("--repeat-errors-max ", "10").
-		FlagWithArg("--hide ", "UnresolvedImport").
-		FlagWithArg("--hide ", "InvalidNullabilityOverride").
-		// b/223382732
-		FlagWithArg("--hide ", "ChangedDefault")
-
-	// Force metalava to ignore classes on the classpath when an API file contains missing classes.
-	// See b/285140653 for more information.
-	cmd.FlagWithArg("--api-class-resolution ", "api")
-
-	// Force metalava to sort overloaded methods by their order in the source code.
-	// See b/285312164 for more information.
-	cmd.FlagWithArg("--api-overloaded-method-order ", "source")
+	cmd.Flag(config.MetalavaFlags)
 
 	return cmd
 }
 
-func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	deps := d.Javadoc.collectDeps(ctx)
+// Pass flagged apis related flags to metalava. When aconfig_declarations property is not
+// defined for a module, simply revert all flagged apis annotations. If aconfig_declarations
+// property is defined, apply transformations and only revert the flagged apis that are not
+// enabled via release configurations and are not specified in aconfig_declarations
+func generateRevertAnnotationArgs(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, aconfigFlagsPaths android.Paths) {
 
-	javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d))
+	if len(aconfigFlagsPaths) == 0 {
+		cmd.Flag("--revert-annotation android.annotation.FlaggedApi")
+		return
+	}
 
-	// Create rule for metalava
+	releasedFlaggedApisFile := android.PathForModuleOut(ctx, fmt.Sprintf("released-flagged-apis-%s.txt", stubsType.String()))
+	revertAnnotationsFile := android.PathForModuleOut(ctx, fmt.Sprintf("revert-annotations-%s.txt", stubsType.String()))
 
-	srcJarDir := android.PathForModuleOut(ctx, "metalava", "srcjars")
+	var filterArgs string
+	switch stubsType {
+	// No flagged apis specific flags need to be passed to metalava when generating
+	// everything stubs
+	case Everything:
+		return
 
-	rule := android.NewRuleBuilder(pctx, ctx)
+	case Runtime:
+		filterArgs = "--filter='state:ENABLED+permission:READ_ONLY' --filter='permission:READ_WRITE'"
 
-	rule.Sbox(android.PathForModuleOut(ctx, "metalava"),
-		android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
-		SandboxInputs()
+	case Exportable:
+		// When the build flag RELEASE_EXPORT_RUNTIME_APIS is set to true, apis marked with
+		// the flagged apis that have read_write permissions are exposed on top of the enabled
+		// and read_only apis. This is to support local override of flag values at runtime.
+		if ctx.Config().ReleaseExportRuntimeApis() {
+			filterArgs = "--filter='state:ENABLED+permission:READ_ONLY' --filter='permission:READ_WRITE'"
+		} else {
+			filterArgs = "--filter='state:ENABLED+permission:READ_ONLY'"
+		}
+	}
 
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        gatherReleasedFlaggedApisRule,
+		Inputs:      aconfigFlagsPaths,
+		Output:      releasedFlaggedApisFile,
+		Description: fmt.Sprintf("%s gather aconfig flags", stubsType),
+		Args: map[string]string{
+			"flags_path":  android.JoinPathsWithPrefix(aconfigFlagsPaths, "--cache "),
+			"filter_args": filterArgs,
+		},
+	})
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        generateMetalavaRevertAnnotationsRule,
+		Input:       releasedFlaggedApisFile,
+		Output:      revertAnnotationsFile,
+		Description: fmt.Sprintf("%s revert annotations", stubsType),
+	})
+
+	cmd.FlagWithInput("@", revertAnnotationsFile)
+}
+
+func (d *Droidstubs) commonMetalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder,
+	params stubsCommandParams) *android.RuleBuilderCommand {
 	if BoolDefault(d.properties.High_mem, false) {
 		// This metalava run uses lots of memory, restrict the number of metalava jobs that can run in parallel.
 		rule.HighMem()
 	}
 
-	generateStubs := BoolDefault(d.properties.Generate_stubs, true)
-	var stubsDir android.OptionalPath
-	if generateStubs {
-		d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
-		stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
-		rule.Command().Text("rm -rf").Text(stubsDir.String())
-		rule.Command().Text("mkdir -p").Text(stubsDir.String())
+	if params.stubConfig.generateStubs {
+		rule.Command().Text("rm -rf").Text(params.stubsDir.String())
+		rule.Command().Text("mkdir -p").Text(params.stubsDir.String())
 	}
 
-	srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
+	srcJarList := zipSyncCmd(ctx, rule, params.srcJarDir, d.Javadoc.srcJars)
 
-	homeDir := android.PathForModuleOut(ctx, "metalava", "home")
-	cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList,
-		deps.bootClasspath, deps.classpath, homeDir)
+	homeDir := android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "home")
+	cmd := metalavaCmd(ctx, rule, d.Javadoc.srcFiles, srcJarList, homeDir, params.stubConfig)
 	cmd.Implicits(d.Javadoc.implicits)
 
-	d.stubsFlags(ctx, cmd, stubsDir)
+	d.stubsFlags(ctx, cmd, params.stubsDir, params.stubConfig.stubsType, params.stubConfig.checkApi)
 
-	d.annotationsFlags(ctx, cmd)
+	if params.stubConfig.writeSdkValues {
+		d.sdkValuesFlags(ctx, cmd, params.metadataDir)
+	}
+
+	annotationParams := annotationFlagsParams{
+		migratingNullability:    params.stubConfig.migratingNullability,
+		validatingNullability:   params.stubConfig.validatingNullability,
+		nullabilityWarningsFile: params.nullabilityWarningsFile,
+		annotationsZip:          params.annotationsZip,
+	}
+
+	d.annotationsFlags(ctx, cmd, annotationParams)
 	d.inclusionAnnotationsFlags(ctx, cmd)
-	d.apiLevelsAnnotationsFlags(ctx, cmd)
+	d.apiLevelsAnnotationsFlags(ctx, cmd, params.stubConfig.stubsType, params.apiVersionsXml)
+
+	if params.stubConfig.doCheckReleased {
+		d.apiCompatibilityFlags(ctx, cmd, params.stubConfig.stubsType)
+	}
 
 	d.expandArgs(ctx, cmd)
 
@@ -592,24 +862,105 @@
 		cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
 	}
 
-	// Add options for the other optional tasks: API-lint and check-released.
-	// We generate separate timestamp files for them.
+	return cmd
+}
 
-	doApiLint := false
-	doCheckReleased := false
+// Sandbox rule for generating the everything stubs and other artifacts
+func (d *Droidstubs) everythingStubCmd(ctx android.ModuleContext, params stubsCommandConfigParams) {
+	srcJarDir := android.PathForModuleOut(ctx, Everything.String(), "srcjars")
+	rule := android.NewRuleBuilder(pctx, ctx)
+	rule.Sbox(android.PathForModuleOut(ctx, Everything.String()),
+		android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
+		SandboxInputs()
+
+	var stubsDir android.OptionalPath
+	if params.generateStubs {
+		stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, Everything.String(), "stubsDir"))
+		d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"-"+"stubs.srcjar")
+	}
+
+	if params.writeSdkValues {
+		d.everythingArtifacts.metadataDir = android.PathForModuleOut(ctx, Everything.String(), "metadata")
+		d.everythingArtifacts.metadataZip = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"-metadata.zip")
+	}
+
+	if Bool(d.properties.Annotations_enabled) {
+		if params.validatingNullability {
+			d.everythingArtifacts.nullabilityWarningsFile = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"_nullability_warnings.txt")
+		}
+		d.everythingArtifacts.annotationsZip = android.PathForModuleOut(ctx, Everything.String(), ctx.ModuleName()+"_annotations.zip")
+	}
+	if Bool(d.properties.Api_levels_annotations_enabled) {
+		d.everythingArtifacts.apiVersionsXml = android.PathForModuleOut(ctx, Everything.String(), "api-versions.xml")
+	}
+
+	commonCmdParams := stubsCommandParams{
+		srcJarDir:               srcJarDir,
+		stubsDir:                stubsDir,
+		stubsSrcJar:             d.Javadoc.stubsSrcJar,
+		metadataDir:             d.everythingArtifacts.metadataDir,
+		apiVersionsXml:          d.everythingArtifacts.apiVersionsXml,
+		nullabilityWarningsFile: d.everythingArtifacts.nullabilityWarningsFile,
+		annotationsZip:          d.everythingArtifacts.annotationsZip,
+		stubConfig:              params,
+	}
+
+	cmd := d.commonMetalavaStubCmd(ctx, rule, commonCmdParams)
+
+	d.everythingOptionalCmd(ctx, cmd, params.doApiLint, params.doCheckReleased)
+
+	if params.generateStubs {
+		rule.Command().
+			BuiltTool("soong_zip").
+			Flag("-write_if_changed").
+			Flag("-jar").
+			FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
+			FlagWithArg("-C ", stubsDir.String()).
+			FlagWithArg("-D ", stubsDir.String())
+	}
+
+	if params.writeSdkValues {
+		rule.Command().
+			BuiltTool("soong_zip").
+			Flag("-write_if_changed").
+			Flag("-d").
+			FlagWithOutput("-o ", d.everythingArtifacts.metadataZip).
+			FlagWithArg("-C ", d.everythingArtifacts.metadataDir.String()).
+			FlagWithArg("-D ", d.everythingArtifacts.metadataDir.String())
+	}
+
+	// TODO: We don't really need two separate API files, but this is a reminiscence of how
+	// we used to run metalava separately for API lint and the "last_released" check. Unify them.
+	if params.doApiLint {
+		rule.Command().Text("touch").Output(d.apiLintTimestamp)
+	}
+	if params.doCheckReleased {
+		rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
+	}
+
+	// TODO(b/183630617): rewrapper doesn't support restat rules
+	if !metalavaUseRbe(ctx) {
+		rule.Restat()
+	}
+
+	zipSyncCleanupCmd(rule, srcJarDir)
+
+	rule.Build("metalava", "metalava merged")
+}
+
+// Sandbox rule for generating the everything artifacts that are not run by
+// default but only run based on the module configurations
+func (d *Droidstubs) everythingOptionalCmd(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, doApiLint bool, doCheckReleased bool) {
 
 	// Add API lint options.
-
-	if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) {
-		doApiLint = true
-
-		newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
-		if newSince.Valid() {
-			cmd.FlagWithInput("--api-lint ", newSince.Path())
-		} else {
-			cmd.Flag("--api-lint")
+	if doApiLint {
+		var newSince android.Paths
+		if d.properties.Check_api.Api_lint.New_since != nil {
+			newSince = android.PathsForModuleSrc(ctx, []string{proptools.String(d.properties.Check_api.Api_lint.New_since)})
 		}
-		d.apiLintReport = android.PathForModuleOut(ctx, "metalava", "api_lint_report.txt")
+		cmd.Flag("--api-lint")
+		cmd.FlagForEachInput("--api-lint-previous-api ", newSince)
+		d.apiLintReport = android.PathForModuleOut(ctx, Everything.String(), "api_lint_report.txt")
 		cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO:  Change to ":api-lint"
 
 		// TODO(b/154317059): Clean up this allowlist by baselining and/or checking in last-released.
@@ -620,8 +971,8 @@
 		}
 
 		baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
-		updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "api_lint_baseline.txt")
-		d.apiLintTimestamp = android.PathForModuleOut(ctx, "metalava", "api_lint.timestamp")
+		updatedBaselineOutput := android.PathForModuleOut(ctx, Everything.String(), "api_lint_baseline.txt")
+		d.apiLintTimestamp = android.PathForModuleOut(ctx, Everything.String(), "api_lint.timestamp")
 
 		// Note this string includes a special shell quote $' ... ', which decodes the "\n"s.
 		//
@@ -662,29 +1013,13 @@
 	}
 
 	// Add "check released" options. (Detect incompatible API changes from the last public release)
-
-	if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") {
-		doCheckReleased = true
-
-		if len(d.Javadoc.properties.Out) > 0 {
-			ctx.PropertyErrorf("out", "out property may not be combined with check_api")
-		}
-
-		apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
-		removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
+	if doCheckReleased {
 		baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
-		updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "last_released_baseline.txt")
-
-		d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_last_released_api.timestamp")
-
-		cmd.FlagWithInput("--check-compatibility:api:released ", apiFile)
-		cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
-
+		d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_last_released_api.timestamp")
 		if baselineFile.Valid() {
-			cmd.FlagWithInput("--baseline:compatibility:released ", baselineFile.Path())
+			updatedBaselineOutput := android.PathForModuleOut(ctx, Everything.String(), "last_released_baseline.txt")
 			cmd.FlagWithOutput("--update-baseline:compatibility:released ", updatedBaselineOutput)
 		}
-
 		// Note this string includes quote ($' ... '), which decodes the "\n"s.
 		msg := `$'\n******************************\n` +
 			`You have tried to change the API from what has been previously released in\n` +
@@ -700,35 +1035,96 @@
 		currentApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
 		cmd.FlagWithInput("--use-same-format-as ", currentApiFile)
 	}
+}
 
-	if generateStubs {
+// Sandbox rule for generating exportable stubs and other artifacts
+func (d *Droidstubs) exportableStubCmd(ctx android.ModuleContext, params stubsCommandConfigParams) {
+	optionalCmdParams := stubsCommandParams{
+		stubConfig: params,
+	}
+
+	if params.generateStubs {
+		d.Javadoc.exportableStubsSrcJar = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-"+"stubs.srcjar")
+		optionalCmdParams.stubsSrcJar = d.Javadoc.exportableStubsSrcJar
+	}
+
+	if params.writeSdkValues {
+		d.exportableArtifacts.metadataZip = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"-metadata.zip")
+		d.exportableArtifacts.metadataDir = android.PathForModuleOut(ctx, params.stubsType.String(), "metadata")
+		optionalCmdParams.metadataZip = d.exportableArtifacts.metadataZip
+		optionalCmdParams.metadataDir = d.exportableArtifacts.metadataDir
+	}
+
+	if Bool(d.properties.Annotations_enabled) {
+		if params.validatingNullability {
+			d.exportableArtifacts.nullabilityWarningsFile = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"_nullability_warnings.txt")
+			optionalCmdParams.nullabilityWarningsFile = d.exportableArtifacts.nullabilityWarningsFile
+		}
+		d.exportableArtifacts.annotationsZip = android.PathForModuleOut(ctx, params.stubsType.String(), ctx.ModuleName()+"_annotations.zip")
+		optionalCmdParams.annotationsZip = d.exportableArtifacts.annotationsZip
+	}
+	if Bool(d.properties.Api_levels_annotations_enabled) {
+		d.exportableArtifacts.apiVersionsXml = android.PathForModuleOut(ctx, params.stubsType.String(), "api-versions.xml")
+		optionalCmdParams.apiVersionsXml = d.exportableArtifacts.apiVersionsXml
+	}
+
+	if params.checkApi || String(d.properties.Api_filename) != "" {
+		filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
+		d.exportableApiFile = android.PathForModuleOut(ctx, params.stubsType.String(), filename)
+	}
+
+	if params.checkApi || String(d.properties.Removed_api_filename) != "" {
+		filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_api.txt")
+		d.exportableRemovedApiFile = android.PathForModuleOut(ctx, params.stubsType.String(), filename)
+	}
+
+	d.optionalStubCmd(ctx, optionalCmdParams)
+}
+
+func (d *Droidstubs) optionalStubCmd(ctx android.ModuleContext, params stubsCommandParams) {
+
+	params.srcJarDir = android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "srcjars")
+	rule := android.NewRuleBuilder(pctx, ctx)
+	rule.Sbox(android.PathForModuleOut(ctx, params.stubConfig.stubsType.String()),
+		android.PathForModuleOut(ctx, fmt.Sprintf("metalava_%s.sbox.textproto", params.stubConfig.stubsType.String()))).
+		SandboxInputs()
+
+	if params.stubConfig.generateStubs {
+		params.stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, params.stubConfig.stubsType.String(), "stubsDir"))
+	}
+
+	cmd := d.commonMetalavaStubCmd(ctx, rule, params)
+
+	generateRevertAnnotationArgs(ctx, cmd, params.stubConfig.stubsType, params.stubConfig.deps.aconfigProtoFiles)
+
+	if params.stubConfig.doApiLint {
+		// Pass the lint baseline file as an input to resolve the lint errors.
+		// The exportable stubs generation does not update the lint baseline file.
+		// Lint baseline file update is handled by the everything stubs
+		baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file)
+		if baselineFile.Valid() {
+			cmd.FlagWithInput("--baseline:api-lint ", baselineFile.Path())
+		}
+	}
+
+	if params.stubConfig.generateStubs {
 		rule.Command().
 			BuiltTool("soong_zip").
 			Flag("-write_if_changed").
 			Flag("-jar").
-			FlagWithOutput("-o ", d.Javadoc.stubsSrcJar).
-			FlagWithArg("-C ", stubsDir.String()).
-			FlagWithArg("-D ", stubsDir.String())
+			FlagWithOutput("-o ", params.stubsSrcJar).
+			FlagWithArg("-C ", params.stubsDir.String()).
+			FlagWithArg("-D ", params.stubsDir.String())
 	}
 
-	if Bool(d.properties.Write_sdk_values) {
-		d.metadataZip = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-metadata.zip")
+	if params.stubConfig.writeSdkValues {
 		rule.Command().
 			BuiltTool("soong_zip").
 			Flag("-write_if_changed").
 			Flag("-d").
-			FlagWithOutput("-o ", d.metadataZip).
-			FlagWithArg("-C ", d.metadataDir.String()).
-			FlagWithArg("-D ", d.metadataDir.String())
-	}
-
-	// TODO: We don't really need two separate API files, but this is a reminiscence of how
-	// we used to run metalava separately for API lint and the "last_released" check. Unify them.
-	if doApiLint {
-		rule.Command().Text("touch").Output(d.apiLintTimestamp)
-	}
-	if doCheckReleased {
-		rule.Command().Text("touch").Output(d.checkLastReleasedApiTimestamp)
+			FlagWithOutput("-o ", params.metadataZip).
+			FlagWithArg("-C ", params.metadataDir.String()).
+			FlagWithArg("-D ", params.metadataDir.String())
 	}
 
 	// TODO(b/183630617): rewrapper doesn't support restat rules
@@ -736,9 +1132,53 @@
 		rule.Restat()
 	}
 
-	zipSyncCleanupCmd(rule, srcJarDir)
+	zipSyncCleanupCmd(rule, params.srcJarDir)
 
-	rule.Build("metalava", "metalava merged")
+	rule.Build(fmt.Sprintf("metalava_%s", params.stubConfig.stubsType.String()), "metalava merged")
+}
+
+func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	deps := d.Javadoc.collectDeps(ctx)
+
+	javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d))
+	generateStubs := BoolDefault(d.properties.Generate_stubs, true)
+
+	// Add options for the other optional tasks: API-lint and check-released.
+	// We generate separate timestamp files for them.
+	doApiLint := BoolDefault(d.properties.Check_api.Api_lint.Enabled, false)
+	doCheckReleased := apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released")
+
+	writeSdkValues := Bool(d.properties.Write_sdk_values)
+
+	annotationsEnabled := Bool(d.properties.Annotations_enabled)
+
+	migratingNullability := annotationsEnabled && String(d.properties.Previous_api) != ""
+	validatingNullability := annotationsEnabled && (strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
+		String(d.properties.Validate_nullability_from_list) != "")
+
+	checkApi := apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
+		apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released")
+
+	stubCmdParams := stubsCommandConfigParams{
+		javaVersion:           javaVersion,
+		deps:                  deps,
+		checkApi:              checkApi,
+		generateStubs:         generateStubs,
+		doApiLint:             doApiLint,
+		doCheckReleased:       doCheckReleased,
+		writeSdkValues:        writeSdkValues,
+		migratingNullability:  migratingNullability,
+		validatingNullability: validatingNullability,
+	}
+	stubCmdParams.stubsType = Everything
+	// Create default (i.e. "everything" stubs) rule for metalava
+	d.everythingStubCmd(ctx, stubCmdParams)
+
+	// The module generates "exportable" (and "runtime" eventually) stubs regardless of whether
+	// aconfig_declarations property is defined or not. If the property is not defined, the module simply
+	// strips all flagged apis to generate the "exportable" stubs
+	stubCmdParams.stubsType = Exportable
+	d.exportableStubCmd(ctx, stubCmdParams)
 
 	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
 
@@ -754,7 +1194,7 @@
 			ctx.PropertyErrorf("baseline_file", "current API check can't have a baseline file. (module %s)", ctx.ModuleName())
 		}
 
-		d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_current_api.timestamp")
+		d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_current_api.timestamp")
 
 		rule := android.NewRuleBuilder(pctx, ctx)
 
@@ -781,6 +1221,12 @@
 			`         m %s-update-current-api\n\n`+
 			`      To submit the revised current.txt to the main Android repository,\n`+
 			`      you will need approval.\n`+
+			`If your build failed due to stub validation, you can resolve the errors with\n`+
+			`either of the two choices above and try re-building the target.\n`+
+			`If the mismatch between the stubs and the current.txt is intended,\n`+
+			`you can try re-building the target by executing the following command:\n`+
+			`m DISABLE_STUB_VALIDATION=true <your build target>.\n`+
+			`Note that DISABLE_STUB_VALIDATION=true does not bypass checkapi.\n`+
 			`******************************\n`, ctx.ModuleName())
 
 		rule.Command().
@@ -792,7 +1238,7 @@
 
 		rule.Build("metalavaCurrentApiCheck", "check current API")
 
-		d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "metalava", "update_current_api.timestamp")
+		d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "update_current_api.timestamp")
 
 		// update API rule
 		rule = android.NewRuleBuilder(pctx, ctx)
@@ -820,14 +1266,14 @@
 	}
 
 	if String(d.properties.Check_nullability_warnings) != "" {
-		if d.nullabilityWarningsFile == nil {
+		if d.everythingArtifacts.nullabilityWarningsFile == nil {
 			ctx.PropertyErrorf("check_nullability_warnings",
 				"Cannot specify check_nullability_warnings unless validating nullability")
 		}
 
 		checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings))
 
-		d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, "metalava", "check_nullability_warnings.timestamp")
+		d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_nullability_warnings.timestamp")
 
 		msg := fmt.Sprintf(`\n******************************\n`+
 			`The warnings encountered during nullability annotation validation did\n`+
@@ -837,13 +1283,13 @@
 			`   2. Update the file of expected warnings by running:\n`+
 			`         cp %s %s\n`+
 			`       and submitting the updated file as part of your change.`,
-			d.nullabilityWarningsFile, checkNullabilityWarnings)
+			d.everythingArtifacts.nullabilityWarningsFile, checkNullabilityWarnings)
 
 		rule := android.NewRuleBuilder(pctx, ctx)
 
 		rule.Command().
 			Text("(").
-			Text("diff").Input(checkNullabilityWarnings).Input(d.nullabilityWarningsFile).
+			Text("diff").Input(checkNullabilityWarnings).Input(d.everythingArtifacts.nullabilityWarningsFile).
 			Text("&&").
 			Text("touch").Output(d.checkNullabilityWarningsTimestamp).
 			Text(") || (").
@@ -853,34 +1299,7 @@
 
 		rule.Build("nullabilityWarningsCheck", "nullability warnings check")
 	}
-}
-
-var _ android.ApiProvider = (*Droidstubs)(nil)
-
-type bazelJavaApiContributionAttributes struct {
-	Api         bazel.LabelAttribute
-	Api_surface *string
-}
-
-func (d *Droidstubs) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "java_api_contribution",
-		Bzl_load_location: "//build/bazel/rules/apis:java_api_contribution.bzl",
-	}
-	apiFile := d.properties.Check_api.Current.Api_file
-	// Do not generate a target if check_api is not set
-	if apiFile == nil {
-		return
-	}
-	attrs := &bazelJavaApiContributionAttributes{
-		Api: *bazel.MakeLabelAttribute(
-			android.BazelLabelForModuleSrcSingle(ctx, proptools.String(apiFile)).Label,
-		),
-		Api_surface: proptools.StringPtr(bazelApiSurfaceName(d.Name())),
-	}
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-		Name: android.ApiContributionTargetName(ctx.ModuleName()),
-	}, attrs)
+	android.CollectDependencyAconfigFiles(ctx, &d.mergedAconfigFiles)
 }
 
 func (d *Droidstubs) createApiContribution(ctx android.DefaultableHookContext) {
@@ -922,28 +1341,6 @@
 	}
 )
 
-// A helper function that returns the api surface of the corresponding java_api_contribution Bazel target
-// The api_surface is populated using the naming convention of the droidstubs module.
-func bazelApiSurfaceName(name string) string {
-	// Sort the keys so that longer strings appear first
-	// Otherwise substrings like system will match both system and system_server
-	sortedKeys := make([]string, 0)
-	for key := range droidstubsModuleNamingToSdkKind {
-		sortedKeys = append(sortedKeys, key)
-	}
-	sort.Slice(sortedKeys, func(i, j int) bool {
-		return len(sortedKeys[i]) > len(sortedKeys[j])
-	})
-	for _, sortedKey := range sortedKeys {
-		if strings.Contains(name, sortedKey) {
-			sdkKind := droidstubsModuleNamingToSdkKind[sortedKey]
-			return sdkKind.String() + "api"
-		}
-	}
-	// Default is publicapi
-	return android.SdkPublic.String() + "api"
-}
-
 func StubsDefaultsFactory() android.Module {
 	module := &DocDefaults{}
 
@@ -961,11 +1358,31 @@
 
 type PrebuiltStubsSourcesProperties struct {
 	Srcs []string `android:"path"`
+
+	// Name of the source soong module that gets shadowed by this prebuilt
+	// If unspecified, follows the naming convention that the source module of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_module_name *string
+
+	// Non-nil if this prebuilt stub srcs  module was dynamically created by a java_sdk_library_import
+	// The name is the undecorated name of the java_sdk_library as it appears in the blueprint file
+	// (without any prebuilt_ prefix)
+	Created_by_java_sdk_library_name *string `blueprint:"mutated"`
+}
+
+func (j *PrebuiltStubsSources) BaseModuleName() string {
+	return proptools.StringDefault(j.properties.Source_module_name, j.ModuleBase.Name())
+}
+
+func (j *PrebuiltStubsSources) CreatedByJavaSdkLibraryName() *string {
+	return j.properties.Created_by_java_sdk_library_name
 }
 
 type PrebuiltStubsSources struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	embeddableInModuleAndImport
+
 	prebuilt android.Prebuilt
 
 	properties PrebuiltStubsSourcesProperties
@@ -975,15 +1392,17 @@
 
 func (p *PrebuiltStubsSources) OutputFiles(tag string) (android.Paths, error) {
 	switch tag {
-	case "":
+	// prebuilt droidstubs does not output "exportable" stubs.
+	// Output the "everything" stubs srcjar file if the tag is ".exportable".
+	case "", ".exportable":
 		return android.Paths{p.stubsSrcJar}, nil
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
 }
 
-func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
-	return d.stubsSrcJar
+func (d *PrebuiltStubsSources) StubsSrcJar(_ StubsType) (android.Path, error) {
+	return d.stubsSrcJar, nil
 }
 
 func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -1044,6 +1463,7 @@
 	module := &PrebuiltStubsSources{}
 
 	module.AddProperties(&module.properties)
+	module.initModuleAndImport(module)
 
 	android.InitPrebuiltModule(module, &module.properties.Srcs)
 	InitDroiddocModule(module, android.HostAndDeviceSupported)
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index 7a04d73..8da695f 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -22,6 +22,8 @@
 	"testing"
 
 	"android/soong/android"
+
+	"github.com/google/blueprint/proptools"
 )
 
 func TestDroidstubs(t *testing.T) {
@@ -82,7 +84,7 @@
 	for _, c := range testcases {
 		m := ctx.ModuleForTests(c.moduleName, "android_common")
 		manifest := m.Output("metalava.sbox.textproto")
-		sboxProto := android.RuleBuilderSboxProtoForTests(t, manifest)
+		sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx, manifest)
 		cmdline := String(sboxProto.Commands[0].Command)
 		android.AssertStringContainsEquals(t, "api-versions generation flag", cmdline, "--generate-api-levels", c.generate_xml)
 		if c.expectedJarFilename != "" {
@@ -131,7 +133,7 @@
 
 	m := ctx.ModuleForTests("foo-stubs", "android_common")
 	manifest := m.Output("metalava.sbox.textproto")
-	cmd := String(android.RuleBuilderSboxProtoForTests(t, manifest).Commands[0].Command)
+	cmd := String(android.RuleBuilderSboxProtoForTests(t, ctx, manifest).Commands[0].Command)
 	r := regexp.MustCompile(`--android-jar-pattern [^ ]+/android.jar`)
 	return r.FindAllString(cmd, -1)
 }
@@ -210,8 +212,8 @@
 		t.Errorf("Expected inputs %q, got %q", w, g)
 	}
 
-	manifest := android.RuleBuilderSboxProtoForTests(t, m.Output("metalava.sbox.textproto"))
-	if g, w := manifest.Commands[0].GetCommand(), "reference __SBOX_SANDBOX_DIR__/out/.intermediates/foo/gen/foo.txt"; !strings.Contains(g, w) {
+	manifest := android.RuleBuilderSboxProtoForTests(t, ctx, m.Output("metalava.sbox.textproto"))
+	if g, w := manifest.Commands[0].GetCommand(), "reference __SBOX_SANDBOX_DIR__/out/soong/.intermediates/foo/gen/foo.txt"; !strings.Contains(g, w) {
 		t.Errorf("Expected command to contain %q, got %q", w, g)
 	}
 }
@@ -300,53 +302,11 @@
 		})
 	m := ctx.ModuleForTests("baz-stubs", "android_common")
 	manifest := m.Output("metalava.sbox.textproto")
-	cmdline := String(android.RuleBuilderSboxProtoForTests(t, manifest).Commands[0].Command)
+	cmdline := String(android.RuleBuilderSboxProtoForTests(t, ctx, manifest).Commands[0].Command)
 	android.AssertStringDoesContain(t, "sdk-extensions-root present", cmdline, "--sdk-extensions-root sdk/extensions")
 	android.AssertStringDoesContain(t, "sdk-extensions-info present", cmdline, "--sdk-extensions-info sdk/extensions/info.txt")
 }
 
-func TestApiSurfaceFromDroidStubsName(t *testing.T) {
-	testCases := []struct {
-		desc               string
-		name               string
-		expectedApiSurface string
-	}{
-		{
-			desc:               "Default is publicapi",
-			name:               "mydroidstubs",
-			expectedApiSurface: "publicapi",
-		},
-		{
-			desc:               "name contains system substring",
-			name:               "mydroidstubs.system.suffix",
-			expectedApiSurface: "systemapi",
-		},
-		{
-			desc:               "name contains system_server substring",
-			name:               "mydroidstubs.system_server.suffix",
-			expectedApiSurface: "system-serverapi",
-		},
-		{
-			desc:               "name contains module_lib substring",
-			name:               "mydroidstubs.module_lib.suffix",
-			expectedApiSurface: "module-libapi",
-		},
-		{
-			desc:               "name contains test substring",
-			name:               "mydroidstubs.test.suffix",
-			expectedApiSurface: "testapi",
-		},
-		{
-			desc:               "name contains intra.core substring",
-			name:               "mydroidstubs.intra.core.suffix",
-			expectedApiSurface: "intracoreapi",
-		},
-	}
-	for _, tc := range testCases {
-		android.AssertStringEquals(t, tc.desc, tc.expectedApiSurface, bazelApiSurfaceName(tc.name))
-	}
-}
-
 func TestDroidStubsApiContributionGeneration(t *testing.T) {
 	ctx, _ := testJavaWithFS(t, `
 		droidstubs {
@@ -377,6 +337,7 @@
 			name: "bar",
 			api_surface: "public",
 			api_contributions: ["foo.api.contribution"],
+			stubs_type: "everything",
 		}
 	`
 	ctx, _ := testJavaWithFS(t, `
@@ -390,7 +351,7 @@
 						removed_api_file: "A/removed.txt",
 					}
 				},
-				visibility: ["//a"],
+				visibility: ["//a", "//b"],
 			}
 		`,
 		map[string][]byte{
@@ -403,3 +364,99 @@
 
 	ctx.ModuleForTests("bar", "android_common")
 }
+
+func TestAconfigDeclarations(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+		}),
+		android.FixtureMergeMockFs(map[string][]byte{
+			"a/A.java":      nil,
+			"a/current.txt": nil,
+			"a/removed.txt": nil,
+		}),
+	).RunTestWithBp(t, `
+	aconfig_declarations {
+		name: "bar",
+		package: "com.example.package",
+		srcs: [
+			"bar.aconfig",
+		],
+	}
+	droidstubs {
+		name: "foo",
+		srcs: ["a/A.java"],
+		api_surface: "public",
+		check_api: {
+			current: {
+				api_file: "a/current.txt",
+				removed_api_file: "a/removed.txt",
+			}
+		},
+		aconfig_declarations: [
+			"bar",
+		],
+	}
+	`)
+
+	// Check that droidstubs depend on aconfig_declarations
+	android.AssertBoolEquals(t, "foo expected to depend on bar",
+		CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "bar"), true)
+
+	m := result.ModuleForTests("foo", "android_common")
+	android.AssertStringDoesContain(t, "foo generates revert annotations file",
+		strings.Join(m.AllOutputs(), ""), "revert-annotations-exportable.txt")
+
+	// revert-annotations.txt passed to exportable stubs generation metalava command
+	manifest := m.Output("metalava_exportable.sbox.textproto")
+	cmdline := String(android.RuleBuilderSboxProtoForTests(t, result.TestContext, manifest).Commands[0].Command)
+	android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "revert-annotations-exportable.txt")
+
+	android.AssertStringDoesContain(t, "foo generates exportable stubs jar",
+		strings.Join(m.AllOutputs(), ""), "exportable/foo-stubs.srcjar")
+}
+
+func TestReleaseExportRuntimeApis(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+			variables.ExportRuntimeApis = proptools.BoolPtr(true)
+		}),
+		android.FixtureMergeMockFs(map[string][]byte{
+			"a/A.java":      nil,
+			"a/current.txt": nil,
+			"a/removed.txt": nil,
+		}),
+	).RunTestWithBp(t, `
+	aconfig_declarations {
+		name: "bar",
+		package: "com.example.package",
+		srcs: [
+			"bar.aconfig",
+		],
+	}
+	droidstubs {
+		name: "foo",
+		srcs: ["a/A.java"],
+		api_surface: "public",
+		check_api: {
+			current: {
+				api_file: "a/current.txt",
+				removed_api_file: "a/removed.txt",
+			}
+		},
+		aconfig_declarations: [
+			"bar",
+		],
+	}
+	`)
+
+	m := result.ModuleForTests("foo", "android_common")
+
+	rule := m.Output("released-flagged-apis-exportable.txt")
+	exposeWritableApisFilter := "--filter='state:ENABLED+permission:READ_ONLY' --filter='permission:READ_WRITE'"
+	android.AssertStringEquals(t, "Filter argument expected to contain READ_WRITE permissions", exposeWritableApisFilter, rule.Args["filter_args"])
+}
diff --git a/java/fuzz.go b/java/fuzz.go
index b3c2fd4..fb31ce7 100644
--- a/java/fuzz.go
+++ b/java/fuzz.go
@@ -64,6 +64,8 @@
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 	module.Module.dexpreopter.isTest = true
 	module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
+	module.Module.sourceProperties.Test_only = proptools.BoolPtr(true)
+	module.Module.sourceProperties.Top_level_test_target = true
 
 	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
 		disableLinuxBionic := struct {
@@ -121,7 +123,7 @@
 
 	_, sharedDeps := cc.CollectAllSharedDependencies(ctx)
 	for _, dep := range sharedDeps {
-		sharedLibInfo := ctx.OtherModuleProvider(dep, cc.SharedLibraryInfoProvider).(cc.SharedLibraryInfo)
+		sharedLibInfo, _ := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider)
 		if sharedLibInfo.SharedLibrary != nil {
 			arch := "lib"
 			if sharedLibInfo.Target.Arch.ArchType.Multilib == "lib64" {
diff --git a/java/gen.go b/java/gen.go
index 638da25..68a9b53 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -129,19 +129,7 @@
 			baseDir = filepath.Clean(baseDir)
 			baseDirSeen := android.InList(baseDir, baseDirs) || android.InList(baseDir, excludeDirsStrings)
 
-			// For go/bp2build mixed builds, a file may be listed under a
-			// directory in the Bazel output tree that is symlinked to a
-			// directory under the android source tree. We should only
-			// include one copy of this directory so that the AIDL tool
-			// doesn't find multiple definitions of the same AIDL class.
-			// This code comes into effect when filegroups are used in mixed builds.
-			bazelPathPrefix := android.PathForBazelOut(ctx, "").String()
-			bazelBaseDir, err := filepath.Rel(bazelPathPrefix, baseDir)
-			bazelBaseDirSeen := err == nil &&
-				android.InList(bazelBaseDir, baseDirs) ||
-				android.InList(bazelBaseDir, excludeDirsStrings)
-
-			if baseDir != "" && !baseDirSeen && !bazelBaseDirSeen {
+			if baseDir != "" && !baseDirSeen {
 				baseDirs = append(baseDirs, baseDir)
 			}
 		}
diff --git a/java/generated_java_library.go b/java/generated_java_library.go
index f9baa85..d5e6d8f 100644
--- a/java/generated_java_library.go
+++ b/java/generated_java_library.go
@@ -22,6 +22,10 @@
 	Library
 	callbacks  GeneratedJavaLibraryCallbacks
 	moduleName string
+
+	// true if we've already called DepsMutator. Can't call AddLibrary or AddSharedLibrary
+	// after DepsMutator.
+	depsMutatorDone bool
 }
 
 type GeneratedJavaLibraryCallbacks interface {
@@ -30,7 +34,7 @@
 
 	// Called from inside GenerateAndroidBuildActions. Add the build rules to
 	// make the srcjar, and return the path to it.
-	GenerateSourceJarBuildActions(module *GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path
+	GenerateSourceJarBuildActions(module *GeneratedJavaLibraryModule, ctx android.ModuleContext) (android.Path, android.Path)
 }
 
 // GeneratedJavaLibraryModuleFactory provides a utility for modules that are generated
@@ -51,7 +55,6 @@
 	module.addHostAndDeviceProperties()
 	module.initModuleAndImport(module)
 	android.InitApexModule(module)
-	android.InitBazelModule(module)
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	if properties != nil {
 		module.AddProperties(properties)
@@ -59,8 +62,25 @@
 	return module
 }
 
+// Add a java shared library as a dependency, as if they had said `libs: [ "name" ]`
+func (module *GeneratedJavaLibraryModule) AddSharedLibrary(name string) {
+	if module.depsMutatorDone {
+		panic("GeneratedJavaLibraryModule.AddLibrary called after DepsMutator")
+	}
+	module.Library.properties.Libs = append(module.Library.properties.Libs, name)
+}
+
+// Add a java shared library as a dependency, as if they had said `libs: [ "name" ]`
+func (module *GeneratedJavaLibraryModule) AddStaticLibrary(name string) {
+	if module.depsMutatorDone {
+		panic("GeneratedJavaLibraryModule.AddStaticLibrary called after DepsMutator")
+	}
+	module.Library.properties.Static_libs = append(module.Library.properties.Static_libs, name)
+}
+
 func (module *GeneratedJavaLibraryModule) DepsMutator(ctx android.BottomUpMutatorContext) {
 	module.callbacks.DepsMutator(module, ctx)
+	module.depsMutatorDone = true
 	module.Library.DepsMutator(ctx)
 }
 
@@ -78,17 +98,19 @@
 	checkPropertyEmpty(ctx, module, "exclude_srcs", module.Library.properties.Exclude_srcs)
 	checkPropertyEmpty(ctx, module, "java_resource_dirs", module.Library.properties.Java_resource_dirs)
 	checkPropertyEmpty(ctx, module, "exclude_java_resource_dirs", module.Library.properties.Exclude_java_resource_dirs)
-	// No additional libraries. The generator should add anything necessary automatically
-	// by returning something from ____ (TODO: Additional libraries aren't needed now, so
-	// these are just blocked).
-	checkPropertyEmpty(ctx, module, "libs", module.Library.properties.Libs)
-	checkPropertyEmpty(ctx, module, "static_libs", module.Library.properties.Static_libs)
 	// Restrict these for no good reason other than to limit the surface area. If there's a
 	// good use case put them back.
 	checkPropertyEmpty(ctx, module, "plugins", module.Library.properties.Plugins)
 	checkPropertyEmpty(ctx, module, "exported_plugins", module.Library.properties.Exported_plugins)
 
-	srcJarPath := module.callbacks.GenerateSourceJarBuildActions(module, ctx)
+	srcJarPath, cacheOutputPath := module.callbacks.GenerateSourceJarBuildActions(module, ctx)
+
 	module.Library.properties.Generated_srcjars = append(module.Library.properties.Generated_srcjars, srcJarPath)
+	module.Library.properties.Aconfig_Cache_files = append(module.Library.properties.Aconfig_Cache_files, cacheOutputPath)
 	module.Library.GenerateAndroidBuildActions(ctx)
 }
+
+// Add a rule to the jarjar renaming rules.  See RepackageProviderData.
+func (module *GeneratedJavaLibraryModule) AddJarJarRenameRule(original string, renamed string) {
+	module.addJarJarRenameRule(original, renamed)
+}
diff --git a/java/generated_java_library_test.go b/java/generated_java_library_test.go
index 7f52fd1..a5c4be1 100644
--- a/java/generated_java_library_test.go
+++ b/java/generated_java_library_test.go
@@ -36,9 +36,8 @@
 func (callbacks *JavaGenLibTestCallbacks) DepsMutator(module *GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext) {
 }
 
-func (callbacks *JavaGenLibTestCallbacks) GenerateSourceJarBuildActions(module *GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path {
-	module.AddAconfigIntermediate(android.PathForOutput(ctx, "aconfig_cache_file"))
-	return android.PathForOutput(ctx, "blah.srcjar")
+func (callbacks *JavaGenLibTestCallbacks) GenerateSourceJarBuildActions(module *GeneratedJavaLibraryModule, ctx android.ModuleContext) (android.Path, android.Path) {
+	return android.PathForOutput(ctx, "blah.srcjar"), android.PathForOutput(ctx, "blah.pb")
 }
 
 func testGenLib(t *testing.T, errorHandler android.FixtureErrorHandler, bp string) *android.TestResult {
diff --git a/java/genrule.go b/java/genrule.go
index 208e1f4..b84225f 100644
--- a/java/genrule.go
+++ b/java/genrule.go
@@ -65,7 +65,6 @@
 
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
-	android.InitBazelModule(module)
 
 	return module
 }
@@ -79,7 +78,6 @@
 
 	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
-	android.InitBazelModule(module)
 
 	return module
 }
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 4d08b83..5441a3b 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -44,7 +44,8 @@
 	//
 	// This must be the path to the unencoded dex jar as the encoded dex jar indirectly depends on
 	// this file so using the encoded dex jar here would result in a cycle in the ninja rules.
-	bootDexJarPath OptionalDexJarPath
+	bootDexJarPath    OptionalDexJarPath
+	bootDexJarPathErr error
 
 	// The paths to the classes jars that contain classes and class members annotated with
 	// the UnsupportedAppUsage annotation that need to be extracted as part of the hidden API
@@ -56,7 +57,10 @@
 	uncompressDexState *bool
 }
 
-func (h *hiddenAPI) bootDexJar() OptionalDexJarPath {
+func (h *hiddenAPI) bootDexJar(ctx android.ModuleErrorfContext) OptionalDexJarPath {
+	if h.bootDexJarPathErr != nil {
+		ctx.ModuleErrorf(h.bootDexJarPathErr.Error())
+	}
 	return h.bootDexJarPath
 }
 
@@ -77,7 +81,7 @@
 }
 
 type hiddenAPIIntf interface {
-	bootDexJar() OptionalDexJarPath
+	bootDexJar(ctx android.ModuleErrorfContext) OptionalDexJarPath
 	classesJars() android.Paths
 	uncompressDex() *bool
 }
@@ -94,7 +98,7 @@
 	// processing.
 	classesJars := android.Paths{classesJar}
 	ctx.VisitDirectDepsWithTag(hiddenApiAnnotationsTag, func(dep android.Module) {
-		javaInfo := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+		javaInfo, _ := android.OtherModuleProvider(ctx, dep, JavaInfoProvider)
 		classesJars = append(classesJars, javaInfo.ImplementationJars...)
 	})
 	h.classesJarPaths = classesJars
@@ -126,6 +130,11 @@
 	h.active = isModuleInBootClassPath(ctx, module)
 }
 
+// Store any error encountered during the initialization of hiddenapi structure (e.g. unflagged co-existing prebuilt apexes)
+func (h *hiddenAPI) initHiddenAPIError(err error) {
+	h.bootDexJarPathErr = err
+}
+
 func isModuleInBootClassPath(ctx android.BaseModuleContext, module android.Module) bool {
 	// Get the configured platform and apex boot jars.
 	nonApexBootJars := ctx.Config().NonApexBootJars()
@@ -305,7 +314,7 @@
 	})
 
 	if uncompressDex {
-		TransformZipAlign(ctx, output, encodeRuleOutput)
+		TransformZipAlign(ctx, output, encodeRuleOutput, nil)
 	}
 
 	return output
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index f31f5d1..ae587ea 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -19,6 +19,7 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/dexpreopt"
 
 	"github.com/google/blueprint"
 )
@@ -38,10 +39,14 @@
 	// The option needed to passed to "hiddenapi list".
 	hiddenAPIListOption string
 
-	// The name sof the source stub library modules that contain the API provided by the platform,
+	// The names of the source stub library modules that contain the API provided by the platform,
 	// i.e. by modules that are not in an APEX.
 	nonUpdatableSourceModule string
 
+	// The names of from-text stub library modules that contain the API provided by the platform,
+	// i.e. by modules that are not in an APEX.
+	nonUpdatableFromTextModule string
+
 	// The names of the prebuilt stub library modules that contain the API provided by the platform,
 	// i.e. by modules that are not in an APEX.
 	nonUpdatablePrebuiltModule string
@@ -86,6 +91,9 @@
 		if ctx.Config().AlwaysUsePrebuiltSdks() {
 			return l.nonUpdatablePrebuiltModule
 		} else {
+			if l.nonUpdatableFromTextModule != "" && ctx.Config().BuildFromTextStub() {
+				return l.nonUpdatableFromTextModule
+			}
 			return l.nonUpdatableSourceModule
 		}
 	} else {
@@ -117,8 +125,9 @@
 		hiddenAPIListOption: "--test-stub-classpath",
 	})
 	ModuleLibHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
-		name:    "module-lib",
-		sdkKind: android.SdkModule,
+		name:                       "module-lib",
+		sdkKind:                    android.SdkModule,
+		nonUpdatableFromTextModule: "android-non-updatable.stubs.test_module_lib",
 	})
 	CorePlatformHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
 		name:                "core-platform",
@@ -236,12 +245,22 @@
 		testStubModules = append(testStubModules, "sdk_test_current_android")
 	} else {
 		// Use stub modules built from source
-		publicStubModules = append(publicStubModules, android.SdkPublic.DefaultJavaLibraryName())
-		systemStubModules = append(systemStubModules, android.SdkSystem.DefaultJavaLibraryName())
-		testStubModules = append(testStubModules, android.SdkTest.DefaultJavaLibraryName())
+		if config.ReleaseHiddenApiExportableStubs() {
+			publicStubModules = append(publicStubModules, android.SdkPublic.DefaultExportableJavaLibraryName())
+			systemStubModules = append(systemStubModules, android.SdkSystem.DefaultExportableJavaLibraryName())
+			testStubModules = append(testStubModules, android.SdkTest.DefaultExportableJavaLibraryName())
+		} else {
+			publicStubModules = append(publicStubModules, android.SdkPublic.DefaultJavaLibraryName())
+			systemStubModules = append(systemStubModules, android.SdkSystem.DefaultJavaLibraryName())
+			testStubModules = append(testStubModules, android.SdkTest.DefaultJavaLibraryName())
+		}
 	}
 	// We do not have prebuilts of the core platform api yet
-	corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs")
+	if config.ReleaseHiddenApiExportableStubs() {
+		corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs.exportable")
+	} else {
+		corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs")
+	}
 
 	// Allow products to define their own stubs for custom product jars that apps can use.
 	publicStubModules = append(publicStubModules, config.ProductHiddenAPIStubs()...)
@@ -280,9 +299,14 @@
 func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path {
 	var dexJar OptionalDexJarPath
 	if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
-		dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind)
+		if ctx.Config().ReleaseHiddenApiExportableStubs() {
+			dexJar = sdkLibrary.SdkApiExportableStubDexJar(ctx, kind)
+		} else {
+			dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind)
+		}
+
 	} else if j, ok := module.(UsesLibraryDependency); ok {
-		dexJar = j.DexJarBuildPath()
+		dexJar = j.DexJarBuildPath(ctx)
 	} else {
 		ctx.ModuleErrorf("dependency %s of module type %s does not support providing a dex jar", module, ctx.OtherModuleType(module))
 		return nil
@@ -350,7 +374,7 @@
 
 	// If there are stub flag files that have been generated by fragments on which this depends then
 	// use them to validate the stub flag file generated by the rules created by this method.
-	if len(stubFlagSubsets) > 0 {
+	if !ctx.Config().DisableVerifyOverlaps() && len(stubFlagSubsets) > 0 {
 		validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, stubFlagSubsets,
 			HIDDENAPI_STUB_FLAGS_IMPL_FLAGS)
 
@@ -411,122 +435,118 @@
 	}
 }
 
-type hiddenAPIFlagFileCategory struct {
-	// PropertyName is the name of the property for this category.
-	PropertyName string
+type hiddenAPIFlagFileCategory int
 
-	// propertyValueReader retrieves the value of the property for this category from the set of
-	// properties.
-	propertyValueReader func(properties *HiddenAPIFlagFileProperties) []string
+const (
+	// The flag file category for removed members of the API.
+	//
+	// This is extracted from HiddenAPIFlagFileCategories as it is needed to add the dex signatures
+	// list of removed API members that are generated automatically from the removed.txt files provided
+	// by API stubs.
+	hiddenAPIFlagFileCategoryRemoved hiddenAPIFlagFileCategory = iota
+	hiddenAPIFlagFileCategoryUnsupported
+	hiddenAPIFlagFileCategoryMaxTargetRLowPriority
+	hiddenAPIFlagFileCategoryMaxTargetQ
+	hiddenAPIFlagFileCategoryMaxTargetP
+	hiddenAPIFlagFileCategoryMaxTargetOLowPriority
+	hiddenAPIFlagFileCategoryBlocked
+	hiddenAPIFlagFileCategoryUnsupportedPackages
+)
 
-	// commandMutator adds the appropriate command line options for this category to the supplied
-	// command
-	commandMutator func(command *android.RuleBuilderCommand, path android.Path)
-}
-
-// The flag file category for removed members of the API.
-//
-// This is extracted from HiddenAPIFlagFileCategories as it is needed to add the dex signatures
-// list of removed API members that are generated automatically from the removed.txt files provided
-// by API stubs.
-var hiddenAPIRemovedFlagFileCategory = &hiddenAPIFlagFileCategory{
-	// See HiddenAPIFlagFileProperties.Removed
-	PropertyName: "removed",
-	propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-		return properties.Hidden_api.Removed
-	},
-	commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
-		command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
-	},
-}
-
-type hiddenAPIFlagFileCategories []*hiddenAPIFlagFileCategory
-
-func (c hiddenAPIFlagFileCategories) byProperty(name string) *hiddenAPIFlagFileCategory {
-	for _, category := range c {
-		if category.PropertyName == name {
-			return category
-		}
+func (c hiddenAPIFlagFileCategory) PropertyName() string {
+	switch c {
+	case hiddenAPIFlagFileCategoryRemoved:
+		return "removed"
+	case hiddenAPIFlagFileCategoryUnsupported:
+		return "unsupported"
+	case hiddenAPIFlagFileCategoryMaxTargetRLowPriority:
+		return "max_target_r_low_priority"
+	case hiddenAPIFlagFileCategoryMaxTargetQ:
+		return "max_target_q"
+	case hiddenAPIFlagFileCategoryMaxTargetP:
+		return "max_target_p"
+	case hiddenAPIFlagFileCategoryMaxTargetOLowPriority:
+		return "max_target_o_low_priority"
+	case hiddenAPIFlagFileCategoryBlocked:
+		return "blocked"
+	case hiddenAPIFlagFileCategoryUnsupportedPackages:
+		return "unsupported_packages"
+	default:
+		panic(fmt.Sprintf("Unknown hidden api flag file category type: %d", c))
 	}
-	panic(fmt.Errorf("no category exists with property name %q in %v", name, c))
 }
 
+// propertyValueReader retrieves the value of the property for this category from the set of properties.
+func (c hiddenAPIFlagFileCategory) propertyValueReader(properties *HiddenAPIFlagFileProperties) []string {
+	switch c {
+	case hiddenAPIFlagFileCategoryRemoved:
+		return properties.Hidden_api.Removed
+	case hiddenAPIFlagFileCategoryUnsupported:
+		return properties.Hidden_api.Unsupported
+	case hiddenAPIFlagFileCategoryMaxTargetRLowPriority:
+		return properties.Hidden_api.Max_target_r_low_priority
+	case hiddenAPIFlagFileCategoryMaxTargetQ:
+		return properties.Hidden_api.Max_target_q
+	case hiddenAPIFlagFileCategoryMaxTargetP:
+		return properties.Hidden_api.Max_target_p
+	case hiddenAPIFlagFileCategoryMaxTargetOLowPriority:
+		return properties.Hidden_api.Max_target_o_low_priority
+	case hiddenAPIFlagFileCategoryBlocked:
+		return properties.Hidden_api.Blocked
+	case hiddenAPIFlagFileCategoryUnsupportedPackages:
+		return properties.Hidden_api.Unsupported_packages
+	default:
+		panic(fmt.Sprintf("Unknown hidden api flag file category type: %d", c))
+	}
+}
+
+// commandMutator adds the appropriate command line options for this category to the supplied command
+func (c hiddenAPIFlagFileCategory) commandMutator(command *android.RuleBuilderCommand, path android.Path) {
+	switch c {
+	case hiddenAPIFlagFileCategoryRemoved:
+		command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
+	case hiddenAPIFlagFileCategoryUnsupported:
+		command.FlagWithInput("--unsupported ", path)
+	case hiddenAPIFlagFileCategoryMaxTargetRLowPriority:
+		command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
+	case hiddenAPIFlagFileCategoryMaxTargetQ:
+		command.FlagWithInput("--max-target-q ", path)
+	case hiddenAPIFlagFileCategoryMaxTargetP:
+		command.FlagWithInput("--max-target-p ", path)
+	case hiddenAPIFlagFileCategoryMaxTargetOLowPriority:
+		command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
+	case hiddenAPIFlagFileCategoryBlocked:
+		command.FlagWithInput("--blocked ", path)
+	case hiddenAPIFlagFileCategoryUnsupportedPackages:
+		command.FlagWithInput("--unsupported ", path).Flag("--packages ")
+	default:
+		panic(fmt.Sprintf("Unknown hidden api flag file category type: %d", c))
+	}
+}
+
+type hiddenAPIFlagFileCategories []hiddenAPIFlagFileCategory
+
 var HiddenAPIFlagFileCategories = hiddenAPIFlagFileCategories{
 	// See HiddenAPIFlagFileProperties.Unsupported
-	{
-		PropertyName: "unsupported",
-		propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-			return properties.Hidden_api.Unsupported
-		},
-		commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
-			command.FlagWithInput("--unsupported ", path)
-		},
-	},
-	hiddenAPIRemovedFlagFileCategory,
+	hiddenAPIFlagFileCategoryUnsupported,
+	// See HiddenAPIFlagFileProperties.Removed
+	hiddenAPIFlagFileCategoryRemoved,
 	// See HiddenAPIFlagFileProperties.Max_target_r_low_priority
-	{
-		PropertyName: "max_target_r_low_priority",
-		propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-			return properties.Hidden_api.Max_target_r_low_priority
-		},
-		commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
-			command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
-		},
-	},
+	hiddenAPIFlagFileCategoryMaxTargetRLowPriority,
 	// See HiddenAPIFlagFileProperties.Max_target_q
-	{
-		PropertyName: "max_target_q",
-		propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-			return properties.Hidden_api.Max_target_q
-		},
-		commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
-			command.FlagWithInput("--max-target-q ", path)
-		},
-	},
+	hiddenAPIFlagFileCategoryMaxTargetQ,
 	// See HiddenAPIFlagFileProperties.Max_target_p
-	{
-		PropertyName: "max_target_p",
-		propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-			return properties.Hidden_api.Max_target_p
-		},
-		commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
-			command.FlagWithInput("--max-target-p ", path)
-		},
-	},
+	hiddenAPIFlagFileCategoryMaxTargetP,
 	// See HiddenAPIFlagFileProperties.Max_target_o_low_priority
-	{
-		PropertyName: "max_target_o_low_priority",
-		propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-			return properties.Hidden_api.Max_target_o_low_priority
-		},
-		commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
-			command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
-		},
-	},
+	hiddenAPIFlagFileCategoryMaxTargetOLowPriority,
 	// See HiddenAPIFlagFileProperties.Blocked
-	{
-		PropertyName: "blocked",
-		propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-			return properties.Hidden_api.Blocked
-		},
-		commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
-			command.FlagWithInput("--blocked ", path)
-		},
-	},
+	hiddenAPIFlagFileCategoryBlocked,
 	// See HiddenAPIFlagFileProperties.Unsupported_packages
-	{
-		PropertyName: "unsupported_packages",
-		propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
-			return properties.Hidden_api.Unsupported_packages
-		},
-		commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
-			command.FlagWithInput("--unsupported ", path).Flag("--packages ")
-		},
-	},
+	hiddenAPIFlagFileCategoryUnsupportedPackages,
 }
 
 // FlagFilesByCategory maps a hiddenAPIFlagFileCategory to the paths to the files in that category.
-type FlagFilesByCategory map[*hiddenAPIFlagFileCategory]android.Paths
+type FlagFilesByCategory map[hiddenAPIFlagFileCategory]android.Paths
 
 // append the supplied flags files to the corresponding category in this map.
 func (s FlagFilesByCategory) append(other FlagFilesByCategory) {
@@ -571,8 +591,7 @@
 	// Merge all the information from the fragments. The fragments form a DAG so it is possible that
 	// this will introduce duplicates so they will be resolved after processing all the fragments.
 	for _, fragment := range fragments {
-		if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
-			info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
+		if info, ok := android.OtherModuleProvider(ctx, fragment, HiddenAPIInfoProvider); ok {
 			i.TransitiveStubDexJarsByScope.addStubDexJarsByModule(info.TransitiveStubDexJarsByScope)
 		}
 	}
@@ -592,7 +611,7 @@
 	return SignatureCsvSubset{i.FilteredFlagsPath, i.SignaturePatternsPath}
 }
 
-var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
+var HiddenAPIInfoProvider = blueprint.NewProvider[HiddenAPIInfo]()
 
 // HiddenAPIInfoForSdk contains information provided by the hidden API processing for use
 // by the sdk snapshot.
@@ -609,7 +628,7 @@
 }
 
 // Provides hidden API info for the sdk snapshot.
-var HiddenAPIInfoForSdkProvider = blueprint.NewProvider(HiddenAPIInfoForSdk{})
+var HiddenAPIInfoForSdkProvider = blueprint.NewProvider[HiddenAPIInfoForSdk]()
 
 // ModuleStubDexJars contains the stub dex jars provided by a single module.
 //
@@ -647,7 +666,7 @@
 	// public version is provided by the art.module.public.api module. In those cases it is necessary
 	// to treat all those modules as they were the same name, otherwise it will result in multiple
 	// definitions of a single class being passed to hidden API processing which will cause an error.
-	if name == scope.nonUpdatablePrebuiltModule || name == scope.nonUpdatableSourceModule {
+	if name == scope.nonUpdatablePrebuiltModule || name == scope.nonUpdatableSourceModule || name == scope.nonUpdatableFromTextModule {
 		// Treat all *android-non-updatable* modules as if they were part of an android-non-updatable
 		// java_sdk_library.
 		// TODO(b/192067200): Remove once android-non-updatable is a java_sdk_library or equivalent.
@@ -741,7 +760,7 @@
 	SplitPackages []string
 }
 
-var hiddenAPIPropertyInfoProvider = blueprint.NewProvider(HiddenAPIPropertyInfo{})
+var hiddenAPIPropertyInfoProvider = blueprint.NewProvider[HiddenAPIPropertyInfo]()
 
 // newHiddenAPIPropertyInfo creates a new initialized HiddenAPIPropertyInfo struct.
 func newHiddenAPIPropertyInfo() HiddenAPIPropertyInfo {
@@ -769,8 +788,7 @@
 
 func (i *HiddenAPIPropertyInfo) gatherPropertyInfo(ctx android.ModuleContext, contents []android.Module) {
 	for _, module := range contents {
-		if ctx.OtherModuleHasProvider(module, hiddenAPIPropertyInfoProvider) {
-			info := ctx.OtherModuleProvider(module, hiddenAPIPropertyInfoProvider).(HiddenAPIPropertyInfo)
+		if info, ok := android.OtherModuleProvider(ctx, module, hiddenAPIPropertyInfoProvider); ok {
 			i.FlagFilesByCategory.append(info.FlagFilesByCategory)
 			i.PackagePrefixes = append(i.PackagePrefixes, info.PackagePrefixes...)
 			i.SinglePackages = append(i.SinglePackages, info.SinglePackages...)
@@ -941,6 +959,7 @@
 	HiddenAPIFlagOutput
 
 	// The map from base module name to the path to the encoded boot dex file.
+	// This field is not available in prebuilt apexes
 	EncodedBootDexFilesByModule bootDexJarByModule
 }
 
@@ -991,14 +1010,14 @@
 	// If available then pass the automatically generated file containing dex signatures of removed
 	// API members to the rule so they can be marked as removed.
 	if generatedRemovedDexSignatures.Valid() {
-		hiddenAPIRemovedFlagFileCategory.commandMutator(command, generatedRemovedDexSignatures.Path())
+		hiddenAPIFlagFileCategoryRemoved.commandMutator(command, generatedRemovedDexSignatures.Path())
 	}
 
 	commitChangeForRestat(rule, tempPath, outputPath)
 
 	// If there are flag files that have been generated by fragments on which this depends then use
 	// them to validate the flag file generated by the rules created by this method.
-	if len(flagSubsets) > 0 {
+	if !ctx.Config().DisableVerifyOverlaps() && len(flagSubsets) > 0 {
 		validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, flagSubsets,
 			HIDDENAPI_FLAGS_CSV_IMPL_FLAGS)
 
@@ -1243,9 +1262,27 @@
 }
 
 // extractBootDexJarsFromModules extracts the boot dex jars from the supplied modules.
+// This information can come from two mechanisms
+// 1. New: Direct deps to _selected_ apexes. The apexes contain a ApexExportsInfo
+// 2. Legacy: An edge to java_sdk_library(_import) module. For prebuilt apexes, this serves as a hook and is populated by deapexers of prebuilt apxes
+// TODO: b/308174306 - Once all mainline modules have been flagged, drop (2)
 func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
 	bootDexJars := bootDexJarByModule{}
+
+	apexNameToApexExportsInfoMap := getApexNameToApexExportsInfoMap(ctx)
+	// For ART and mainline module jars, query apexNameToApexExportsInfoMap to get the dex file
+	apexJars := dexpreopt.GetGlobalConfig(ctx).ArtApexJars.AppendList(&dexpreopt.GetGlobalConfig(ctx).ApexBootJars)
+	for i := 0; i < apexJars.Len(); i++ {
+		if dex, found := apexNameToApexExportsInfoMap.javaLibraryDexPathOnHost(ctx, apexJars.Apex(i), apexJars.Jar(i)); found {
+			bootDexJars[apexJars.Jar(i)] = dex
+		}
+	}
+
+	// TODO - b/308174306: Drop the legacy mechanism
 	for _, module := range contents {
+		if _, exists := bootDexJars[android.RemoveOptionalPrebuiltPrefix(module.Name())]; exists {
+			continue
+		}
 		hiddenAPIModule := hiddenAPIModuleFromModule(ctx, module)
 		if hiddenAPIModule == nil {
 			continue
@@ -1316,7 +1353,7 @@
 // invalid, then create a fake path and either report an error immediately or defer reporting of the
 // error until the path is actually used.
 func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module hiddenAPIModule) android.Path {
-	bootDexJar := module.bootDexJar()
+	bootDexJar := module.bootDexJar(ctx)
 	if !bootDexJar.Valid() {
 		fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/boot-dex/%s.jar", module.Name()))
 		handleMissingDexBootFile(ctx, module, fake, bootDexJar.InvalidReason())
@@ -1396,7 +1433,7 @@
 		}
 
 		if am, ok := module.(android.ApexModule); ok && am.InAnyApex() {
-			apexInfo := ctx.OtherModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+			apexInfo, _ := android.OtherModuleProvider(ctx, module, android.ApexInfoProvider)
 			if apexInfo.IsForPlatform() {
 				return true
 			}
@@ -1431,7 +1468,9 @@
 // However, under certain conditions, e.g. errors, or special build configurations it will return
 // a path to a fake file.
 func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path {
-	bootDexJar := module.(interface{ DexJarBuildPath() OptionalDexJarPath }).DexJarBuildPath()
+	bootDexJar := module.(interface {
+		DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath
+	}).DexJarBuildPath(ctx)
 	if !bootDexJar.Valid() {
 		fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name()))
 		handleMissingDexBootFile(ctx, module, fake, bootDexJar.InvalidReason())
@@ -1439,13 +1478,3 @@
 	}
 	return bootDexJar.Path()
 }
-
-// extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules.
-func extractEncodedDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
-	encodedDexJarsByModuleName := bootDexJarByModule{}
-	for _, module := range contents {
-		path := retrieveEncodedBootDexJarFromModule(ctx, module)
-		encodedDexJarsByModuleName.addPath(module, path)
-	}
-	return encodedDexJarsByModuleName
-}
diff --git a/java/hiddenapi_monolithic.go b/java/hiddenapi_monolithic.go
index 5956e3c..1e30c5f 100644
--- a/java/hiddenapi_monolithic.go
+++ b/java/hiddenapi_monolithic.go
@@ -67,9 +67,8 @@
 
 		case *ClasspathFragmentElement:
 			fragment := e.Module()
-			if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
-				info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
-				monolithicInfo.append(&info)
+			if info, ok := android.OtherModuleProvider(ctx, fragment, HiddenAPIInfoProvider); ok {
+				monolithicInfo.append(ctx, fragment, &info)
 			} else {
 				ctx.ModuleErrorf("%s does not provide hidden API information", fragment)
 			}
@@ -80,14 +79,25 @@
 }
 
 // append appends all the files from the supplied info to the corresponding files in this struct.
-func (i *MonolithicHiddenAPIInfo) append(other *HiddenAPIInfo) {
+func (i *MonolithicHiddenAPIInfo) append(ctx android.ModuleContext, otherModule android.Module, other *HiddenAPIInfo) {
 	i.FlagsFilesByCategory.append(other.FlagFilesByCategory)
 	i.AnnotationFlagsPaths = append(i.AnnotationFlagsPaths, other.AnnotationFlagsPath)
 	i.MetadataPaths = append(i.MetadataPaths, other.MetadataPath)
 	i.IndexPaths = append(i.IndexPaths, other.IndexPath)
 
-	i.StubFlagSubsets = append(i.StubFlagSubsets, other.StubFlagSubset())
-	i.FlagSubsets = append(i.FlagSubsets, other.FlagSubset())
+	apexInfo, ok := android.OtherModuleProvider(ctx, otherModule, android.ApexInfoProvider)
+	if !ok {
+		ctx.ModuleErrorf("Could not determine min_version_version of %s\n", otherModule.Name())
+		return
+	}
+	if apexInfo.MinSdkVersion.LessThanOrEqualTo(android.ApiLevelR) {
+		// Restrict verify_overlaps to R and older modules.
+		// The runtime in S does not have the same restriction that
+		// requires the hiddenapi flags to be generated in a monolithic
+		// invocation.
+		i.StubFlagSubsets = append(i.StubFlagSubsets, other.StubFlagSubset())
+		i.FlagSubsets = append(i.FlagSubsets, other.FlagSubset())
+	}
 }
 
-var MonolithicHiddenAPIInfoProvider = blueprint.NewProvider(MonolithicHiddenAPIInfo{})
+var MonolithicHiddenAPIInfoProvider = blueprint.NewProvider[MonolithicHiddenAPIInfo]()
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 8ec1797..8cb78cd 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -162,7 +162,7 @@
 		return false
 	}
 
-	apexInfo := ctx.OtherModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.OtherModuleProvider(ctx, module, android.ApexInfoProvider)
 
 	// Now match the apex part of the boot image configuration.
 	requiredApex := configuredBootJars.Apex(index)
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index ef792f9..c1fee21 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -177,10 +177,10 @@
 		{
 			name:             "testBundled",
 			unbundledBuild:   false,
-			publicStub:       "android_stubs_current",
-			systemStub:       "android_system_stubs_current",
-			testStub:         "android_test_stubs_current",
-			corePlatformStub: "legacy.core.platform.api.stubs",
+			publicStub:       "android_stubs_current_exportable",
+			systemStub:       "android_system_stubs_current_exportable",
+			testStub:         "android_test_stubs_current_exportable",
+			corePlatformStub: "legacy.core.platform.api.stubs.exportable",
 			preparer:         android.GroupFixturePreparers(),
 		}, {
 			name:             "testUnbundled",
@@ -188,7 +188,7 @@
 			publicStub:       "sdk_public_current_android",
 			systemStub:       "sdk_system_current_android",
 			testStub:         "sdk_test_current_android",
-			corePlatformStub: "legacy.core.platform.api.stubs",
+			corePlatformStub: "legacy.core.platform.api.stubs.exportable",
 			preparer:         PrepareForTestWithPrebuiltsOfCurrentApi,
 		},
 	}
@@ -200,6 +200,9 @@
 				prepareForTestWithDefaultPlatformBootclasspath,
 				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 					variables.Always_use_prebuilt_sdks = proptools.BoolPtr(tc.unbundledBuild)
+					variables.BuildFlags = map[string]string{
+						"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+					}
 				}),
 			).RunTest(t)
 
@@ -309,7 +312,8 @@
 		android.AssertStringEquals(t, "encode embedded java_library", unencodedDexJar, actualUnencodedDexJar.String())
 
 		// Make sure that the encoded dex jar is the exported one.
-		exportedDexJar := moduleForTests.Module().(UsesLibraryDependency).DexJarBuildPath().Path()
+		errCtx := moduleErrorfTestCtx{}
+		exportedDexJar := moduleForTests.Module().(UsesLibraryDependency).DexJarBuildPath(errCtx).Path()
 		android.AssertPathRelativeToTopEquals(t, "encode embedded java_library", encodedDexJar, exportedDexJar)
 	}
 
diff --git a/java/jacoco.go b/java/jacoco.go
index f8012b8..a820b38 100644
--- a/java/jacoco.go
+++ b/java/jacoco.go
@@ -34,13 +34,11 @@
 			`${config.Zip2ZipCmd} -i $in -o $strippedJar $stripSpec && ` +
 			`${config.JavaCmd} ${config.JavaVmFlags} -jar ${config.JacocoCLIJar} ` +
 			`  instrument --quiet --dest $tmpDir $strippedJar && ` +
-			`${config.Ziptime} $tmpJar && ` +
 			`${config.MergeZipsCmd} --ignore-duplicates -j $out $tmpJar $in`,
 		CommandDeps: []string{
 			"${config.Zip2ZipCmd}",
 			"${config.JavaCmd}",
 			"${config.JacocoCLIJar}",
-			"${config.Ziptime}",
 			"${config.MergeZipsCmd}",
 		},
 	},
diff --git a/java/java.go b/java/java.go
index 6667a52..725e25a 100644
--- a/java/java.go
+++ b/java/java.go
@@ -21,12 +21,12 @@
 import (
 	"fmt"
 	"path/filepath"
+	"slices"
+	"sort"
 	"strings"
 
-	"android/soong/bazel"
-	"android/soong/bazel/cquery"
 	"android/soong/remoteexec"
-	"android/soong/ui/metrics/bp2build_metrics_proto"
+	"android/soong/testing"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -63,6 +63,7 @@
 	ctx.RegisterModuleType("dex_import", DexImportFactory)
 	ctx.RegisterModuleType("java_api_library", ApiLibraryFactory)
 	ctx.RegisterModuleType("java_api_contribution", ApiContributionFactory)
+	ctx.RegisterModuleType("java_api_contribution_import", ApiContributionImportFactory)
 
 	// This mutator registers dependencies on dex2oat for modules that should be
 	// dexpreopted. This is done late when the final variants have been
@@ -82,11 +83,19 @@
 	// Register sdk member types.
 	android.RegisterSdkMemberType(javaHeaderLibsSdkMemberType)
 	android.RegisterSdkMemberType(javaLibsSdkMemberType)
-	android.RegisterSdkMemberType(javaBootLibsSdkMemberType)
-	android.RegisterSdkMemberType(javaSystemserverLibsSdkMemberType)
+	android.RegisterSdkMemberType(JavaBootLibsSdkMemberType)
+	android.RegisterSdkMemberType(JavaSystemserverLibsSdkMemberType)
 	android.RegisterSdkMemberType(javaTestSdkMemberType)
 }
 
+type StubsLinkType int
+
+const (
+	Unknown StubsLinkType = iota
+	Stubs
+	Implementation
+)
+
 var (
 	// Supports adding java header libraries to module_exports and sdk.
 	javaHeaderLibsSdkMemberType = &librarySdkMemberType{
@@ -146,7 +155,7 @@
 	// either java_libs, or java_header_libs would end up exporting more information than was strictly
 	// necessary. The java_boot_libs property to allow those modules to be exported as part of the
 	// sdk/module_exports without exposing any unnecessary information.
-	javaBootLibsSdkMemberType = &librarySdkMemberType{
+	JavaBootLibsSdkMemberType = &librarySdkMemberType{
 		android.SdkMemberTypeBase{
 			PropertyName: "java_boot_libs",
 			SupportsSdk:  true,
@@ -185,7 +194,7 @@
 	// either java_libs, or java_header_libs would end up exporting more information than was strictly
 	// necessary. The java_systemserver_libs property to allow those modules to be exported as part of
 	// the sdk/module_exports without exposing any unnecessary information.
-	javaSystemserverLibsSdkMemberType = &librarySdkMemberType{
+	JavaSystemserverLibsSdkMemberType = &librarySdkMemberType{
 		android.SdkMemberTypeBase{
 			PropertyName: "java_systemserver_libs",
 			SupportsSdk:  true,
@@ -225,12 +234,31 @@
 	}, "jar_name", "partition", "main_class")
 )
 
+type ProguardSpecInfo struct {
+	// If true, proguard flags files will be exported to reverse dependencies across libs edges
+	// If false, proguard flags files will only be exported to reverse dependencies across
+	// static_libs edges.
+	Export_proguard_flags_files bool
+
+	// TransitiveDepsProguardSpecFiles is a depset of paths to proguard flags files that are exported from
+	// all transitive deps. This list includes all proguard flags files from transitive static dependencies,
+	// and all proguard flags files from transitive libs dependencies which set `export_proguard_spec: true`.
+	ProguardFlagsFiles *android.DepSet[android.Path]
+
+	// implementation detail to store transitive proguard flags files from exporting shared deps
+	UnconditionallyExportedProguardFlags *android.DepSet[android.Path]
+}
+
+var ProguardSpecInfoProvider = blueprint.NewProvider[ProguardSpecInfo]()
+
 // JavaInfo contains information about a java module for use by modules that depend on it.
 type JavaInfo struct {
 	// HeaderJars is a list of jars that can be passed as the javac classpath in order to link
 	// against this module.  If empty, ImplementationJars should be used instead.
 	HeaderJars android.Paths
 
+	RepackagedHeaderJars android.Paths
+
 	// set of header jars for all transitive libs deps
 	TransitiveLibsHeaderJars *android.DepSet[android.Path]
 
@@ -259,6 +287,9 @@
 	// SrcJarDeps is a list of paths to depend on when packaging the sources of this module.
 	SrcJarDeps android.Paths
 
+	// The source files of this module and all its transitive static dependencies.
+	TransitiveSrcFiles *android.DepSet[android.Path]
+
 	// ExportedPlugins is a list of paths that should be used as annotation processors for any
 	// module that depends on this module.
 	ExportedPlugins android.Paths
@@ -275,17 +306,17 @@
 	// instrumented by jacoco.
 	JacocoReportClassesFile android.Path
 
-	// set of aconfig flags for all transitive libs deps
-	// TODO(joeo): It would be nice if this were over in the aconfig package instead of here.
-	// In order to do that, generated_java_library would need a way doing
-	// collectTransitiveAconfigFiles with one of the callbacks, and having that automatically
-	// propagated. If we were to clean up more of the stuff on JavaInfo that's not part of
-	// core java rules (e.g. AidlIncludeDirs), then maybe adding more framework to do that would be
-	// worth it.
-	TransitiveAconfigFiles *android.DepSet[android.Path]
+	// StubsLinkType provides information about whether the provided jars are stub jars or
+	// implementation jars. If the provider is set by java_sdk_library, the link type is "unknown"
+	// and selection between the stub jar vs implementation jar is deferred to SdkLibrary.sdkJars(...)
+	StubsLinkType StubsLinkType
+
+	// AconfigIntermediateCacheOutputPaths is a path to the cache files collected from the
+	// java_aconfig_library modules that are statically linked to this module.
+	AconfigIntermediateCacheOutputPaths android.Paths
 }
 
-var JavaInfoProvider = blueprint.NewProvider(JavaInfo{})
+var JavaInfoProvider = blueprint.NewProvider[JavaInfo]()
 
 // SyspropPublicStubInfo contains info about the sysprop public stub library that corresponds to
 // the sysprop implementation library.
@@ -295,7 +326,7 @@
 	JavaInfo JavaInfo
 }
 
-var SyspropPublicStubInfoProvider = blueprint.NewProvider(SyspropPublicStubInfo{})
+var SyspropPublicStubInfoProvider = blueprint.NewProvider[SyspropPublicStubInfo]()
 
 // Methods that need to be implemented for a module that is added to apex java_libs property.
 type ApexDependency interface {
@@ -305,16 +336,11 @@
 
 // Provides build path and install path to DEX jars.
 type UsesLibraryDependency interface {
-	DexJarBuildPath() OptionalDexJarPath
+	DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath
 	DexJarInstallPath() android.Path
 	ClassLoaderContexts() dexpreopt.ClassLoaderContextMap
 }
 
-// Provides transitive Proguard flag files to downstream DEX jars.
-type LibraryDependency interface {
-	ExportedProguardFlagFiles() android.Paths
-}
-
 // TODO(jungjw): Move this to kythe.go once it's created.
 type xref interface {
 	XrefJavaFiles() android.Paths
@@ -324,6 +350,12 @@
 	return j.kytheFiles
 }
 
+func (d dependencyTag) PropagateAconfigValidation() bool {
+	return d.static
+}
+
+var _ android.PropagateAconfigValidationDependencyTag = dependencyTag{}
+
 type dependencyTag struct {
 	blueprint.BaseDependencyTag
 	name string
@@ -333,6 +365,8 @@
 
 	// True if the dependency is a toolchain, for example an annotation processor.
 	toolchain bool
+
+	static bool
 }
 
 // installDependencyTag is a dependency tag that is annotated to cause the installed files of the
@@ -378,7 +412,7 @@
 var (
 	dataNativeBinsTag       = dependencyTag{name: "dataNativeBins"}
 	dataDeviceBinsTag       = dependencyTag{name: "dataDeviceBins"}
-	staticLibTag            = dependencyTag{name: "staticlib"}
+	staticLibTag            = dependencyTag{name: "staticlib", static: true}
 	libTag                  = dependencyTag{name: "javalib", runtimeLinked: true}
 	sdkLibTag               = dependencyTag{name: "sdklib", runtimeLinked: true}
 	java9LibTag             = dependencyTag{name: "java9lib", runtimeLinked: true}
@@ -400,6 +434,7 @@
 	syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"}
 	javaApiContributionTag  = dependencyTag{name: "java-api-contribution"}
 	depApiSrcsTag           = dependencyTag{name: "dep-api-srcs"}
+	aconfigDeclarationTag   = dependencyTag{name: "aconfig-declaration"}
 	jniInstallTag           = installDependencyTag{name: "jni install"}
 	binaryInstallTag        = installDependencyTag{name: "binary install"}
 	usesLibReqTag           = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false)
@@ -513,6 +548,7 @@
 	kotlinStdlib            android.Paths
 	kotlinAnnotations       android.Paths
 	kotlinPlugins           android.Paths
+	aconfigProtoFiles       android.Paths
 
 	disableTurbine bool
 }
@@ -551,14 +587,17 @@
 	JAVA_VERSION_9           = 9
 	JAVA_VERSION_11          = 11
 	JAVA_VERSION_17          = 17
+	JAVA_VERSION_21          = 21
 )
 
 func (v javaVersion) String() string {
 	switch v {
 	case JAVA_VERSION_6:
-		return "1.6"
+		// Java version 1.6 no longer supported, bumping to 1.8
+		return "1.8"
 	case JAVA_VERSION_7:
-		return "1.7"
+		// Java version 1.7 no longer supported, bumping to 1.8
+		return "1.8"
 	case JAVA_VERSION_8:
 		return "1.8"
 	case JAVA_VERSION_9:
@@ -567,6 +606,8 @@
 		return "11"
 	case JAVA_VERSION_17:
 		return "17"
+	case JAVA_VERSION_21:
+		return "21"
 	default:
 		return "unsupported"
 	}
@@ -575,10 +616,12 @@
 func (v javaVersion) StringForKotlinc() string {
 	// $ ./external/kotlinc/bin/kotlinc -jvm-target foo
 	// error: unknown JVM target version: foo
-	// Supported versions: 1.6, 1.8, 9, 10, 11, 12, 13, 14, 15, 16, 17
+	// Supported versions: 1.8, 9, 10, 11, 12, 13, 14, 15, 16, 17
 	switch v {
+	case JAVA_VERSION_6:
+		return "1.8"
 	case JAVA_VERSION_7:
-		return "1.6"
+		return "1.8"
 	case JAVA_VERSION_9:
 		return "9"
 	default:
@@ -594,9 +637,11 @@
 func normalizeJavaVersion(ctx android.BaseModuleContext, javaVersion string) javaVersion {
 	switch javaVersion {
 	case "1.6", "6":
-		return JAVA_VERSION_6
+		// Java version 1.6 no longer supported, bumping to 1.8
+		return JAVA_VERSION_8
 	case "1.7", "7":
-		return JAVA_VERSION_7
+		// Java version 1.7 no longer supported, bumping to 1.8
+		return JAVA_VERSION_8
 	case "1.8", "8":
 		return JAVA_VERSION_8
 	case "1.9", "9":
@@ -605,6 +650,8 @@
 		return JAVA_VERSION_11
 	case "17":
 		return JAVA_VERSION_17
+	case "21":
+		return JAVA_VERSION_21
 	case "10", "12", "13", "14", "15", "16":
 		ctx.PropertyErrorf("java_version", "Java language level %s is not supported", javaVersion)
 		return JAVA_VERSION_UNSUPPORTED
@@ -621,15 +668,9 @@
 type Library struct {
 	Module
 
-	exportedProguardFlagFiles android.Paths
+	combinedExportedProguardFlagsFile android.Path
 
-	InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths)
-}
-
-var _ LibraryDependency = (*Library)(nil)
-
-func (j *Library) ExportedProguardFlagFiles() android.Paths {
-	return j.exportedProguardFlagFiles
+	InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.InstallPaths)
 }
 
 var _ android.ApexModule = (*Library)(nil)
@@ -645,9 +686,9 @@
 	return j.properties.Permitted_packages
 }
 
-func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bool {
+func shouldUncompressDex(ctx android.ModuleContext, libName string, dexpreopter *dexpreopter) bool {
 	// Store uncompressed (and aligned) any dex files from jars in APEXes.
-	if apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo); !apexInfo.IsForPlatform() {
+	if apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider); !apexInfo.IsForPlatform() {
 		return true
 	}
 
@@ -656,10 +697,11 @@
 		return true
 	}
 
-	// Store uncompressed dex files that are preopted on /system.
-	if !dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !dexpreopter.odexOnSystemOther(ctx, dexpreopter.installPath)) {
+	// Store uncompressed dex files that are preopted on /system or /system_other.
+	if !dexpreopter.dexpreoptDisabled(ctx, libName) {
 		return true
 	}
+
 	if ctx.Config().UncompressPrivAppDex() &&
 		inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules()) {
 		return true
@@ -672,42 +714,240 @@
 func setUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter, dexer *dexer) {
 	if dexer.dexProperties.Uncompress_dex == nil {
 		// If the value was not force-set by the user, use reasonable default based on the module.
-		dexer.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, dexpreopter))
+		dexer.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), dexpreopter))
+	}
+}
+
+// list of java_library modules that set platform_apis: true
+// this property is a no-op for java_library
+// TODO (b/215379393): Remove this allowlist
+var (
+	aospPlatformApiAllowlist = map[string]bool{
+		"adservices-test-scenarios":                         true,
+		"aidl-cpp-java-test-interface-java":                 true,
+		"aidl-test-extras-java":                             true,
+		"aidl-test-interface-java":                          true,
+		"aidl-test-interface-permission-java":               true,
+		"aidl_test_java_client_permission":                  true,
+		"aidl_test_java_client_sdk1":                        true,
+		"aidl_test_java_client_sdk29":                       true,
+		"aidl_test_java_client":                             true,
+		"aidl_test_java_service_permission":                 true,
+		"aidl_test_java_service_sdk1":                       true,
+		"aidl_test_java_service_sdk29":                      true,
+		"aidl_test_java_service":                            true,
+		"aidl_test_loggable_interface-java":                 true,
+		"aidl_test_nonvintf_parcelable-V1-java":             true,
+		"aidl_test_nonvintf_parcelable-V2-java":             true,
+		"aidl_test_unstable_parcelable-java":                true,
+		"aidl_test_vintf_parcelable-V1-java":                true,
+		"aidl_test_vintf_parcelable-V2-java":                true,
+		"android.aidl.test.trunk-V1-java":                   true,
+		"android.aidl.test.trunk-V2-java":                   true,
+		"android.frameworks.location.altitude-V1-java":      true,
+		"android.frameworks.location.altitude-V2-java":      true,
+		"android.frameworks.stats-V1-java":                  true,
+		"android.frameworks.stats-V2-java":                  true,
+		"android.frameworks.stats-V3-java":                  true,
+		"android.hardware.authsecret-V1-java":               true,
+		"android.hardware.authsecret-V2-java":               true,
+		"android.hardware.biometrics.common-V1-java":        true,
+		"android.hardware.biometrics.common-V2-java":        true,
+		"android.hardware.biometrics.common-V3-java":        true,
+		"android.hardware.biometrics.common-V4-java":        true,
+		"android.hardware.biometrics.face-V1-java":          true,
+		"android.hardware.biometrics.face-V2-java":          true,
+		"android.hardware.biometrics.face-V3-java":          true,
+		"android.hardware.biometrics.face-V4-java":          true,
+		"android.hardware.biometrics.fingerprint-V1-java":   true,
+		"android.hardware.biometrics.fingerprint-V2-java":   true,
+		"android.hardware.biometrics.fingerprint-V3-java":   true,
+		"android.hardware.biometrics.fingerprint-V4-java":   true,
+		"android.hardware.bluetooth.lmp_event-V1-java":      true,
+		"android.hardware.confirmationui-V1-java":           true,
+		"android.hardware.confirmationui-V2-java":           true,
+		"android.hardware.gatekeeper-V1-java":               true,
+		"android.hardware.gatekeeper-V2-java":               true,
+		"android.hardware.gnss-V1-java":                     true,
+		"android.hardware.gnss-V2-java":                     true,
+		"android.hardware.gnss-V3-java":                     true,
+		"android.hardware.gnss-V4-java":                     true,
+		"android.hardware.graphics.common-V1-java":          true,
+		"android.hardware.graphics.common-V2-java":          true,
+		"android.hardware.graphics.common-V3-java":          true,
+		"android.hardware.graphics.common-V4-java":          true,
+		"android.hardware.graphics.common-V5-java":          true,
+		"android.hardware.identity-V1-java":                 true,
+		"android.hardware.identity-V2-java":                 true,
+		"android.hardware.identity-V3-java":                 true,
+		"android.hardware.identity-V4-java":                 true,
+		"android.hardware.identity-V5-java":                 true,
+		"android.hardware.identity-V6-java":                 true,
+		"android.hardware.keymaster-V1-java":                true,
+		"android.hardware.keymaster-V2-java":                true,
+		"android.hardware.keymaster-V3-java":                true,
+		"android.hardware.keymaster-V4-java":                true,
+		"android.hardware.keymaster-V5-java":                true,
+		"android.hardware.oemlock-V1-java":                  true,
+		"android.hardware.oemlock-V2-java":                  true,
+		"android.hardware.power.stats-V1-java":              true,
+		"android.hardware.power.stats-V2-java":              true,
+		"android.hardware.power.stats-V3-java":              true,
+		"android.hardware.power-V1-java":                    true,
+		"android.hardware.power-V2-java":                    true,
+		"android.hardware.power-V3-java":                    true,
+		"android.hardware.power-V4-java":                    true,
+		"android.hardware.power-V5-java":                    true,
+		"android.hardware.rebootescrow-V1-java":             true,
+		"android.hardware.rebootescrow-V2-java":             true,
+		"android.hardware.security.authgraph-V1-java":       true,
+		"android.hardware.security.keymint-V1-java":         true,
+		"android.hardware.security.keymint-V2-java":         true,
+		"android.hardware.security.keymint-V3-java":         true,
+		"android.hardware.security.keymint-V4-java":         true,
+		"android.hardware.security.secretkeeper-V1-java":    true,
+		"android.hardware.security.secureclock-V1-java":     true,
+		"android.hardware.security.secureclock-V2-java":     true,
+		"android.hardware.thermal-V1-java":                  true,
+		"android.hardware.thermal-V2-java":                  true,
+		"android.hardware.threadnetwork-V1-java":            true,
+		"android.hardware.weaver-V1-java":                   true,
+		"android.hardware.weaver-V2-java":                   true,
+		"android.hardware.weaver-V3-java":                   true,
+		"android.security.attestationmanager-java":          true,
+		"android.security.authorization-java":               true,
+		"android.security.compat-java":                      true,
+		"android.security.legacykeystore-java":              true,
+		"android.security.maintenance-java":                 true,
+		"android.security.metrics-java":                     true,
+		"android.system.keystore2-V1-java":                  true,
+		"android.system.keystore2-V2-java":                  true,
+		"android.system.keystore2-V3-java":                  true,
+		"android.system.keystore2-V4-java":                  true,
+		"binderReadParcelIface-java":                        true,
+		"binderRecordReplayTestIface-java":                  true,
+		"car-experimental-api-static-lib":                   true,
+		"collector-device-lib-platform":                     true,
+		"com.android.car.oem":                               true,
+		"com.google.hardware.pixel.display-V10-java":        true,
+		"com.google.hardware.pixel.display-V1-java":         true,
+		"com.google.hardware.pixel.display-V2-java":         true,
+		"com.google.hardware.pixel.display-V3-java":         true,
+		"com.google.hardware.pixel.display-V4-java":         true,
+		"com.google.hardware.pixel.display-V5-java":         true,
+		"com.google.hardware.pixel.display-V6-java":         true,
+		"com.google.hardware.pixel.display-V7-java":         true,
+		"com.google.hardware.pixel.display-V8-java":         true,
+		"com.google.hardware.pixel.display-V9-java":         true,
+		"conscrypt-support":                                 true,
+		"cts-keystore-test-util":                            true,
+		"cts-keystore-user-auth-helper-library":             true,
+		"ctsmediautil":                                      true,
+		"CtsNetTestsNonUpdatableLib":                        true,
+		"DpmWrapper":                                        true,
+		"flickerlib-apphelpers":                             true,
+		"flickerlib-helpers":                                true,
+		"flickerlib-parsers":                                true,
+		"flickerlib":                                        true,
+		"hardware.google.bluetooth.ccc-V1-java":             true,
+		"hardware.google.bluetooth.sar-V1-java":             true,
+		"monet":                                             true,
+		"pixel-power-ext-V1-java":                           true,
+		"pixel-power-ext-V2-java":                           true,
+		"pixel_stateresidency_provider_aidl_interface-java": true,
+		"pixel-thermal-ext-V1-java":                         true,
+		"protolog-lib":                                      true,
+		"RkpRegistrationCheck":                              true,
+		"rotary-service-javastream-protos":                  true,
+		"service_based_camera_extensions":                   true,
+		"statsd-helper-test":                                true,
+		"statsd-helper":                                     true,
+		"test-piece-2-V1-java":                              true,
+		"test-piece-2-V2-java":                              true,
+		"test-piece-3-V1-java":                              true,
+		"test-piece-3-V2-java":                              true,
+		"test-piece-3-V3-java":                              true,
+		"test-piece-4-V1-java":                              true,
+		"test-piece-4-V2-java":                              true,
+		"test-root-package-V1-java":                         true,
+		"test-root-package-V2-java":                         true,
+		"test-root-package-V3-java":                         true,
+		"test-root-package-V4-java":                         true,
+		"testServiceIface-java":                             true,
+		"wm-flicker-common-app-helpers":                     true,
+		"wm-flicker-common-assertions":                      true,
+		"wm-shell-flicker-utils":                            true,
+		"wycheproof-keystore":                               true,
+	}
+
+	// Union of aosp and internal allowlists
+	PlatformApiAllowlist = map[string]bool{}
+)
+
+func init() {
+	for k, v := range aospPlatformApiAllowlist {
+		PlatformApiAllowlist[k] = v
 	}
 }
 
 func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-
+	if disableSourceApexVariant(ctx) {
+		// Prebuilts are active, do not create the installation rules for the source javalib.
+		// Even though the source javalib is not used, we need to hide it to prevent duplicate installation rules.
+		// TODO (b/331665856): Implement a principled solution for this.
+		j.HideFromMake()
+	}
 	j.provideHiddenAPIPropertyInfo(ctx)
 
 	j.sdkVersion = j.SdkVersion(ctx)
 	j.minSdkVersion = j.MinSdkVersion(ctx)
 	j.maxSdkVersion = j.MaxSdkVersion(ctx)
 
-	j.stem = proptools.StringDefault(j.overridableDeviceProperties.Stem, ctx.ModuleName())
+	// SdkLibrary.GenerateAndroidBuildActions(ctx) sets the stubsLinkType to Unknown.
+	// If the stubsLinkType has already been set to Unknown, the stubsLinkType should
+	// not be overridden.
+	if j.stubsLinkType != Unknown {
+		if proptools.Bool(j.properties.Is_stubs_module) {
+			j.stubsLinkType = Stubs
+		} else {
+			j.stubsLinkType = Implementation
+		}
+	}
 
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	j.stem = proptools.StringDefault(j.overridableProperties.Stem, ctx.ModuleName())
+
+	proguardSpecInfo := j.collectProguardSpecInfo(ctx)
+	android.SetProvider(ctx, ProguardSpecInfoProvider, proguardSpecInfo)
+	exportedProguardFlagsFiles := proguardSpecInfo.ProguardFlagsFiles.ToList()
+	j.extraProguardFlagsFiles = append(j.extraProguardFlagsFiles, exportedProguardFlagsFiles...)
+
+	combinedExportedProguardFlagFile := android.PathForModuleOut(ctx, "export_proguard_flags")
+	writeCombinedProguardFlagsFile(ctx, combinedExportedProguardFlagFile, exportedProguardFlagsFiles)
+	j.combinedExportedProguardFlagsFile = combinedExportedProguardFlagFile
+
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	if !apexInfo.IsForPlatform() {
 		j.hideApexVariantFromMake = true
 	}
 
 	j.checkSdkVersions(ctx)
+	j.checkHeadersOnly(ctx)
 	if ctx.Device() {
 		j.dexpreopter.installPath = j.dexpreopter.getInstallPath(
-			ctx, android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar"))
+			ctx, j.Name(), android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar"))
 		j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
 		setUncompressDex(ctx, &j.dexpreopter, &j.dexer)
 		j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
 		j.classLoaderContexts = j.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
+		if j.usesLibrary.shouldDisableDexpreopt {
+			j.dexpreopter.disableDexpreopt()
+		}
 	}
 	j.compile(ctx, nil, nil, nil)
 
-	// Collect the module directory for IDE info in java/jdeps.go.
-	j.modulePaths = append(j.modulePaths, ctx.ModuleDir())
-
 	exclusivelyForApex := !apexInfo.IsForPlatform()
 	if (Bool(j.properties.Installable) || ctx.Host()) && !exclusivelyForApex {
-		var extraInstallDeps android.Paths
+		var extraInstallDeps android.InstallPaths
 		if j.InstallMixin != nil {
 			extraInstallDeps = j.InstallMixin(ctx, j.outputFile)
 		}
@@ -730,20 +970,15 @@
 		j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...)
 	}
 
-	j.exportedProguardFlagFiles = append(j.exportedProguardFlagFiles,
-		android.PathsForModuleSrc(ctx, j.dexProperties.Optimize.Proguard_flags_files)...)
-	ctx.VisitDirectDeps(func(m android.Module) {
-		if lib, ok := m.(LibraryDependency); ok && ctx.OtherModuleDependencyTag(m) == staticLibTag {
-			j.exportedProguardFlagFiles = append(j.exportedProguardFlagFiles, lib.ExportedProguardFlagFiles()...)
-		}
+	android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
+		TestOnly:       Bool(j.sourceProperties.Test_only),
+		TopLevelTarget: j.sourceProperties.Top_level_test_target,
 	})
-	j.exportedProguardFlagFiles = android.FirstUniquePaths(j.exportedProguardFlagFiles)
-
 }
 
 func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
-	j.deps(ctx)
 	j.usesLibrary.deps(ctx, false)
+	j.deps(ctx)
 }
 
 const (
@@ -904,11 +1139,11 @@
 	module := &Library{}
 
 	module.addHostAndDeviceProperties()
+	module.AddProperties(&module.sourceProperties)
 
 	module.initModuleAndImport(module)
 
 	android.InitApexModule(module)
-	android.InitBazelModule(module)
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
 }
@@ -930,7 +1165,6 @@
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 
 	android.InitApexModule(module)
-	android.InitBazelModule(module)
 	InitJavaModule(module, android.HostSupported)
 	return module
 }
@@ -1081,6 +1315,10 @@
 	return true
 }
 
+func (j *TestHost) IsNativeCoverageNeeded(ctx android.IncomingTransitionContext) bool {
+	return ctx.DeviceConfig().NativeCoverageEnabled()
+}
+
 func (j *TestHost) addDataDeviceBinsDeps(ctx android.BottomUpMutatorContext) {
 	if len(j.testHostProperties.Data_device_bins_first) > 0 {
 		deviceVariations := ctx.Config().AndroidFirstDeviceTarget.Variations()
@@ -1217,10 +1455,20 @@
 	}
 
 	j.Test.generateAndroidBuildActionsWithConfig(ctx, configs)
+	android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+	android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{
+		InstalledFiles:      j.data,
+		OutputFile:          j.outputFile,
+		TestConfig:          j.testConfig,
+		RequiredModuleNames: j.RequiredModuleNames(),
+		TestSuites:          j.testProperties.Test_suites,
+		IsHost:              true,
+	})
 }
 
 func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.generateAndroidBuildActionsWithConfig(ctx, nil)
+	android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, configs []tradefed.Config) {
@@ -1256,7 +1504,7 @@
 	})
 
 	ctx.VisitDirectDepsWithTag(jniLibTag, func(dep android.Module) {
-		sharedLibInfo := ctx.OtherModuleProvider(dep, cc.SharedLibraryInfoProvider).(cc.SharedLibraryInfo)
+		sharedLibInfo, _ := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider)
 		if sharedLibInfo.SharedLibrary != nil {
 			// Copy to an intermediate output directory to append "lib[64]" to the path,
 			// so that it's compatible with the default rpath values.
@@ -1373,6 +1621,8 @@
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 	module.Module.dexpreopter.isTest = true
 	module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
+	module.Module.sourceProperties.Test_only = proptools.BoolPtr(true)
+	module.Module.sourceProperties.Top_level_test_target = true
 
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
@@ -1388,6 +1638,7 @@
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 	module.Module.dexpreopter.isTest = true
 	module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
+	module.Module.sourceProperties.Test_only = proptools.BoolPtr(true)
 
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
@@ -1434,8 +1685,6 @@
 		nil,
 		nil)
 
-	android.InitBazelModule(module)
-
 	InitJavaModuleMultiTargets(module, android.HostSupported)
 
 	return module
@@ -1445,6 +1694,8 @@
 	th.properties.Installable = installable
 	th.testProperties.Auto_gen_config = autoGenConfig
 	th.testProperties.Test_suites = testSuites
+	th.sourceProperties.Test_only = proptools.BoolPtr(true)
+	th.sourceProperties.Top_level_test_target = true
 }
 
 //
@@ -1479,7 +1730,7 @@
 }
 
 func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	j.stem = proptools.StringDefault(j.overridableDeviceProperties.Stem, ctx.ModuleName())
+	j.stem = proptools.StringDefault(j.overridableProperties.Stem, ctx.ModuleName())
 
 	if ctx.Arch().ArchType == android.Common {
 		// Compile the jar
@@ -1570,13 +1821,12 @@
 	module := &Binary{}
 
 	module.addHostAndDeviceProperties()
-	module.AddProperties(&module.binaryProperties)
+	module.AddProperties(&module.binaryProperties, &module.sourceProperties)
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommonFirst)
 	android.InitDefaultableModule(module)
-	android.InitBazelModule(module)
 
 	return module
 }
@@ -1595,13 +1845,13 @@
 
 	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommonFirst)
 	android.InitDefaultableModule(module)
-	android.InitBazelModule(module)
 	return module
 }
 
 type JavaApiContribution struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	embeddableInModuleAndImport
 
 	properties struct {
 		// name of the API surface
@@ -1617,14 +1867,16 @@
 	android.InitAndroidModule(module)
 	android.InitDefaultableModule(module)
 	module.AddProperties(&module.properties)
+	module.initModuleAndImport(module)
 	return module
 }
 
 type JavaApiImportInfo struct {
-	ApiFile android.Path
+	ApiFile    android.Path
+	ApiSurface string
 }
 
-var JavaApiImportProvider = blueprint.NewProvider(JavaApiImportInfo{})
+var JavaApiImportProvider = blueprint.NewProvider[JavaApiImportInfo]()
 
 func (ap *JavaApiContribution) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	var apiFile android.Path = nil
@@ -1632,8 +1884,9 @@
 		apiFile = android.PathForModuleSrc(ctx, String(apiFileString))
 	}
 
-	ctx.SetProvider(JavaApiImportProvider, JavaApiImportInfo{
-		ApiFile: apiFile,
+	android.SetProvider(ctx, JavaApiImportProvider, JavaApiImportInfo{
+		ApiFile:    apiFile,
+		ApiSurface: proptools.String(ap.properties.Api_surface),
 	})
 }
 
@@ -1643,6 +1896,7 @@
 
 	hiddenAPI
 	dexer
+	embeddableInModuleAndImport
 
 	properties JavaApiLibraryProperties
 
@@ -1652,6 +1906,12 @@
 	extractedSrcJar           android.WritablePath
 	// .dex of stubs, used for hiddenapi processing
 	dexJarFile OptionalDexJarPath
+
+	validationPaths android.Paths
+
+	stubsType StubsType
+
+	aconfigProtoFiles android.Paths
 }
 
 type JavaApiLibraryProperties struct {
@@ -1662,11 +1922,6 @@
 	// This is a list of Soong modules
 	Api_contributions []string
 
-	// list of api.txt files relative to this directory that contribute to the
-	// API surface.
-	// This is a list of relative paths
-	Api_files []string `android:"path"`
-
 	// List of flags to be passed to the javac compiler to generate jar file
 	Javacflags []string
 
@@ -1683,12 +1938,42 @@
 	// extracting the compiled class files provided by the
 	// full_api_surface_stub module.
 	Full_api_surface_stub *string
+
+	// Version of previously released API file for compatibility check.
+	Previous_api *string `android:"path"`
+
+	// java_system_modules module providing the jar to be added to the
+	// bootclasspath when compiling the stubs.
+	// The jar will also be passed to metalava as a classpath to
+	// generate compilable stubs.
+	System_modules *string
+
+	// If true, the module runs validation on the API signature files provided
+	// by the modules passed via api_contributions by checking if the files are
+	// in sync with the source Java files. However, the environment variable
+	// DISABLE_STUB_VALIDATION has precedence over this property.
+	Enable_validation *bool
+
+	// Type of stubs the module should generate. Must be one of "everything", "runtime" or
+	// "exportable". Defaults to "everything".
+	// - "everything" stubs include all non-flagged apis and flagged apis, regardless of the state
+	// of the flag.
+	// - "runtime" stubs include all non-flagged apis and flagged apis that are ENABLED or
+	// READ_WRITE, and all other flagged apis are stripped.
+	// - "exportable" stubs include all non-flagged apis and flagged apis that are ENABLED and
+	// READ_ONLY, and all other flagged apis are stripped.
+	Stubs_type *string
+
+	// List of aconfig_declarations module names that the stubs generated in this module
+	// depend on.
+	Aconfig_declarations []string
 }
 
 func ApiLibraryFactory() android.Module {
 	module := &ApiLibrary{}
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	module.AddProperties(&module.properties)
+	module.initModuleAndImport(module)
 	android.InitDefaultableModule(module)
 	return module
 }
@@ -1702,7 +1987,8 @@
 }
 
 func metalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder,
-	srcs android.Paths, homeDir android.WritablePath) *android.RuleBuilderCommand {
+	srcs android.Paths, homeDir android.WritablePath,
+	classpath android.Paths) *android.RuleBuilderCommand {
 	rule.Command().Text("rm -rf").Flag(homeDir.String())
 	rule.Command().Text("mkdir -p").Flag(homeDir.String())
 
@@ -1730,7 +2016,6 @@
 
 	cmd.Flag("--color").
 		Flag("--quiet").
-		Flag("--format=v2").
 		Flag("--include-annotations").
 		// The flag makes nullability issues as warnings rather than errors by replacing
 		// @Nullable/@NonNull in the listed packages APIs with @RecentlyNullable/@RecentlyNonNull,
@@ -1742,13 +2027,17 @@
 		FlagWithArg("--hide ", "InvalidNullabilityOverride").
 		FlagWithArg("--hide ", "ChangedDefault")
 
-	// Force metalava to ignore classes on the classpath when an API file contains missing classes.
-	// See b/285140653 for more information.
-	cmd.FlagWithArg("--api-class-resolution ", "api")
-
-	// Force metalava to sort overloaded methods by their order in the source code.
-	// See b/285312164 for more information.
-	cmd.FlagWithArg("--api-overloaded-method-order ", "source")
+	if len(classpath) == 0 {
+		// The main purpose of the `--api-class-resolution api` option is to force metalava to ignore
+		// classes on the classpath when an API file contains missing classes. However, as this command
+		// does not specify `--classpath` this is not needed for that. However, this is also used as a
+		// signal to the special metalava code for generating stubs from text files that it needs to add
+		// some additional items into the API (e.g. default constructors).
+		cmd.FlagWithArg("--api-class-resolution ", "api")
+	} else {
+		cmd.FlagWithArg("--api-class-resolution ", "api:classpath")
+		cmd.FlagWithInputList("--classpath ", classpath, ":")
+	}
 
 	return cmd
 }
@@ -1767,6 +2056,12 @@
 	}
 }
 
+func (al *ApiLibrary) addValidation(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, validationPaths android.Paths) {
+	for _, validationPath := range validationPaths {
+		cmd.Validation(validationPath)
+	}
+}
+
 // This method extracts the stub class files from the stub jar file provided
 // from full_api_surface_stub module instead of compiling the srcjar generated from invoking metalava.
 // This method is used because metalava can generate compilable from-text stubs only when
@@ -1795,6 +2090,7 @@
 		Flag("-jar").
 		Flag("-write_if_changed").
 		Flag("-ignore_missing_files").
+		Flag("-quiet").
 		FlagWithArg("-C ", unzippedSrcJarDir.String()).
 		FlagWithInput("-l ", classFilesList).
 		FlagWithOutput("-o ", al.stubsJarWithoutStaticLibs)
@@ -1802,39 +2098,78 @@
 
 func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
 	apiContributions := al.properties.Api_contributions
+	addValidations := !ctx.Config().IsEnvTrue("DISABLE_STUB_VALIDATION") &&
+		!ctx.Config().IsEnvTrue("WITHOUT_CHECK_API") &&
+		proptools.BoolDefault(al.properties.Enable_validation, true)
 	for _, apiContributionName := range apiContributions {
 		ctx.AddDependency(ctx.Module(), javaApiContributionTag, apiContributionName)
+
+		// Add the java_api_contribution module generating droidstubs module
+		// as dependency when validation adding conditions are met and
+		// the java_api_contribution module name has ".api.contribution" suffix.
+		// All droidstubs-generated modules possess the suffix in the name,
+		// but there is no such guarantee for tests.
+		if addValidations {
+			if strings.HasSuffix(apiContributionName, ".api.contribution") {
+				ctx.AddDependency(ctx.Module(), metalavaCurrentApiTimestampTag, strings.TrimSuffix(apiContributionName, ".api.contribution"))
+			} else {
+				ctx.ModuleErrorf("Validation is enabled for module %s but a "+
+					"current timestamp provider is not found for the api "+
+					"contribution %s",
+					ctx.ModuleName(),
+					apiContributionName,
+				)
+			}
+		}
 	}
 	ctx.AddVariationDependencies(nil, libTag, al.properties.Libs...)
 	ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs...)
 	if al.properties.Full_api_surface_stub != nil {
 		ctx.AddVariationDependencies(nil, depApiSrcsTag, String(al.properties.Full_api_surface_stub))
 	}
+	if al.properties.System_modules != nil {
+		ctx.AddVariationDependencies(nil, systemModulesTag, String(al.properties.System_modules))
+	}
+	for _, aconfigDeclarationsName := range al.properties.Aconfig_declarations {
+		ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfigDeclarationsName)
+	}
 }
 
-// API signature file names sorted from
-// the narrowest api scope to the widest api scope
-var scopeOrderedSourceFileNames = allApiScopes.Strings(
-	func(s *apiScope) string { return s.apiFilePrefix + "current.txt" })
+// Map where key is the api scope name and value is the int value
+// representing the order of the api scope, narrowest to the widest
+var scopeOrderMap = allApiScopes.MapToIndex(
+	func(s *apiScope) string { return s.name })
 
-func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFiles android.Paths) android.Paths {
-	sortedSrcFiles := android.Paths{}
-
-	for _, scopeSourceFileName := range scopeOrderedSourceFileNames {
-		for _, sourceFileName := range srcFiles {
-			if sourceFileName.Base() == scopeSourceFileName {
-				sortedSrcFiles = append(sortedSrcFiles, sourceFileName)
-			}
+func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFilesInfo []JavaApiImportInfo) []JavaApiImportInfo {
+	for _, srcFileInfo := range srcFilesInfo {
+		if srcFileInfo.ApiSurface == "" {
+			ctx.ModuleErrorf("Api surface not defined for the associated api file %s", srcFileInfo.ApiFile)
 		}
 	}
-	if len(srcFiles) != len(sortedSrcFiles) {
-		ctx.ModuleErrorf("Unrecognizable source file found within %s", srcFiles)
+	sort.Slice(srcFilesInfo, func(i, j int) bool {
+		return scopeOrderMap[srcFilesInfo[i].ApiSurface] < scopeOrderMap[srcFilesInfo[j].ApiSurface]
+	})
+
+	return srcFilesInfo
+}
+
+var validstubsType = []StubsType{Everything, Runtime, Exportable}
+
+func (al *ApiLibrary) validateProperties(ctx android.ModuleContext) {
+	if al.properties.Stubs_type == nil {
+		ctx.ModuleErrorf("java_api_library module type must specify stubs_type property.")
+	} else {
+		al.stubsType = StringToStubsType(proptools.String(al.properties.Stubs_type))
 	}
 
-	return sortedSrcFiles
+	if !android.InList(al.stubsType, validstubsType) {
+		ctx.PropertyErrorf("stubs_type", "%s is not a valid stubs_type property value. "+
+			"Must be one of %s.", proptools.String(al.properties.Stubs_type), validstubsType)
+	}
 }
 
 func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	al.validateProperties(ctx)
 
 	rule := android.NewRuleBuilder(pctx, ctx)
 
@@ -1842,54 +2177,81 @@
 		android.PathForModuleOut(ctx, "metalava.sbox.textproto")).
 		SandboxInputs()
 
-	var stubsDir android.OptionalPath
-	stubsDir = android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
+	stubsDir := android.OptionalPathForPath(android.PathForModuleOut(ctx, "metalava", "stubsDir"))
 	rule.Command().Text("rm -rf").Text(stubsDir.String())
 	rule.Command().Text("mkdir -p").Text(stubsDir.String())
 
 	homeDir := android.PathForModuleOut(ctx, "metalava", "home")
 
-	var srcFiles android.Paths
+	var srcFilesInfo []JavaApiImportInfo
 	var classPaths android.Paths
 	var staticLibs android.Paths
 	var depApiSrcsStubsJar android.Path
+	var systemModulesPaths android.Paths
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		tag := ctx.OtherModuleDependencyTag(dep)
 		switch tag {
 		case javaApiContributionTag:
-			provider := ctx.OtherModuleProvider(dep, JavaApiImportProvider).(JavaApiImportInfo)
-			providerApiFile := provider.ApiFile
-			if providerApiFile == nil && !ctx.Config().AllowMissingDependencies() {
+			provider, _ := android.OtherModuleProvider(ctx, dep, JavaApiImportProvider)
+			if provider.ApiFile == nil && !ctx.Config().AllowMissingDependencies() {
 				ctx.ModuleErrorf("Error: %s has an empty api file.", dep.Name())
 			}
-			srcFiles = append(srcFiles, android.PathForSource(ctx, providerApiFile.String()))
+			srcFilesInfo = append(srcFilesInfo, provider)
 		case libTag:
-			provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+			provider, _ := android.OtherModuleProvider(ctx, dep, JavaInfoProvider)
 			classPaths = append(classPaths, provider.HeaderJars...)
 		case staticLibTag:
-			provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+			provider, _ := android.OtherModuleProvider(ctx, dep, JavaInfoProvider)
 			staticLibs = append(staticLibs, provider.HeaderJars...)
 		case depApiSrcsTag:
-			provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+			provider, _ := android.OtherModuleProvider(ctx, dep, JavaInfoProvider)
 			depApiSrcsStubsJar = provider.HeaderJars[0]
+		case systemModulesTag:
+			module := dep.(SystemModulesProvider)
+			systemModulesPaths = append(systemModulesPaths, module.HeaderJars()...)
+		case metalavaCurrentApiTimestampTag:
+			if currentApiTimestampProvider, ok := dep.(currentApiTimestampProvider); ok {
+				al.validationPaths = append(al.validationPaths, currentApiTimestampProvider.CurrentApiTimestamp())
+			}
+		case aconfigDeclarationTag:
+			if provider, ok := android.OtherModuleProvider(ctx, dep, android.AconfigDeclarationsProviderKey); ok {
+				al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.IntermediateCacheOutputPath)
+			} else if provider, ok := android.OtherModuleProvider(ctx, dep, android.CodegenInfoProvider); ok {
+				al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.IntermediateCacheOutputPaths...)
+			} else {
+				ctx.ModuleErrorf("Only aconfig_declarations and aconfig_declarations_group "+
+					"module type is allowed for flags_packages property, but %s is neither "+
+					"of these supported module types",
+					dep.Name(),
+				)
+			}
 		}
 	})
 
-	// Add the api_files inputs
-	for _, api := range al.properties.Api_files {
-		srcFiles = append(srcFiles, android.PathForModuleSrc(ctx, api))
+	srcFilesInfo = al.sortApiFilesByApiScope(ctx, srcFilesInfo)
+	var srcFiles android.Paths
+	for _, srcFileInfo := range srcFilesInfo {
+		srcFiles = append(srcFiles, android.PathForSource(ctx, srcFileInfo.ApiFile.String()))
 	}
 
 	if srcFiles == nil && !ctx.Config().AllowMissingDependencies() {
 		ctx.ModuleErrorf("Error: %s has an empty api file.", ctx.ModuleName())
 	}
 
-	srcFiles = al.sortApiFilesByApiScope(ctx, srcFiles)
-
-	cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir)
+	cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir, systemModulesPaths)
 
 	al.stubsFlags(ctx, cmd, stubsDir)
 
+	migratingNullability := String(al.properties.Previous_api) != ""
+	if migratingNullability {
+		previousApi := android.PathForModuleSrc(ctx, String(al.properties.Previous_api))
+		cmd.FlagWithInput("--migrate-nullness ", previousApi)
+	}
+
+	al.addValidation(ctx, cmd, al.validationPaths)
+
+	generateRevertAnnotationArgs(ctx, cmd, al.stubsType, al.aconfigProtoFiles)
+
 	al.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
 	al.stubsJarWithoutStaticLibs = android.PathForModuleOut(ctx, "metalava", "stubs.jar")
 	al.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName(), fmt.Sprintf("%s.jar", ctx.ModuleName()))
@@ -1905,13 +2267,14 @@
 		FlagWithArg("-C ", stubsDir.String()).
 		FlagWithArg("-D ", stubsDir.String())
 
-	rule.Build("metalava", "metalava merged")
+	rule.Build("metalava", "metalava merged text")
 
 	if depApiSrcsStubsJar == nil {
 		var flags javaBuilderFlags
 		flags.javaVersion = getStubsJavaVersion()
 		flags.javacFlags = strings.Join(al.properties.Javacflags, " ")
 		flags.classpath = classpath(classPaths)
+		flags.bootClasspath = classpath(systemModulesPaths)
 
 		annoSrcJar := android.PathForModuleOut(ctx, ctx.ModuleName(), "anno.srcjar")
 
@@ -1943,16 +2306,17 @@
 
 	ctx.Phony(ctx.ModuleName(), al.stubsJar)
 
-	ctx.SetProvider(JavaInfoProvider, JavaInfo{
+	android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
 		HeaderJars:                     android.PathsIfNonNil(al.stubsJar),
 		ImplementationAndResourcesJars: android.PathsIfNonNil(al.stubsJar),
 		ImplementationJars:             android.PathsIfNonNil(al.stubsJar),
 		AidlIncludeDirs:                android.Paths{},
+		StubsLinkType:                  Stubs,
 		// No aconfig libraries on api libraries
 	})
 }
 
-func (al *ApiLibrary) DexJarBuildPath() OptionalDexJarPath {
+func (al *ApiLibrary) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
 	return al.dexJarFile
 }
 
@@ -2005,6 +2369,9 @@
 	// List of shared java libs that this module has dependencies to
 	Libs []string
 
+	// List of static java libs that this module has dependencies to
+	Static_libs []string
+
 	// List of files to remove from the jar file(s)
 	Exclude_files []string
 
@@ -2022,13 +2389,25 @@
 		// that depend on this module, as well as to aidl for this module.
 		Export_include_dirs []string
 	}
+
+	// Name of the source soong module that gets shadowed by this prebuilt
+	// If unspecified, follows the naming convention that the source module of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_module_name *string
+
+	// Non-nil if this java_import module was dynamically created by a java_sdk_library_import
+	// The name is the undecorated name of the java_sdk_library as it appears in the blueprint file
+	// (without any prebuilt_ prefix)
+	Created_by_java_sdk_library_name *string `blueprint:"mutated"`
+
+	// Property signifying whether the module provides stubs jar or not.
+	Is_stubs_module *bool
 }
 
 type Import struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
 	android.ApexModuleBase
-	android.BazelModuleBase
 	prebuilt android.Prebuilt
 
 	// Functionality common to Module and Import.
@@ -2042,16 +2421,20 @@
 
 	// output file containing classes.dex and resources
 	dexJarFile        OptionalDexJarPath
+	dexJarFileErr     error
 	dexJarInstallFile android.Path
 
-	combinedClasspathFile android.Path
-	classLoaderContexts   dexpreopt.ClassLoaderContextMap
-	exportAidlIncludeDirs android.Paths
+	combinedImplementationFile android.Path
+	combinedHeaderFile         android.Path
+	classLoaderContexts        dexpreopt.ClassLoaderContextMap
+	exportAidlIncludeDirs      android.Paths
 
 	hideApexVariantFromMake bool
 
 	sdkVersion    android.SdkSpec
 	minSdkVersion android.ApiLevel
+
+	stubsLinkType StubsLinkType
 }
 
 var _ PermittedPackagesForUpdatableBootJars = (*Import)(nil)
@@ -2095,12 +2478,20 @@
 	return j.properties.Jars
 }
 
+func (j *Import) BaseModuleName() string {
+	return proptools.StringDefault(j.properties.Source_module_name, j.ModuleBase.Name())
+}
+
 func (j *Import) Name() string {
 	return j.prebuilt.Name(j.ModuleBase.Name())
 }
 
 func (j *Import) Stem() string {
-	return proptools.StringDefault(j.properties.Stem, j.ModuleBase.Name())
+	return proptools.StringDefault(j.properties.Stem, j.BaseModuleName())
+}
+
+func (j *Import) CreatedByJavaSdkLibraryName() *string {
+	return j.properties.Created_by_java_sdk_library_name
 }
 
 func (a *Import) JacocoReportClassesFile() android.Path {
@@ -2120,6 +2511,7 @@
 
 func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
 	ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
+	ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...)
 
 	if ctx.Device() && Bool(j.dexProperties.Compile_dex) {
 		sdkDeps(ctx, android.SdkContext(j), j.dexer)
@@ -2127,49 +2519,46 @@
 }
 
 func (j *Import) commonBuildActions(ctx android.ModuleContext) {
-	//TODO(b/231322772) these should come from Bazel once available
 	j.sdkVersion = j.SdkVersion(ctx)
 	j.minSdkVersion = j.MinSdkVersion(ctx)
 
-	if !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() {
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+	if !apexInfo.IsForPlatform() {
 		j.hideApexVariantFromMake = true
 	}
 
 	if ctx.Windows() {
 		j.HideFromMake()
 	}
+
+	if proptools.Bool(j.properties.Is_stubs_module) {
+		j.stubsLinkType = Stubs
+	} else {
+		j.stubsLinkType = Implementation
+	}
 }
 
 func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.commonBuildActions(ctx)
 
-	jars := android.PathsForModuleSrc(ctx, j.properties.Jars)
-
-	jarName := j.Stem() + ".jar"
-	outputFile := android.PathForModuleOut(ctx, "combined", jarName)
-	TransformJarsToJar(ctx, outputFile, "for prebuilts", jars, android.OptionalPath{},
-		false, j.properties.Exclude_files, j.properties.Exclude_dirs)
-	if Bool(j.properties.Jetifier) {
-		inputFile := outputFile
-		outputFile = android.PathForModuleOut(ctx, "jetifier", jarName)
-		TransformJetifier(ctx, outputFile, inputFile)
-	}
-	j.combinedClasspathFile = outputFile
 	j.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap)
 
 	var flags javaBuilderFlags
 
 	j.collectTransitiveHeaderJars(ctx)
+	var staticJars android.Paths
+	var staticHeaderJars android.Paths
 	ctx.VisitDirectDeps(func(module android.Module) {
 		tag := ctx.OtherModuleDependencyTag(module)
-		if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
-			dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+		if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok {
 			switch tag {
 			case libTag, sdkLibTag:
 				flags.classpath = append(flags.classpath, dep.HeaderJars...)
 				flags.dexClasspath = append(flags.dexClasspath, dep.HeaderJars...)
 			case staticLibTag:
 				flags.classpath = append(flags.classpath, dep.HeaderJars...)
+				staticJars = append(staticJars, dep.ImplementationAndResourcesJars...)
+				staticHeaderJars = append(staticHeaderJars, dep.HeaderJars...)
 			case bootClasspathTag:
 				flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars...)
 			}
@@ -2183,6 +2572,50 @@
 		addCLCFromDep(ctx, module, j.classLoaderContexts)
 	})
 
+	jars := android.PathsForModuleSrc(ctx, j.properties.Jars)
+	jarName := j.Stem() + ".jar"
+
+	// Always pass the input jars to TransformJarsToJar, even if there is only a single jar, we need the output
+	// file of the module to be named jarName.
+	outputFile := android.PathForModuleOut(ctx, "combined", jarName)
+	implementationJars := append(slices.Clone(jars), staticJars...)
+	TransformJarsToJar(ctx, outputFile, "combine prebuilt implementation jars", implementationJars, android.OptionalPath{},
+		false, j.properties.Exclude_files, j.properties.Exclude_dirs)
+
+	// If no dependencies have separate header jars then there is no need to create a separate
+	// header jar for this module.
+	reuseImplementationJarAsHeaderJar := slices.Equal(staticJars, staticHeaderJars)
+
+	var headerOutputFile android.ModuleOutPath
+	if reuseImplementationJarAsHeaderJar {
+		headerOutputFile = outputFile
+	} else {
+		headerJars := append(slices.Clone(jars), staticHeaderJars...)
+		headerOutputFile = android.PathForModuleOut(ctx, "turbine-combined", jarName)
+		TransformJarsToJar(ctx, headerOutputFile, "combine prebuilt header jars", headerJars, android.OptionalPath{},
+			false, j.properties.Exclude_files, j.properties.Exclude_dirs)
+	}
+
+	if Bool(j.properties.Jetifier) {
+		inputFile := outputFile
+		outputFile = android.PathForModuleOut(ctx, "jetifier", jarName)
+		TransformJetifier(ctx, outputFile, inputFile)
+
+		if !reuseImplementationJarAsHeaderJar {
+			headerInputFile := headerOutputFile
+			headerOutputFile = android.PathForModuleOut(ctx, "jetifier-headers", jarName)
+			TransformJetifier(ctx, headerOutputFile, headerInputFile)
+		} else {
+			headerOutputFile = outputFile
+		}
+	}
+
+	// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource.
+	// Also strip the relative path from the header output file so that the reuseImplementationJarAsHeaderJar check
+	// in a module that depends on this module considers them equal.
+	j.combinedHeaderFile = headerOutputFile.WithoutRel()
+	j.combinedImplementationFile = outputFile.WithoutRel()
+
 	j.maybeInstall(ctx, jarName, outputFile)
 
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
@@ -2190,21 +2623,25 @@
 	if ctx.Device() {
 		// If this is a variant created for a prebuilt_apex then use the dex implementation jar
 		// obtained from the associated deapexer module.
-		ai := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+		ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 		if ai.ForPrebuiltApex {
 			// Get the path of the dex implementation jar from the `deapexer` module.
-			di := android.FindDeapexerProviderForModule(ctx)
-			if di == nil {
-				return // An error has been reported by FindDeapexerProviderForModule.
+			di, err := android.FindDeapexerProviderForModule(ctx)
+			if err != nil {
+				// An error was found, possibly due to multiple apexes in the tree that export this library
+				// Defer the error till a client tries to call DexJarBuildPath
+				j.dexJarFileErr = err
+				j.initHiddenAPIError(err)
+				return
 			}
-			dexJarFileApexRootRelative := apexRootRelativePathToJavaLib(j.BaseModuleName())
+			dexJarFileApexRootRelative := ApexRootRelativePathToJavaLib(j.BaseModuleName())
 			if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
 				dexJarFile := makeDexJarPathFromPath(dexOutputPath)
 				j.dexJarFile = dexJarFile
-				installPath := android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(j.BaseModuleName()))
+				installPath := android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, ApexRootRelativePathToJavaLib(j.BaseModuleName()))
 				j.dexJarInstallFile = installPath
 
-				j.dexpreopter.installPath = j.dexpreopter.getInstallPath(ctx, installPath)
+				j.dexpreopter.installPath = j.dexpreopter.getInstallPath(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), installPath)
 				setUncompressDex(ctx, &j.dexpreopter, &j.dexer)
 				j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
 
@@ -2212,8 +2649,6 @@
 					j.dexpreopter.inputProfilePathOnHost = profilePath
 				}
 
-				j.dexpreopt(ctx, dexOutputPath)
-
 				// Initialize the hiddenapi structure.
 				j.initHiddenAPI(ctx, dexJarFile, outputFile, j.dexProperties.Uncompress_dex)
 			} else {
@@ -2234,7 +2669,7 @@
 			// Dex compilation
 
 			j.dexpreopter.installPath = j.dexpreopter.getInstallPath(
-				ctx, android.PathForModuleInstall(ctx, "framework", jarName))
+				ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), android.PathForModuleInstall(ctx, "framework", jarName))
 			setUncompressDex(ctx, &j.dexpreopter, &j.dexer)
 			j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
 
@@ -2263,13 +2698,14 @@
 		}
 	}
 
-	ctx.SetProvider(JavaInfoProvider, JavaInfo{
-		HeaderJars:                     android.PathsIfNonNil(j.combinedClasspathFile),
+	android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
+		HeaderJars:                     android.PathsIfNonNil(j.combinedHeaderFile),
 		TransitiveLibsHeaderJars:       j.transitiveLibsHeaderJars,
 		TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
-		ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedClasspathFile),
-		ImplementationJars:             android.PathsIfNonNil(j.combinedClasspathFile),
+		ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedImplementationFile),
+		ImplementationJars:             android.PathsIfNonNil(j.combinedImplementationFile),
 		AidlIncludeDirs:                j.exportAidlIncludeDirs,
+		StubsLinkType:                  j.stubsLinkType,
 		// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
 	})
 }
@@ -2295,7 +2731,7 @@
 func (j *Import) OutputFiles(tag string) (android.Paths, error) {
 	switch tag {
 	case "", ".jar":
-		return android.Paths{j.combinedClasspathFile}, nil
+		return android.Paths{j.combinedImplementationFile}, nil
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
@@ -2304,20 +2740,17 @@
 var _ android.OutputFileProducer = (*Import)(nil)
 
 func (j *Import) HeaderJars() android.Paths {
-	if j.combinedClasspathFile == nil {
-		return nil
-	}
-	return android.Paths{j.combinedClasspathFile}
+	return android.PathsIfNonNil(j.combinedHeaderFile)
 }
 
 func (j *Import) ImplementationAndResourcesJars() android.Paths {
-	if j.combinedClasspathFile == nil {
-		return nil
-	}
-	return android.Paths{j.combinedClasspathFile}
+	return android.PathsIfNonNil(j.combinedImplementationFile)
 }
 
-func (j *Import) DexJarBuildPath() OptionalDexJarPath {
+func (j *Import) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
+	if j.dexJarFileErr != nil {
+		ctx.ModuleErrorf(j.dexJarFileErr.Error())
+	}
 	return j.dexJarFile
 }
 
@@ -2358,7 +2791,7 @@
 // java_sdk_library_import with the specified base module name requires to be exported from a
 // prebuilt_apex/apex_set.
 func requiredFilesFromPrebuiltApexForImport(name string, d *dexpreopter) []string {
-	dexJarFileApexRootRelative := apexRootRelativePathToJavaLib(name)
+	dexJarFileApexRootRelative := ApexRootRelativePathToJavaLib(name)
 	// Add the dex implementation jar to the set of exported files.
 	files := []string{
 		dexJarFileApexRootRelative,
@@ -2369,9 +2802,9 @@
 	return files
 }
 
-// apexRootRelativePathToJavaLib returns the path, relative to the root of the apex's contents, for
+// ApexRootRelativePathToJavaLib returns the path, relative to the root of the apex's contents, for
 // the java library with the specified name.
-func apexRootRelativePathToJavaLib(name string) string {
+func ApexRootRelativePathToJavaLib(name string) string {
 	return filepath.Join("javalib", name+".jar")
 }
 
@@ -2382,6 +2815,10 @@
 	return requiredFilesFromPrebuiltApexForImport(name, &j.dexpreopter)
 }
 
+func (j *Import) UseProfileGuidedDexpreopt() bool {
+	return proptools.Bool(j.importDexpreoptProperties.Dex_preopt.Profile_guided)
+}
+
 // Add compile time check for interface implementation
 var _ android.IDEInfo = (*Import)(nil)
 var _ android.IDECustomizedModuleName = (*Import)(nil)
@@ -2429,7 +2866,6 @@
 
 	android.InitPrebuiltModule(module, &module.properties.Jars)
 	android.InitApexModule(module)
-	android.InitBazelModule(module)
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
 }
@@ -2446,7 +2882,6 @@
 
 	android.InitPrebuiltModule(module, &module.properties.Jars)
 	android.InitApexModule(module)
-	android.InitBazelModule(module)
 	InitJavaModule(module, android.HostSupported)
 	return module
 }
@@ -2515,14 +2950,14 @@
 		ctx.PropertyErrorf("jars", "exactly one jar must be provided")
 	}
 
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	if !apexInfo.IsForPlatform() {
 		j.hideApexVariantFromMake = true
 	}
 
 	j.dexpreopter.installPath = j.dexpreopter.getInstallPath(
-		ctx, android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar"))
-	j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
+		ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar"))
+	j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), &j.dexpreopter)
 
 	inputJar := ctx.ExpandSource(j.properties.Jars[0], "jars")
 	dexOutputFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".jar")
@@ -2561,7 +2996,7 @@
 
 	j.dexJarFile = makeDexJarPathFromPath(dexOutputFile)
 
-	j.dexpreopt(ctx, dexOutputFile)
+	j.dexpreopt(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), dexOutputFile)
 
 	if apexInfo.IsForPlatform() {
 		ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
@@ -2569,7 +3004,7 @@
 	}
 }
 
-func (j *DexImport) DexJarBuildPath() OptionalDexJarPath {
+func (j *DexImport) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
 	return j.dexJarFile
 }
 
@@ -2641,7 +3076,7 @@
 	module.AddProperties(
 		&CommonProperties{},
 		&DeviceProperties{},
-		&OverridableDeviceProperties{},
+		&OverridableProperties{},
 		&DexProperties{},
 		&DexpreoptProperties{},
 		&android.ProtoProperties{},
@@ -2662,6 +3097,8 @@
 		&LintProperties{},
 		&appTestHelperAppProperties{},
 		&JavaApiLibraryProperties{},
+		&bootclasspathFragmentProperties{},
+		&SourceOnlyBootclasspathProperties{},
 	)
 
 	android.InitDefaultsModule(module)
@@ -2736,632 +3173,80 @@
 	// <uses_library> and should not be added to CLC, but the transitive <uses-library> dependencies
 	// from its CLC should be added to the current CLC.
 	if sdkLib != nil {
-		clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib, false,
-			dep.DexJarBuildPath().PathOrNil(), dep.DexJarInstallPath(), dep.ClassLoaderContexts())
+		optional := false
+		if module, ok := ctx.Module().(ModuleWithUsesLibrary); ok {
+			if android.InList(*sdkLib, module.UsesLibrary().usesLibraryProperties.Optional_uses_libs) {
+				optional = true
+			}
+		}
+		clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib, optional,
+			dep.DexJarBuildPath(ctx).PathOrNil(), dep.DexJarInstallPath(), dep.ClassLoaderContexts())
 	} else {
 		clcMap.AddContextMap(dep.ClassLoaderContexts(), depName)
 	}
 }
 
-type javaResourcesAttributes struct {
-	Resources             bazel.LabelListAttribute
-	Resource_strip_prefix *string
-}
+func addMissingOptionalUsesLibsFromDep(ctx android.ModuleContext, depModule android.Module,
+	usesLibrary *usesLibrary) {
 
-func (m *Library) javaResourcesGetSingleFilegroupStripPrefix(ctx android.TopDownMutatorContext) (string, bool) {
-	if otherM, ok := ctx.ModuleFromName(m.properties.Java_resources[0]); ok && len(m.properties.Java_resources) == 1 {
-		if fg, isFilegroup := otherM.(android.FileGroupPath); isFilegroup {
-			return filepath.Join(ctx.OtherModuleDir(otherM), fg.GetPath(ctx)), true
-		}
-	}
-	return "", false
-}
-
-func (m *Library) convertJavaResourcesAttributes(ctx android.TopDownMutatorContext) *javaResourcesAttributes {
-	var resources bazel.LabelList
-	var resourceStripPrefix *string
-
-	if m.properties.Java_resources != nil && len(m.properties.Java_resource_dirs) > 0 {
-		ctx.ModuleErrorf("bp2build doesn't support both java_resources and java_resource_dirs being set on the same module.")
-	}
-
-	if m.properties.Java_resources != nil {
-		if prefix, ok := m.javaResourcesGetSingleFilegroupStripPrefix(ctx); ok {
-			resourceStripPrefix = proptools.StringPtr(prefix)
-		} else {
-			resourceStripPrefix = proptools.StringPtr(ctx.ModuleDir())
-		}
-		resources.Append(android.BazelLabelForModuleSrc(ctx, m.properties.Java_resources))
-	}
-
-	//TODO(b/179889880) handle case where glob includes files outside package
-	resDeps := ResourceDirsToFiles(
-		ctx,
-		m.properties.Java_resource_dirs,
-		m.properties.Exclude_java_resource_dirs,
-		m.properties.Exclude_java_resources,
-	)
-
-	for i, resDep := range resDeps {
-		dir, files := resDep.dir, resDep.files
-
-		resources.Append(bazel.MakeLabelList(android.RootToModuleRelativePaths(ctx, files)))
-
-		// Bazel includes the relative path from the WORKSPACE root when placing the resource
-		// inside the JAR file, so we need to remove that prefix
-		resourceStripPrefix = proptools.StringPtr(dir.String())
-		if i > 0 {
-			// TODO(b/226423379) allow multiple resource prefixes
-			ctx.ModuleErrorf("bp2build does not support more than one directory in java_resource_dirs (b/226423379)")
-		}
-	}
-
-	return &javaResourcesAttributes{
-		Resources:             bazel.MakeLabelListAttribute(resources),
-		Resource_strip_prefix: resourceStripPrefix,
-	}
-}
-
-type javaCommonAttributes struct {
-	*javaResourcesAttributes
-	*kotlinAttributes
-	Srcs                    bazel.LabelListAttribute
-	Plugins                 bazel.LabelListAttribute
-	Javacopts               bazel.StringListAttribute
-	Sdk_version             bazel.StringAttribute
-	Java_version            bazel.StringAttribute
-	Errorprone_force_enable bazel.BoolAttribute
-}
-
-type javaDependencyLabels struct {
-	// Dependencies which DO NOT contribute to the API visible to upstream dependencies.
-	Deps bazel.LabelListAttribute
-	// Dependencies which DO contribute to the API visible to upstream dependencies.
-	StaticDeps bazel.LabelListAttribute
-}
-
-type eventLogTagsAttributes struct {
-	Srcs bazel.LabelListAttribute
-}
-
-type aidlLibraryAttributes struct {
-	Srcs bazel.LabelListAttribute
-	Tags bazel.StringListAttribute
-}
-
-type javaAidlLibraryAttributes struct {
-	Deps bazel.LabelListAttribute
-	Tags bazel.StringListAttribute
-}
-
-// bp2BuildJavaInfo has information needed for the conversion of  java*_modules
-// that is needed bor Bp2Build conversion but that requires different handling
-// depending on the module type.
-type bp2BuildJavaInfo struct {
-	// separates dependencies into dynamic dependencies and static dependencies.
-	DepLabels *javaDependencyLabels
-	hasKotlin bool
-}
-
-func javaXsdTargetName(xsd android.XsdConfigBp2buildTargets) string {
-	return xsd.JavaBp2buildTargetName()
-}
-
-// convertLibraryAttrsBp2Build returns a javaCommonAttributes struct with
-// converted attributes shared across java_* modules and a bp2BuildJavaInfo struct
-// which has other non-attribute information needed for bp2build conversion
-// that needs different handling depending on the module types, and thus needs
-// to be returned to the calling function.
-func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) (*javaCommonAttributes, *bp2BuildJavaInfo, bool) {
-	var srcs bazel.LabelListAttribute
-	var deps bazel.LabelListAttribute
-	var staticDeps bazel.LabelListAttribute
-
-	archVariantProps := m.GetArchVariantProperties(ctx, &CommonProperties{})
-	for axis, configToProps := range archVariantProps {
-		for config, _props := range configToProps {
-			if archProps, ok := _props.(*CommonProperties); ok {
-				archSrcs := android.BazelLabelForModuleSrcExcludes(ctx, archProps.Srcs, archProps.Exclude_srcs)
-				srcs.SetSelectValue(axis, config, archSrcs)
-				if archProps.Jarjar_rules != nil {
-					ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "jarjar_rules")
-					return &javaCommonAttributes{}, &bp2BuildJavaInfo{}, false
-				}
-			}
-		}
-	}
-	srcs.ResolveExcludes()
-
-	javaSrcPartition := "java"
-	protoSrcPartition := "proto"
-	xsdSrcPartition := "xsd"
-	logtagSrcPartition := "logtag"
-	aidlSrcPartition := "aidl"
-	kotlinPartition := "kotlin"
-	srcPartitions := bazel.PartitionLabelListAttribute(ctx, &srcs, bazel.LabelPartitions{
-		javaSrcPartition:   bazel.LabelPartition{Extensions: []string{".java"}, Keep_remainder: true},
-		logtagSrcPartition: bazel.LabelPartition{Extensions: []string{".logtags", ".logtag"}},
-		protoSrcPartition:  android.ProtoSrcLabelPartition,
-		aidlSrcPartition:   android.AidlSrcLabelPartition,
-		xsdSrcPartition:    bazel.LabelPartition{LabelMapper: android.XsdLabelMapper(javaXsdTargetName)},
-		kotlinPartition:    bazel.LabelPartition{Extensions: []string{".kt"}},
-	})
-
-	javaSrcs := srcPartitions[javaSrcPartition]
-	kotlinSrcs := srcPartitions[kotlinPartition]
-	javaSrcs.Append(kotlinSrcs)
-
-	staticDeps.Append(srcPartitions[xsdSrcPartition])
-
-	if !srcPartitions[logtagSrcPartition].IsEmpty() {
-		logtagsLibName := m.Name() + "_logtags"
-		ctx.CreateBazelTargetModule(
-			bazel.BazelTargetModuleProperties{
-				Rule_class:        "event_log_tags",
-				Bzl_load_location: "//build/bazel/rules/java:event_log_tags.bzl",
-			},
-			android.CommonAttributes{Name: logtagsLibName},
-			&eventLogTagsAttributes{
-				Srcs: srcPartitions[logtagSrcPartition],
-			},
-		)
-
-		logtagsSrcs := bazel.MakeLabelList([]bazel.Label{{Label: ":" + logtagsLibName}})
-		javaSrcs.Append(bazel.MakeLabelListAttribute(logtagsSrcs))
-	}
-
-	if !srcPartitions[aidlSrcPartition].IsEmpty() {
-		aidlLibs, aidlSrcs := srcPartitions[aidlSrcPartition].Partition(func(src bazel.Label) bool {
-			return android.IsConvertedToAidlLibrary(ctx, src.OriginalModuleName)
-		})
-
-		apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx, ctx.Module())
-
-		if !aidlSrcs.IsEmpty() {
-			aidlLibName := m.Name() + "_aidl_library"
-			ctx.CreateBazelTargetModule(
-				bazel.BazelTargetModuleProperties{
-					Rule_class:        "aidl_library",
-					Bzl_load_location: "//build/bazel/rules/aidl:aidl_library.bzl",
-				},
-				android.CommonAttributes{Name: aidlLibName},
-				&aidlLibraryAttributes{
-					Srcs: aidlSrcs,
-					Tags: apexAvailableTags,
-				},
-			)
-			aidlLibs.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + aidlLibName}})
-		}
-
-		javaAidlLibName := m.Name() + "_java_aidl_library"
-		ctx.CreateBazelTargetModule(
-			bazel.BazelTargetModuleProperties{
-				Rule_class:        "java_aidl_library",
-				Bzl_load_location: "//build/bazel/rules/java:java_aidl_library.bzl",
-			},
-			android.CommonAttributes{Name: javaAidlLibName},
-			&javaAidlLibraryAttributes{
-				Deps: aidlLibs,
-				Tags: apexAvailableTags,
-			},
-		)
-
-		staticDeps.Append(bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + javaAidlLibName}))
-	}
-
-	var javacopts bazel.StringListAttribute //[]string
-	plugins := bazel.MakeLabelListAttribute(
-		android.BazelLabelForModuleDeps(ctx, m.properties.Plugins),
-	)
-	if m.properties.Javacflags != nil {
-		javacopts = bazel.MakeStringListAttribute(m.properties.Javacflags)
-	}
-
-	epEnabled := m.properties.Errorprone.Enabled
-	epJavacflags := m.properties.Errorprone.Javacflags
-	var errorproneForceEnable bazel.BoolAttribute
-	if epEnabled == nil {
-		//TODO(b/227504307) add configuration that depends on RUN_ERROR_PRONE environment variable
-	} else if *epEnabled {
-		plugins.Append(bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, m.properties.Errorprone.Extra_check_modules)))
-		javacopts.Append(bazel.MakeStringListAttribute(epJavacflags))
-		errorproneForceEnable.Value = epEnabled
-	} else {
-		javacopts.Append(bazel.MakeStringListAttribute([]string{"-XepDisableAllChecks"}))
-	}
-
-	commonAttrs := &javaCommonAttributes{
-		Srcs:                    javaSrcs,
-		javaResourcesAttributes: m.convertJavaResourcesAttributes(ctx),
-		Plugins:                 plugins,
-		Javacopts:               javacopts,
-		Java_version:            bazel.StringAttribute{Value: m.properties.Java_version},
-		Sdk_version:             bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
-		Errorprone_force_enable: errorproneForceEnable,
-	}
-
-	for axis, configToProps := range archVariantProps {
-		for config, _props := range configToProps {
-			if archProps, ok := _props.(*CommonProperties); ok {
-				var libLabels []bazel.Label
-				for _, d := range archProps.Libs {
-					neverlinkLabel := android.BazelLabelForModuleDepSingle(ctx, d)
-					neverlinkLabel.Label = neverlinkLabel.Label + "-neverlink"
-					libLabels = append(libLabels, neverlinkLabel)
-				}
-				deps.SetSelectValue(axis, config, bazel.MakeLabelList(libLabels))
-			}
-		}
-	}
-
-	protoDepLabel := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition])
-	// Soong does not differentiate between a java_library and the Bazel equivalent of
-	// a java_proto_library + proto_library pair. Instead, in Soong proto sources are
-	// listed directly in the srcs of a java_library, and the classes produced
-	// by protoc are included directly in the resulting JAR. Thus upstream dependencies
-	// that depend on a java_library with proto sources can link directly to the protobuf API,
-	// and so this should be a static dependency.
-	if protoDepLabel != nil {
-		staticDeps.Append(bazel.MakeSingleLabelListAttribute(*protoDepLabel))
-	}
-
-	depLabels := &javaDependencyLabels{}
-	depLabels.Deps = deps
-
-	for axis, configToProps := range archVariantProps {
-		for config, _props := range configToProps {
-			if archProps, ok := _props.(*CommonProperties); ok {
-				archStaticLibs := android.BazelLabelForModuleDeps(
-					ctx,
-					android.LastUniqueStrings(android.CopyOf(archProps.Static_libs)))
-				depLabels.StaticDeps.SetSelectValue(axis, config, archStaticLibs)
-			}
-		}
-	}
-	depLabels.StaticDeps.Append(staticDeps)
-
-	hasKotlin := !kotlinSrcs.IsEmpty()
-	commonAttrs.kotlinAttributes = &kotlinAttributes{
-		Kotlincflags: &m.properties.Kotlincflags,
-	}
-	if len(m.properties.Common_srcs) != 0 {
-		hasKotlin = true
-		commonAttrs.kotlinAttributes.Common_srcs = bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Common_srcs))
-	}
-
-	bp2BuildInfo := &bp2BuildJavaInfo{
-		DepLabels: depLabels,
-		hasKotlin: hasKotlin,
-	}
-
-	return commonAttrs, bp2BuildInfo, true
-}
-
-type javaLibraryAttributes struct {
-	*javaCommonAttributes
-	Deps      bazel.LabelListAttribute
-	Exports   bazel.LabelListAttribute
-	Neverlink bazel.BoolAttribute
-}
-
-type kotlinAttributes struct {
-	Common_srcs  bazel.LabelListAttribute
-	Kotlincflags *[]string
-}
-
-func ktJvmLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties {
-	return bazel.BazelTargetModuleProperties{
-		Rule_class:        "kt_jvm_library",
-		Bzl_load_location: "//build/bazel/rules/kotlin:kt_jvm_library.bzl",
-	}
-}
-
-func javaLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties {
-	return bazel.BazelTargetModuleProperties{
-		Rule_class:        "java_library",
-		Bzl_load_location: "//build/bazel/rules/java:library.bzl",
-	}
-}
-
-func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) {
-	commonAttrs, bp2BuildInfo, supported := m.convertLibraryAttrsBp2Build(ctx)
-	if !supported {
-		return
-	}
-	depLabels := bp2BuildInfo.DepLabels
-
-	deps := depLabels.Deps
-	if !commonAttrs.Srcs.IsEmpty() {
-		deps.Append(depLabels.StaticDeps) // we should only append these if there are sources to use them
-	} else if !deps.IsEmpty() {
-		ctx.ModuleErrorf("Module has direct dependencies but no sources. Bazel will not allow this.")
-	}
-	var props bazel.BazelTargetModuleProperties
-	attrs := &javaLibraryAttributes{
-		javaCommonAttributes: commonAttrs,
-		Deps:                 deps,
-		Exports:              depLabels.StaticDeps,
-	}
-	name := m.Name()
-
-	if !bp2BuildInfo.hasKotlin {
-		props = javaLibraryBazelTargetModuleProperties()
-	} else {
-		props = ktJvmLibraryBazelTargetModuleProperties()
-	}
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, attrs)
-	neverlinkProp := true
-	neverLinkAttrs := &javaLibraryAttributes{
-		Exports:   bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}),
-		Neverlink: bazel.BoolAttribute{Value: &neverlinkProp},
-		javaCommonAttributes: &javaCommonAttributes{
-			Sdk_version:  bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
-			Java_version: bazel.StringAttribute{Value: m.properties.Java_version},
-		},
-	}
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name + "-neverlink"}, neverLinkAttrs)
-
-}
-
-type javaBinaryHostAttributes struct {
-	*javaCommonAttributes
-	Deps         bazel.LabelListAttribute
-	Runtime_deps bazel.LabelListAttribute
-	Main_class   string
-	Jvm_flags    bazel.StringListAttribute
-}
-
-// JavaBinaryHostBp2Build is for java_binary_host bp2build.
-func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) {
-	commonAttrs, bp2BuildInfo, supported := m.convertLibraryAttrsBp2Build(ctx)
-	if !supported {
-		return
-	}
-	depLabels := bp2BuildInfo.DepLabels
-
-	deps := depLabels.Deps
-	deps.Append(depLabels.StaticDeps)
-	if m.binaryProperties.Jni_libs != nil {
-		deps.Append(bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, m.binaryProperties.Jni_libs)))
-	}
-
-	var runtimeDeps bazel.LabelListAttribute
-	if commonAttrs.Srcs.IsEmpty() {
-		// if there are no sources, then the dependencies can only be used at runtime
-		runtimeDeps = deps
-		deps = bazel.LabelListAttribute{}
-	}
-
-	mainClass := ""
-	if m.binaryProperties.Main_class != nil {
-		mainClass = *m.binaryProperties.Main_class
-	}
-	if m.properties.Manifest != nil {
-		mainClassInManifest, err := android.GetMainClassInManifest(ctx.Config(), android.PathForModuleSrc(ctx, *m.properties.Manifest).String())
-		if err != nil {
-			return
-		}
-		mainClass = mainClassInManifest
-	}
-
-	// Attribute jvm_flags
-	var jvmFlags bazel.StringListAttribute
-	if m.binaryProperties.Jni_libs != nil {
-		jniLibPackages := []string{}
-		for _, jniLib := range m.binaryProperties.Jni_libs {
-			if jniLibModule, exists := ctx.ModuleFromName(jniLib); exists {
-				otherDir := ctx.OtherModuleDir(jniLibModule)
-				jniLibPackages = append(jniLibPackages, filepath.Join(otherDir, jniLib))
-			}
-		}
-		jniLibPaths := []string{}
-		for _, jniLibPackage := range jniLibPackages {
-			// See cs/f:.*/third_party/bazel/.*java_stub_template.txt for the use of RUNPATH
-			jniLibPaths = append(jniLibPaths, "$${RUNPATH}"+jniLibPackage)
-		}
-		jvmFlags = bazel.MakeStringListAttribute([]string{"-Djava.library.path=" + strings.Join(jniLibPaths, ":")})
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "java_binary",
-		Bzl_load_location: "@rules_java//java:defs.bzl",
-	}
-	binAttrs := &javaBinaryHostAttributes{
-		Runtime_deps: runtimeDeps,
-		Main_class:   mainClass,
-		Jvm_flags:    jvmFlags,
-	}
-
-	if commonAttrs.Srcs.IsEmpty() {
-		binAttrs.javaCommonAttributes = commonAttrs
-		ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, binAttrs)
+	dep, ok := depModule.(ModuleWithUsesLibrary)
+	if !ok {
 		return
 	}
 
-	libInfo := libraryCreationInfo{
-		deps:      deps,
-		attrs:     commonAttrs,
-		baseName:  m.Name(),
-		hasKotlin: bp2BuildInfo.hasKotlin,
-	}
-	libName := createLibraryTarget(ctx, libInfo)
-	binAttrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + libName}})
-
-	// Create the BazelTargetModule.
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, binAttrs)
-}
-
-type javaTestHostAttributes struct {
-	*javaCommonAttributes
-	Srcs         bazel.LabelListAttribute
-	Deps         bazel.LabelListAttribute
-	Runtime_deps bazel.LabelListAttribute
-}
-
-// javaTestHostBp2Build is for java_test_host bp2build.
-func javaTestHostBp2Build(ctx android.TopDownMutatorContext, m *TestHost) {
-	commonAttrs, bp2BuildInfo, supported := m.convertLibraryAttrsBp2Build(ctx)
-	if !supported {
-		return
-	}
-	depLabels := bp2BuildInfo.DepLabels
-
-	deps := depLabels.Deps
-	deps.Append(depLabels.StaticDeps)
-
-	var runtimeDeps bazel.LabelListAttribute
-	attrs := &javaTestHostAttributes{
-		Runtime_deps: runtimeDeps,
-	}
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "java_test",
-		Bzl_load_location: "//build/bazel/rules/java:test.bzl",
-	}
-
-	if commonAttrs.Srcs.IsEmpty() {
-		// if there are no sources, then the dependencies can only be used at runtime
-		attrs.Runtime_deps = deps
-		attrs.javaCommonAttributes = commonAttrs
-		ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
-		return
-	}
-
-	libInfo := libraryCreationInfo{
-		deps:      deps,
-		attrs:     commonAttrs,
-		baseName:  m.Name(),
-		hasKotlin: bp2BuildInfo.hasKotlin,
-	}
-	libName := createLibraryTarget(ctx, libInfo)
-
-	attrs.Srcs = commonAttrs.Srcs
-	attrs.Deps = deps
-	attrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + libName}})
-	// Create the BazelTargetModule.
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
-}
-
-// libraryCreationInfo encapsulates the info needed to create java_library target from
-// java_binary_host or java_test_host.
-type libraryCreationInfo struct {
-	deps      bazel.LabelListAttribute
-	attrs     *javaCommonAttributes
-	baseName  string
-	hasKotlin bool
-}
-
-// helper function that creates java_library target from java_binary_host or java_test_host,
-// and returns the library target name,
-func createLibraryTarget(ctx android.TopDownMutatorContext, libInfo libraryCreationInfo) string {
-	libName := libInfo.baseName + "_lib"
-	var libProps bazel.BazelTargetModuleProperties
-	if libInfo.hasKotlin {
-		libProps = ktJvmLibraryBazelTargetModuleProperties()
-	} else {
-		libProps = javaLibraryBazelTargetModuleProperties()
-	}
-	libAttrs := &javaLibraryAttributes{
-		Deps:                 libInfo.deps,
-		javaCommonAttributes: libInfo.attrs,
-	}
-
-	ctx.CreateBazelTargetModule(libProps, android.CommonAttributes{Name: libName}, libAttrs)
-	return libName
-}
-
-type bazelJavaImportAttributes struct {
-	Jars    bazel.LabelListAttribute
-	Exports bazel.LabelListAttribute
-}
-
-// java_import bp2Build converter.
-func (i *Import) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	var jars bazel.LabelListAttribute
-	archVariantProps := i.GetArchVariantProperties(ctx, &ImportProperties{})
-	for axis, configToProps := range archVariantProps {
-		for config, _props := range configToProps {
-			if archProps, ok := _props.(*ImportProperties); ok {
-				archJars := android.BazelLabelForModuleSrcExcludes(ctx, archProps.Jars, []string(nil))
-				jars.SetSelectValue(axis, config, archJars)
-			}
+	for _, lib := range dep.UsesLibrary().usesLibraryProperties.Missing_optional_uses_libs {
+		if !android.InList(lib, usesLibrary.usesLibraryProperties.Missing_optional_uses_libs) {
+			usesLibrary.usesLibraryProperties.Missing_optional_uses_libs =
+				append(usesLibrary.usesLibraryProperties.Missing_optional_uses_libs, lib)
 		}
 	}
-
-	attrs := &bazelJavaImportAttributes{
-		Jars: jars,
-	}
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "java_import",
-		Bzl_load_location: "//build/bazel/rules/java:import.bzl",
-	}
-
-	name := android.RemoveOptionalPrebuiltPrefix(i.Name())
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, attrs)
-
-	neverlink := true
-	neverlinkAttrs := &javaLibraryAttributes{
-		Neverlink: bazel.BoolAttribute{Value: &neverlink},
-		Exports:   bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + name}),
-		javaCommonAttributes: &javaCommonAttributes{
-			Sdk_version: bazel.StringAttribute{Value: proptools.StringPtr("none")},
-		},
-	}
-	ctx.CreateBazelTargetModule(
-		javaLibraryBazelTargetModuleProperties(),
-		android.CommonAttributes{Name: name + "-neverlink"},
-		neverlinkAttrs)
-
 }
 
-var _ android.MixedBuildBuildable = (*Import)(nil)
+type JavaApiContributionImport struct {
+	JavaApiContribution
 
-func (i *Import) getBazelModuleLabel(ctx android.BaseModuleContext) string {
-	return android.RemoveOptionalPrebuiltPrefixFromBazelLabel(i.GetBazelLabel(ctx, i))
+	prebuilt           android.Prebuilt
+	prebuiltProperties javaApiContributionImportProperties
 }
 
-func (i *Import) ProcessBazelQueryResponse(ctx android.ModuleContext) {
-	i.commonBuildActions(ctx)
+type javaApiContributionImportProperties struct {
+	// Name of the source soong module that gets shadowed by this prebuilt
+	// If unspecified, follows the naming convention that the source module of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_module_name *string
 
-	bazelCtx := ctx.Config().BazelContext
-	filePaths, err := bazelCtx.GetOutputFiles(i.getBazelModuleLabel(ctx), android.GetConfigKey(ctx))
-	if err != nil {
-		ctx.ModuleErrorf(err.Error())
-		return
-	}
-
-	bazelJars := android.Paths{}
-	for _, bazelOutputFile := range filePaths {
-		bazelJars = append(bazelJars, android.PathForBazelOut(ctx, bazelOutputFile))
-	}
-
-	jarName := android.RemoveOptionalPrebuiltPrefix(i.Name()) + ".jar"
-	outputFile := android.PathForModuleOut(ctx, "bazelCombined", jarName)
-	TransformJarsToJar(ctx, outputFile, "combine prebuilt jars", bazelJars,
-		android.OptionalPath{}, // manifest
-		false,                  // stripDirEntries
-		[]string{},             // filesToStrip
-		[]string{},             // dirsToStrip
-	)
-	i.combinedClasspathFile = outputFile
-
-	ctx.SetProvider(JavaInfoProvider, JavaInfo{
-		HeaderJars:                     android.PathsIfNonNil(i.combinedClasspathFile),
-		ImplementationAndResourcesJars: android.PathsIfNonNil(i.combinedClasspathFile),
-		ImplementationJars:             android.PathsIfNonNil(i.combinedClasspathFile),
-		// TODO(b/240308299) include AIDL information from Bazel
-		// TODO: aconfig files?
-	})
-
-	i.maybeInstall(ctx, jarName, outputFile)
+	// Non-nil if this java_import module was dynamically created by a java_sdk_library_import
+	// The name is the undecorated name of the java_sdk_library as it appears in the blueprint file
+	// (without any prebuilt_ prefix)
+	Created_by_java_sdk_library_name *string `blueprint:"mutated"`
 }
 
-func (i *Import) QueueBazelCall(ctx android.BaseModuleContext) {
-	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(i.getBazelModuleLabel(ctx), cquery.GetOutputFiles, android.GetConfigKey(ctx))
+func ApiContributionImportFactory() android.Module {
+	module := &JavaApiContributionImport{}
+	android.InitAndroidModule(module)
+	android.InitDefaultableModule(module)
+	android.InitPrebuiltModule(module, &[]string{""})
+	module.AddProperties(&module.properties, &module.prebuiltProperties)
+	module.AddProperties(&module.sdkLibraryComponentProperties)
+	return module
 }
 
-func (i *Import) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
-	return true
+func (module *JavaApiContributionImport) Prebuilt() *android.Prebuilt {
+	return &module.prebuilt
+}
+
+func (module *JavaApiContributionImport) Name() string {
+	return module.prebuilt.Name(module.ModuleBase.Name())
+}
+
+func (j *JavaApiContributionImport) BaseModuleName() string {
+	return proptools.StringDefault(j.prebuiltProperties.Source_module_name, j.ModuleBase.Name())
+}
+
+func (j *JavaApiContributionImport) CreatedByJavaSdkLibraryName() *string {
+	return j.prebuiltProperties.Created_by_java_sdk_library_name
+}
+
+func (ap *JavaApiContributionImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	ap.JavaApiContribution.GenerateAndroidBuildActions(ctx)
 }
diff --git a/java/java_test.go b/java/java_test.go
index 6110e21..a1192bb 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -24,8 +24,10 @@
 	"strings"
 	"testing"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
+	"android/soong/aconfig"
 	"android/soong/android"
 	"android/soong/cc"
 	"android/soong/dexpreopt"
@@ -47,10 +49,8 @@
 	cc.PrepareForTestWithCcBuildComponents,
 	// Include all the default java modules.
 	PrepareForTestWithDexpreopt,
-	PrepareForTestWithOverlayBuildComponents,
-	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
-		ctx.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory)
-	}),
+	// Include aconfig modules.
+	aconfig.PrepareForTestWithAconfigBuildComponents,
 )
 
 func TestMain(m *testing.M) {
@@ -529,6 +529,15 @@
 	}
 }
 
+// A minimal context object for use with DexJarBuildPath
+type moduleErrorfTestCtx struct {
+}
+
+func (ctx moduleErrorfTestCtx) ModuleErrorf(format string, args ...interface{}) {
+}
+
+var _ android.ModuleErrorfContext = (*moduleErrorfTestCtx)(nil)
+
 func TestPrebuilts(t *testing.T) {
 	ctx, _ := testJava(t, `
 		java_library {
@@ -579,10 +588,11 @@
 	javac := fooModule.Rule("javac")
 	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
 	barModule := ctx.ModuleForTests("bar", "android_common")
-	barJar := barModule.Rule("combineJar").Output
+	barJar := barModule.Output("combined/bar.jar").Output
 	bazModule := ctx.ModuleForTests("baz", "android_common")
 	bazJar := bazModule.Rule("combineJar").Output
-	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output
+	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").
+		Output("combined/sdklib.stubs.jar").Output
 
 	fooLibrary := fooModule.Module().(*Library)
 	assertDeepEquals(t, "foo unique sources incorrect",
@@ -596,7 +606,8 @@
 		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barJar.String())
 	}
 
-	barDexJar := barModule.Module().(*Import).DexJarBuildPath()
+	errCtx := moduleErrorfTestCtx{}
+	barDexJar := barModule.Module().(*Import).DexJarBuildPath(errCtx)
 	if barDexJar.IsSet() {
 		t.Errorf("bar dex jar build path expected to be set, got %s", barDexJar)
 	}
@@ -609,7 +620,7 @@
 		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, bazJar.String())
 	}
 
-	bazDexJar := bazModule.Module().(*Import).DexJarBuildPath().Path()
+	bazDexJar := bazModule.Module().(*Import).DexJarBuildPath(errCtx).Path()
 	expectedDexJar := "out/soong/.intermediates/baz/android_common/dex/baz.jar"
 	android.AssertPathRelativeToTopEquals(t, "baz dex jar build path", expectedDexJar, bazDexJar)
 
@@ -619,8 +630,6 @@
 	android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_library", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
 	entries = android.AndroidMkEntriesForTest(t, ctx, barModule.Module())[0]
 	android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_import", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
-	entries = android.AndroidMkEntriesForTest(t, ctx, ctx.ModuleForTests("sdklib", "android_common").Module())[0]
-	android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_sdk_library_import", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0])
 }
 
 func assertDeepEquals(t *testing.T, message string, expected interface{}, actual interface{}) {
@@ -1027,7 +1036,7 @@
 	}
 }
 
-func TestJavaLibrary(t *testing.T) {
+func TestJavaLibraryOutputFiles(t *testing.T) {
 	testJavaWithFS(t, "", map[string][]byte{
 		"libcore/Android.bp": []byte(`
 				java_library {
@@ -1044,7 +1053,7 @@
 	})
 }
 
-func TestJavaImport(t *testing.T) {
+func TestJavaImportOutputFiles(t *testing.T) {
 	testJavaWithFS(t, "", map[string][]byte{
 		"libcore/Android.bp": []byte(`
 				java_import {
@@ -1060,6 +1069,85 @@
 	})
 }
 
+func TestJavaImport(t *testing.T) {
+	bp := `
+		java_library {
+			name: "source_library",
+			srcs: ["source.java"],
+		}
+
+		java_import {
+			name: "import_with_no_deps",
+			jars: ["no_deps.jar"],
+		}
+
+		java_import {
+			name: "import_with_source_deps",
+			jars: ["source_deps.jar"],
+			static_libs: ["source_library"],
+		}
+
+		java_import {
+			name: "import_with_import_deps",
+			jars: ["import_deps.jar"],
+			static_libs: ["import_with_no_deps"],
+		}
+	`
+	ctx := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+	).RunTestWithBp(t, bp)
+
+	source := ctx.ModuleForTests("source_library", "android_common")
+	sourceJar := source.Output("javac/source_library.jar")
+	sourceHeaderJar := source.Output("turbine-combined/source_library.jar")
+	sourceJavaInfo, _ := android.SingletonModuleProvider(ctx, source.Module(), JavaInfoProvider)
+
+	// The source library produces separate implementation and header jars
+	android.AssertPathsRelativeToTopEquals(t, "source library implementation jar",
+		[]string{sourceJar.Output.String()}, sourceJavaInfo.ImplementationAndResourcesJars)
+	android.AssertPathsRelativeToTopEquals(t, "source library header jar",
+		[]string{sourceHeaderJar.Output.String()}, sourceJavaInfo.HeaderJars)
+
+	importWithNoDeps := ctx.ModuleForTests("import_with_no_deps", "android_common")
+	importWithNoDepsJar := importWithNoDeps.Output("combined/import_with_no_deps.jar")
+	importWithNoDepsJavaInfo, _ := android.SingletonModuleProvider(ctx, importWithNoDeps.Module(), JavaInfoProvider)
+
+	// An import with no deps produces a single jar used as both the header and implementation jar.
+	android.AssertPathsRelativeToTopEquals(t, "import with no deps implementation jar",
+		[]string{importWithNoDepsJar.Output.String()}, importWithNoDepsJavaInfo.ImplementationAndResourcesJars)
+	android.AssertPathsRelativeToTopEquals(t, "import with no deps header jar",
+		[]string{importWithNoDepsJar.Output.String()}, importWithNoDepsJavaInfo.HeaderJars)
+	android.AssertPathsRelativeToTopEquals(t, "import with no deps combined inputs",
+		[]string{"no_deps.jar"}, importWithNoDepsJar.Inputs)
+
+	importWithSourceDeps := ctx.ModuleForTests("import_with_source_deps", "android_common")
+	importWithSourceDepsJar := importWithSourceDeps.Output("combined/import_with_source_deps.jar")
+	importWithSourceDepsHeaderJar := importWithSourceDeps.Output("turbine-combined/import_with_source_deps.jar")
+	importWithSourceDepsJavaInfo, _ := android.SingletonModuleProvider(ctx, importWithSourceDeps.Module(), JavaInfoProvider)
+
+	// An import with source deps produces separate header and implementation jars.
+	android.AssertPathsRelativeToTopEquals(t, "import with source deps implementation jar",
+		[]string{importWithSourceDepsJar.Output.String()}, importWithSourceDepsJavaInfo.ImplementationAndResourcesJars)
+	android.AssertPathsRelativeToTopEquals(t, "import with source deps header jar",
+		[]string{importWithSourceDepsHeaderJar.Output.String()}, importWithSourceDepsJavaInfo.HeaderJars)
+	android.AssertPathsRelativeToTopEquals(t, "import with source deps combined implementation jar inputs",
+		[]string{"source_deps.jar", sourceJar.Output.String()}, importWithSourceDepsJar.Inputs)
+	android.AssertPathsRelativeToTopEquals(t, "import with source deps combined header jar inputs",
+		[]string{"source_deps.jar", sourceHeaderJar.Output.String()}, importWithSourceDepsHeaderJar.Inputs)
+
+	importWithImportDeps := ctx.ModuleForTests("import_with_import_deps", "android_common")
+	importWithImportDepsJar := importWithImportDeps.Output("combined/import_with_import_deps.jar")
+	importWithImportDepsJavaInfo, _ := android.SingletonModuleProvider(ctx, importWithImportDeps.Module(), JavaInfoProvider)
+
+	// An import with only import deps produces a single jar used as both the header and implementation jar.
+	android.AssertPathsRelativeToTopEquals(t, "import with import deps implementation jar",
+		[]string{importWithImportDepsJar.Output.String()}, importWithImportDepsJavaInfo.ImplementationAndResourcesJars)
+	android.AssertPathsRelativeToTopEquals(t, "import with import deps header jar",
+		[]string{importWithImportDepsJar.Output.String()}, importWithImportDepsJavaInfo.HeaderJars)
+	android.AssertPathsRelativeToTopEquals(t, "import with import deps combined implementation jar inputs",
+		[]string{"import_deps.jar", importWithNoDepsJar.Output.String()}, importWithImportDepsJar.Inputs)
+}
+
 var compilerFlagsTestCases = []struct {
 	in  string
 	out bool
@@ -1206,7 +1294,7 @@
 		expected := "java.base=.:out/soong"
 		checkPatchModuleFlag(t, ctx, "bar", expected)
 		expected = "java.base=" + strings.Join([]string{
-			".", "out/soong", "dir", "dir2", "nested", defaultModuleToPath("ext"), defaultModuleToPath("framework")}, ":")
+			".", "out/soong", defaultModuleToPath("ext"), defaultModuleToPath("framework")}, ":")
 		checkPatchModuleFlag(t, ctx, "baz", expected)
 	})
 }
@@ -1291,43 +1379,6 @@
 	}
 }
 
-func TestAidlIncludeDirFromConvertedFileGroupWithPathPropInMixedBuilds(t *testing.T) {
-	// TODO(b/247782695), TODO(b/242847534) Fix mixed builds for filegroups
-	t.Skip("Re-enable once filegroups are corrected for mixed builds")
-	bp := `
-	filegroup {
-		name: "foo_aidl",
-		srcs: ["aidl/foo/IFoo.aidl"],
-		path: "aidl/foo",
-		bazel_module: { label: "//:foo_aidl" },
-	}
-	java_library {
-		name: "foo",
-		srcs: [":foo_aidl"],
-	}
-`
-
-	outBaseDir := "out/bazel/output"
-	result := android.GroupFixturePreparers(
-		prepareForJavaTest,
-		android.PrepareForTestWithFilegroup,
-		android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: outBaseDir,
-				LabelToOutputFiles: map[string][]string{
-					"//:foo_aidl": []string{"aidl/foo/IFoo.aidl"},
-				},
-			}
-		}),
-	).RunTestWithBp(t, bp)
-
-	aidlCommand := result.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command
-	expectedAidlFlag := "-I" + outBaseDir + "/execroot/__main__/aidl/foo"
-	if !strings.Contains(aidlCommand, expectedAidlFlag) {
-		t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
-	}
-}
-
 func TestAidlFlagsArePassedToTheAidlCompiler(t *testing.T) {
 	ctx, _ := testJava(t, `
 		java_library {
@@ -1744,85 +1795,6 @@
 	}
 }
 
-func TestImportMixedBuild(t *testing.T) {
-	bp := `
-		java_import {
-			name: "baz",
-			jars: [
-				"test1.jar",
-				"test2.jar",
-			],
-			bazel_module: { label: "//foo/bar:baz" },
-		}
-	`
-
-	ctx := android.GroupFixturePreparers(
-		prepareForJavaTest,
-		android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: "outputbase",
-				LabelToOutputFiles: map[string][]string{
-					"//foo/bar:baz": []string{"test1.jar", "test2.jar"},
-				},
-			}
-		}),
-	).RunTestWithBp(t, bp)
-
-	bazMod := ctx.ModuleForTests("baz", "android_common").Module()
-	producer := bazMod.(android.OutputFileProducer)
-	expectedOutputFiles := []string{".intermediates/baz/android_common/bazelCombined/baz.jar"}
-
-	outputFiles, err := producer.OutputFiles("")
-	if err != nil {
-		t.Errorf("Unexpected error getting java_import outputfiles %s", err)
-	}
-	actualOutputFiles := android.NormalizePathsForTesting(outputFiles)
-	android.AssertDeepEquals(t, "Output files are produced", expectedOutputFiles, actualOutputFiles)
-
-	javaInfoProvider := ctx.ModuleProvider(bazMod, JavaInfoProvider)
-	javaInfo, ok := javaInfoProvider.(JavaInfo)
-	if !ok {
-		t.Error("could not get JavaInfo from java_import module")
-	}
-	android.AssertDeepEquals(t, "Header JARs are produced", expectedOutputFiles, android.NormalizePathsForTesting(javaInfo.HeaderJars))
-	android.AssertDeepEquals(t, "Implementation/Resources JARs are produced", expectedOutputFiles, android.NormalizePathsForTesting(javaInfo.ImplementationAndResourcesJars))
-	android.AssertDeepEquals(t, "Implementation JARs are produced", expectedOutputFiles, android.NormalizePathsForTesting(javaInfo.ImplementationJars))
-}
-
-func TestGenAidlIncludeFlagsForMixedBuilds(t *testing.T) {
-	bazelOutputBaseDir := filepath.Join("out", "bazel")
-	result := android.GroupFixturePreparers(
-		PrepareForIntegrationTestWithJava,
-		android.FixtureModifyConfig(func(config android.Config) {
-			config.BazelContext = android.MockBazelContext{
-				OutputBaseDir: bazelOutputBaseDir,
-			}
-		}),
-	).RunTest(t)
-
-	ctx := &android.TestPathContext{TestResult: result}
-
-	srcDirectory := filepath.Join("frameworks", "base")
-	srcDirectoryAlreadyIncluded := filepath.Join("frameworks", "base", "core", "java")
-	bazelSrcDirectory := android.PathForBazelOut(ctx, srcDirectory)
-	bazelSrcDirectoryAlreadyIncluded := android.PathForBazelOut(ctx, srcDirectoryAlreadyIncluded)
-	srcs := android.Paths{
-		android.PathForTestingWithRel(bazelSrcDirectory.String(), "bazelAidl.aidl"),
-		android.PathForTestingWithRel(bazelSrcDirectory.String(), "bazelAidl2.aidl"),
-		android.PathForTestingWithRel(bazelSrcDirectoryAlreadyIncluded.String(), "bazelAidlExclude.aidl"),
-		android.PathForTestingWithRel(bazelSrcDirectoryAlreadyIncluded.String(), "bazelAidl2Exclude.aidl"),
-	}
-	dirsAlreadyIncluded := android.Paths{
-		android.PathForTesting(srcDirectoryAlreadyIncluded),
-	}
-
-	expectedFlags := " -Iout/bazel/execroot/__main__/frameworks/base"
-	flags := genAidlIncludeFlags(ctx, srcs, dirsAlreadyIncluded)
-	if flags != expectedFlags {
-		t.Errorf("expected flags to be %q; was %q", expectedFlags, flags)
-	}
-}
-
 func TestDeviceBinaryWrapperGeneration(t *testing.T) {
 	// Scenario 1: java_binary has main_class property in its bp
 	ctx, _ := testJava(t, `
@@ -1847,15 +1819,24 @@
 }
 
 func TestJavaApiContributionEmptyApiFile(t *testing.T) {
-	testJavaError(t,
+	android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureMergeEnv(
+			map[string]string{
+				"DISABLE_STUB_VALIDATION": "true",
+			},
+		),
+	).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
 		"Error: foo has an empty api file.",
-		`java_api_contribution {
+	)).RunTestWithBp(t, `
+		java_api_contribution {
 			name: "foo",
 		}
 		java_api_library {
 			name: "bar",
 			api_surface: "public",
 			api_contributions: ["foo"],
+			stubs_type: "everything",
 		}
 	`)
 }
@@ -1865,31 +1846,43 @@
 	java_api_contribution {
 		name: "foo1",
 		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	provider_bp_b := `java_api_contribution {
 		name: "foo2",
 		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
-	ctx, _ := testJavaWithFS(t, `
+	ctx := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureMergeMockFs(
+			map[string][]byte{
+				"a/Android.bp": []byte(provider_bp_a),
+				"b/Android.bp": []byte(provider_bp_b),
+			},
+		),
+		android.FixtureMergeEnv(
+			map[string]string{
+				"DISABLE_STUB_VALIDATION": "true",
+			},
+		),
+	).RunTestWithBp(t, `
 		java_api_library {
 			name: "bar1",
 			api_surface: "public",
 			api_contributions: ["foo1"],
+			stubs_type: "everything",
 		}
 
 		java_api_library {
 			name: "bar2",
 			api_surface: "system",
 			api_contributions: ["foo1", "foo2"],
-			api_files: ["api1/current.txt", "api2/current.txt"]
+			stubs_type: "everything",
 		}
-		`,
-		map[string][]byte{
-			"a/Android.bp": []byte(provider_bp_a),
-			"b/Android.bp": []byte(provider_bp_b),
-		})
+	`)
 
 	testcases := []struct {
 		moduleName         string
@@ -1901,13 +1894,13 @@
 		},
 		{
 			moduleName:         "bar2",
-			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt", "api1/current.txt", "api2/current.txt"},
+			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt"},
 		},
 	}
 	for _, c := range testcases {
 		m := ctx.ModuleForTests(c.moduleName, "android_common")
 		manifest := m.Output("metalava.sbox.textproto")
-		sboxProto := android.RuleBuilderSboxProtoForTests(t, manifest)
+		sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx.TestContext, manifest)
 		manifestCommand := sboxProto.Commands[0].GetCommand()
 		sourceFilesFlag := "--source-files " + strings.Join(c.sourceTextFileDirs, " ")
 		android.AssertStringDoesContain(t, "source text files not present", manifestCommand, sourceFilesFlag)
@@ -1919,27 +1912,46 @@
 	java_api_contribution {
 		name: "foo1",
 		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
 		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	provider_bp_c := `
 	java_api_contribution {
 		name: "foo3",
-		api_file: "current.txt",
+		api_file: "system-current.txt",
+		api_surface: "system",
 	}
 	`
 	provider_bp_d := `
 	java_api_contribution {
 		name: "foo4",
-		api_file: "current.txt",
+		api_file: "system-current.txt",
+		api_surface: "system",
 	}
 	`
-	ctx, _ := testJavaWithFS(t, `
+	ctx := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureMergeMockFs(
+			map[string][]byte{
+				"a/Android.bp": []byte(provider_bp_a),
+				"b/Android.bp": []byte(provider_bp_b),
+				"c/Android.bp": []byte(provider_bp_c),
+				"d/Android.bp": []byte(provider_bp_d),
+			},
+		),
+		android.FixtureMergeEnv(
+			map[string]string{
+				"DISABLE_STUB_VALIDATION": "true",
+			},
+		),
+	).RunTestWithBp(t, `
 		java_defaults {
 			name: "baz1",
 			api_surface: "public",
@@ -1956,12 +1968,14 @@
 			name: "bar1",
 			api_surface: "public",
 			api_contributions: ["foo1"],
+			stubs_type: "everything",
 		}
 
 		java_api_library {
 			name: "bar2",
 			api_surface: "public",
 			defaults:["baz1"],
+			stubs_type: "everything",
 		}
 
 		java_api_library {
@@ -1969,15 +1983,9 @@
 			api_surface: "system",
 			defaults:["baz1", "baz2"],
 			api_contributions: ["foo4"],
-			api_files: ["api1/current.txt", "api2/current.txt"]
+			stubs_type: "everything",
 		}
-		`,
-		map[string][]byte{
-			"a/Android.bp": []byte(provider_bp_a),
-			"b/Android.bp": []byte(provider_bp_b),
-			"c/Android.bp": []byte(provider_bp_c),
-			"d/Android.bp": []byte(provider_bp_d),
-		})
+	`)
 
 	testcases := []struct {
 		moduleName         string
@@ -1992,14 +2000,15 @@
 			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt"},
 		},
 		{
-			moduleName:         "bar3",
-			sourceTextFileDirs: []string{"c/current.txt", "a/current.txt", "b/current.txt", "d/current.txt", "api1/current.txt", "api2/current.txt"},
+			moduleName: "bar3",
+			// API text files need to be sorted from the narrower api scope to the wider api scope
+			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt", "c/system-current.txt", "d/system-current.txt"},
 		},
 	}
 	for _, c := range testcases {
 		m := ctx.ModuleForTests(c.moduleName, "android_common")
 		manifest := m.Output("metalava.sbox.textproto")
-		sboxProto := android.RuleBuilderSboxProtoForTests(t, manifest)
+		sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx.TestContext, manifest)
 		manifestCommand := sboxProto.Commands[0].GetCommand()
 		sourceFilesFlag := "--source-files " + strings.Join(c.sourceTextFileDirs, " ")
 		android.AssertStringDoesContain(t, "source text files not present", manifestCommand, sourceFilesFlag)
@@ -2011,31 +2020,44 @@
 	java_api_contribution {
 		name: "foo1",
 		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
 		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
-	ctx, _ := testJavaWithFS(t, `
+	ctx := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureMergeMockFs(
+			map[string][]byte{
+				"a/Android.bp": []byte(provider_bp_a),
+				"b/Android.bp": []byte(provider_bp_b),
+			},
+		),
+		android.FixtureMergeEnv(
+			map[string]string{
+				"DISABLE_STUB_VALIDATION": "true",
+			},
+		),
+	).RunTestWithBp(t, `
 		java_api_library {
 			name: "bar1",
 			api_surface: "public",
 			api_contributions: ["foo1"],
+			stubs_type: "everything",
 		}
 
 		java_api_library {
 			name: "bar2",
 			api_surface: "system",
 			api_contributions: ["foo1", "foo2"],
+			stubs_type: "everything",
 		}
-		`,
-		map[string][]byte{
-			"a/Android.bp": []byte(provider_bp_a),
-			"b/Android.bp": []byte(provider_bp_b),
-		})
+	`)
 
 	testcases := []struct {
 		moduleName    string
@@ -2064,12 +2086,14 @@
 	java_api_contribution {
 		name: "foo1",
 		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
 		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	lib_bp_a := `
@@ -2085,12 +2109,30 @@
 	}
 	`
 
-	ctx, _ := testJavaWithFS(t, `
+	ctx := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureMergeMockFs(
+			map[string][]byte{
+				"a/Android.bp": []byte(provider_bp_a),
+				"b/Android.bp": []byte(provider_bp_b),
+				"c/Android.bp": []byte(lib_bp_a),
+				"c/Lib.java":   {},
+				"d/Android.bp": []byte(lib_bp_b),
+				"d/Lib.java":   {},
+			},
+		),
+		android.FixtureMergeEnv(
+			map[string]string{
+				"DISABLE_STUB_VALIDATION": "true",
+			},
+		),
+	).RunTestWithBp(t, `
 		java_api_library {
 			name: "bar1",
 			api_surface: "public",
 			api_contributions: ["foo1"],
 			libs: ["lib1"],
+			stubs_type: "everything",
 		}
 
 		java_api_library {
@@ -2098,16 +2140,9 @@
 			api_surface: "system",
 			api_contributions: ["foo1", "foo2"],
 			libs: ["lib1", "lib2", "bar1"],
+			stubs_type: "everything",
 		}
-		`,
-		map[string][]byte{
-			"a/Android.bp": []byte(provider_bp_a),
-			"b/Android.bp": []byte(provider_bp_b),
-			"c/Android.bp": []byte(lib_bp_a),
-			"c/Lib.java":   {},
-			"d/Android.bp": []byte(lib_bp_b),
-			"d/Lib.java":   {},
-		})
+	`)
 
 	testcases := []struct {
 		moduleName        string
@@ -2139,12 +2174,14 @@
 	java_api_contribution {
 		name: "foo1",
 		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
 		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	lib_bp_a := `
@@ -2160,12 +2197,30 @@
 	}
 	`
 
-	ctx, _ := testJavaWithFS(t, `
+	ctx := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureMergeMockFs(
+			map[string][]byte{
+				"a/Android.bp": []byte(provider_bp_a),
+				"b/Android.bp": []byte(provider_bp_b),
+				"c/Android.bp": []byte(lib_bp_a),
+				"c/Lib.java":   {},
+				"d/Android.bp": []byte(lib_bp_b),
+				"d/Lib.java":   {},
+			},
+		),
+		android.FixtureMergeEnv(
+			map[string]string{
+				"DISABLE_STUB_VALIDATION": "true",
+			},
+		),
+	).RunTestWithBp(t, `
 		java_api_library {
 			name: "bar1",
 			api_surface: "public",
 			api_contributions: ["foo1"],
 			static_libs: ["lib1"],
+			stubs_type: "everything",
 		}
 
 		java_api_library {
@@ -2173,16 +2228,9 @@
 			api_surface: "system",
 			api_contributions: ["foo1", "foo2"],
 			static_libs: ["lib1", "lib2", "bar1"],
+			stubs_type: "everything",
 		}
-		`,
-		map[string][]byte{
-			"a/Android.bp": []byte(provider_bp_a),
-			"b/Android.bp": []byte(provider_bp_b),
-			"c/Android.bp": []byte(lib_bp_a),
-			"c/Lib.java":   {},
-			"d/Android.bp": []byte(lib_bp_b),
-			"d/Lib.java":   {},
-		})
+	`)
 
 	testcases := []struct {
 		moduleName        string
@@ -2213,12 +2261,14 @@
 	java_api_contribution {
 		name: "foo1",
 		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
 		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	lib_bp_a := `
@@ -2226,51 +2276,62 @@
 		name: "lib1",
 		api_surface: "public",
 		api_contributions: ["foo1", "foo2"],
+		stubs_type: "everything",
 	}
 	`
 
-	ctx, _ := testJavaWithFS(t, `
+	ctx := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureMergeMockFs(
+			map[string][]byte{
+				"a/Android.bp": []byte(provider_bp_a),
+				"b/Android.bp": []byte(provider_bp_b),
+				"c/Android.bp": []byte(lib_bp_a),
+			},
+		),
+		android.FixtureMergeEnv(
+			map[string]string{
+				"DISABLE_STUB_VALIDATION": "true",
+			},
+		),
+	).RunTestWithBp(t, `
 		java_api_library {
 			name: "bar1",
 			api_surface: "public",
 			api_contributions: ["foo1"],
 			full_api_surface_stub: "lib1",
+			stubs_type: "everything",
 		}
-		`,
-		map[string][]byte{
-			"a/Android.bp": []byte(provider_bp_a),
-			"b/Android.bp": []byte(provider_bp_b),
-			"c/Android.bp": []byte(lib_bp_a),
-		})
+	`)
 
 	m := ctx.ModuleForTests("bar1", "android_common")
 	manifest := m.Output("metalava.sbox.textproto")
-	sboxProto := android.RuleBuilderSboxProtoForTests(t, manifest)
+	sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx.TestContext, manifest)
 	manifestCommand := sboxProto.Commands[0].GetCommand()
 	android.AssertStringDoesContain(t, "Command expected to contain full_api_surface_stub output jar", manifestCommand, "lib1.jar")
 }
 
-func TestJavaApiLibraryFilegroupInput(t *testing.T) {
-	ctx, _ := testJavaWithFS(t, `
-	    filegroup {
-			name: "default_current.txt",
-			srcs: ["current.txt"],
+func TestTransitiveSrcFiles(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_library {
+			name: "a",
+			srcs: ["a.java"],
 		}
-
-		java_api_library {
-			name: "foo",
-			api_files: [":default_current.txt"],
+		java_library {
+			name: "b",
+			srcs: ["b.java"],
 		}
-		`,
-		map[string][]byte{
-			"current.txt": nil,
-		})
-
-	m := ctx.ModuleForTests("foo", "android_common")
-	outputs := fmt.Sprint(m.AllOutputs())
-	if !strings.Contains(outputs, "foo/foo.jar") {
-		t.Errorf("Module output does not contain expected jar %s", "foo/foo.jar")
-	}
+		java_library {
+			name: "c",
+			srcs: ["c.java"],
+			libs: ["a"],
+			static_libs: ["b"],
+		}
+	`)
+	c := ctx.ModuleForTests("c", "android_common").Module()
+	javaInfo, _ := android.SingletonModuleProvider(ctx, c, JavaInfoProvider)
+	transitiveSrcFiles := android.Paths(javaInfo.TransitiveSrcFiles.ToList())
+	android.AssertArrayString(t, "unexpected jar deps", []string{"b.java", "c.java"}, transitiveSrcFiles.Strings())
 }
 
 func TestTradefedOptions(t *testing.T) {
@@ -2370,3 +2431,613 @@
 		t.Errorf("Module output does not contain expected jar %s", "test.jar")
 	}
 }
+
+func TestHeadersOnly(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			headers_only: true,
+		}
+	`)
+
+	turbine := ctx.ModuleForTests("foo", "android_common").Rule("turbine")
+	if len(turbine.Inputs) != 1 || turbine.Inputs[0].String() != "a.java" {
+		t.Errorf(`foo inputs %v != ["a.java"]`, turbine.Inputs)
+	}
+
+	javac := ctx.ModuleForTests("foo", "android_common").MaybeRule("javac")
+	android.AssertDeepEquals(t, "javac rule", nil, javac.Rule)
+}
+
+func TestJavaApiContributionImport(t *testing.T) {
+	ctx := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureMergeEnv(
+			map[string]string{
+				"DISABLE_STUB_VALIDATION": "true",
+			},
+		),
+	).RunTestWithBp(t, `
+		java_api_library {
+			name: "foo",
+			api_contributions: ["bar"],
+			stubs_type: "everything",
+		}
+		java_api_contribution_import {
+			name: "bar",
+			api_file: "current.txt",
+			api_surface: "public",
+		}
+	`)
+	m := ctx.ModuleForTests("foo", "android_common")
+	manifest := m.Output("metalava.sbox.textproto")
+	sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx.TestContext, manifest)
+	manifestCommand := sboxProto.Commands[0].GetCommand()
+	sourceFilesFlag := "--source-files current.txt"
+	android.AssertStringDoesContain(t, "source text files not present", manifestCommand, sourceFilesFlag)
+}
+
+func TestJavaApiLibraryApiFilesSorting(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_api_library {
+			name: "foo",
+			api_contributions: [
+				"system-server-api-stubs-docs-non-updatable.api.contribution",
+				"test-api-stubs-docs-non-updatable.api.contribution",
+				"system-api-stubs-docs-non-updatable.api.contribution",
+				"module-lib-api-stubs-docs-non-updatable.api.contribution",
+				"api-stubs-docs-non-updatable.api.contribution",
+			],
+			stubs_type: "everything",
+		}
+	`)
+	m := ctx.ModuleForTests("foo", "android_common")
+	manifest := m.Output("metalava.sbox.textproto")
+	sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx, manifest)
+	manifestCommand := sboxProto.Commands[0].GetCommand()
+
+	// Api files are sorted from the narrowest api scope to the widest api scope.
+	// test api and module lib api surface do not have subset/superset relationship,
+	// but they will never be passed as inputs at the same time.
+	sourceFilesFlag := "--source-files default/java/api/current.txt " +
+		"default/java/api/system-current.txt default/java/api/test-current.txt " +
+		"default/java/api/module-lib-current.txt default/java/api/system-server-current.txt"
+	android.AssertStringDoesContain(t, "source text files not in api scope order", manifestCommand, sourceFilesFlag)
+}
+
+func TestSdkLibraryProvidesSystemModulesToApiLibrary(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("foo"),
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.SetApiLibraries([]string{"foo"})
+		}),
+		android.FixtureMergeMockFs(
+			map[string][]byte{
+				"A.java": nil,
+			},
+		),
+	).RunTestWithBp(t, `
+		java_library {
+			name: "bar",
+			srcs: ["a.java"],
+		}
+		java_system_modules {
+			name: "baz",
+			libs: ["bar"],
+		}
+		java_sdk_library {
+			name: "foo",
+			srcs: ["A.java"],
+			system_modules: "baz",
+		}
+	`)
+	m := result.ModuleForTests(apiScopePublic.apiLibraryModuleName("foo"), "android_common")
+	manifest := m.Output("metalava.sbox.textproto")
+	sboxProto := android.RuleBuilderSboxProtoForTests(t, result.TestContext, manifest)
+	manifestCommand := sboxProto.Commands[0].GetCommand()
+	classPathFlag := "--classpath __SBOX_SANDBOX_DIR__/out/soong/.intermediates/bar/android_common/turbine-combined/bar.jar"
+	android.AssertStringDoesContain(t, "command expected to contain classpath flag", manifestCommand, classPathFlag)
+}
+
+func TestApiLibraryDroidstubsDependency(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("foo"),
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.SetApiLibraries([]string{"foo"})
+		}),
+		android.FixtureMergeMockFs(
+			map[string][]byte{
+				"A.java": nil,
+			},
+		),
+	).RunTestWithBp(t, `
+		java_api_library {
+			name: "foo",
+			api_contributions: [
+				"api-stubs-docs-non-updatable.api.contribution",
+			],
+			enable_validation: true,
+			stubs_type: "everything",
+		}
+		java_api_library {
+			name: "bar",
+			api_contributions: [
+				"api-stubs-docs-non-updatable.api.contribution",
+			],
+			enable_validation: false,
+			stubs_type: "everything",
+		}
+	`)
+
+	currentApiTimestampPath := "api-stubs-docs-non-updatable/android_common/everything/check_current_api.timestamp"
+	foo := result.ModuleForTests("foo", "android_common").Module().(*ApiLibrary)
+	fooValidationPathsString := strings.Join(foo.validationPaths.Strings(), " ")
+	bar := result.ModuleForTests("bar", "android_common").Module().(*ApiLibrary)
+	barValidationPathsString := strings.Join(bar.validationPaths.Strings(), " ")
+	android.AssertStringDoesContain(t,
+		"Module expected to have validation",
+		fooValidationPathsString,
+		currentApiTimestampPath,
+	)
+	android.AssertStringDoesNotContain(t,
+		"Module expected to not have validation",
+		barValidationPathsString,
+		currentApiTimestampPath,
+	)
+}
+
+func TestDisableFromTextStubForCoverageBuild(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		PrepareForTestWithJacocoInstrumentation,
+		FixtureWithLastReleaseApis("foo"),
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.SetApiLibraries([]string{"foo"})
+			config.SetBuildFromTextStub(true)
+		}),
+		android.FixtureModifyEnv(func(env map[string]string) {
+			env["EMMA_INSTRUMENT"] = "true"
+		}),
+	).RunTestWithBp(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["A.java"],
+		}
+	`)
+	android.AssertBoolEquals(t, "stub module expected to depend on from-source stub",
+		true, CheckModuleHasDependency(t, result.TestContext,
+			apiScopePublic.stubsLibraryModuleName("foo"), "android_common",
+			apiScopePublic.sourceStubLibraryModuleName("foo")))
+
+	android.AssertBoolEquals(t, "stub module expected to not depend on from-text stub",
+		false, CheckModuleHasDependency(t, result.TestContext,
+			apiScopePublic.stubsLibraryModuleName("foo"), "android_common",
+			apiScopePublic.apiLibraryModuleName("foo")))
+}
+
+func TestMultiplePrebuilts(t *testing.T) {
+	bp := `
+		// an rdep
+		java_library {
+			name: "foo",
+			libs: ["bar"],
+		}
+
+		// multiple variations of dep
+		// source
+		java_library {
+			name: "bar",
+			srcs: ["bar.java"],
+		}
+		// prebuilt "v1"
+		java_import {
+			name: "bar",
+			jars: ["bar.jar"],
+		}
+		// prebuilt "v2"
+		java_import {
+			name: "bar.v2",
+			source_module_name: "bar",
+			jars: ["bar.v1.jar"],
+		}
+
+		// selectors
+		apex_contributions {
+			name: "myapex_contributions",
+			contents: ["%v"],
+		}
+	`
+	hasDep := func(ctx *android.TestResult, m android.Module, wantDep android.Module) bool {
+		t.Helper()
+		var found bool
+		ctx.VisitDirectDeps(m, func(dep blueprint.Module) {
+			if dep == wantDep {
+				found = true
+			}
+		})
+		return found
+	}
+
+	hasFileWithStem := func(m android.TestingModule, stem string) bool {
+		t.Helper()
+		for _, o := range m.AllOutputs() {
+			_, file := filepath.Split(o)
+			if file == stem+".jar" {
+				return true
+			}
+		}
+		return false
+	}
+
+	testCases := []struct {
+		desc                   string
+		selectedDependencyName string
+		expectedDependencyName string
+	}{
+		{
+			desc:                   "Source library is selected using apex_contributions",
+			selectedDependencyName: "bar",
+			expectedDependencyName: "bar",
+		},
+		{
+			desc:                   "Prebuilt library v1 is selected using apex_contributions",
+			selectedDependencyName: "prebuilt_bar",
+			expectedDependencyName: "prebuilt_bar",
+		},
+		{
+			desc:                   "Prebuilt library v2 is selected using apex_contributions",
+			selectedDependencyName: "prebuilt_bar.v2",
+			expectedDependencyName: "prebuilt_bar.v2",
+		},
+	}
+
+	for _, tc := range testCases {
+		ctx := android.GroupFixturePreparers(
+			prepareForJavaTest,
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "myapex_contributions",
+				}
+			}),
+		).RunTestWithBp(t, fmt.Sprintf(bp, tc.selectedDependencyName))
+
+		// check that rdep gets the correct variation of dep
+		foo := ctx.ModuleForTests("foo", "android_common")
+		expectedDependency := ctx.ModuleForTests(tc.expectedDependencyName, "android_common")
+		android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", foo.Module().Name(), tc.expectedDependencyName), true, hasDep(ctx, foo.Module(), expectedDependency.Module()))
+
+		// check that output file of dep is always bar.jar
+		// The filename should be agnostic to source/prebuilt/prebuilt_version
+		android.AssertBoolEquals(t, fmt.Sprintf("could not find bar.jar in outputs of %s. All Outputs %v\n", tc.expectedDependencyName, expectedDependency.AllOutputs()), true, hasFileWithStem(expectedDependency, "bar"))
+
+		// check LOCAL_MODULE of the selected module name
+		// the prebuilt should have the same LOCAL_MODULE when exported to make
+		entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, expectedDependency.Module())[0]
+		android.AssertStringEquals(t, "unexpected LOCAL_MODULE", "bar", entries.EntryMap["LOCAL_MODULE"][0])
+	}
+}
+
+func TestMultiplePlatformCompatConfigPrebuilts(t *testing.T) {
+	bp := `
+		// multiple variations of platform_compat_config
+		// source
+		platform_compat_config {
+			name: "myconfig",
+		}
+		// prebuilt "v1"
+		prebuilt_platform_compat_config {
+			name: "myconfig",
+			metadata: "myconfig.xml",
+		}
+		// prebuilt "v2"
+		prebuilt_platform_compat_config {
+			name: "myconfig.v2",
+			source_module_name: "myconfig", // without source_module_name, the singleton will merge two .xml files
+			metadata: "myconfig.v2.xml",
+		}
+
+		// selectors
+		apex_contributions {
+			name: "myapex_contributions",
+			contents: ["%v"],
+		}
+	`
+	testCases := []struct {
+		desc                            string
+		selectedDependencyName          string
+		expectedPlatformCompatConfigXml string
+	}{
+		{
+			desc:                            "Source platform_compat_config is selected using apex_contributions",
+			selectedDependencyName:          "myconfig",
+			expectedPlatformCompatConfigXml: "out/soong/.intermediates/myconfig/android_common/myconfig_meta.xml",
+		},
+		{
+			desc:                            "Prebuilt platform_compat_config v1 is selected using apex_contributions",
+			selectedDependencyName:          "prebuilt_myconfig",
+			expectedPlatformCompatConfigXml: "myconfig.xml",
+		},
+		{
+			desc:                            "Prebuilt platform_compat_config v2 is selected using apex_contributions",
+			selectedDependencyName:          "prebuilt_myconfig.v2",
+			expectedPlatformCompatConfigXml: "myconfig.v2.xml",
+		},
+	}
+
+	for _, tc := range testCases {
+		ctx := android.GroupFixturePreparers(
+			prepareForJavaTest,
+			PrepareForTestWithPlatformCompatConfig,
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "myapex_contributions",
+				}
+			}),
+		).RunTestWithBp(t, fmt.Sprintf(bp, tc.selectedDependencyName))
+
+		mergedGlobalConfig := ctx.SingletonForTests("platform_compat_config_singleton").Output("compat_config/merged_compat_config.xml")
+		android.AssertIntEquals(t, "The merged compat config file should only have a single dependency", 1, len(mergedGlobalConfig.Implicits))
+		android.AssertStringEquals(t, "The merged compat config file is missing the appropriate platform compat config", mergedGlobalConfig.Implicits[0].String(), tc.expectedPlatformCompatConfigXml)
+	}
+}
+
+func TestApiLibraryAconfigDeclarations(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+		}),
+		android.FixtureMergeMockFs(map[string][]byte{
+			"a/A.java":      nil,
+			"a/current.txt": nil,
+			"a/removed.txt": nil,
+		}),
+	).RunTestWithBp(t, `
+	aconfig_declarations {
+		name: "bar",
+		package: "com.example.package",
+		srcs: [
+			"bar.aconfig",
+		],
+	}
+	java_api_contribution {
+		name: "baz",
+		api_file: "a/current.txt",
+		api_surface: "public",
+	}
+	java_api_library {
+		name: "foo",
+		api_surface: "public",
+		api_contributions: [
+			"baz",
+		],
+		aconfig_declarations: [
+			"bar",
+		],
+		stubs_type: "exportable",
+		enable_validation: false,
+	}
+	`)
+
+	// Check if java_api_library depends on aconfig_declarations
+	android.AssertBoolEquals(t, "foo expected to depend on bar",
+		CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "bar"), true)
+
+	m := result.ModuleForTests("foo", "android_common")
+	android.AssertStringDoesContain(t, "foo generates revert annotations file",
+		strings.Join(m.AllOutputs(), ""), "revert-annotations-exportable.txt")
+
+	// revert-annotations.txt passed to exportable stubs generation metalava command
+	manifest := m.Output("metalava.sbox.textproto")
+	cmdline := String(android.RuleBuilderSboxProtoForTests(t, result.TestContext, manifest).Commands[0].Command)
+	android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "revert-annotations-exportable.txt")
+}
+
+func TestTestOnly(t *testing.T) {
+	t.Parallel()
+	ctx := android.GroupFixturePreparers(
+		prepareForJavaTest,
+	).RunTestWithBp(t, `
+                // These should be test-only
+		java_library {
+			name: "lib1-test-only",
+                        srcs: ["a.java"],
+                        test_only: true,
+		}
+                java_test {
+                        name: "java-test",
+                }
+                java_test_host {
+                        name: "java-test-host",
+                }
+                java_test_helper_library {
+                        name: "helper-library",
+                }
+                java_binary {
+                        name: "java-data-binary",
+			srcs: ["foo.java"],
+			main_class: "foo.bar.jb",
+                        test_only: true,
+                }
+
+                // These are NOT
+		java_library {
+			name: "lib2-app",
+                        srcs: ["b.java"],
+		}
+		java_import {
+			name: "bar",
+			jars: ["bar.jar"],
+		}
+                java_binary {
+                        name: "java-binary",
+			srcs: ["foo.java"],
+			main_class: "foo.bar.jb",
+                }
+	`)
+
+	expectedTestOnlyModules := []string{
+		"lib1-test-only",
+		"java-test",
+		"java-test-host",
+		"helper-library",
+		"java-data-binary",
+	}
+	expectedTopLevelTests := []string{
+		"java-test",
+		"java-test-host",
+	}
+	assertTestOnlyAndTopLevel(t, ctx, expectedTestOnlyModules, expectedTopLevelTests)
+}
+
+// Don't allow setting test-only on things that are always tests or never tests.
+func TestInvalidTestOnlyTargets(t *testing.T) {
+	testCases := []string{
+		` java_test {  name: "java-test", test_only: true, srcs: ["foo.java"],  } `,
+		` java_test_host {  name: "java-test-host", test_only: true, srcs: ["foo.java"],  } `,
+		` java_test_import {  name: "java-test-import", test_only: true, } `,
+		` java_api_library {  name: "java-api-library", test_only: true, } `,
+		` java_test_helper_library { name: "test-help-lib", test_only: true, } `,
+		` java_defaults { name: "java-defaults", test_only: true, } `,
+	}
+
+	for i, bp := range testCases {
+		android.GroupFixturePreparers(prepareForJavaTest).
+			ExtendWithErrorHandler(
+				expectOneError("unrecognized property \"test_only\"",
+					fmt.Sprintf("testcase: %d", i))).
+			RunTestWithBp(t, bp)
+	}
+}
+
+// Expect exactly one that matches 'expected'.
+// Append 'msg' to the Errorf that printed.
+func expectOneError(expected string, msg string) android.FixtureErrorHandler {
+	return android.FixtureCustomErrorHandler(func(t *testing.T, result *android.TestResult) {
+		t.Helper()
+		if len(result.Errs) != 1 {
+			t.Errorf("Expected exactly one error, but found: %d when  setting test_only on: %s", len(result.Errs), msg)
+			return
+		}
+		actualErrMsg := result.Errs[0].Error()
+		if !strings.Contains(actualErrMsg, expected) {
+			t.Errorf("Different error than expected.  Received: [%v] on %s expected: %s", actualErrMsg, msg, expected)
+		}
+	})
+}
+
+func TestJavaLibHostWithStem(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_library_host {
+			name: "foo",
+			srcs: ["a.java"],
+			stem: "foo-new",
+		}
+	`)
+
+	buildOS := ctx.Config().BuildOS.String()
+	foo := ctx.ModuleForTests("foo", buildOS+"_common")
+
+	outputs := fmt.Sprint(foo.AllOutputs())
+	if !strings.Contains(outputs, "foo-new.jar") {
+		t.Errorf("Module output does not contain expected jar %s", "foo-new.jar")
+	}
+}
+
+func TestJavaLibWithStem(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			stem: "foo-new",
+		}
+	`)
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+
+	outputs := fmt.Sprint(foo.AllOutputs())
+	if !strings.Contains(outputs, "foo-new.jar") {
+		t.Errorf("Module output does not contain expected jar %s", "foo-new.jar")
+	}
+}
+
+func TestJavaLibraryOutputFilesRel(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+	).RunTestWithBp(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+		}
+
+		java_import {
+			name: "bar",
+			jars: ["bar.aar"],
+
+		}
+
+		java_import {
+			name: "baz",
+			jars: ["baz.aar"],
+			static_libs: ["bar"],
+		}
+	`)
+
+	foo := result.ModuleForTests("foo", "android_common")
+	bar := result.ModuleForTests("bar", "android_common")
+	baz := result.ModuleForTests("baz", "android_common")
+
+	fooOutputPath := android.OutputFileForModule(android.PathContext(nil), foo.Module(), "")
+	barOutputPath := android.OutputFileForModule(android.PathContext(nil), bar.Module(), "")
+	bazOutputPath := android.OutputFileForModule(android.PathContext(nil), baz.Module(), "")
+
+	android.AssertPathRelativeToTopEquals(t, "foo output path",
+		"out/soong/.intermediates/foo/android_common/javac/foo.jar", fooOutputPath)
+	android.AssertPathRelativeToTopEquals(t, "bar output path",
+		"out/soong/.intermediates/bar/android_common/combined/bar.jar", barOutputPath)
+	android.AssertPathRelativeToTopEquals(t, "baz output path",
+		"out/soong/.intermediates/baz/android_common/combined/baz.jar", bazOutputPath)
+
+	android.AssertStringEquals(t, "foo relative output path",
+		"foo.jar", fooOutputPath.Rel())
+	android.AssertStringEquals(t, "bar relative output path",
+		"bar.jar", barOutputPath.Rel())
+	android.AssertStringEquals(t, "baz relative output path",
+		"baz.jar", bazOutputPath.Rel())
+}
+
+func assertTestOnlyAndTopLevel(t *testing.T, ctx *android.TestResult, expectedTestOnly []string, expectedTopLevel []string) {
+	t.Helper()
+	actualTrueModules := []string{}
+	actualTopLevelTests := []string{}
+	addActuals := func(m blueprint.Module, key blueprint.ProviderKey[android.TestModuleInformation]) {
+		if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, key); ok {
+			if provider.TestOnly {
+				actualTrueModules = append(actualTrueModules, m.Name())
+			}
+			if provider.TopLevelTarget {
+				actualTopLevelTests = append(actualTopLevelTests, m.Name())
+			}
+		}
+	}
+
+	ctx.VisitAllModules(func(m blueprint.Module) {
+		addActuals(m, android.TestOnlyProviderKey)
+
+	})
+
+	notEqual, left, right := android.ListSetDifference(expectedTestOnly, actualTrueModules)
+	if notEqual {
+		t.Errorf("test-only: Expected but not found: %v, Found but not expected: %v", left, right)
+	}
+
+	notEqual, left, right = android.ListSetDifference(expectedTopLevel, actualTopLevelTests)
+	if notEqual {
+		t.Errorf("top-level: Expected but not found: %v, Found but not expected: %v", left, right)
+	}
+}
diff --git a/java/jdeps.go b/java/jdeps.go
index 4c8c11c..91f7ce7 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -75,7 +75,7 @@
 		dpInfo.Jarjar_rules = android.FirstUniqueStrings(dpInfo.Jarjar_rules)
 		dpInfo.Jars = android.FirstUniqueStrings(dpInfo.Jars)
 		dpInfo.SrcJars = android.FirstUniqueStrings(dpInfo.SrcJars)
-		dpInfo.Paths = android.FirstUniqueStrings(dpInfo.Paths)
+		dpInfo.Paths = []string{ctx.ModuleDir(module)}
 		dpInfo.Static_libs = android.FirstUniqueStrings(dpInfo.Static_libs)
 		dpInfo.Libs = android.FirstUniqueStrings(dpInfo.Libs)
 		moduleInfos[name] = dpInfo
@@ -89,8 +89,7 @@
 			dpInfo.Classes = append(dpInfo.Classes, data.Class)
 		}
 
-		if ctx.ModuleHasProvider(module, JavaInfoProvider) {
-			dep := ctx.ModuleProvider(module, JavaInfoProvider).(JavaInfo)
+		if dep, ok := android.SingletonModuleProvider(ctx, module, JavaInfoProvider); ok {
 			dpInfo.Installed_paths = append(dpInfo.Installed_paths, dep.ImplementationJars.Strings()...)
 		}
 		dpInfo.Classes = android.FirstUniqueStrings(dpInfo.Classes)
diff --git a/java/kotlin.go b/java/kotlin.go
index 3637e2e..aa2db0e 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -145,7 +145,7 @@
 			`$kaptProcessorPath ` +
 			`$kaptProcessor ` +
 			`-Xbuild-file=$kotlinBuildFile && ` +
-			`${config.SoongZipCmd} -jar -o $out -C $kaptDir/stubs -D $kaptDir/stubs && ` +
+			`${config.SoongZipCmd} -jar -write_if_changed -o $out -C $kaptDir/stubs -D $kaptDir/stubs && ` +
 			`rm -rf "$srcJarDir"`,
 		CommandDeps: []string{
 			"${config.KotlincCmd}",
@@ -157,6 +157,7 @@
 		},
 		Rspfile:        "$out.rsp",
 		RspfileContent: `$in`,
+		Restat:         true,
 	},
 	"kotlincFlags", "encodedJavacFlags", "kaptProcessorPath", "kaptProcessor",
 	"classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "kaptDir", "kotlinJvmTarget",
diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go
index 6cb549e..4be7d04 100644
--- a/java/legacy_core_platform_api_usage.go
+++ b/java/legacy_core_platform_api_usage.go
@@ -28,6 +28,7 @@
 	"FloralClocks",
 	"framework-jobscheduler",
 	"framework-minus-apex",
+	"framework-minus-apex-headers",
 	"framework-minus-apex-intdefs",
 	"FrameworksCoreTests",
 	"HelloOslo",
diff --git a/java/lint.go b/java/lint.go
index f84f1c0..31e7f35 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -17,7 +17,6 @@
 import (
 	"fmt"
 	"sort"
-	"strconv"
 	"strings"
 
 	"github.com/google/blueprint/proptools"
@@ -56,7 +55,8 @@
 		// Modules that provide extra lint checks
 		Extra_check_modules []string
 
-		// Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml".
+		// The lint baseline file to use. If specified, lint warnings listed in this file will be
+		// suppressed during lint checks.
 		Baseline_filename *string
 
 		// If true, baselining updatability lint checks (e.g. NewApi) is prohibited. Defaults to false.
@@ -66,6 +66,10 @@
 		// This will be true by default for test module types, false otherwise.
 		// If soong gets support for testonly, this flag should be replaced with that.
 		Test *bool
+
+		// Whether to ignore the exit code of Android lint. This is the --exit_code
+		// option. Defaults to false.
+		Suppress_exit_code *bool
 	}
 }
 
@@ -80,15 +84,16 @@
 	classes                 android.Path
 	extraLintCheckJars      android.Paths
 	library                 bool
-	minSdkVersion           int
-	targetSdkVersion        int
-	compileSdkVersion       int
+	minSdkVersion           android.ApiLevel
+	targetSdkVersion        android.ApiLevel
+	compileSdkVersion       android.ApiLevel
 	compileSdkKind          android.SdkKind
 	javaLanguageLevel       string
 	kotlinLanguageLevel     string
 	outputs                 lintOutputs
 	properties              LintProperties
 	extraMainlineLintErrors []string
+	compile_data            android.Paths
 
 	reports android.Paths
 
@@ -352,33 +357,26 @@
 		Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
 		Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
 		Text(`echo "    android:versionCode='1' android:versionName='1' >" &&`).
-		Textf(`echo "  <uses-sdk android:minSdkVersion='%d' android:targetSdkVersion='%d'/>" &&`,
-			l.minSdkVersion, l.targetSdkVersion).
+		Textf(`echo "  <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
+			l.minSdkVersion.String(), l.targetSdkVersion.String()).
 		Text(`echo "</manifest>"`).
 		Text(") >").Output(manifestPath)
 
 	return manifestPath
 }
 
-func (l *linter) getBaselineFilepath(ctx android.ModuleContext) android.OptionalPath {
-	var lintBaseline android.OptionalPath
-	if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
-		if String(l.properties.Lint.Baseline_filename) != "" {
-			// if manually specified, we require the file to exist
-			lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
-		} else {
-			lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
-		}
-	}
-	return lintBaseline
-}
-
 func (l *linter) lint(ctx android.ModuleContext) {
 	if !l.enabled() {
 		return
 	}
 
-	if l.minSdkVersion != l.compileSdkVersion {
+	for _, flag := range l.properties.Lint.Flags {
+		if strings.Contains(flag, "--disable") || strings.Contains(flag, "--enable") || strings.Contains(flag, "--check") {
+			ctx.PropertyErrorf("lint.flags", "Don't use --disable, --enable, or --check in the flags field, instead use the dedicated disabled_checks, warning_checks, error_checks, or fatal_checks fields")
+		}
+	}
+
+	if l.minSdkVersion.CompareTo(l.compileSdkVersion) == -1 {
 		l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
 		// Skip lint warning checks for NewApi warnings for libcore where they come from source
 		// files that reference the API they are adding (b/208656169).
@@ -408,8 +406,7 @@
 
 	extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
 	for _, extraLintCheckModule := range extraLintCheckModules {
-		if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
-			dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
+		if dep, ok := android.OtherModuleProvider(ctx, extraLintCheckModule, JavaInfoProvider); ok {
 			l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
 		} else {
 			ctx.PropertyErrorf("lint.extra_check_modules",
@@ -444,7 +441,7 @@
 
 	srcsList := android.PathForModuleOut(ctx, "lint", "lint-srcs.list")
 	srcsListRsp := android.PathForModuleOut(ctx, "lint-srcs.list.rsp")
-	rule.Command().Text("cp").FlagWithRspFileInputList("", srcsListRsp, l.srcs).Output(srcsList)
+	rule.Command().Text("cp").FlagWithRspFileInputList("", srcsListRsp, l.srcs).Output(srcsList).Implicits(l.compile_data)
 
 	lintPaths := l.writeLintProjectXML(ctx, rule, srcsList)
 
@@ -487,12 +484,13 @@
 
 	cmd.BuiltTool("lint").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "lint.jar")).
 		Flag("--quiet").
+		Flag("--include-aosp-issues").
 		FlagWithInput("--project ", lintPaths.projectXML).
 		FlagWithInput("--config ", lintPaths.configXML).
 		FlagWithOutput("--html ", html).
 		FlagWithOutput("--text ", text).
 		FlagWithOutput("--xml ", xml).
-		FlagWithArg("--compile-sdk-version ", strconv.Itoa(l.compileSdkVersion)).
+		FlagWithArg("--compile-sdk-version ", l.compileSdkVersion.String()).
 		FlagWithArg("--java-language-level ", l.javaLanguageLevel).
 		FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
 		FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
@@ -504,7 +502,8 @@
 	rule.Temporary(lintPaths.projectXML)
 	rule.Temporary(lintPaths.configXML)
 
-	if exitCode := ctx.Config().Getenv("ANDROID_LINT_SUPPRESS_EXIT_CODE"); exitCode == "" {
+	suppressExitCode := BoolDefault(l.properties.Lint.Suppress_exit_code, false)
+	if exitCode := ctx.Config().Getenv("ANDROID_LINT_SUPPRESS_EXIT_CODE"); exitCode == "" && !suppressExitCode {
 		cmd.Flag("--exitcode")
 	}
 
@@ -512,9 +511,8 @@
 		cmd.FlagWithArg("--check ", checkOnly)
 	}
 
-	lintBaseline := l.getBaselineFilepath(ctx)
-	if lintBaseline.Valid() {
-		cmd.FlagWithInput("--baseline ", lintBaseline.Path())
+	if l.properties.Lint.Baseline_filename != nil {
+		cmd.FlagWithInput("--baseline ", android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename))
 	}
 
 	cmd.FlagWithOutput("--write-reference-baseline ", referenceBaseline)
@@ -550,6 +548,10 @@
 	if l.buildModuleReportZip {
 		l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
 	}
+
+	// Create a per-module phony target to run the lint check.
+	phonyName := ctx.ModuleName() + "-lint"
+	ctx.Phony(phonyName, xml)
 }
 
 func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
@@ -654,7 +656,7 @@
 		}
 
 		if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
-			apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
+			apexInfo, _ := android.SingletonModuleProvider(ctx, m, android.ApexInfoProvider)
 			if apexInfo.IsForPlatform() {
 				// There are stray platform variants of modules in apexes that are not available for
 				// the platform, and they sometimes can't be built.  Don't depend on them.
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
index 8494d02..b8ce95c 100644
--- a/java/lint_defaults.txt
+++ b/java/lint_defaults.txt
@@ -122,10 +122,10 @@
 --warning_check RemoteViewLayout
 --warning_check SupportAnnotationUsage
 --warning_check UniqueConstants
-
-# TODO(b/294098365): these checks fail in AOSP, but pass downstream
---warning_check ForegroundServiceType
---warning_check MutableImplicitPendingIntent
+--warning_check UseSdkSuppress
+# TODO(b/303434307) The intent is for this to be set to error severity
+# once existing violations are cleaned up
+--warning_check FlaggedApi
 
 --warning_check ExactAlarm
 --warning_check ExpiredTargetSdkVersion
diff --git a/java/lint_test.go b/java/lint_test.go
index ec901aa..751b139 100644
--- a/java/lint_test.go
+++ b/java/lint_test.go
@@ -21,7 +21,7 @@
 	"android/soong/android"
 )
 
-func TestJavaLint(t *testing.T) {
+func TestJavaLintDoesntUseBaselineImplicitly(t *testing.T) {
 	ctx, _ := testJavaWithFS(t, `
 		java_library {
 			name: "foo",
@@ -39,31 +39,9 @@
 
 	foo := ctx.ModuleForTests("foo", "android_common")
 
-	sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
-	if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml") {
-		t.Error("did not pass --baseline flag")
-	}
-}
-
-func TestJavaLintWithoutBaseline(t *testing.T) {
-	ctx, _ := testJavaWithFS(t, `
-		java_library {
-			name: "foo",
-			srcs: [
-				"a.java",
-				"b.java",
-				"c.java",
-			],
-			min_sdk_version: "29",
-			sdk_version: "system_current",
-		}
-       `, map[string][]byte{})
-
-	foo := ctx.ModuleForTests("foo", "android_common")
-
-	sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
-	if strings.Contains(*sboxProto.Commands[0].Command, "--baseline") {
-		t.Error("passed --baseline flag for non existent file")
+	sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx, foo.Output("lint.sbox.textproto"))
+	if strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml") {
+		t.Error("Passed --baseline flag when baseline_filename was not set")
 	}
 }
 
@@ -108,7 +86,7 @@
 
 	foo := ctx.ModuleForTests("foo", "android_common")
 
-	sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
+	sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx, foo.Output("lint.sbox.textproto"))
 	if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline mybaseline.xml") {
 		t.Error("did not use the correct file for baseline")
 	}
@@ -276,9 +254,28 @@
 			RunTestWithBp(t, thisBp)
 
 		foo := result.ModuleForTests("foo", "android_common")
-		sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
+		sboxProto := android.RuleBuilderSboxProtoForTests(t, result.TestContext, foo.Output("lint.sbox.textproto"))
 		if !strings.Contains(*sboxProto.Commands[0].Command, "/"+testCase.expected_file) {
 			t.Error("did not use full api database for case", testCase)
 		}
 	}
 }
+
+func TestCantControlCheckSeverityWithFlags(t *testing.T) {
+	bp := `
+		java_library {
+			name: "foo",
+			srcs: [
+				"a.java",
+			],
+			min_sdk_version: "29",
+			sdk_version: "current",
+			lint: {
+				flags: ["--disabled", "NewApi"],
+			},
+		}
+	`
+	PrepareForTestWithJavaDefaultModules.
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Don't use --disable, --enable, or --check in the flags field, instead use the dedicated disabled_checks, warning_checks, error_checks, or fatal_checks fields")).
+		RunTestWithBp(t, bp)
+}
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index ade7395..4db426e 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -57,6 +57,9 @@
 
 	// Path to the monolithic hiddenapi-unsupported.csv file.
 	hiddenAPIMetadataCSV android.OutputPath
+
+	// Path to a srcjar containing all the transitive sources of the bootclasspath.
+	srcjar android.OutputPath
 }
 
 type platformBootclasspathProperties struct {
@@ -95,12 +98,17 @@
 		return android.Paths{b.hiddenAPIIndexCSV}, nil
 	case "hiddenapi-metadata.csv":
 		return android.Paths{b.hiddenAPIMetadataCSV}, nil
+	case ".srcjar":
+		return android.Paths{b.srcjar}, nil
 	}
 
 	return nil, fmt.Errorf("unknown tag %s", tag)
 }
 
 func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// Create a dependency on all_apex_contributions to determine the selected mainline module
+	ctx.AddDependency(ctx.Module(), apexContributionsMetadataDepTag, "all_apex_contributions")
+
 	b.hiddenAPIDepsMutator(ctx)
 
 	if !dexpreopt.IsDex2oatNeeded(ctx) {
@@ -125,6 +133,8 @@
 func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
 	// Add dependencies on all the ART jars.
 	global := dexpreopt.GetGlobalConfig(ctx)
+	addDependenciesOntoSelectedBootImageApexes(ctx, "com.android.art")
+	// TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly
 	addDependenciesOntoBootImageModules(ctx, global.ArtApexJars, platformBootclasspathArtBootJarDepTag)
 
 	// Add dependencies on all the non-updatable jars, which are on the platform or in non-updatable
@@ -133,6 +143,12 @@
 
 	// Add dependencies on all the updatable jars, except the ART jars.
 	apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
+	apexes := []string{}
+	for i := 0; i < apexJars.Len(); i++ {
+		apexes = append(apexes, apexJars.Apex(i))
+	}
+	addDependenciesOntoSelectedBootImageApexes(ctx, android.FirstUniqueStrings(apexes)...)
+	// TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly
 	addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag)
 
 	// Add dependencies on all the fragments.
@@ -173,6 +189,18 @@
 	allModules = append(allModules, apexModules...)
 	b.configuredModules = allModules
 
+	var transitiveSrcFiles android.Paths
+	for _, module := range allModules {
+		depInfo, _ := android.OtherModuleProvider(ctx, module, JavaInfoProvider)
+		if depInfo.TransitiveSrcFiles != nil {
+			transitiveSrcFiles = append(transitiveSrcFiles, depInfo.TransitiveSrcFiles.ToList()...)
+		}
+	}
+	jarArgs := resourcePathsToJarArgs(transitiveSrcFiles)
+	jarArgs = append(jarArgs, "-srcjar") // Move srcfiles to the right package
+	b.srcjar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-transitive.srcjar").OutputPath
+	TransformResourcesToJar(ctx, b.srcjar, jarArgs, transitiveSrcFiles)
+
 	// Gather all the fragments dependencies.
 	b.fragments = gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag)
 
@@ -185,8 +213,6 @@
 
 	bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments)
 	buildRuleForBootJarsPackageCheck(ctx, bootDexJarByModule)
-
-	b.copyApexBootJarsForAppsDexpreopt(ctx, apexModules)
 }
 
 // Generate classpaths.proto config
@@ -204,7 +230,7 @@
 	// Include jars from APEXes that don't populate their classpath proto config.
 	remainingJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
 	for _, fragment := range b.fragments {
-		info := ctx.OtherModuleProvider(fragment, ClasspathFragmentProtoContentInfoProvider).(ClasspathFragmentProtoContentInfo)
+		info, _ := android.OtherModuleProvider(ctx, fragment, ClasspathFragmentProtoContentInfoProvider)
 		if info.ClasspathFragmentProtoGenerated {
 			remainingJars = remainingJars.RemoveList(info.ClasspathFragmentProtoContents)
 		}
@@ -226,7 +252,7 @@
 func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleContext, modules []android.Module) {
 	// TODO(satayev): change this check to only allow core-icu4j, all apex jars should not be here.
 	for _, m := range modules {
-		apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
+		apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider)
 		fromUpdatableApex := apexInfo.Updatable
 		if fromUpdatableApex {
 			// error: this jar is part of an updatable apex
@@ -240,7 +266,7 @@
 // checkApexModules ensures that the apex modules supplied are not from the platform.
 func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext, modules []android.Module) {
 	for _, m := range modules {
-		apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
+		apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider)
 		fromUpdatableApex := apexInfo.Updatable
 		if fromUpdatableApex {
 			// ok: this jar is part of an updatable apex
@@ -374,7 +400,7 @@
 	monolithicInfo := newMonolithicHiddenAPIInfo(ctx, temporaryInput.FlagFilesByCategory, classpathElements)
 
 	// Store the information for testing.
-	ctx.SetProvider(MonolithicHiddenAPIInfoProvider, monolithicInfo)
+	android.SetProvider(ctx, MonolithicHiddenAPIInfoProvider, monolithicInfo)
 	return monolithicInfo
 }
 
@@ -398,10 +424,3 @@
 	// INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/.
 	ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", b.hiddenAPIFlagsCSV.String())
 }
-
-// Copy apex module dex jars to their predefined locations. They will be used for dexpreopt for apps.
-func (b *platformBootclasspathModule) copyApexBootJarsForAppsDexpreopt(ctx android.ModuleContext, apexModules []android.Module) {
-	config := GetApexBootConfig(ctx)
-	apexBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, apexModules)
-	copyBootJarsToPredefinedLocations(ctx, apexBootDexJarsByModule, config.dexPathsByModule)
-}
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index ff2da4b..37ff639 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -81,6 +81,15 @@
 			RunTest(t)
 	})
 
+	fooSourceSrc := "source/a.java"
+	barSrc := "a.java"
+
+	checkSrcJarInputs := func(t *testing.T, result *android.TestResult, name string, expected []string) {
+		t.Helper()
+		srcjar := result.ModuleForTests(name, "android_common").Output(name + "-transitive.srcjar")
+		android.AssertStringDoesContain(t, "srcjar arg", srcjar.Args["jarArgs"], "-srcjar")
+		android.AssertArrayString(t, "srcjar inputs", expected, srcjar.Implicits.Strings())
+	}
 	t.Run("source", func(t *testing.T) {
 		result := android.GroupFixturePreparers(
 			preparer,
@@ -91,6 +100,10 @@
 			"platform:foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			fooSourceSrc,
+			barSrc,
+		})
 	})
 
 	t.Run("prebuilt", func(t *testing.T) {
@@ -103,6 +116,10 @@
 			"platform:prebuilt_foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			// TODO(b/151360309): This should also have the srcs for prebuilt_foo
+			barSrc,
+		})
 	})
 
 	t.Run("source+prebuilt - source preferred", func(t *testing.T) {
@@ -116,6 +133,10 @@
 			"platform:foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			fooSourceSrc,
+			barSrc,
+		})
 	})
 
 	t.Run("source+prebuilt - prebuilt preferred", func(t *testing.T) {
@@ -129,6 +150,10 @@
 			"platform:prebuilt_foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			// TODO(b/151360309): This should also have the srcs for prebuilt_foo
+			barSrc,
+		})
 	})
 
 	t.Run("dex import", func(t *testing.T) {
@@ -146,6 +171,10 @@
 			"platform:prebuilt_foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			// TODO(b/151360309): This should also have the srcs for prebuilt_foo
+			barSrc,
+		})
 	})
 }
 
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index 1248275..2fc6c02 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -19,8 +19,6 @@
 	"path/filepath"
 
 	"android/soong/android"
-	"android/soong/bazel"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -57,7 +55,6 @@
 
 type platformCompatConfig struct {
 	android.ModuleBase
-	android.BazelModuleBase
 
 	properties     platformCompatConfigProperties
 	installDirPath android.InstallPath
@@ -126,29 +123,10 @@
 	}}
 }
 
-type bazelPlatformCompatConfigAttributes struct {
-	Src bazel.LabelAttribute
-}
-
-func (p *platformCompatConfig) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "platform_compat_config",
-		Bzl_load_location: "//build/bazel/rules/java:platform_compat_config.bzl",
-	}
-	attr := &bazelPlatformCompatConfigAttributes{
-		Src: *bazel.MakeLabelAttribute(
-			android.BazelLabelForModuleSrcSingle(ctx, proptools.String(p.properties.Src)).Label),
-	}
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-		Name: p.Name(),
-	}, attr)
-}
-
 func PlatformCompatConfigFactory() android.Module {
 	module := &platformCompatConfig{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
-	android.InitBazelModule(module)
 	return module
 }
 
@@ -207,6 +185,11 @@
 
 type prebuiltCompatConfigProperties struct {
 	Metadata *string `android:"path"`
+
+	// Name of the source soong module that gets shadowed by this prebuilt
+	// If unspecified, follows the naming convention that the source module of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_module_name *string
 }
 
 func (module *prebuiltCompatConfigModule) Prebuilt() *android.Prebuilt {
@@ -221,6 +204,10 @@
 	return module.metadataFile
 }
 
+func (module *prebuiltCompatConfigModule) BaseModuleName() string {
+	return proptools.StringDefault(module.properties.Source_module_name, module.ModuleBase.Name())
+}
+
 var _ platformCompatConfigMetadataProvider = (*prebuiltCompatConfigModule)(nil)
 
 func (module *prebuiltCompatConfigModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
diff --git a/java/plugin.go b/java/plugin.go
index 5127298..9c4774a 100644
--- a/java/plugin.go
+++ b/java/plugin.go
@@ -16,7 +16,6 @@
 
 import (
 	"android/soong/android"
-	"android/soong/bazel"
 )
 
 func init() {
@@ -35,8 +34,6 @@
 
 	InitJavaModule(module, android.HostSupported)
 
-	android.InitBazelModule(module)
-
 	return module
 }
 
@@ -56,38 +53,3 @@
 	// parallelism and cause more recompilation for modules that depend on modules that use this plugin.
 	Generates_api *bool
 }
-
-type pluginAttributes struct {
-	*javaCommonAttributes
-	Deps            bazel.LabelListAttribute
-	Processor_class *string
-}
-
-// ConvertWithBp2build is used to convert android_app to Bazel.
-func (p *Plugin) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	pluginName := p.Name()
-	commonAttrs, bp2BuildInfo, supported := p.convertLibraryAttrsBp2Build(ctx)
-	if !supported {
-		return
-	}
-	depLabels := bp2BuildInfo.DepLabels
-
-	deps := depLabels.Deps
-	deps.Append(depLabels.StaticDeps)
-
-	var processorClass *string
-	if p.pluginProperties.Processor_class != nil {
-		processorClass = p.pluginProperties.Processor_class
-	}
-
-	attrs := &pluginAttributes{
-		javaCommonAttributes: commonAttrs,
-		Deps:                 deps,
-		Processor_class:      processorClass,
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class: "java_plugin",
-	}
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: pluginName}, attrs)
-}
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 044802e..00613ee 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -55,6 +55,11 @@
 
 	// If set to true, compile dex for java_import modules. Defaults to false.
 	Imports_compile_dex *bool
+
+	// If set to true, allow incremental platform API of the form MM.m where MM is the major release
+	// version corresponding to the API level/SDK_INT and m is an incremental release version
+	// (e.g. API changes associated with QPR). Defaults to false.
+	Allow_incremental_platform_api *bool
 }
 
 type prebuiltApis struct {
@@ -69,6 +74,8 @@
 // parsePrebuiltPath parses the relevant variables out of a variety of paths, e.g.
 // <version>/<scope>/<module>.jar
 // <version>/<scope>/api/<module>.txt
+// *Note when using incremental platform API, <version> may be of the form MM.m where MM is the
+// API level and m is an incremental release, otherwise <version> is a single integer corresponding to the API level only.
 // extensions/<version>/<scope>/<module>.jar
 // extensions/<version>/<scope>/api/<module>.txt
 func parsePrebuiltPath(ctx android.LoadHookContext, p string) (module string, version string, scope string) {
@@ -90,8 +97,25 @@
 }
 
 // parseFinalizedPrebuiltPath is like parsePrebuiltPath, but verifies the version is numeric (a finalized version).
-func parseFinalizedPrebuiltPath(ctx android.LoadHookContext, p string) (module string, version int, scope string) {
+func parseFinalizedPrebuiltPath(ctx android.LoadHookContext, p string, allowIncremental bool) (module string, version int, release int, scope string) {
 	module, v, scope := parsePrebuiltPath(ctx, p)
+	if allowIncremental {
+		parts := strings.Split(v, ".")
+		if len(parts) != 2 {
+			ctx.ModuleErrorf("Found unexpected version '%v' for incremental prebuilts - expect MM.m format for incremental API with both major (MM) an minor (m) revision.", v)
+			return
+		}
+		sdk, sdk_err := strconv.Atoi(parts[0])
+		qpr, qpr_err := strconv.Atoi(parts[1])
+		if sdk_err != nil || qpr_err != nil {
+			ctx.ModuleErrorf("Unable to read version number for incremental prebuilt api '%v'", v)
+			return
+		}
+		version = sdk
+		release = qpr
+		return
+	}
+	release = 0
 	version, err := strconv.Atoi(v)
 	if err != nil {
 		ctx.ModuleErrorf("Found finalized API files in non-numeric dir '%v'", v)
@@ -103,41 +127,13 @@
 func prebuiltApiModuleName(mctx android.LoadHookContext, module, scope, version string) string {
 	return fmt.Sprintf("%s_%s_%s_%s", mctx.ModuleName(), scope, version, module)
 }
-
-func hasBazelPrebuilt(module string) bool {
-	return module == "android" || module == "core-for-system-modules"
-}
-
-func bazelPrebuiltApiModuleName(module, scope, version string) string {
-	bazelModule := module
-	switch module {
-	case "android":
-		bazelModule = "android_jar"
-	case "core-for-system-modules":
-		bazelModule = "core_jar"
-	}
-	bazelVersion := version
-	if version == "current" {
-		bazelVersion = strconv.Itoa(android.FutureApiLevelInt)
-	}
-	bazelScope := scope
-	switch scope {
-	case "module-lib":
-		bazelScope = "module"
-	case "system-server":
-		bazelScope = "system_server"
-	}
-	return fmt.Sprintf("//prebuilts/sdk:%s_%s_%s", bazelScope, bazelVersion, bazelModule)
-}
-
 func createImport(mctx android.LoadHookContext, module, scope, version, path, sdkVersion string, compileDex bool) {
 	props := struct {
-		Name         *string
-		Jars         []string
-		Sdk_version  *string
-		Installable  *bool
-		Compile_dex  *bool
-		Bazel_module android.BazelModuleProperties
+		Name        *string
+		Jars        []string
+		Sdk_version *string
+		Installable *bool
+		Compile_dex *bool
 	}{
 		Name:        proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, version)),
 		Jars:        []string{path},
@@ -145,10 +141,6 @@
 		Installable: proptools.BoolPtr(false),
 		Compile_dex: proptools.BoolPtr(compileDex),
 	}
-	if hasBazelPrebuilt(module) {
-		props.Bazel_module = android.BazelModuleProperties{
-			Label: proptools.StringPtr(bazelPrebuiltApiModuleName(module, scope, version))}
-	}
 	mctx.CreateModule(ImportFactory, &props)
 }
 
@@ -166,6 +158,21 @@
 	mctx.CreateModule(genrule.GenRuleFactory, &genruleProps)
 }
 
+func createCombinedApiFilegroupModule(mctx android.LoadHookContext, name string, srcs []string) {
+	filegroupProps := struct {
+		Name *string
+		Srcs []string
+	}{}
+	filegroupProps.Name = proptools.StringPtr(name)
+
+	var transformedSrcs []string
+	for _, src := range srcs {
+		transformedSrcs = append(transformedSrcs, ":"+src)
+	}
+	filegroupProps.Srcs = transformedSrcs
+	mctx.CreateModule(android.FileGroupFactory, &filegroupProps)
+}
+
 func createLatestApiModuleExtensionVersionFile(mctx android.LoadHookContext, name string, version string) {
 	genruleProps := struct {
 		Name *string
@@ -260,6 +267,10 @@
 	return module + ".api." + scope + "." + version
 }
 
+func PrebuiltApiCombinedModuleName(module, scope, version string) string {
+	return module + ".api.combined." + scope + "." + version
+}
+
 func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) {
 	// <apiver>/<scope>/api/<module>.txt
 	apiLevelFiles := globApiDirs(mctx, p, "api/*.txt")
@@ -268,29 +279,35 @@
 	}
 
 	// Create modules for all (<module>, <scope, <version>) triplets,
+	allowIncremental := proptools.BoolDefault(p.properties.Allow_incremental_platform_api, false)
 	for _, f := range apiLevelFiles {
-		module, version, scope := parseFinalizedPrebuiltPath(mctx, f)
-		createApiModule(mctx, PrebuiltApiModuleName(module, scope, strconv.Itoa(version)), f)
+		module, version, release, scope := parseFinalizedPrebuiltPath(mctx, f, allowIncremental)
+		if allowIncremental {
+			incrementalVersion := strconv.Itoa(version) + "." + strconv.Itoa(release)
+			createApiModule(mctx, PrebuiltApiModuleName(module, scope, incrementalVersion), f)
+		} else {
+			createApiModule(mctx, PrebuiltApiModuleName(module, scope, strconv.Itoa(version)), f)
+		}
 	}
 
 	// Figure out the latest version of each module/scope
 	type latestApiInfo struct {
 		module, scope, path string
-		version             int
+		version, release    int
 		isExtensionApiFile  bool
 	}
 
 	getLatest := func(files []string, isExtensionApiFile bool) map[string]latestApiInfo {
 		m := make(map[string]latestApiInfo)
 		for _, f := range files {
-			module, version, scope := parseFinalizedPrebuiltPath(mctx, f)
+			module, version, release, scope := parseFinalizedPrebuiltPath(mctx, f, allowIncremental)
 			if strings.HasSuffix(module, "incompatibilities") {
 				continue
 			}
 			key := module + "." + scope
 			info, exists := m[key]
-			if !exists || version > info.version {
-				m[key] = latestApiInfo{module, scope, f, version, isExtensionApiFile}
+			if !exists || version > info.version || (version == info.version && release > info.release) {
+				m[key] = latestApiInfo{module, scope, f, version, release, isExtensionApiFile}
 			}
 		}
 		return m
@@ -309,7 +326,9 @@
 	}
 
 	// Sort the keys in order to make build.ninja stable
-	for _, k := range android.SortedKeys(latest) {
+	sortedLatestKeys := android.SortedKeys(latest)
+
+	for _, k := range sortedLatestKeys {
 		info := latest[k]
 		name := PrebuiltApiModuleName(info.module, info.scope, "latest")
 		latestExtensionVersionModuleName := PrebuiltApiModuleName(info.module, info.scope, "latest.extension_version")
@@ -335,11 +354,38 @@
 		}
 	}
 	// Create empty incompatibilities files for remaining modules
-	for _, k := range android.SortedKeys(latest) {
+	// If the incompatibility module has been created, create a corresponding combined module
+	for _, k := range sortedLatestKeys {
 		if _, ok := incompatibilities[k]; !ok {
 			createEmptyFile(mctx, PrebuiltApiModuleName(latest[k].module+"-incompatibilities", latest[k].scope, "latest"))
 		}
 	}
+
+	// Create combined latest api and removed api files modules.
+	// The combined modules list all api files of the api scope and its subset api scopes.
+	for _, k := range sortedLatestKeys {
+		info := latest[k]
+		name := PrebuiltApiCombinedModuleName(info.module, info.scope, "latest")
+
+		// Iterate until the currentApiScope does not extend any other api scopes
+		// i.e. is not a superset of any other api scopes
+		// the relationship between the api scopes is defined in java/sdk_library.go
+		var srcs []string
+		currentApiScope := scopeByName[info.scope]
+		for currentApiScope != nil {
+			if _, ok := latest[fmt.Sprintf("%s.%s", info.module, currentApiScope.name)]; ok {
+				srcs = append(srcs, PrebuiltApiModuleName(info.module, currentApiScope.name, "latest"))
+			}
+			currentApiScope = currentApiScope.extends
+		}
+
+		// srcs is currently listed in the order from the widest api scope to the narrowest api scopes
+		// e.g. module lib -> system -> public
+		// In order to pass the files in metalava from the narrowest api scope to the widest api scope,
+		// the list has to be reversed.
+		android.ReverseSliceInPlace(srcs)
+		createCombinedApiFilegroupModule(mctx, name, srcs)
+	}
 }
 
 func createPrebuiltApiModules(mctx android.LoadHookContext) {
diff --git a/java/prebuilt_apis_test.go b/java/prebuilt_apis_test.go
index 2b84353..b6fb2c6 100644
--- a/java/prebuilt_apis_test.go
+++ b/java/prebuilt_apis_test.go
@@ -99,3 +99,26 @@
 	android.AssertStringEquals(t, "Expected latest bar = extension level 2", "prebuilts/sdk/extensions/2/public/api/bar.txt", bar_input)
 	android.AssertStringEquals(t, "Expected latest baz = api level 32", "prebuilts/sdk/32/public/api/baz.txt", baz_input)
 }
+
+func TestPrebuiltApis_WithIncrementalApi(t *testing.T) {
+	runTestWithIncrementalApi := func() (foo_input, bar_input, baz_input string) {
+		result := android.GroupFixturePreparers(
+			prepareForJavaTest,
+			FixtureWithPrebuiltIncrementalApis(map[string][]string{
+				"33.0":    {"foo"},
+				"33.1":    {"foo", "bar", "baz"},
+				"33.2":    {"foo", "bar"},
+				"current": {"foo", "bar"},
+			}),
+		).RunTest(t)
+		foo_input = result.ModuleForTests("foo.api.public.latest", "").Rule("generator").Implicits[0].String()
+		bar_input = result.ModuleForTests("bar.api.public.latest", "").Rule("generator").Implicits[0].String()
+		baz_input = result.ModuleForTests("baz.api.public.latest", "").Rule("generator").Implicits[0].String()
+		return
+	}
+	// 33.1 is the latest for baz, 33.2 is the latest for both foo & bar
+	foo_input, bar_input, baz_input := runTestWithIncrementalApi()
+	android.AssertStringEquals(t, "Expected latest foo = api level 33.2", "prebuilts/sdk/33.2/public/api/foo.txt", foo_input)
+	android.AssertStringEquals(t, "Expected latest bar = api level 33.2", "prebuilts/sdk/33.2/public/api/bar.txt", bar_input)
+	android.AssertStringEquals(t, "Expected latest baz = api level 33.1", "prebuilts/sdk/33.1/public/api/baz.txt", baz_input)
+}
diff --git a/java/proto.go b/java/proto.go
index c732d98..e27ef2c 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -19,9 +19,6 @@
 	"strconv"
 
 	"android/soong/android"
-	"android/soong/bazel"
-
-	"github.com/google/blueprint/proptools"
 )
 
 const (
@@ -141,57 +138,3 @@
 
 	return flags
 }
-
-type protoAttributes struct {
-	Deps         bazel.LabelListAttribute
-	Sdk_version  bazel.StringAttribute
-	Java_version bazel.StringAttribute
-}
-
-func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) *bazel.Label {
-	protoInfo, ok := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, protoSrcs)
-	if !ok {
-		return nil
-	}
-
-	typ := proptools.StringDefault(protoInfo.Type, protoTypeDefault)
-	var rule_class string
-	suffix := "_java_proto"
-	switch typ {
-	case "nano":
-		suffix += "_nano"
-		rule_class = "java_nano_proto_library"
-	case "micro":
-		suffix += "_micro"
-		rule_class = "java_micro_proto_library"
-	case "lite":
-		suffix += "_lite"
-		rule_class = "java_lite_proto_library"
-	case "stream":
-		suffix += "_stream"
-		rule_class = "java_stream_proto_library"
-	case "full":
-		rule_class = "java_proto_library"
-	default:
-		ctx.PropertyErrorf("proto.type", "cannot handle conversion at this time: %q", typ)
-	}
-
-	protoLabel := bazel.Label{Label: ":" + m.Name() + "_proto"}
-	protoAttrs := &protoAttributes{
-		Deps:         bazel.MakeSingleLabelListAttribute(protoLabel),
-		Java_version: bazel.StringAttribute{Value: m.properties.Java_version},
-		Sdk_version:  bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
-	}
-
-	name := m.Name() + suffix
-
-	ctx.CreateBazelTargetModule(
-		bazel.BazelTargetModuleProperties{
-			Rule_class:        rule_class,
-			Bzl_load_location: "//build/bazel/rules/java:proto.bzl",
-		},
-		android.CommonAttributes{Name: name},
-		protoAttrs)
-
-	return &bazel.Label{Label: ":" + name}
-}
diff --git a/java/ravenwood.go b/java/ravenwood.go
new file mode 100644
index 0000000..908619d
--- /dev/null
+++ b/java/ravenwood.go
@@ -0,0 +1,278 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package java
+
+import (
+	"android/soong/android"
+	"android/soong/tradefed"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+func init() {
+	RegisterRavenwoodBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterRavenwoodBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("android_ravenwood_test", ravenwoodTestFactory)
+	ctx.RegisterModuleType("android_ravenwood_libgroup", ravenwoodLibgroupFactory)
+}
+
+var ravenwoodLibContentTag = dependencyTag{name: "ravenwoodlibcontent"}
+var ravenwoodUtilsTag = dependencyTag{name: "ravenwoodutils"}
+var ravenwoodRuntimeTag = dependencyTag{name: "ravenwoodruntime"}
+
+const ravenwoodUtilsName = "ravenwood-utils"
+const ravenwoodRuntimeName = "ravenwood-runtime"
+
+type ravenwoodLibgroupJniDepProviderInfo struct {
+	// All the jni_libs module names with transient dependencies.
+	names map[string]bool
+}
+
+var ravenwoodLibgroupJniDepProvider = blueprint.NewProvider[ravenwoodLibgroupJniDepProviderInfo]()
+
+func getLibPath(archType android.ArchType) string {
+	if archType.Multilib == "lib64" {
+		return "lib64"
+	}
+	return "lib"
+}
+
+type ravenwoodTestProperties struct {
+	Jni_libs []string
+}
+
+type ravenwoodTest struct {
+	Library
+
+	ravenwoodTestProperties ravenwoodTestProperties
+
+	testProperties testProperties
+	testConfig     android.Path
+
+	forceOSType   android.OsType
+	forceArchType android.ArchType
+}
+
+func ravenwoodTestFactory() android.Module {
+	module := &ravenwoodTest{}
+
+	module.addHostAndDeviceProperties()
+	module.AddProperties(&module.testProperties, &module.ravenwoodTestProperties)
+
+	module.Module.dexpreopter.isTest = true
+	module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
+
+	module.testProperties.Test_suites = []string{
+		"general-tests",
+		"ravenwood-tests",
+	}
+	module.testProperties.Test_options.Unit_test = proptools.BoolPtr(false)
+
+	InitJavaModule(module, android.DeviceSupported)
+	android.InitDefaultableModule(module)
+
+	return module
+}
+
+func (r *ravenwoodTest) InstallInTestcases() bool { return true }
+func (r *ravenwoodTest) InstallForceOS() (*android.OsType, *android.ArchType) {
+	return &r.forceOSType, &r.forceArchType
+}
+func (r *ravenwoodTest) TestSuites() []string {
+	return r.testProperties.Test_suites
+}
+
+func (r *ravenwoodTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+	r.Library.DepsMutator(ctx)
+
+	// Generically depend on the runtime so that it's installed together with us
+	ctx.AddVariationDependencies(nil, ravenwoodRuntimeTag, ravenwoodRuntimeName)
+
+	// Directly depend on any utils so that we link against them
+	utils := ctx.AddVariationDependencies(nil, ravenwoodUtilsTag, ravenwoodUtilsName)[0]
+	if utils != nil {
+		for _, lib := range utils.(*ravenwoodLibgroup).ravenwoodLibgroupProperties.Libs {
+			ctx.AddVariationDependencies(nil, libTag, lib)
+		}
+	}
+
+	// Add jni libs
+	for _, lib := range r.ravenwoodTestProperties.Jni_libs {
+		ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib)
+	}
+}
+
+func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	r.forceOSType = ctx.Config().BuildOS
+	r.forceArchType = ctx.Config().BuildArch
+
+	r.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
+		TestConfigProp:         r.testProperties.Test_config,
+		TestConfigTemplateProp: r.testProperties.Test_config_template,
+		TestSuites:             r.testProperties.Test_suites,
+		AutoGenConfig:          r.testProperties.Auto_gen_config,
+		DeviceTemplate:         "${RavenwoodTestConfigTemplate}",
+		HostTemplate:           "${RavenwoodTestConfigTemplate}",
+	})
+
+	r.Library.GenerateAndroidBuildActions(ctx)
+
+	// Start by depending on all files installed by dependencies
+	var installDeps android.InstallPaths
+
+	// All JNI libraries included in the runtime
+	var runtimeJniModuleNames map[string]bool
+
+	if utils := ctx.GetDirectDepsWithTag(ravenwoodUtilsTag)[0]; utils != nil {
+		for _, installFile := range utils.FilesToInstall() {
+			installDeps = append(installDeps, installFile)
+		}
+		jniDeps, ok := android.OtherModuleProvider(ctx, utils, ravenwoodLibgroupJniDepProvider)
+		if ok {
+			runtimeJniModuleNames = jniDeps.names
+		}
+	}
+
+	if runtime := ctx.GetDirectDepsWithTag(ravenwoodRuntimeTag)[0]; runtime != nil {
+		for _, installFile := range runtime.FilesToInstall() {
+			installDeps = append(installDeps, installFile)
+		}
+		jniDeps, ok := android.OtherModuleProvider(ctx, runtime, ravenwoodLibgroupJniDepProvider)
+		if ok {
+			runtimeJniModuleNames = jniDeps.names
+		}
+	}
+
+	// Also remember what JNI libs are in the runtime.
+
+	// Also depend on our config
+	installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
+	installConfig := ctx.InstallFile(installPath, ctx.ModuleName()+".config", r.testConfig)
+	installDeps = append(installDeps, installConfig)
+
+	// Depend on the JNI libraries, but don't install the ones that the runtime already
+	// contains.
+	soInstallPath := installPath.Join(ctx, getLibPath(r.forceArchType))
+	for _, jniLib := range collectTransitiveJniDeps(ctx) {
+		if _, ok := runtimeJniModuleNames[jniLib.name]; ok {
+			continue // Runtime already includes it.
+		}
+		installJni := ctx.InstallFile(soInstallPath, jniLib.path.Base(), jniLib.path)
+		installDeps = append(installDeps, installJni)
+	}
+
+	// Install our JAR with all dependencies
+	ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...)
+}
+
+func (r *ravenwoodTest) AndroidMkEntries() []android.AndroidMkEntries {
+	entriesList := r.Library.AndroidMkEntries()
+	entries := &entriesList[0]
+	entries.ExtraEntries = append(entries.ExtraEntries,
+		func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+			entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+			entries.AddStrings("LOCAL_COMPATIBILITY_SUITE",
+				"general-tests", "ravenwood-tests")
+			if r.testConfig != nil {
+				entries.SetPath("LOCAL_FULL_TEST_CONFIG", r.testConfig)
+			}
+		})
+	return entriesList
+}
+
+type ravenwoodLibgroupProperties struct {
+	Libs []string
+
+	Jni_libs []string
+}
+
+type ravenwoodLibgroup struct {
+	android.ModuleBase
+
+	ravenwoodLibgroupProperties ravenwoodLibgroupProperties
+
+	forceOSType   android.OsType
+	forceArchType android.ArchType
+}
+
+func ravenwoodLibgroupFactory() android.Module {
+	module := &ravenwoodLibgroup{}
+	module.AddProperties(&module.ravenwoodLibgroupProperties)
+
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	return module
+}
+
+func (r *ravenwoodLibgroup) InstallInTestcases() bool { return true }
+func (r *ravenwoodLibgroup) InstallForceOS() (*android.OsType, *android.ArchType) {
+	return &r.forceOSType, &r.forceArchType
+}
+func (r *ravenwoodLibgroup) TestSuites() []string {
+	return []string{
+		"general-tests",
+		"ravenwood-tests",
+	}
+}
+
+func (r *ravenwoodLibgroup) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// Always depends on our underlying libs
+	for _, lib := range r.ravenwoodLibgroupProperties.Libs {
+		ctx.AddVariationDependencies(nil, ravenwoodLibContentTag, lib)
+	}
+	for _, lib := range r.ravenwoodLibgroupProperties.Jni_libs {
+		ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib)
+	}
+}
+
+func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	r.forceOSType = ctx.Config().BuildOS
+	r.forceArchType = ctx.Config().BuildArch
+
+	// Collect the JNI dependencies, including the transitive deps.
+	jniDepNames := make(map[string]bool)
+	jniLibs := collectTransitiveJniDeps(ctx)
+
+	for _, jni := range jniLibs {
+		jniDepNames[jni.name] = true
+	}
+	android.SetProvider(ctx, ravenwoodLibgroupJniDepProvider, ravenwoodLibgroupJniDepProviderInfo{
+		names: jniDepNames,
+	})
+
+	// Install our runtime into expected location for packaging
+	installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
+	for _, lib := range r.ravenwoodLibgroupProperties.Libs {
+		libModule := ctx.GetDirectDepWithTag(lib, ravenwoodLibContentTag)
+		libJar := android.OutputFileForModule(ctx, libModule, "")
+		ctx.InstallFile(installPath, lib+".jar", libJar)
+	}
+	soInstallPath := android.PathForModuleInstall(ctx, r.BaseModuleName()).Join(ctx, getLibPath(r.forceArchType))
+
+	for _, jniLib := range jniLibs {
+		ctx.InstallFile(soInstallPath, jniLib.path.Base(), jniLib.path)
+	}
+
+	// Normal build should perform install steps
+	ctx.Phony(r.BaseModuleName(), android.PathForPhony(ctx, r.BaseModuleName()+"-install"))
+}
+
+// collectTransitiveJniDeps returns all JNI dependencies, including transitive
+// ones, including NDK / stub libs. (Because Ravenwood has no "preinstalled" libraries)
+func collectTransitiveJniDeps(ctx android.ModuleContext) []jniLib {
+	libs, _ := collectJniDeps(ctx, true, false, nil)
+	return libs
+}
diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go
new file mode 100644
index 0000000..5961264
--- /dev/null
+++ b/java/ravenwood_test.go
@@ -0,0 +1,186 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"runtime"
+	"testing"
+
+	"android/soong/android"
+)
+
+var prepareRavenwoodRuntime = android.GroupFixturePreparers(
+	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+		RegisterRavenwoodBuildComponents(ctx)
+	}),
+	android.FixtureAddTextFile("ravenwood/Android.bp", `
+		cc_library_shared {
+			name: "ravenwood-runtime-jni1",
+			host_supported: true,
+			srcs: ["jni.cpp"],
+		}
+		cc_library_shared {
+			name: "ravenwood-runtime-jni2",
+			host_supported: true,
+			srcs: ["jni.cpp"],
+			stem: "libred",
+			shared_libs: [
+				"ravenwood-runtime-jni3",
+			],
+		}
+		cc_library_shared {
+			name: "ravenwood-runtime-jni3",
+			host_supported: true,
+			srcs: ["jni.cpp"],
+		}
+		java_library_static {
+			name: "framework-minus-apex.ravenwood",
+			srcs: ["Framework.java"],
+		}
+		java_library_static {
+			name: "framework-services.ravenwood",
+			srcs: ["Services.java"],
+		}
+		java_library_static {
+			name: "framework-rules.ravenwood",
+			srcs: ["Rules.java"],
+		}
+		android_ravenwood_libgroup {
+			name: "ravenwood-runtime",
+			libs: [
+				"framework-minus-apex.ravenwood",
+				"framework-services.ravenwood",
+			],
+			jni_libs: [
+				"ravenwood-runtime-jni1",
+				"ravenwood-runtime-jni2",
+			],
+		}
+		android_ravenwood_libgroup {
+			name: "ravenwood-utils",
+			libs: [
+				"framework-rules.ravenwood",
+			],
+		}
+	`),
+)
+
+var installPathPrefix = "out/soong/host/linux-x86/testcases"
+
+func TestRavenwoodRuntime(t *testing.T) {
+	if runtime.GOOS != "linux" {
+		t.Skip("requires linux")
+	}
+
+	ctx := android.GroupFixturePreparers(
+		PrepareForIntegrationTestWithJava,
+		prepareRavenwoodRuntime,
+	).RunTest(t)
+
+	// Verify that our runtime depends on underlying libs
+	CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-runtime", "android_common", "framework-minus-apex.ravenwood")
+	CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-runtime", "android_common", "framework-services.ravenwood")
+	CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-runtime", "android_common", "ravenwood-runtime-jni")
+	CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-utils", "android_common", "framework-rules.ravenwood")
+
+	// Verify that we've emitted artifacts in expected location
+	runtime := ctx.ModuleForTests("ravenwood-runtime", "android_common")
+	runtime.Output(installPathPrefix + "/ravenwood-runtime/framework-minus-apex.ravenwood.jar")
+	runtime.Output(installPathPrefix + "/ravenwood-runtime/framework-services.ravenwood.jar")
+	runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni1.so")
+	runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/libred.so")
+	runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni3.so")
+	utils := ctx.ModuleForTests("ravenwood-utils", "android_common")
+	utils.Output(installPathPrefix + "/ravenwood-utils/framework-rules.ravenwood.jar")
+}
+
+func TestRavenwoodTest(t *testing.T) {
+	if runtime.GOOS != "linux" {
+		t.Skip("requires linux")
+	}
+
+	ctx := android.GroupFixturePreparers(
+		PrepareForIntegrationTestWithJava,
+		prepareRavenwoodRuntime,
+	).RunTestWithBp(t, `
+	cc_library_shared {
+		name: "jni-lib1",
+		host_supported: true,
+		srcs: ["jni.cpp"],
+	}
+	cc_library_shared {
+		name: "jni-lib2",
+		host_supported: true,
+		srcs: ["jni.cpp"],
+		stem: "libblue",
+		shared_libs: [
+			"jni-lib3",
+		],
+	}
+	cc_library_shared {
+		name: "jni-lib3",
+		host_supported: true,
+		srcs: ["jni.cpp"],
+		stem: "libpink",
+	}
+	android_ravenwood_test {
+			name: "ravenwood-test",
+			srcs: ["Test.java"],
+			jni_libs: [
+				"jni-lib1",
+				"jni-lib2",
+				"ravenwood-runtime-jni2",
+			],
+			sdk_version: "test_current",
+		}
+	`)
+
+	// Verify that our test depends on underlying libs
+	CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-test", "android_common", "ravenwood-buildtime")
+	CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-test", "android_common", "ravenwood-utils")
+	CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-test", "android_common", "jni-lib")
+
+	module := ctx.ModuleForTests("ravenwood-test", "android_common")
+	classpath := module.Rule("javac").Args["classpath"]
+
+	// Verify that we're linking against test_current
+	android.AssertStringDoesContain(t, "classpath", classpath, "android_test_stubs_current.jar")
+	// Verify that we're linking against utils
+	android.AssertStringDoesContain(t, "classpath", classpath, "framework-rules.ravenwood.jar")
+	// Verify that we're *NOT* linking against runtime
+	android.AssertStringDoesNotContain(t, "classpath", classpath, "framework-minus-apex.ravenwood.jar")
+	android.AssertStringDoesNotContain(t, "classpath", classpath, "framework-services.ravenwood.jar")
+
+	// Verify that we've emitted test artifacts in expected location
+	outputJar := module.Output(installPathPrefix + "/ravenwood-test/ravenwood-test.jar")
+	module.Output(installPathPrefix + "/ravenwood-test/ravenwood-test.config")
+	module.Output(installPathPrefix + "/ravenwood-test/lib64/jni-lib1.so")
+	module.Output(installPathPrefix + "/ravenwood-test/lib64/libblue.so")
+	module.Output(installPathPrefix + "/ravenwood-test/lib64/libpink.so")
+
+	// ravenwood-runtime*.so are included in the runtime, so it shouldn't be emitted.
+	for _, o := range module.AllOutputs() {
+		android.AssertStringDoesNotContain(t, "runtime libs shouldn't be included", o, "/ravenwood-test/lib64/ravenwood-runtime")
+	}
+
+	// Verify that we're going to install underlying libs
+	orderOnly := outputJar.OrderOnly.Strings()
+	android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/framework-minus-apex.ravenwood.jar")
+	android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/framework-services.ravenwood.jar")
+	android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/lib64/ravenwood-runtime-jni1.so")
+	android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/lib64/libred.so")
+	android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/lib64/ravenwood-runtime-jni3.so")
+	android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-utils/framework-rules.ravenwood.jar")
+}
diff --git a/java/resourceshrinker.go b/java/resourceshrinker.go
deleted file mode 100644
index bf1b04d..0000000
--- a/java/resourceshrinker.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package java
-
-import (
-	"android/soong/android"
-
-	"github.com/google/blueprint"
-)
-
-var shrinkResources = pctx.AndroidStaticRule("shrinkResources",
-	blueprint.RuleParams{
-		// Note that we suppress stdout to avoid successful log confirmations.
-		Command:     `${config.ResourceShrinkerCmd} --output $out --input $in --raw_resources $raw_resources >/dev/null`,
-		CommandDeps: []string{"${config.ResourceShrinkerCmd}"},
-	}, "raw_resources")
-
-func ShrinkResources(ctx android.ModuleContext, apk android.Path, outputFile android.WritablePath) {
-	protoFile := android.PathForModuleOut(ctx, apk.Base()+".proto.apk")
-	aapt2Convert(ctx, protoFile, apk, "proto")
-	strictModeFile := android.PathForSource(ctx, "prebuilts/cmdline-tools/shrinker.xml")
-	protoOut := android.PathForModuleOut(ctx, apk.Base()+".proto.out.apk")
-	ctx.Build(pctx, android.BuildParams{
-		Rule:   shrinkResources,
-		Input:  protoFile,
-		Output: protoOut,
-		Args: map[string]string{
-			"raw_resources": strictModeFile.String(),
-		},
-	})
-	aapt2Convert(ctx, outputFile, protoOut, "binary")
-}
diff --git a/java/resourceshrinker_test.go b/java/resourceshrinker_test.go
deleted file mode 100644
index 3bbf116..0000000
--- a/java/resourceshrinker_test.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package java
-
-import (
-	"testing"
-
-	"android/soong/android"
-)
-
-func TestShrinkResourcesArgs(t *testing.T) {
-	result := android.GroupFixturePreparers(
-		PrepareForTestWithJavaDefaultModules,
-	).RunTestWithBp(t, `
-		android_app {
-			name: "app_shrink",
-			platform_apis: true,
-			optimize: {
-				shrink_resources: true,
-			}
-		}
-
-		android_app {
-			name: "app_no_shrink",
-			platform_apis: true,
-			optimize: {
-				shrink_resources: false,
-			}
-		}
-	`)
-
-	appShrink := result.ModuleForTests("app_shrink", "android_common")
-	appShrinkResources := appShrink.Rule("shrinkResources")
-	android.AssertStringDoesContain(t, "expected shrinker.xml in app_shrink resource shrinker flags",
-		appShrinkResources.Args["raw_resources"], "shrinker.xml")
-
-	appNoShrink := result.ModuleForTests("app_no_shrink", "android_common")
-	if appNoShrink.MaybeRule("shrinkResources").Rule != nil {
-		t.Errorf("unexpected shrinkResources rule for app_no_shrink")
-	}
-}
diff --git a/java/robolectric.go b/java/robolectric.go
index 0041af4..18386c9 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -22,6 +22,7 @@
 
 	"android/soong/android"
 	"android/soong/java/config"
+	"android/soong/testing"
 	"android/soong/tradefed"
 
 	"github.com/google/blueprint/proptools"
@@ -34,7 +35,7 @@
 
 var robolectricDefaultLibs = []string{
 	"mockito-robolectric-prebuilt",
-	"truth-prebuilt",
+	"truth",
 	// TODO(ccross): this is not needed at link time
 	"junitxml",
 }
@@ -45,6 +46,7 @@
 var (
 	roboCoverageLibsTag = dependencyTag{name: "roboCoverageLibs"}
 	roboRuntimesTag     = dependencyTag{name: "roboRuntimes"}
+	roboRuntimeOnlyTag  = dependencyTag{name: "roboRuntimeOnlyTag"}
 )
 
 type robolectricProperties struct {
@@ -66,9 +68,12 @@
 	// instead of the one built from source in external/robolectric-shadows.
 	Robolectric_prebuilt_version *string
 
-	// Use /external/robolectric rather than /external/robolectric-shadows as the version of robolectri
+	// Use /external/robolectric rather than /external/robolectric-shadows as the version of robolectric
 	// to use.  /external/robolectric closely tracks github's master, and will fully replace /external/robolectric-shadows
 	Upstream *bool
+
+	// Use strict mode to limit access of Robolectric API directly. See go/roboStrictMode
+	Strict_mode *bool
 }
 
 type robolectricTest struct {
@@ -111,7 +116,7 @@
 
 	if v := String(r.robolectricProperties.Robolectric_prebuilt_version); v != "" {
 		ctx.AddVariationDependencies(nil, libTag, fmt.Sprintf(robolectricPrebuiltLibPattern, v))
-	} else {
+	} else if !proptools.Bool(r.robolectricProperties.Strict_mode) {
 		if proptools.Bool(r.robolectricProperties.Upstream) {
 			ctx.AddVariationDependencies(nil, libTag, robolectricCurrentLib+"_upstream")
 		} else {
@@ -119,6 +124,10 @@
 		}
 	}
 
+	if proptools.Bool(r.robolectricProperties.Strict_mode) {
+		ctx.AddVariationDependencies(nil, roboRuntimeOnlyTag, robolectricCurrentLib+"_upstream")
+	}
+
 	ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
 
 	ctx.AddVariationDependencies(nil, roboCoverageLibsTag, r.robolectricProperties.Coverage_libs...)
@@ -191,19 +200,25 @@
 		combinedJarJars = append(combinedJarJars, instrumentedApp.implementationAndResourcesJar)
 	}
 
-	handleLibDeps := func(dep android.Module) {
-		m := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
-		r.libs = append(r.libs, ctx.OtherModuleName(dep))
+	handleLibDeps := func(dep android.Module, runtimeOnly bool) {
+		m, _ := android.OtherModuleProvider(ctx, dep, JavaInfoProvider)
+		if !runtimeOnly {
+			r.libs = append(r.libs, ctx.OtherModuleName(dep))
+		}
 		if !android.InList(ctx.OtherModuleName(dep), config.FrameworkLibraries) {
 			combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars...)
 		}
 	}
 
 	for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
-		handleLibDeps(dep)
+		handleLibDeps(dep, false)
 	}
 	for _, dep := range ctx.GetDirectDepsWithTag(sdkLibTag) {
-		handleLibDeps(dep)
+		handleLibDeps(dep, false)
+	}
+	// handle the runtimeOnly tag for strict_mode
+	for _, dep := range ctx.GetDirectDepsWithTag(roboRuntimeOnlyTag) {
+		handleLibDeps(dep, true)
 	}
 
 	r.combinedJar = android.PathForModuleOut(ctx, "robolectric_combined", r.outputFile.Base())
@@ -225,7 +240,7 @@
 	}
 
 	installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
-	var installDeps android.Paths
+	var installDeps android.InstallPaths
 
 	if r.manifest != nil {
 		r.data = append(r.data, r.manifest)
@@ -253,6 +268,7 @@
 	}
 
 	r.installFile = ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...)
+	android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath,
@@ -303,8 +319,7 @@
 	srcJarDeps := append(android.Paths(nil), instrumentedApp.srcJarDeps...)
 
 	for _, m := range ctx.GetDirectDepsWithTag(roboCoverageLibsTag) {
-		if ctx.OtherModuleHasProvider(m, JavaInfoProvider) {
-			dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo)
+		if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok {
 			srcJarArgs = append(srcJarArgs, dep.SrcJarArgs...)
 			srcJarDeps = append(srcJarDeps, dep.SrcJarDeps...)
 		}
diff --git a/java/rro.go b/java/rro.go
index 53faca0..72170fc 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -122,6 +122,10 @@
 
 	ctx.AddVariationDependencies(nil, staticLibTag, r.properties.Static_libs...)
 	ctx.AddVariationDependencies(nil, libTag, r.properties.Resource_libs...)
+
+	for _, aconfig_declaration := range r.aaptProperties.Flags_packages {
+		ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration)
+	}
 }
 
 func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -146,7 +150,14 @@
 		aaptLinkFlags = append(aaptLinkFlags,
 			"--rename-overlay-category "+*r.overridableProperties.Category)
 	}
-	r.aapt.buildActions(ctx, r, nil, nil, false, aaptLinkFlags...)
+	r.aapt.buildActions(ctx,
+		aaptBuildActionOptions{
+			sdkContext:                     r,
+			enforceDefaultTargetSdkVersion: false,
+			extraLinkFlags:                 aaptLinkFlags,
+			aconfigTextFiles:               getAconfigFilePaths(ctx),
+		},
+	)
 
 	// Sign the built package
 	_, _, certificates := collectAppDeps(ctx, r, false, false)
diff --git a/java/rro_test.go b/java/rro_test.go
index 8067a47..d697ec6 100644
--- a/java/rro_test.go
+++ b/java/rro_test.go
@@ -62,7 +62,6 @@
 
 	result := android.GroupFixturePreparers(
 		PrepareForTestWithJavaDefaultModules,
-		PrepareForTestWithOverlayBuildComponents,
 		android.FixtureModifyConfig(android.SetKatiEnabledForTests),
 		fs.AddToFixture(),
 	).RunTestWithBp(t, bp)
@@ -330,7 +329,6 @@
 		t.Run(testCase.name, func(t *testing.T) {
 			result := android.GroupFixturePreparers(
 				PrepareForTestWithJavaDefaultModules,
-				PrepareForTestWithOverlayBuildComponents,
 				fs.AddToFixture(),
 				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 					variables.ProductResourceOverlays = productResourceOverlays
@@ -407,3 +405,49 @@
 		android.AssertPathRelativeToTopEquals(t, "Install dir is not correct for "+testCase.name, testCase.expectedPath, mod.installDir)
 	}
 }
+
+func TestRuntimeResourceOverlayFlagsPackages(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+	).RunTestWithBp(t, `
+		runtime_resource_overlay {
+			name: "foo",
+			sdk_version: "current",
+			flags_packages: [
+				"bar",
+				"baz",
+			],
+		}
+		aconfig_declarations {
+			name: "bar",
+			package: "com.example.package.bar",
+			srcs: [
+				"bar.aconfig",
+			],
+		}
+		aconfig_declarations {
+			name: "baz",
+			package: "com.example.package.baz",
+			srcs: [
+				"baz.aconfig",
+			],
+		}
+	`)
+
+	foo := result.ModuleForTests("foo", "android_common")
+
+	// runtime_resource_overlay module depends on aconfig_declarations listed in flags_packages
+	android.AssertBoolEquals(t, "foo expected to depend on bar", true,
+		CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "bar"))
+
+	android.AssertBoolEquals(t, "foo expected to depend on baz", true,
+		CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "baz"))
+
+	aapt2LinkRule := foo.Rule("android/soong/java.aapt2Link")
+	linkInFlags := aapt2LinkRule.Args["inFlags"]
+	android.AssertStringDoesContain(t,
+		"aapt2 link command expected to pass feature flags arguments",
+		linkInFlags,
+		"--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt",
+	)
+}
diff --git a/java/sdk.go b/java/sdk.go
index 7c702c4..d972c19 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -17,8 +17,6 @@
 import (
 	"fmt"
 	"path/filepath"
-	"sort"
-	"strconv"
 
 	"android/soong/android"
 	"android/soong/java/config"
@@ -27,23 +25,33 @@
 )
 
 func init() {
-	android.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory)
 	android.RegisterParallelSingletonType("sdk", sdkSingletonFactory)
 	android.RegisterMakeVarsProvider(pctx, sdkMakeVars)
 }
 
-var sdkVersionsKey = android.NewOnceKey("sdkVersionsKey")
 var sdkFrameworkAidlPathKey = android.NewOnceKey("sdkFrameworkAidlPathKey")
 var nonUpdatableFrameworkAidlPathKey = android.NewOnceKey("nonUpdatableFrameworkAidlPathKey")
-var apiFingerprintPathKey = android.NewOnceKey("apiFingerprintPathKey")
 
-func UseApiFingerprint(ctx android.BaseModuleContext) bool {
-	if ctx.Config().UnbundledBuild() &&
-		!ctx.Config().AlwaysUsePrebuiltSdks() &&
-		ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT") {
-		return true
+func UseApiFingerprint(ctx android.BaseModuleContext) (useApiFingerprint bool, fingerprintSdkVersion string, fingerprintDeps android.OutputPath) {
+	if ctx.Config().UnbundledBuild() && !ctx.Config().AlwaysUsePrebuiltSdks() {
+		apiFingerprintTrue := ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT")
+		dessertShaIsSet := ctx.Config().Getenv("UNBUNDLED_BUILD_TARGET_SDK_WITH_DESSERT_SHA") != ""
+
+		// Error when both UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT and UNBUNDLED_BUILD_TARGET_SDK_WITH_DESSERT_SHA are set
+		if apiFingerprintTrue && dessertShaIsSet {
+			ctx.ModuleErrorf("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT=true cannot be set alongside with UNBUNDLED_BUILD_TARGET_SDK_WITH_DESSERT_SHA")
+		}
+
+		useApiFingerprint = apiFingerprintTrue || dessertShaIsSet
+		if apiFingerprintTrue {
+			fingerprintSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", android.ApiFingerprintPath(ctx).String())
+			fingerprintDeps = android.ApiFingerprintPath(ctx)
+		}
+		if dessertShaIsSet {
+			fingerprintSdkVersion = ctx.Config().Getenv("UNBUNDLED_BUILD_TARGET_SDK_WITH_DESSERT_SHA")
+		}
 	}
-	return false
+	return useApiFingerprint, fingerprintSdkVersion, fingerprintDeps
 }
 
 func defaultJavaLanguageVersion(ctx android.EarlyModuleContext, s android.SdkSpec) javaVersion {
@@ -51,9 +59,7 @@
 	if err != nil {
 		ctx.PropertyErrorf("sdk_version", "%s", err)
 	}
-	if sdk.FinalOrFutureInt() <= 23 {
-		return JAVA_VERSION_7
-	} else if sdk.FinalOrFutureInt() <= 29 {
+	if sdk.FinalOrFutureInt() <= 29 {
 		return JAVA_VERSION_8
 	} else if sdk.FinalOrFutureInt() <= 31 {
 		return JAVA_VERSION_9
@@ -76,7 +82,8 @@
 		// Core is by definition what is included in the system module for the public API so should
 		// just use its system modules.
 		systemModuleKind = android.SdkPublic
-	} else if systemModuleKind == android.SdkSystem || systemModuleKind == android.SdkTest {
+	} else if systemModuleKind == android.SdkSystem || systemModuleKind == android.SdkTest ||
+		systemModuleKind == android.SdkTestFrameworksCore {
 		// The core system and test APIs are currently the same as the public API so they should use
 		// its system modules.
 		systemModuleKind = android.SdkPublic
@@ -192,7 +199,7 @@
 			bootclasspath:    corePlatformBootclasspathLibraries(ctx),
 			noFrameworksLibs: true,
 		}
-	case android.SdkPublic, android.SdkSystem, android.SdkTest:
+	case android.SdkPublic, android.SdkSystem, android.SdkTest, android.SdkTestFrameworksCore:
 		return toModule(sdkVersion.Kind.DefaultJavaLibraryName(), sdkFrameworkAidlPath(ctx))
 	case android.SdkCore:
 		return sdkDep{
@@ -212,44 +219,6 @@
 	}
 }
 
-func sdkPreSingletonFactory() android.Singleton {
-	return sdkPreSingleton{}
-}
-
-type sdkPreSingleton struct{}
-
-func (sdkPreSingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	sdkJars, err := ctx.GlobWithDeps("prebuilts/sdk/*/public/android.jar", nil)
-	if err != nil {
-		ctx.Errorf("failed to glob prebuilts/sdk/*/public/android.jar: %s", err.Error())
-	}
-
-	var sdkVersions []int
-	for _, sdkJar := range sdkJars {
-		dir := filepath.Base(filepath.Dir(filepath.Dir(sdkJar)))
-		v, err := strconv.Atoi(dir)
-		if scerr, ok := err.(*strconv.NumError); ok && scerr.Err == strconv.ErrSyntax {
-			continue
-		} else if err != nil {
-			ctx.Errorf("invalid sdk jar %q, %s, %v", sdkJar, err.Error())
-		}
-		sdkVersions = append(sdkVersions, v)
-	}
-
-	sort.Ints(sdkVersions)
-
-	ctx.Config().Once(sdkVersionsKey, func() interface{} { return sdkVersions })
-}
-
-func LatestSdkVersionInt(ctx android.EarlyModuleContext) int {
-	sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int)
-	latestSdkVersion := 0
-	if len(sdkVersions) > 0 {
-		latestSdkVersion = sdkVersions[len(sdkVersions)-1]
-	}
-	return latestSdkVersion
-}
-
 func sdkSingletonFactory() android.Singleton {
 	return sdkSingleton{}
 }
@@ -303,8 +272,7 @@
 
 	ctx.VisitAllModules(func(module android.Module) {
 		// Collect dex jar paths for the modules listed above.
-		if ctx.ModuleHasProvider(module, JavaInfoProvider) {
-			j := ctx.ModuleProvider(module, JavaInfoProvider).(JavaInfo)
+		if j, ok := android.SingletonModuleProvider(ctx, module, JavaInfoProvider); ok {
 			name := ctx.ModuleName(module)
 			if i := android.IndexList(name, stubsModules); i != -1 {
 				stubsJars[i] = j.HeaderJars
@@ -368,7 +336,7 @@
 
 // Create api_fingerprint.txt
 func createAPIFingerprint(ctx android.SingletonContext) {
-	out := ApiFingerprintPath(ctx)
+	out := android.ApiFingerprintPath(ctx)
 
 	rule := android.NewRuleBuilder(pctx, ctx)
 
@@ -409,17 +377,11 @@
 	rule.Build("api_fingerprint", "generate api_fingerprint.txt")
 }
 
-func ApiFingerprintPath(ctx android.PathContext) android.OutputPath {
-	return ctx.Config().Once(apiFingerprintPathKey, func() interface{} {
-		return android.PathForOutput(ctx, "api_fingerprint.txt")
-	}).(android.OutputPath)
-}
-
 func sdkMakeVars(ctx android.MakeVarsContext) {
 	if ctx.Config().AlwaysUsePrebuiltSdks() {
 		return
 	}
 
 	ctx.Strict("FRAMEWORK_AIDL", sdkFrameworkAidlPath(ctx).String())
-	ctx.Strict("API_FINGERPRINT", ApiFingerprintPath(ctx).String())
+	ctx.Strict("API_FINGERPRINT", android.ApiFingerprintPath(ctx).String())
 }
diff --git a/java/sdk_library.go b/java/sdk_library.go
index dbb2f02..113071f 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"errors"
 	"fmt"
 	"path"
 	"path/filepath"
@@ -24,14 +25,12 @@
 	"strings"
 	"sync"
 
-	"android/soong/ui/metrics/bp2build_metrics_proto"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/dexpreopt"
+	"android/soong/etc"
 )
 
 const (
@@ -107,8 +106,14 @@
 	// The name of the property in the java_sdk_library_import
 	propertyName string
 
-	// The tag to use to depend on the stubs library module.
-	stubsTag scopeDependencyTag
+	// The tag to use to depend on the prebuilt stubs library module
+	prebuiltStubsTag scopeDependencyTag
+
+	// The tag to use to depend on the everything stubs library module.
+	everythingStubsTag scopeDependencyTag
+
+	// The tag to use to depend on the exportable stubs library module.
+	exportableStubsTag scopeDependencyTag
 
 	// The tag to use to depend on the stubs source module (if separate from the API module).
 	stubsSourceTag scopeDependencyTag
@@ -170,11 +175,21 @@
 	allScopeNames = append(allScopeNames, name)
 	scope.propertyName = strings.ReplaceAll(name, "-", "_")
 	scope.fieldName = proptools.FieldNameForProperty(scope.propertyName)
-	scope.stubsTag = scopeDependencyTag{
+	scope.prebuiltStubsTag = scopeDependencyTag{
 		name:             name + "-stubs",
 		apiScope:         scope,
 		depInfoExtractor: (*scopePaths).extractStubsLibraryInfoFromDependency,
 	}
+	scope.everythingStubsTag = scopeDependencyTag{
+		name:             name + "-stubs-everything",
+		apiScope:         scope,
+		depInfoExtractor: (*scopePaths).extractEverythingStubsLibraryInfoFromDependency,
+	}
+	scope.exportableStubsTag = scopeDependencyTag{
+		name:             name + "-stubs-exportable",
+		apiScope:         scope,
+		depInfoExtractor: (*scopePaths).extractExportableStubsLibraryInfoFromDependency,
+	}
 	scope.stubsSourceTag = scopeDependencyTag{
 		name:             name + "-stubs-source",
 		apiScope:         scope,
@@ -234,6 +249,10 @@
 	return ".stubs" + scope.moduleSuffix
 }
 
+func (scope *apiScope) exportableStubsLibraryModuleNameSuffix() string {
+	return ".stubs.exportable" + scope.moduleSuffix
+}
+
 func (scope *apiScope) apiLibraryModuleName(baseName string) string {
 	return scope.stubsLibraryModuleName(baseName) + ".from-text"
 }
@@ -242,10 +261,18 @@
 	return scope.stubsLibraryModuleName(baseName) + ".from-source"
 }
 
+func (scope *apiScope) exportableSourceStubsLibraryModuleName(baseName string) string {
+	return scope.exportableStubsLibraryModuleName(baseName) + ".from-source"
+}
+
 func (scope *apiScope) stubsLibraryModuleName(baseName string) string {
 	return baseName + scope.stubsLibraryModuleNameSuffix()
 }
 
+func (scope *apiScope) exportableStubsLibraryModuleName(baseName string) string {
+	return baseName + scope.exportableStubsLibraryModuleNameSuffix()
+}
+
 func (scope *apiScope) stubsSourceModuleName(baseName string) string {
 	return baseName + ".stubs.source" + scope.moduleSuffix
 }
@@ -286,6 +313,17 @@
 	return list
 }
 
+// Method that maps the apiScopes properties to the index of each apiScopes elements.
+// apiScopes property to be used as the key can be specified with the input accessor.
+// Only a string property of apiScope can be used as the key of the map.
+func (scopes apiScopes) MapToIndex(accessor func(*apiScope) string) map[string]int {
+	ret := make(map[string]int)
+	for i, scope := range scopes {
+		ret[accessor(scope)] = i
+	}
+	return ret
+}
+
 var (
 	scopeByName    = make(map[string]*apiScope)
 	allScopeNames  []string
@@ -387,6 +425,23 @@
 		apiScopeModuleLib,
 		apiScopeSystemServer,
 	}
+	apiLibraryAdditionalProperties = map[string]struct {
+		FullApiSurfaceStubLib     string
+		AdditionalApiContribution string
+	}{
+		"legacy.i18n.module.platform.api": {
+			FullApiSurfaceStubLib:     "legacy.core.platform.api.stubs",
+			AdditionalApiContribution: "i18n.module.public.api.stubs.source.api.contribution",
+		},
+		"stable.i18n.module.platform.api": {
+			FullApiSurfaceStubLib:     "stable.core.platform.api.stubs",
+			AdditionalApiContribution: "i18n.module.public.api.stubs.source.api.contribution",
+		},
+		"conscrypt.module.platform.api": {
+			FullApiSurfaceStubLib:     "stable.core.platform.api.stubs",
+			AdditionalApiContribution: "conscrypt.module.public.api.stubs.source.api.contribution",
+		},
+	}
 )
 
 var (
@@ -442,6 +497,9 @@
 	// or the API file. They both have to use the same sdk_version as is used for
 	// compiling the implementation library.
 	Sdk_version *string
+
+	// Extra libs used when compiling stubs for this scope.
+	Libs []string
 }
 
 type sdkLibraryProperties struct {
@@ -587,8 +645,23 @@
 	Api_lint struct {
 		// Enable api linting.
 		Enabled *bool
+
+		// If API lint is enabled, this flag controls whether a set of legitimate lint errors
+		// are turned off. The default is true.
+		Legacy_errors_allowed *bool
 	}
 
+	// Determines if the module contributes to any api surfaces.
+	// This property should be set to true only if the module is listed under
+	// frameworks-base-api.bootclasspath in frameworks/base/api/Android.bp.
+	// Otherwise, this property should be set to false.
+	// Defaults to false.
+	Contribute_to_android_api *bool
+
+	// a list of aconfig_declarations module names that the stubs generated in this module
+	// depend on.
+	Aconfig_declarations []string
+
 	// TODO: determines whether to create HTML doc or not
 	// Html_doc *bool
 }
@@ -614,6 +687,11 @@
 	// This is not the implementation jar, it still only contains stubs.
 	stubsDexJarPath OptionalDexJarPath
 
+	// The exportable dex jar for the stubs.
+	// This is not the implementation jar, it still only contains stubs.
+	// Includes unflagged apis and flagged apis enabled by release configurations.
+	exportableStubsDexJarPath OptionalDexJarPath
+
 	// The API specification file, e.g. system_current.txt.
 	currentApiFilePath android.OptionalPath
 
@@ -627,95 +705,149 @@
 	annotationsZip android.OptionalPath
 
 	// The path to the latest API file.
-	latestApiPath android.OptionalPath
+	latestApiPaths android.Paths
 
 	// The path to the latest removed API file.
-	latestRemovedApiPath android.OptionalPath
+	latestRemovedApiPaths android.Paths
 }
 
 func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error {
-	if ctx.OtherModuleHasProvider(dep, JavaInfoProvider) {
-		lib := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+	if lib, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
 		paths.stubsHeaderPath = lib.HeaderJars
 		paths.stubsImplPath = lib.ImplementationJars
 
 		libDep := dep.(UsesLibraryDependency)
-		paths.stubsDexJarPath = libDep.DexJarBuildPath()
+		paths.stubsDexJarPath = libDep.DexJarBuildPath(ctx)
+		paths.exportableStubsDexJarPath = libDep.DexJarBuildPath(ctx)
 		return nil
 	} else {
 		return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library")
 	}
 }
 
-func (paths *scopePaths) treatDepAsApiStubsProvider(dep android.Module, action func(provider ApiStubsProvider)) error {
-	if apiStubsProvider, ok := dep.(ApiStubsProvider); ok {
-		action(apiStubsProvider)
+func (paths *scopePaths) extractEverythingStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error {
+	if lib, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
+		paths.stubsHeaderPath = lib.HeaderJars
+		if !ctx.Config().ReleaseHiddenApiExportableStubs() {
+			paths.stubsImplPath = lib.ImplementationJars
+		}
+
+		libDep := dep.(UsesLibraryDependency)
+		paths.stubsDexJarPath = libDep.DexJarBuildPath(ctx)
 		return nil
 	} else {
-		return fmt.Errorf("expected module that implements ApiStubsProvider, e.g. droidstubs")
+		return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library")
 	}
 }
 
-func (paths *scopePaths) treatDepAsApiStubsSrcProvider(dep android.Module, action func(provider ApiStubsSrcProvider)) error {
+func (paths *scopePaths) extractExportableStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error {
+	if lib, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
+		if ctx.Config().ReleaseHiddenApiExportableStubs() {
+			paths.stubsImplPath = lib.ImplementationJars
+		}
+
+		libDep := dep.(UsesLibraryDependency)
+		paths.exportableStubsDexJarPath = libDep.DexJarBuildPath(ctx)
+		return nil
+	} else {
+		return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library")
+	}
+}
+
+func (paths *scopePaths) treatDepAsApiStubsProvider(dep android.Module, action func(provider ApiStubsProvider) error) error {
+	if apiStubsProvider, ok := dep.(ApiStubsProvider); ok {
+		err := action(apiStubsProvider)
+		if err != nil {
+			return err
+		}
+		return nil
+	} else {
+		return fmt.Errorf("expected module that implements ExportableApiStubsSrcProvider, e.g. droidstubs")
+	}
+}
+
+func (paths *scopePaths) treatDepAsApiStubsSrcProvider(dep android.Module, action func(provider ApiStubsSrcProvider) error) error {
 	if apiStubsProvider, ok := dep.(ApiStubsSrcProvider); ok {
-		action(apiStubsProvider)
+		err := action(apiStubsProvider)
+		if err != nil {
+			return err
+		}
 		return nil
 	} else {
 		return fmt.Errorf("expected module that implements ApiStubsSrcProvider, e.g. droidstubs")
 	}
 }
 
-func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider) {
-	paths.annotationsZip = android.OptionalPathForPath(provider.AnnotationsZip())
-	paths.currentApiFilePath = android.OptionalPathForPath(provider.ApiFilePath())
-	paths.removedApiFilePath = android.OptionalPathForPath(provider.RemovedApiFilePath())
+func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider, stubsType StubsType) error {
+	var annotationsZip, currentApiFilePath, removedApiFilePath android.Path
+	annotationsZip, annotationsZipErr := provider.AnnotationsZip(stubsType)
+	currentApiFilePath, currentApiFilePathErr := provider.ApiFilePath(stubsType)
+	removedApiFilePath, removedApiFilePathErr := provider.RemovedApiFilePath(stubsType)
+
+	combinedError := errors.Join(annotationsZipErr, currentApiFilePathErr, removedApiFilePathErr)
+
+	if combinedError == nil {
+		paths.annotationsZip = android.OptionalPathForPath(annotationsZip)
+		paths.currentApiFilePath = android.OptionalPathForPath(currentApiFilePath)
+		paths.removedApiFilePath = android.OptionalPathForPath(removedApiFilePath)
+	}
+	return combinedError
 }
 
 func (paths *scopePaths) extractApiInfoFromDep(ctx android.ModuleContext, dep android.Module) error {
-	return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) {
-		paths.extractApiInfoFromApiStubsProvider(provider)
+	return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) error {
+		return paths.extractApiInfoFromApiStubsProvider(provider, Everything)
 	})
 }
 
-func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsSrcProvider) {
-	paths.stubsSrcJar = android.OptionalPathForPath(provider.StubsSrcJar())
+func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsSrcProvider, stubsType StubsType) error {
+	stubsSrcJar, err := provider.StubsSrcJar(stubsType)
+	if err == nil {
+		paths.stubsSrcJar = android.OptionalPathForPath(stubsSrcJar)
+	}
+	return err
 }
 
 func (paths *scopePaths) extractStubsSourceInfoFromDep(ctx android.ModuleContext, dep android.Module) error {
-	return paths.treatDepAsApiStubsSrcProvider(dep, func(provider ApiStubsSrcProvider) {
-		paths.extractStubsSourceInfoFromApiStubsProviders(provider)
+	return paths.treatDepAsApiStubsSrcProvider(dep, func(provider ApiStubsSrcProvider) error {
+		return paths.extractStubsSourceInfoFromApiStubsProviders(provider, Everything)
 	})
 }
 
 func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(ctx android.ModuleContext, dep android.Module) error {
-	return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) {
-		paths.extractApiInfoFromApiStubsProvider(provider)
-		paths.extractStubsSourceInfoFromApiStubsProviders(provider)
+	if ctx.Config().ReleaseHiddenApiExportableStubs() {
+		return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) error {
+			extractApiInfoErr := paths.extractApiInfoFromApiStubsProvider(provider, Exportable)
+			extractStubsSourceInfoErr := paths.extractStubsSourceInfoFromApiStubsProviders(provider, Exportable)
+			return errors.Join(extractApiInfoErr, extractStubsSourceInfoErr)
+		})
+	}
+	return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) error {
+		extractApiInfoErr := paths.extractApiInfoFromApiStubsProvider(provider, Everything)
+		extractStubsSourceInfoErr := paths.extractStubsSourceInfoFromApiStubsProviders(provider, Everything)
+		return errors.Join(extractApiInfoErr, extractStubsSourceInfoErr)
 	})
 }
 
-func extractSingleOptionalOutputPath(dep android.Module) (android.OptionalPath, error) {
+func extractOutputPaths(dep android.Module) (android.Paths, error) {
 	var paths android.Paths
 	if sourceFileProducer, ok := dep.(android.SourceFileProducer); ok {
 		paths = sourceFileProducer.Srcs()
+		return paths, nil
 	} else {
-		return android.OptionalPath{}, fmt.Errorf("module %q does not produce source files", dep)
+		return nil, fmt.Errorf("module %q does not produce source files", dep)
 	}
-	if len(paths) != 1 {
-		return android.OptionalPath{}, fmt.Errorf("expected one path from %q, got %q", dep, paths)
-	}
-	return android.OptionalPathForPath(paths[0]), nil
 }
 
 func (paths *scopePaths) extractLatestApiPath(ctx android.ModuleContext, dep android.Module) error {
-	outputPath, err := extractSingleOptionalOutputPath(dep)
-	paths.latestApiPath = outputPath
+	outputPaths, err := extractOutputPaths(dep)
+	paths.latestApiPaths = outputPaths
 	return err
 }
 
 func (paths *scopePaths) extractLatestRemovedApiPath(ctx android.ModuleContext, dep android.Module) error {
-	outputPath, err := extractSingleOptionalOutputPath(dep)
-	paths.latestRemovedApiPath = outputPath
+	outputPaths, err := extractOutputPaths(dep)
+	paths.latestRemovedApiPaths = outputPaths
 	return err
 }
 
@@ -773,7 +905,30 @@
 type commonSdkLibraryAndImportModule interface {
 	android.Module
 
-	BaseModuleName() string
+	// Returns the name of the root java_sdk_library that creates the child stub libraries
+	// This is the `name` as it appears in Android.bp, and not the name in Soong's build graph
+	// (with the prebuilt_ prefix)
+	//
+	// e.g. in the following java_sdk_library_import
+	// java_sdk_library_import {
+	//    name: "framework-foo.v1",
+	//    source_module_name: "framework-foo",
+	// }
+	// the values returned by
+	// 1. Name(): prebuilt_framework-foo.v1 # unique
+	// 2. BaseModuleName(): framework-foo # the source
+	// 3. RootLibraryName: framework-foo.v1 # the undecordated `name` from Android.bp
+	RootLibraryName() string
+}
+
+func (m *SdkLibrary) RootLibraryName() string {
+	return m.BaseModuleName()
+}
+
+func (m *SdkLibraryImport) RootLibraryName() string {
+	// m.BaseModuleName refers to the source of the import
+	// use moduleBase.Name to get the name of the module as it appears in the .bp file
+	return m.ModuleBase.Name()
 }
 
 // Common code between sdk library and sdk library import
@@ -791,6 +946,10 @@
 
 	// Functionality related to this being used as a component of a java_sdk_library.
 	EmbeddableSdkLibraryComponent
+
+	// Path to the header jars of the implementation library
+	// This is non-empty only when api_only is false.
+	implLibraryHeaderJars android.Paths
 }
 
 func (c *commonToSdkLibraryAndImport) initCommon(module commonSdkLibraryAndImportModule) {
@@ -812,7 +971,7 @@
 		return false
 	}
 
-	namePtr := proptools.StringPtr(c.module.BaseModuleName())
+	namePtr := proptools.StringPtr(c.module.RootLibraryName())
 	c.sdkLibraryComponentProperties.SdkLibraryName = namePtr
 
 	// Only track this sdk library if this can be used as a shared library.
@@ -839,39 +998,52 @@
 
 // Module name of the runtime implementation library
 func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string {
-	return c.module.BaseModuleName() + ".impl"
+	return c.module.RootLibraryName() + ".impl"
 }
 
 // Module name of the XML file for the lib
 func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string {
-	return c.module.BaseModuleName() + sdkXmlFileSuffix
+	return c.module.RootLibraryName() + sdkXmlFileSuffix
 }
 
 // Name of the java_library module that compiles the stubs source.
 func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string {
-	baseName := c.module.BaseModuleName()
+	baseName := c.module.RootLibraryName()
 	return c.namingScheme.stubsLibraryModuleName(apiScope, baseName)
 }
 
+// Name of the java_library module that compiles the exportable stubs source.
+func (c *commonToSdkLibraryAndImport) exportableStubsLibraryModuleName(apiScope *apiScope) string {
+	baseName := c.module.RootLibraryName()
+	return c.namingScheme.exportableStubsLibraryModuleName(apiScope, baseName)
+}
+
 // Name of the droidstubs module that generates the stubs source and may also
 // generate/check the API.
 func (c *commonToSdkLibraryAndImport) stubsSourceModuleName(apiScope *apiScope) string {
-	baseName := c.module.BaseModuleName()
+	baseName := c.module.RootLibraryName()
 	return c.namingScheme.stubsSourceModuleName(apiScope, baseName)
 }
 
 // Name of the java_api_library module that generates the from-text stubs source
 // and compiles to a jar file.
 func (c *commonToSdkLibraryAndImport) apiLibraryModuleName(apiScope *apiScope) string {
-	baseName := c.module.BaseModuleName()
+	baseName := c.module.RootLibraryName()
 	return c.namingScheme.apiLibraryModuleName(apiScope, baseName)
 }
 
 // Name of the java_library module that compiles the stubs
 // generated from source Java files.
-func (c *commonToSdkLibraryAndImport) sourceStubLibraryModuleName(apiScope *apiScope) string {
-	baseName := c.module.BaseModuleName()
-	return c.namingScheme.sourceStubLibraryModuleName(apiScope, baseName)
+func (c *commonToSdkLibraryAndImport) sourceStubsLibraryModuleName(apiScope *apiScope) string {
+	baseName := c.module.RootLibraryName()
+	return c.namingScheme.sourceStubsLibraryModuleName(apiScope, baseName)
+}
+
+// Name of the java_library module that compiles the exportable stubs
+// generated from source Java files.
+func (c *commonToSdkLibraryAndImport) exportableSourceStubsLibraryModuleName(apiScope *apiScope) string {
+	baseName := c.module.RootLibraryName()
+	return c.namingScheme.exportableSourceStubsLibraryModuleName(apiScope, baseName)
 }
 
 // The component names for different outputs of the java_sdk_library.
@@ -920,7 +1092,7 @@
 		if scope, ok := scopeByName[scopeName]; ok {
 			paths := c.findScopePaths(scope)
 			if paths == nil {
-				return nil, fmt.Errorf("%q does not provide api scope %s", c.module.BaseModuleName(), scopeName)
+				return nil, fmt.Errorf("%q does not provide api scope %s", c.module.RootLibraryName(), scopeName)
 			}
 
 			switch component {
@@ -956,7 +1128,7 @@
 			if c.doctagPaths != nil {
 				return c.doctagPaths, nil
 			} else {
-				return nil, fmt.Errorf("no doctag_files specified on %s", c.module.BaseModuleName())
+				return nil, fmt.Errorf("no doctag_files specified on %s", c.module.RootLibraryName())
 			}
 		}
 		return nil, nil
@@ -1002,7 +1174,7 @@
 
 	// If a specific numeric version has been requested then use prebuilt versions of the sdk.
 	if !sdkVersion.ApiLevel.IsPreview() {
-		return PrebuiltJars(ctx, c.module.BaseModuleName(), sdkVersion)
+		return PrebuiltJars(ctx, c.module.RootLibraryName(), sdkVersion)
 	}
 
 	paths := c.selectScopePaths(ctx, sdkVersion.Kind)
@@ -1029,7 +1201,7 @@
 				scopes = append(scopes, s.name)
 			}
 		}
-		ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.module.BaseModuleName(), scopes)
+		ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.module.RootLibraryName(), scopes)
 		return nil
 	}
 
@@ -1065,6 +1237,16 @@
 }
 
 // to satisfy SdkLibraryDependency interface
+func (c *commonToSdkLibraryAndImport) SdkApiExportableStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath {
+	paths := c.selectScopePaths(ctx, kind)
+	if paths == nil {
+		return makeUnsetDexJarPath()
+	}
+
+	return paths.exportableStubsDexJarPath
+}
+
+// to satisfy SdkLibraryDependency interface
 func (c *commonToSdkLibraryAndImport) SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath {
 	apiScope := sdkKindToApiScope(kind)
 	paths := c.findScopePaths(apiScope)
@@ -1081,7 +1263,7 @@
 		SdkLibraryToImplicitlyTrack *string
 	}{}
 
-	namePtr := proptools.StringPtr(c.module.BaseModuleName())
+	namePtr := proptools.StringPtr(c.module.RootLibraryName())
 	componentProps.SdkLibraryName = namePtr
 
 	if c.sharedLibrary() {
@@ -1175,17 +1357,16 @@
 	// class changes but it does not contain and implementation or JavaDoc.
 	SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths
 
-	// Get the implementation jars appropriate for the supplied sdk version.
-	//
-	// These are either the implementation jar for the whole sdk library or the implementation
-	// jars for the stubs. The latter should only be needed when generating JavaDoc as otherwise
-	// they are identical to the corresponding header jars.
-	SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths
-
-	// SdkApiStubDexJar returns the dex jar for the stubs. It is needed by the hiddenapi processing
-	// tool which processes dex files.
+	// SdkApiStubDexJar returns the dex jar for the stubs for the prebuilt
+	// java_sdk_library_import module. It is needed by the hiddenapi processing tool which
+	// processes dex files.
 	SdkApiStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath
 
+	// SdkApiExportableStubDexJar returns the exportable dex jar for the stubs for
+	// java_sdk_library module. It is needed by the hiddenapi processing tool which processes
+	// dex files.
+	SdkApiExportableStubDexJar(ctx android.BaseModuleContext, kind android.SdkKind) OptionalDexJarPath
+
 	// SdkRemovedTxtFile returns the optional path to the removed.txt file for the specified sdk kind.
 	SdkRemovedTxtFile(ctx android.BaseModuleContext, kind android.SdkKind) android.OptionalPath
 
@@ -1196,8 +1377,6 @@
 type SdkLibrary struct {
 	Library
 
-	android.BazelModuleBase
-
 	sdkLibraryProperties sdkLibraryProperties
 
 	// Map from api scope to the scope specific property structure.
@@ -1300,8 +1479,10 @@
 	for _, apiScope := range module.getGeneratedApiScopes(ctx) {
 		// Add dependencies to the stubs library
 		stubModuleName := module.stubsLibraryModuleName(apiScope)
+		ctx.AddVariationDependencies(nil, apiScope.everythingStubsTag, stubModuleName)
 
-		ctx.AddVariationDependencies(nil, apiScope.stubsTag, stubModuleName)
+		exportableStubModuleName := module.exportableStubsLibraryModuleName(apiScope)
+		ctx.AddVariationDependencies(nil, apiScope.exportableStubsTag, exportableStubModuleName)
 
 		// Add a dependency on the stubs source in order to access both stubs source and api information.
 		ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope))
@@ -1378,6 +1559,12 @@
 }
 
 func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if disableSourceApexVariant(ctx) {
+		// Prebuilts are active, do not create the installation rules for the source javalib.
+		// Even though the source javalib is not used, we need to hide it to prevent duplicate installation rules.
+		// TODO (b/331665856): Implement a principled solution for this.
+		module.HideFromMake()
+	}
 	if proptools.String(module.deviceProperties.Min_sdk_version) != "" {
 		module.CheckMinSdkVersion(ctx)
 	}
@@ -1386,6 +1573,8 @@
 
 	// Only build an implementation library if required.
 	if module.requiresRuntimeImplementationLibrary() {
+		// stubsLinkType must be set before calling Library.GenerateAndroidBuildActions
+		module.Library.stubsLinkType = Unknown
 		module.Library.GenerateAndroidBuildActions(ctx)
 	}
 
@@ -1410,11 +1599,17 @@
 
 			exportedComponents[ctx.OtherModuleName(to)] = struct{}{}
 		}
+
+		if tag == implLibraryTag {
+			if dep, ok := android.OtherModuleProvider(ctx, to, JavaInfoProvider); ok {
+				module.implLibraryHeaderJars = append(module.implLibraryHeaderJars, dep.HeaderJars...)
+			}
+		}
 	})
 
 	// Make the set of components exported by this module available for use elsewhere.
 	exportedComponentInfo := android.ExportedComponentsInfo{Components: android.SortedKeys(exportedComponents)}
-	ctx.SetProvider(android.ExportedComponentsInfoProvider, exportedComponentInfo)
+	android.SetProvider(ctx, android.ExportedComponentsInfoProvider, exportedComponentInfo)
 
 	// Provide additional information for inclusion in an sdk's generated .info file.
 	additionalSdkInfo := map[string]interface{}{}
@@ -1427,14 +1622,18 @@
 		scopes[scope.name] = scopeInfo
 		scopeInfo["current_api"] = scope.snapshotRelativeCurrentApiTxtPath(baseModuleName)
 		scopeInfo["removed_api"] = scope.snapshotRelativeRemovedApiTxtPath(baseModuleName)
-		if p := scopePaths.latestApiPath; p.Valid() {
-			scopeInfo["latest_api"] = p.Path().String()
+		if p := scopePaths.latestApiPaths; len(p) > 0 {
+			// The last path in the list is the one that applies to this scope, the
+			// preceding ones, if any, are for the scope(s) that it extends.
+			scopeInfo["latest_api"] = p[len(p)-1].String()
 		}
-		if p := scopePaths.latestRemovedApiPath; p.Valid() {
-			scopeInfo["latest_removed_api"] = p.Path().String()
+		if p := scopePaths.latestRemovedApiPaths; len(p) > 0 {
+			// The last path in the list is the one that applies to this scope, the
+			// preceding ones, if any, are for the scope(s) that it extends.
+			scopeInfo["latest_removed_api"] = p[len(p)-1].String()
 		}
 	}
-	ctx.SetProvider(android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo})
+	android.SetProvider(ctx, android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo})
 }
 
 func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries {
@@ -1484,12 +1683,16 @@
 	return PrebuiltApiModuleName(name, apiScope.name, "latest")
 }
 
+func latestPrebuiltApiCombinedModuleName(name string, apiScope *apiScope) string {
+	return PrebuiltApiCombinedModuleName(name, apiScope.name, "latest")
+}
+
 func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string {
 	return ":" + module.latestApiModuleName(apiScope)
 }
 
 func (module *SdkLibrary) latestApiModuleName(apiScope *apiScope) string {
-	return latestPrebuiltApiModuleName(module.distStem(), apiScope)
+	return latestPrebuiltApiCombinedModuleName(module.distStem(), apiScope)
 }
 
 func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope *apiScope) string {
@@ -1497,7 +1700,7 @@
 }
 
 func (module *SdkLibrary) latestRemovedApiModuleName(apiScope *apiScope) string {
-	return latestPrebuiltApiModuleName(module.distStem()+"-removed", apiScope)
+	return latestPrebuiltApiCombinedModuleName(module.distStem()+"-removed", apiScope)
 }
 
 func (module *SdkLibrary) latestIncompatibilitiesFilegroupName(apiScope *apiScope) string {
@@ -1513,6 +1716,29 @@
 	return exists
 }
 
+// The listed modules are the special java_sdk_libraries where apiScope.kind do not match the
+// api surface that the module contribute to. For example, the public droidstubs and java_library
+// do not contribute to the public api surface, but contributes to the core platform api surface.
+// This method returns the full api surface stub lib that
+// the generated java_api_library should depend on.
+func (module *SdkLibrary) alternativeFullApiSurfaceStubLib() string {
+	if val, ok := apiLibraryAdditionalProperties[module.Name()]; ok {
+		return val.FullApiSurfaceStubLib
+	}
+	return ""
+}
+
+// The listed modules' stubs contents do not match the corresponding txt files,
+// but require additional api contributions to generate the full stubs.
+// This method returns the name of the additional api contribution module
+// for corresponding sdk_library modules.
+func (module *SdkLibrary) apiLibraryAdditionalApiContribution() string {
+	if val, ok := apiLibraryAdditionalProperties[module.Name()]; ok {
+		return val.AdditionalApiContribution
+	}
+	return ""
+}
+
 func childModuleVisibility(childVisibility []string) []string {
 	if childVisibility == nil {
 		// No child visibility set. The child will use the visibility of the sdk_library.
@@ -1566,42 +1792,42 @@
 	mctx.CreateModule(LibraryFactory, properties...)
 }
 
-// Creates a static java library that has API stubs
-func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
-	props := struct {
-		Name           *string
-		Visibility     []string
-		Srcs           []string
-		Installable    *bool
-		Sdk_version    *string
-		System_modules *string
-		Patch_module   *string
-		Libs           []string
-		Static_libs    []string
-		Compile_dex    *bool
-		Java_version   *string
-		Openjdk9       struct {
-			Srcs       []string
-			Javacflags []string
-		}
-		Dist struct {
-			Targets []string
-			Dest    *string
-			Dir     *string
-			Tag     *string
-		}
-	}{}
+type libraryProperties struct {
+	Name           *string
+	Visibility     []string
+	Srcs           []string
+	Installable    *bool
+	Sdk_version    *string
+	System_modules *string
+	Patch_module   *string
+	Libs           []string
+	Static_libs    []string
+	Compile_dex    *bool
+	Java_version   *string
+	Openjdk9       struct {
+		Srcs       []string
+		Javacflags []string
+	}
+	Dist struct {
+		Targets []string
+		Dest    *string
+		Dir     *string
+		Tag     *string
+	}
+	Is_stubs_module *bool
+}
 
-	props.Name = proptools.StringPtr(module.sourceStubLibraryModuleName(apiScope))
-	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
+func (module *SdkLibrary) stubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties {
+	props := libraryProperties{}
+	props.Visibility = []string{"//visibility:override", "//visibility:private"}
 	// sources are generated from the droiddoc
-	props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)}
 	sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
 	props.Sdk_version = proptools.StringPtr(sdkVersion)
 	props.System_modules = module.deviceProperties.System_modules
 	props.Patch_module = module.properties.Patch_module
 	props.Installable = proptools.BoolPtr(false)
 	props.Libs = module.sdkLibraryProperties.Stub_only_libs
+	props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...)
 	props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
 	// The stub-annotations library contains special versions of the annotations
 	// with CLASS retention policy, so that they're kept.
@@ -1613,6 +1839,26 @@
 	// We compile the stubs for 1.8 in line with the main android.jar stubs, and potential
 	// interop with older developer tools that don't support 1.9.
 	props.Java_version = proptools.StringPtr("1.8")
+	props.Is_stubs_module = proptools.BoolPtr(true)
+
+	return props
+}
+
+// Creates a static java library that has API stubs
+func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
+
+	props := module.stubsLibraryProps(mctx, apiScope)
+	props.Name = proptools.StringPtr(module.sourceStubsLibraryModuleName(apiScope))
+	props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)}
+
+	mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
+}
+
+// Create a static java library that compiles the "exportable" stubs
+func (module *SdkLibrary) createExportableStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
+	props := module.stubsLibraryProps(mctx, apiScope)
+	props.Name = proptools.StringPtr(module.exportableSourceStubsLibraryModuleName(apiScope))
+	props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope) + "{.exportable}"}
 
 	mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
 }
@@ -1638,6 +1884,7 @@
 		Merge_inclusion_annotations_dirs []string
 		Generate_stubs                   *bool
 		Previous_api                     *string
+		Aconfig_declarations             []string
 		Check_api                        struct {
 			Current       ApiToCheck
 			Last_released ApiToCheck
@@ -1674,6 +1921,7 @@
 	props.Libs = module.properties.Libs
 	props.Libs = append(props.Libs, module.properties.Static_libs...)
 	props.Libs = append(props.Libs, module.sdkLibraryProperties.Stub_only_libs...)
+	props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...)
 	props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs
 	props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs
 	props.Java_version = module.properties.Java_version
@@ -1681,6 +1929,7 @@
 	props.Annotations_enabled = module.sdkLibraryProperties.Annotations_enabled
 	props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
 	props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
+	props.Aconfig_declarations = module.sdkLibraryProperties.Aconfig_declarations
 
 	droidstubsArgs := []string{}
 	if len(module.sdkLibraryProperties.Api_packages) != 0 {
@@ -1691,15 +1940,15 @@
 			android.JoinWithPrefix(module.sdkLibraryProperties.Hidden_api_packages, " --hide-package "))
 	}
 	droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...)
-	disabledWarnings := []string{
-		"BroadcastBehavior",
-		"DeprecationMismatch",
-		"HiddenSuperclass",
-		"HiddenTypeParameter",
-		"MissingPermission",
-		"SdkConstant",
-		"Todo",
-		"UnavailableSymbol",
+	disabledWarnings := []string{"HiddenSuperclass"}
+	if proptools.BoolDefault(module.sdkLibraryProperties.Api_lint.Legacy_errors_allowed, true) {
+		disabledWarnings = append(disabledWarnings,
+			"BroadcastBehavior",
+			"DeprecationMismatch",
+			"MissingPermission",
+			"SdkConstant",
+			"Todo",
+		)
 	}
 	droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
 
@@ -1759,26 +2008,33 @@
 	if !Bool(module.sdkLibraryProperties.No_dist) {
 		// Dist the api txt and removed api txt artifacts for sdk builds.
 		distDir := proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
+		stubsTypeTagPrefix := ""
+		if mctx.Config().ReleaseHiddenApiExportableStubs() {
+			stubsTypeTagPrefix = ".exportable"
+		}
 		for _, p := range []struct {
 			tag     string
 			pattern string
 		}{
-			{tag: ".api.txt", pattern: "%s.txt"},
-			{tag: ".removed-api.txt", pattern: "%s-removed.txt"},
+			// "exportable" api files are copied to the dist directory instead of the
+			// "everything" api files when "RELEASE_HIDDEN_API_EXPORTABLE_STUBS" build flag
+			// is set. Otherwise, the "everything" api files are copied to the dist directory.
+			{tag: "%s.api.txt", pattern: "%s.txt"},
+			{tag: "%s.removed-api.txt", pattern: "%s-removed.txt"},
 		} {
 			props.Dists = append(props.Dists, android.Dist{
 				Targets: []string{"sdk", "win_sdk"},
 				Dir:     distDir,
 				Dest:    proptools.StringPtr(fmt.Sprintf(p.pattern, module.distStem())),
-				Tag:     proptools.StringPtr(p.tag),
+				Tag:     proptools.StringPtr(fmt.Sprintf(p.tag, stubsTypeTagPrefix)),
 			})
 		}
 	}
 
-	mctx.CreateModule(DroidstubsFactory, &props).(*Droidstubs).CallHookIfAvailable(mctx)
+	mctx.CreateModule(DroidstubsFactory, &props, module.sdkComponentPropertiesForChildLibrary()).(*Droidstubs).CallHookIfAvailable(mctx)
 }
 
-func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
+func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope, alternativeFullApiSurfaceStub string) {
 	props := struct {
 		Name                  *string
 		Visibility            []string
@@ -1786,10 +2042,13 @@
 		Libs                  []string
 		Static_libs           []string
 		Full_api_surface_stub *string
+		System_modules        *string
+		Enable_validation     *bool
+		Stubs_type            *string
 	}{}
 
 	props.Name = proptools.StringPtr(module.apiLibraryModuleName(apiScope))
-	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
+	props.Visibility = []string{"//visibility:override", "//visibility:private"}
 
 	apiContributions := []string{}
 
@@ -1801,13 +2060,23 @@
 		apiContributions = append(apiContributions, module.stubsSourceModuleName(scope)+".api.contribution")
 		scope = scope.extends
 	}
+	if apiScope == apiScopePublic {
+		additionalApiContribution := module.apiLibraryAdditionalApiContribution()
+		if additionalApiContribution != "" {
+			apiContributions = append(apiContributions, additionalApiContribution)
+		}
+	}
 
 	props.Api_contributions = apiContributions
 	props.Libs = module.properties.Libs
 	props.Libs = append(props.Libs, module.sdkLibraryProperties.Stub_only_libs...)
+	props.Libs = append(props.Libs, module.scopeToProperties[apiScope].Libs...)
 	props.Libs = append(props.Libs, "stub-annotations")
 	props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
-	props.Full_api_surface_stub = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName() + ".from-text")
+	props.Full_api_surface_stub = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName())
+	if alternativeFullApiSurfaceStub != "" {
+		props.Full_api_surface_stub = proptools.StringPtr(alternativeFullApiSurfaceStub)
+	}
 
 	// android_module_lib_stubs_current.from-text only comprises api contributions from art, conscrypt and i18n.
 	// Thus, replace with android_module_lib_stubs_current_full.from-text, which comprises every api domains.
@@ -1815,46 +2084,30 @@
 		props.Full_api_surface_stub = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName() + "_full.from-text")
 	}
 
-	mctx.CreateModule(ApiLibraryFactory, &props)
+	// java_sdk_library modules that set sdk_version as none does not depend on other api
+	// domains. Therefore, java_api_library created from such modules should not depend on
+	// full_api_surface_stubs but create and compile stubs by the java_api_library module
+	// itself.
+	if module.SdkVersion(mctx).Kind == android.SdkNone {
+		props.Full_api_surface_stub = nil
+	}
+
+	props.System_modules = module.deviceProperties.System_modules
+	props.Enable_validation = proptools.BoolPtr(true)
+	props.Stubs_type = proptools.StringPtr("everything")
+
+	mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
 }
 
-func (module *SdkLibrary) createTopLevelStubsLibrary(
-	mctx android.DefaultableHookContext, apiScope *apiScope, contributesToApiSurface bool) {
-	props := struct {
-		Name           *string
-		Visibility     []string
-		Sdk_version    *string
-		Static_libs    []string
-		System_modules *string
-		Dist           struct {
-			Targets []string
-			Dest    *string
-			Dir     *string
-			Tag     *string
-		}
-		Compile_dex *bool
-	}{}
-	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
+func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope, doDist bool) libraryProperties {
+	props := libraryProperties{}
+
 	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
 	sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
 	props.Sdk_version = proptools.StringPtr(sdkVersion)
 
-	// Add the stub compiling java_library/java_api_library as static lib based on build config
-	staticLib := module.sourceStubLibraryModuleName(apiScope)
-	if mctx.Config().BuildFromTextStub() && contributesToApiSurface {
-		staticLib = module.apiLibraryModuleName(apiScope)
-	}
-	props.Static_libs = append(props.Static_libs, staticLib)
 	props.System_modules = module.deviceProperties.System_modules
 
-	// Dist the class jar artifact for sdk builds.
-	if !Bool(module.sdkLibraryProperties.No_dist) {
-		props.Dist.Targets = []string{"sdk", "win_sdk"}
-		props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem()))
-		props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
-		props.Dist.Tag = proptools.StringPtr(".jar")
-	}
-
 	// The imports need to be compiled to dex if the java_sdk_library requests it.
 	compileDex := module.dexProperties.Compile_dex
 	if module.stubLibrariesCompiledForDex() {
@@ -1862,6 +2115,45 @@
 	}
 	props.Compile_dex = compileDex
 
+	if !Bool(module.sdkLibraryProperties.No_dist) && doDist {
+		props.Dist.Targets = []string{"sdk", "win_sdk"}
+		props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.jar", module.distStem()))
+		props.Dist.Dir = proptools.StringPtr(module.apiDistPath(apiScope))
+		props.Dist.Tag = proptools.StringPtr(".jar")
+	}
+
+	return props
+}
+
+func (module *SdkLibrary) createTopLevelStubsLibrary(
+	mctx android.DefaultableHookContext, apiScope *apiScope, contributesToApiSurface bool) {
+
+	// Dist the "everything" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is false
+	doDist := !mctx.Config().ReleaseHiddenApiExportableStubs()
+	props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist)
+	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
+
+	// Add the stub compiling java_library/java_api_library as static lib based on build config
+	staticLib := module.sourceStubsLibraryModuleName(apiScope)
+	if mctx.Config().BuildFromTextStub() && contributesToApiSurface {
+		staticLib = module.apiLibraryModuleName(apiScope)
+	}
+	props.Static_libs = append(props.Static_libs, staticLib)
+
+	mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
+}
+
+func (module *SdkLibrary) createTopLevelExportableStubsLibrary(
+	mctx android.DefaultableHookContext, apiScope *apiScope) {
+
+	// Dist the "exportable" stubs when the RELEASE_HIDDEN_API_EXPORTABLE_STUBS build flag is true
+	doDist := mctx.Config().ReleaseHiddenApiExportableStubs()
+	props := module.topLevelStubsLibraryProps(mctx, apiScope, doDist)
+	props.Name = proptools.StringPtr(module.exportableStubsLibraryModuleName(apiScope))
+
+	staticLib := module.exportableSourceStubsLibraryModuleName(apiScope)
+	props.Static_libs = append(props.Static_libs, staticLib)
+
 	mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
 }
 
@@ -1883,6 +2175,10 @@
 	return module.uniqueApexVariations()
 }
 
+func (module *SdkLibrary) ContributeToApi() bool {
+	return proptools.BoolDefault(module.sdkLibraryProperties.Contribute_to_android_api, false)
+}
+
 // Creates the xml file that publicizes the runtime library
 func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
 	moduleMinApiLevel := module.Library.MinSdkVersion(mctx)
@@ -1899,6 +2195,7 @@
 		Min_device_sdk            *string
 		Max_device_sdk            *string
 		Sdk_library_min_api_level *string
+		Uses_libs_dependencies    []string
 	}{
 		Name:                      proptools.StringPtr(module.xmlPermissionsModuleName()),
 		Lib_name:                  proptools.StringPtr(module.BaseModuleName()),
@@ -1908,6 +2205,7 @@
 		Min_device_sdk:            module.commonSdkLibraryProperties.Min_device_sdk,
 		Max_device_sdk:            module.commonSdkLibraryProperties.Max_device_sdk,
 		Sdk_library_min_api_level: &moduleMinApiLevelStr,
+		Uses_libs_dependencies:    module.usesLibraryProperties.Uses_libs,
 	}
 
 	mctx.CreateModule(sdkLibraryXmlFactory, &props)
@@ -1945,12 +2243,12 @@
 // If either this or the other module are on the platform then this will return
 // false.
 func withinSameApexesAs(ctx android.BaseModuleContext, other android.Module) bool {
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
-	otherApexInfo := ctx.OtherModuleProvider(other, android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+	otherApexInfo, _ := android.OtherModuleProvider(ctx, other, android.ApexInfoProvider)
 	return len(otherApexInfo.InApexVariants) > 0 && reflect.DeepEqual(apexInfo.InApexVariants, otherApexInfo.InApexVariants)
 }
 
-func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec, headerJars bool) android.Paths {
+func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
 	// If the client doesn't set sdk_version, but if this library prefers stubs over
 	// the impl library, let's provide the widest API surface possible. To do so,
 	// force override sdk_version to module_current so that the closest possible API
@@ -1967,11 +2265,7 @@
 		// * No sdk_version specified on the referencing module.
 		// * The referencing module is in the same apex as this.
 		if sdkVersion.Kind == android.SdkPrivate || withinSameApexesAs(ctx, module) {
-			if headerJars {
-				return module.HeaderJars()
-			} else {
-				return module.ImplementationJars()
-			}
+			return module.implLibraryHeaderJars
 		}
 	}
 
@@ -1980,12 +2274,7 @@
 
 // to satisfy SdkLibraryDependency interface
 func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
-	return module.sdkJars(ctx, sdkVersion, true /*headerJars*/)
-}
-
-// to satisfy SdkLibraryDependency interface
-func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
-	return module.sdkJars(ctx, sdkVersion, false /*headerJars*/)
+	return module.sdkJars(ctx, sdkVersion)
 }
 
 var javaSdkLibrariesKey = android.NewOnceKey("javaSdkLibraries")
@@ -2061,13 +2350,19 @@
 		module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs)
 
 		module.createStubsLibrary(mctx, scope)
+		module.createExportableStubsLibrary(mctx, scope)
 
-		contributesToApiSurface := module.contributesToApiSurface(mctx.Config())
+		alternativeFullApiSurfaceStubLib := ""
+		if scope == apiScopePublic {
+			alternativeFullApiSurfaceStubLib = module.alternativeFullApiSurfaceStubLib()
+		}
+		contributesToApiSurface := module.contributesToApiSurface(mctx.Config()) || alternativeFullApiSurfaceStubLib != ""
 		if contributesToApiSurface {
-			module.createApiLibrary(mctx, scope)
+			module.createApiLibrary(mctx, scope, alternativeFullApiSurfaceStubLib)
 		}
 
 		module.createTopLevelStubsLibrary(mctx, scope, contributesToApiSurface)
+		module.createTopLevelExportableStubsLibrary(mctx, scope)
 	}
 
 	if module.requiresRuntimeImplementationLibrary() {
@@ -2123,7 +2418,11 @@
 
 	apiLibraryModuleName(scope *apiScope, baseName string) string
 
-	sourceStubLibraryModuleName(scope *apiScope, baseName string) string
+	sourceStubsLibraryModuleName(scope *apiScope, baseName string) string
+
+	exportableStubsLibraryModuleName(scope *apiScope, baseName string) string
+
+	exportableSourceStubsLibraryModuleName(scope *apiScope, baseName string) string
 }
 
 type defaultNamingScheme struct {
@@ -2141,34 +2440,47 @@
 	return scope.apiLibraryModuleName(baseName)
 }
 
-func (s *defaultNamingScheme) sourceStubLibraryModuleName(scope *apiScope, baseName string) string {
+func (s *defaultNamingScheme) sourceStubsLibraryModuleName(scope *apiScope, baseName string) string {
 	return scope.sourceStubLibraryModuleName(baseName)
 }
 
+func (s *defaultNamingScheme) exportableStubsLibraryModuleName(scope *apiScope, baseName string) string {
+	return scope.exportableStubsLibraryModuleName(baseName)
+}
+
+func (s *defaultNamingScheme) exportableSourceStubsLibraryModuleName(scope *apiScope, baseName string) string {
+	return scope.exportableSourceStubsLibraryModuleName(baseName)
+}
+
 var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil)
 
+func hasStubsLibrarySuffix(name string, apiScope *apiScope) bool {
+	return strings.HasSuffix(name, apiScope.stubsLibraryModuleNameSuffix()) ||
+		strings.HasSuffix(name, apiScope.exportableStubsLibraryModuleNameSuffix())
+}
+
 func moduleStubLinkType(name string) (stub bool, ret sdkLinkType) {
 	name = strings.TrimSuffix(name, ".from-source")
 
 	// This suffix-based approach is fragile and could potentially mis-trigger.
 	// TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly.
-	if strings.HasSuffix(name, apiScopePublic.stubsLibraryModuleNameSuffix()) {
+	if hasStubsLibrarySuffix(name, apiScopePublic) {
 		if name == "hwbinder.stubs" || name == "libcore_private.stubs" {
 			// Due to a previous bug, these modules were not considered stubs, so we retain that.
 			return false, javaPlatform
 		}
 		return true, javaSdk
 	}
-	if strings.HasSuffix(name, apiScopeSystem.stubsLibraryModuleNameSuffix()) {
+	if hasStubsLibrarySuffix(name, apiScopeSystem) {
 		return true, javaSystem
 	}
-	if strings.HasSuffix(name, apiScopeModuleLib.stubsLibraryModuleNameSuffix()) {
+	if hasStubsLibrarySuffix(name, apiScopeModuleLib) {
 		return true, javaModule
 	}
-	if strings.HasSuffix(name, apiScopeTest.stubsLibraryModuleNameSuffix()) {
+	if hasStubsLibrarySuffix(name, apiScopeTest) {
 		return true, javaSystem
 	}
-	if strings.HasSuffix(name, apiScopeSystemServer.stubsLibraryModuleNameSuffix()) {
+	if hasStubsLibrarySuffix(name, apiScopeSystemServer) {
 		return true, javaSystemServer
 	}
 	return false, javaPlatform
@@ -2218,49 +2530,9 @@
 			module.CreateInternalModules(ctx)
 		}
 	})
-	android.InitBazelModule(module)
 	return module
 }
 
-type bazelSdkLibraryAttributes struct {
-	Public        bazel.StringAttribute
-	System        bazel.StringAttribute
-	Test          bazel.StringAttribute
-	Module_lib    bazel.StringAttribute
-	System_server bazel.StringAttribute
-}
-
-// java_sdk_library bp2build converter
-func (module *SdkLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	if ctx.ModuleType() != "java_sdk_library" {
-		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
-		return
-	}
-
-	nameToAttr := make(map[string]bazel.StringAttribute)
-
-	for _, scope := range module.getGeneratedApiScopes(ctx) {
-		apiSurfaceFile := path.Join(module.getApiDir(), scope.apiFilePrefix+"current.txt")
-		var scopeStringAttribute bazel.StringAttribute
-		scopeStringAttribute.SetValue(apiSurfaceFile)
-		nameToAttr[scope.name] = scopeStringAttribute
-	}
-
-	attrs := bazelSdkLibraryAttributes{
-		Public:        nameToAttr["public"],
-		System:        nameToAttr["system"],
-		Test:          nameToAttr["test"],
-		Module_lib:    nameToAttr["module-lib"],
-		System_server: nameToAttr["system-server"],
-	}
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "java_sdk_library",
-		Bzl_load_location: "//build/bazel/rules/java:sdk_library.bzl",
-	}
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, &attrs)
-}
-
 //
 // SDK library prebuilts
 //
@@ -2297,6 +2569,11 @@
 
 	// If not empty, classes are restricted to the specified packages and their sub-packages.
 	Permitted_packages []string
+
+	// Name of the source soong module that gets shadowed by this prebuilt
+	// If unspecified, follows the naming convention that the source module of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_module_name *string
 }
 
 type SdkLibraryImport struct {
@@ -2324,7 +2601,8 @@
 	xmlPermissionsFileModule *sdkLibraryXml
 
 	// Build path to the dex implementation jar obtained from the prebuilt_apex, if any.
-	dexJarFile OptionalDexJarPath
+	dexJarFile    OptionalDexJarPath
+	dexJarFileErr error
 
 	// Expected install file path of the source module(sdk_library)
 	// or dex implementation jar obtained from the prebuilt_apex, if any.
@@ -2409,6 +2687,10 @@
 	return module.prebuilt.Name(module.ModuleBase.Name())
 }
 
+func (module *SdkLibraryImport) BaseModuleName() string {
+	return proptools.StringDefault(module.properties.Source_module_name, module.ModuleBase.Name())
+}
+
 func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) {
 
 	// If the build is configured to use prebuilts then force this to be preferred.
@@ -2426,6 +2708,10 @@
 		if len(scopeProperties.Stub_srcs) > 0 {
 			module.createPrebuiltStubsSources(mctx, apiScope, scopeProperties)
 		}
+
+		if scopeProperties.Current_api != nil {
+			module.createPrebuiltApiContribution(mctx, apiScope, scopeProperties)
+		}
 	}
 
 	javaSdkLibraries := javaSdkLibraries(mctx.Config())
@@ -2437,15 +2723,20 @@
 func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
 	// Creates a java import for the jar with ".stubs" suffix
 	props := struct {
-		Name        *string
-		Sdk_version *string
-		Libs        []string
-		Jars        []string
-		Compile_dex *bool
+		Name                             *string
+		Source_module_name               *string
+		Created_by_java_sdk_library_name *string
+		Sdk_version                      *string
+		Libs                             []string
+		Jars                             []string
+		Compile_dex                      *bool
+		Is_stubs_module                  *bool
 
 		android.UserSuppliedPrebuiltProperties
 	}{}
 	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
+	props.Source_module_name = proptools.StringPtr(apiScope.stubsLibraryModuleName(module.BaseModuleName()))
+	props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
 	props.Sdk_version = scopeProperties.Sdk_version
 	// Prepend any of the libs from the legacy public properties to the libs for each of the
 	// scopes to avoid having to duplicate them in each scope.
@@ -2461,24 +2752,52 @@
 		compileDex = proptools.BoolPtr(true)
 	}
 	props.Compile_dex = compileDex
+	props.Is_stubs_module = proptools.BoolPtr(true)
 
 	mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
 }
 
 func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
 	props := struct {
-		Name *string
-		Srcs []string
+		Name                             *string
+		Source_module_name               *string
+		Created_by_java_sdk_library_name *string
+		Srcs                             []string
 
 		android.UserSuppliedPrebuiltProperties
 	}{}
 	props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope))
+	props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()))
+	props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
 	props.Srcs = scopeProperties.Stub_srcs
 
 	// The stubs source is preferred if the java_sdk_library_import is preferred.
 	props.CopyUserSuppliedPropertiesFromPrebuilt(&module.prebuilt)
 
-	mctx.CreateModule(PrebuiltStubsSourcesFactory, &props)
+	mctx.CreateModule(PrebuiltStubsSourcesFactory, &props, module.sdkComponentPropertiesForChildLibrary())
+}
+
+func (module *SdkLibraryImport) createPrebuiltApiContribution(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
+	api_file := scopeProperties.Current_api
+	api_surface := &apiScope.name
+
+	props := struct {
+		Name                             *string
+		Source_module_name               *string
+		Created_by_java_sdk_library_name *string
+		Api_surface                      *string
+		Api_file                         *string
+		Visibility                       []string
+	}{}
+
+	props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope) + ".api.contribution")
+	props.Source_module_name = proptools.StringPtr(apiScope.stubsSourceModuleName(module.BaseModuleName()) + ".api.contribution")
+	props.Created_by_java_sdk_library_name = proptools.StringPtr(module.RootLibraryName())
+	props.Api_surface = api_surface
+	props.Api_file = api_file
+	props.Visibility = []string{"//visibility:override", "//visibility:public"}
+
+	mctx.CreateModule(ApiContributionImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
 }
 
 // Add the dependencies on the child module in the component deps mutator so that it
@@ -2490,7 +2809,7 @@
 		}
 
 		// Add dependencies to the prebuilt stubs library
-		ctx.AddVariationDependencies(nil, apiScope.stubsTag, android.PrebuiltNameFromSource(module.stubsLibraryModuleName(apiScope)))
+		ctx.AddVariationDependencies(nil, apiScope.prebuiltStubsTag, android.PrebuiltNameFromSource(module.stubsLibraryModuleName(apiScope)))
 
 		if len(scopeProperties.Stub_srcs) > 0 {
 			// Add dependencies to the prebuilt stubs source library
@@ -2514,14 +2833,6 @@
 	}
 }
 
-func (module *SdkLibraryImport) AndroidMkEntries() []android.AndroidMkEntries {
-	// For an SDK library imported from a prebuilt APEX, we don't need a Make module for itself, as we
-	// don't need to install it. However, we need to add its dexpreopt outputs as sub-modules, if it
-	// is preopted.
-	dexpreoptEntries := module.dexpreopter.AndroidMkEntriesForApex()
-	return append(dexpreoptEntries, android.AndroidMkEntries{Disabled: true})
-}
-
 var _ android.ApexModule = (*SdkLibraryImport)(nil)
 
 // Implements android.ApexModule
@@ -2615,14 +2926,18 @@
 	if ctx.Device() {
 		// If this is a variant created for a prebuilt_apex then use the dex implementation jar
 		// obtained from the associated deapexer module.
-		ai := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+		ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 		if ai.ForPrebuiltApex {
 			// Get the path of the dex implementation jar from the `deapexer` module.
-			di := android.FindDeapexerProviderForModule(ctx)
-			if di == nil {
-				return // An error has been reported by FindDeapexerProviderForModule.
+			di, err := android.FindDeapexerProviderForModule(ctx)
+			if err != nil {
+				// An error was found, possibly due to multiple apexes in the tree that export this library
+				// Defer the error till a client tries to call DexJarBuildPath
+				module.dexJarFileErr = err
+				module.initHiddenAPIError(err)
+				return
 			}
-			dexJarFileApexRootRelative := apexRootRelativePathToJavaLib(module.BaseModuleName())
+			dexJarFileApexRootRelative := ApexRootRelativePathToJavaLib(module.BaseModuleName())
 			if dexOutputPath := di.PrebuiltExportPath(dexJarFileApexRootRelative); dexOutputPath != nil {
 				dexJarFile := makeDexJarPathFromPath(dexOutputPath)
 				module.dexJarFile = dexJarFile
@@ -2631,16 +2946,13 @@
 				module.installFile = installPath
 				module.initHiddenAPI(ctx, dexJarFile, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil)
 
-				module.dexpreopter.installPath = module.dexpreopter.getInstallPath(ctx, installPath)
+				module.dexpreopter.installPath = module.dexpreopter.getInstallPath(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), installPath)
 				module.dexpreopter.isSDKLibrary = true
-				module.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &module.dexpreopter)
+				module.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), &module.dexpreopter)
 
 				if profilePath := di.PrebuiltExportPath(dexJarFileApexRootRelative + ".prof"); profilePath != nil {
 					module.dexpreopter.inputProfilePathOnHost = profilePath
 				}
-
-				// Dexpreopting.
-				module.dexpreopt(ctx, dexOutputPath)
 			} else {
 				// This should never happen as a variant for a prebuilt_apex is only created if the
 				// prebuilt_apex has been configured to export the java library dex file.
@@ -2672,23 +2984,20 @@
 	return module.sdkJars(ctx, sdkVersion, true)
 }
 
-// to satisfy SdkLibraryDependency interface
-func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths {
-	// This module is just a wrapper for the stubs.
-	return module.sdkJars(ctx, sdkVersion, false)
-}
-
 // to satisfy UsesLibraryDependency interface
-func (module *SdkLibraryImport) DexJarBuildPath() OptionalDexJarPath {
+func (module *SdkLibraryImport) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
 	// The dex implementation jar extracted from the .apex file should be used in preference to the
 	// source.
+	if module.dexJarFileErr != nil {
+		ctx.ModuleErrorf(module.dexJarFileErr.Error())
+	}
 	if module.dexJarFile.IsSet() {
 		return module.dexJarFile
 	}
 	if module.implLibraryModule == nil {
 		return makeUnsetDexJarPath()
 	} else {
-		return module.implLibraryModule.DexJarBuildPath()
+		return module.implLibraryModule.DexJarBuildPath(ctx)
 	}
 }
 
@@ -2771,6 +3080,10 @@
 	return requiredFilesFromPrebuiltApexForImport(name, &module.dexpreopter)
 }
 
+func (j *SdkLibraryImport) UseProfileGuidedDexpreopt() bool {
+	return proptools.Bool(j.importDexpreoptProperties.Dex_preopt.Profile_guided)
+}
+
 // java_sdk_library_xml
 type sdkLibraryXml struct {
 	android.ModuleBase
@@ -2820,6 +3133,11 @@
 	//
 	// This value comes from the ApiLevel of the MinSdkVersion property.
 	Sdk_library_min_api_level *string
+
+	// Uses-libs dependencies that the shared library requires to work correctly.
+	//
+	// This will add dependency="foo:bar" to the <library> section.
+	Uses_libs_dependencies []string
 }
 
 // java_sdk_library_xml builds the permission xml file for a java_sdk_library.
@@ -2852,10 +3170,12 @@
 }
 
 // from android.PrebuiltEtcModule
-func (module *sdkLibraryXml) OutputFile() android.OutputPath {
-	return module.outputFilePath
+func (module *sdkLibraryXml) OutputFiles(tag string) (android.Paths, error) {
+	return android.OutputPaths{module.outputFilePath}.Paths(), nil
 }
 
+var _ etc.PrebuiltEtcModule = (*sdkLibraryXml)(nil)
+
 // from android.ApexModule
 func (module *sdkLibraryXml) AvailableFor(what string) bool {
 	return true
@@ -2877,7 +3197,7 @@
 // File path to the runtime implementation library
 func (module *sdkLibraryXml) implPath(ctx android.ModuleContext) string {
 	implName := proptools.String(module.properties.Lib_name)
-	if apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo); !apexInfo.IsForPlatform() {
+	if apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider); !apexInfo.IsForPlatform() {
 		// TODO(b/146468504): ApexVariationName() is only a soong module name, not apex name.
 		// In most cases, this works fine. But when apex_name is set or override_apex is used
 		// this can be wrong.
@@ -2925,7 +3245,14 @@
 	if value == nil {
 		return ""
 	}
-	return fmt.Sprintf(`        %s=\"%s\"\n`, attrName, *value)
+	return fmt.Sprintf("        %s=\"%s\"\n", attrName, *value)
+}
+
+func formattedDependenciesAttribute(dependencies []string) string {
+	if dependencies == nil {
+		return ""
+	}
+	return fmt.Sprintf("        dependency=\"%s\"\n", strings.Join(dependencies, ":"))
 }
 
 func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) string {
@@ -2937,32 +3264,33 @@
 	implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-before", module.properties.On_bootclasspath_before)
 	minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min-device-sdk", module.properties.Min_device_sdk)
 	maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max-device-sdk", module.properties.Max_device_sdk)
+	dependenciesAttr := formattedDependenciesAttribute(module.properties.Uses_libs_dependencies)
 	// <library> is understood in all android versions whereas <apex-library> is only understood from API T (and ignored before that).
 	// similarly, min_device_sdk is only understood from T. So if a library is using that, we need to use the apex-library to make sure this library is not loaded before T
 	var libraryTag string
 	if module.properties.Min_device_sdk != nil {
-		libraryTag = `    <apex-library\n`
+		libraryTag = "    <apex-library\n"
 	} else {
-		libraryTag = `    <library\n`
+		libraryTag = "    <library\n"
 	}
 
 	return strings.Join([]string{
-		`<?xml version=\"1.0\" encoding=\"utf-8\"?>\n`,
-		`<!-- Copyright (C) 2018 The Android Open Source Project\n`,
-		`\n`,
-		`    Licensed under the Apache License, Version 2.0 (the \"License\");\n`,
-		`    you may not use this file except in compliance with the License.\n`,
-		`    You may obtain a copy of the License at\n`,
-		`\n`,
-		`        http://www.apache.org/licenses/LICENSE-2.0\n`,
-		`\n`,
-		`    Unless required by applicable law or agreed to in writing, software\n`,
-		`    distributed under the License is distributed on an \"AS IS\" BASIS,\n`,
-		`    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n`,
-		`    See the License for the specific language governing permissions and\n`,
-		`    limitations under the License.\n`,
-		`-->\n`,
-		`<permissions>\n`,
+		"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
+		"<!-- Copyright (C) 2018 The Android Open Source Project\n",
+		"\n",
+		"    Licensed under the Apache License, Version 2.0 (the \"License\");\n",
+		"    you may not use this file except in compliance with the License.\n",
+		"    You may obtain a copy of the License at\n",
+		"\n",
+		"        http://www.apache.org/licenses/LICENSE-2.0\n",
+		"\n",
+		"    Unless required by applicable law or agreed to in writing, software\n",
+		"    distributed under the License is distributed on an \"AS IS\" BASIS,\n",
+		"    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
+		"    See the License for the specific language governing permissions and\n",
+		"    limitations under the License.\n",
+		"-->\n",
+		"<permissions>\n",
 		libraryTag,
 		libNameAttr,
 		filePathAttr,
@@ -2970,26 +3298,25 @@
 		implicitUntilAttr,
 		minSdkAttr,
 		maxSdkAttr,
-		`    />\n`,
-		`</permissions>\n`}, "")
+		dependenciesAttr,
+		"    />\n",
+		"</permissions>\n",
+	}, "")
 }
 
 func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	module.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+	module.hideApexVariantFromMake = !apexInfo.IsForPlatform()
 
 	libName := proptools.String(module.properties.Lib_name)
 	module.selfValidate(ctx)
 	xmlContent := module.permissionsContents(ctx)
 
 	module.outputFilePath = android.PathForModuleOut(ctx, libName+".xml").OutputPath
-	rule := android.NewRuleBuilder(pctx, ctx)
-	rule.Command().
-		Text("/bin/bash -c \"echo -e '" + xmlContent + "'\" > ").
-		Output(module.outputFilePath)
-
-	rule.Build("java_sdk_xml", "Permission XML")
+	android.WriteFileRuleVerbatim(ctx, module.outputFilePath, xmlContent)
 
 	module.installDirPath = android.PathForModuleInstall(ctx, "etc", module.SubDir())
+	ctx.PackageFile(module.installDirPath, libName+".xml", module.outputFilePath)
 }
 
 func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index c22b980..0f163e6 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -38,6 +38,11 @@
 		android.FixtureModifyConfig(func(config android.Config) {
 			config.SetApiLibraries([]string{"foo"})
 		}),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
 	).RunTestWithBp(t, `
 		droiddoc_exported_dir {
 			name: "droiddoc-templates-sdk",
@@ -74,6 +79,8 @@
 		    name: "quuz",
 				public: {
 					jars: ["c.jar"],
+					current_api: "api/current.txt",
+					removed_api: "api/removed.txt",
 				},
 		}
 		java_sdk_library_import {
@@ -130,13 +137,16 @@
 	result.ModuleForTests("foo.api.system.28", "")
 	result.ModuleForTests("foo.api.test.28", "")
 
-	exportedComponentsInfo := result.ModuleProvider(foo.Module(), android.ExportedComponentsInfoProvider).(android.ExportedComponentsInfo)
+	exportedComponentsInfo, _ := android.SingletonModuleProvider(result, foo.Module(), android.ExportedComponentsInfoProvider)
 	expectedFooExportedComponents := []string{
-		"foo-removed.api.public.latest",
-		"foo-removed.api.system.latest",
-		"foo.api.public.latest",
-		"foo.api.system.latest",
+		"foo-removed.api.combined.public.latest",
+		"foo-removed.api.combined.system.latest",
+		"foo.api.combined.public.latest",
+		"foo.api.combined.system.latest",
 		"foo.stubs",
+		"foo.stubs.exportable",
+		"foo.stubs.exportable.system",
+		"foo.stubs.exportable.test",
 		"foo.stubs.source",
 		"foo.stubs.source.system",
 		"foo.stubs.source.test",
@@ -173,6 +183,9 @@
 		android.AssertDeepEquals(t, "qux exports (optional)", []string{}, optionalSdkLibs)
 	}
 
+	// test if quuz have created the api_contribution module
+	result.ModuleForTests(apiScopePublic.stubsSourceModuleName("quuz")+".api.contribution", "")
+
 	fooDexJar := result.ModuleForTests("foo", "android_common").Rule("d8")
 	// tests if kotlinc generated files are NOT excluded from output of foo.
 	android.AssertStringDoesNotContain(t, "foo dex", fooDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module")
@@ -214,19 +227,21 @@
 `)
 
 	// test that updatability attributes are passed on correctly
-	fooUpdatable := result.ModuleForTests("fooUpdatable.xml", "android_common").Rule("java_sdk_xml")
-	android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on-bootclasspath-since=\"U\"`)
-	android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `on-bootclasspath-before=\"V\"`)
-	android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `min-device-sdk=\"W\"`)
-	android.AssertStringDoesContain(t, "fooUpdatable.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `max-device-sdk=\"X\"`)
+	fooUpdatable := result.ModuleForTests("fooUpdatable.xml", "android_common").Output("fooUpdatable.xml")
+	fooUpdatableContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooUpdatable)
+	android.AssertStringDoesContain(t, "fooUpdatable.xml contents", fooUpdatableContents, `on-bootclasspath-since="U"`)
+	android.AssertStringDoesContain(t, "fooUpdatable.xml contents", fooUpdatableContents, `on-bootclasspath-before="V"`)
+	android.AssertStringDoesContain(t, "fooUpdatable.xml contents", fooUpdatableContents, `min-device-sdk="W"`)
+	android.AssertStringDoesContain(t, "fooUpdatable.xml contents", fooUpdatableContents, `max-device-sdk="X"`)
 
 	// double check that updatability attributes are not written if they don't exist in the bp file
 	// the permissions file for the foo library defined above
-	fooPermissions := result.ModuleForTests("foo.xml", "android_common").Rule("java_sdk_xml")
-	android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `on-bootclasspath-since`)
-	android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `on-bootclasspath-before`)
-	android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `min-device-sdk`)
-	android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooPermissions.RuleParams.Command, `max-device-sdk`)
+	fooPermissions := result.ModuleForTests("foo.xml", "android_common").Output("foo.xml")
+	fooPermissionsContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooPermissions)
+	android.AssertStringDoesNotContain(t, "foo.xml contents", fooPermissionsContents, `on-bootclasspath-since`)
+	android.AssertStringDoesNotContain(t, "foo.xml contents", fooPermissionsContents, `on-bootclasspath-before`)
+	android.AssertStringDoesNotContain(t, "foo.xml contents", fooPermissionsContents, `min-device-sdk`)
+	android.AssertStringDoesNotContain(t, "foo.xml contents", fooPermissionsContents, `max-device-sdk`)
 }
 
 func TestJavaSdkLibrary_UpdatableLibrary_Validation_ValidVersion(t *testing.T) {
@@ -357,9 +372,10 @@
 		}
 `)
 	// test that updatability attributes are passed on correctly
-	fooUpdatable := result.ModuleForTests("foo.xml", "android_common").Rule("java_sdk_xml")
-	android.AssertStringDoesContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `<apex-library`)
-	android.AssertStringDoesNotContain(t, "foo.xml java_sdk_xml command", fooUpdatable.RuleParams.Command, `<library`)
+	fooUpdatable := result.ModuleForTests("foo.xml", "android_common").Output("foo.xml")
+	fooUpdatableContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooUpdatable)
+	android.AssertStringDoesContain(t, "foo.xml contents", fooUpdatableContents, `<apex-library`)
+	android.AssertStringDoesNotContain(t, "foo.xml contents", fooUpdatableContents, `<library`)
 }
 
 func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) {
@@ -524,6 +540,11 @@
 		prepareForJavaTest,
 		PrepareForTestWithJavaSdkLibraryFiles,
 		FixtureWithLastReleaseApis("sdklib"),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
 	).RunTestWithBp(t, `
 		java_sdk_library {
 			name: "sdklib",
@@ -538,10 +559,11 @@
 
 	CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
 		`dex2oatd`,
-		`sdklib-removed.api.public.latest`,
-		`sdklib.api.public.latest`,
+		`sdklib-removed.api.combined.public.latest`,
+		`sdklib.api.combined.public.latest`,
 		`sdklib.impl`,
 		`sdklib.stubs`,
+		`sdklib.stubs.exportable`,
 		`sdklib.stubs.source`,
 		`sdklib.xml`,
 	})
@@ -914,6 +936,11 @@
 		prepareForJavaTest,
 		PrepareForTestWithJavaSdkLibraryFiles,
 		FixtureWithLastReleaseApis("sdklib"),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
 	).RunTestWithBp(t, `
 		java_sdk_library {
 			name: "sdklib",
@@ -936,15 +963,17 @@
 	CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
 		`dex2oatd`,
 		`prebuilt_sdklib`,
-		`sdklib-removed.api.public.latest`,
-		`sdklib.api.public.latest`,
+		`sdklib-removed.api.combined.public.latest`,
+		`sdklib.api.combined.public.latest`,
 		`sdklib.impl`,
 		`sdklib.stubs`,
+		`sdklib.stubs.exportable`,
 		`sdklib.stubs.source`,
 		`sdklib.xml`,
 	})
 
 	CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
+		`all_apex_contributions`,
 		`prebuilt_sdklib.stubs`,
 		`sdklib.impl`,
 		// This should be prebuilt_sdklib.stubs but is set to sdklib.stubs because the
@@ -960,6 +989,11 @@
 		PrepareForTestWithJavaSdkLibraryFiles,
 		FixtureWithLastReleaseApis("sdklib"),
 		preparer,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
 	).RunTestWithBp(t, `
 		java_sdk_library {
 			name: "sdklib",
@@ -1008,15 +1042,17 @@
 
 	CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
 		`prebuilt_sdklib`,
-		`sdklib-removed.api.public.latest`,
-		`sdklib.api.public.latest`,
+		`sdklib-removed.api.combined.public.latest`,
+		`sdklib.api.combined.public.latest`,
 		`sdklib.impl`,
 		`sdklib.stubs`,
+		`sdklib.stubs.exportable`,
 		`sdklib.stubs.source`,
 		`sdklib.xml`,
 	})
 
 	CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
+		`all_apex_contributions`,
 		`dex2oatd`,
 		`prebuilt_sdklib.stubs`,
 		`prebuilt_sdklib.stubs.source`,
@@ -1049,18 +1085,131 @@
 	t.Run("prefer", func(t *testing.T) {
 		testJavaSdkLibraryImport_Preferred(t, "prefer: true,", android.NullFixturePreparer)
 	})
+}
 
-	t.Run("use_source_config_var", func(t *testing.T) {
-		testJavaSdkLibraryImport_Preferred(t,
-			"use_source_config_var: {config_namespace: \"acme\", var_name: \"use_source\"},",
-			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-				variables.VendorVars = map[string]map[string]string{
-					"acme": {
-						"use_source": "false",
-					},
-				}
-			}))
-	})
+// If a module is listed in `mainline_module_contributions, it should be used
+// It will supersede any other source vs prebuilt selection mechanism like `prefer` attribute
+func TestSdkLibraryImport_MetadataModuleSupersedesPreferred(t *testing.T) {
+	bp := `
+		apex_contributions {
+			name: "my_mainline_module_contributions",
+			api_domain: "my_mainline_module",
+			contents: [
+				// legacy mechanism prefers the prebuilt
+				// mainline_module_contributions supersedes this since source is listed explicitly
+				"sdklib.prebuilt_preferred_using_legacy_flags",
+
+				// legacy mechanism prefers the source
+				// mainline_module_contributions supersedes this since prebuilt is listed explicitly
+				"prebuilt_sdklib.source_preferred_using_legacy_flags",
+			],
+		}
+		java_sdk_library {
+			name: "sdklib.prebuilt_preferred_using_legacy_flags",
+			srcs: ["a.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			public: {
+				enabled: true,
+			},
+			system: {
+				enabled: true,
+			}
+		}
+		java_sdk_library_import {
+			name: "sdklib.prebuilt_preferred_using_legacy_flags",
+			prefer: true, // prebuilt is preferred using legacy mechanism
+			public: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+			system: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+		}
+		java_sdk_library {
+			name: "sdklib.source_preferred_using_legacy_flags",
+			srcs: ["a.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			public: {
+				enabled: true,
+			},
+			system: {
+				enabled: true,
+			}
+		}
+		java_sdk_library_import {
+			name: "sdklib.source_preferred_using_legacy_flags",
+			prefer: false, // source is preferred using legacy mechanism
+			public: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+			system: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+		}
+
+		// rdeps
+		java_library {
+			name: "public",
+			srcs: ["a.java"],
+			libs: [
+				// this should get source since source is listed in my_mainline_module_contributions
+				"sdklib.prebuilt_preferred_using_legacy_flags.stubs",
+				"sdklib.prebuilt_preferred_using_legacy_flags.stubs.system",
+
+				// this should get prebuilt since source is listed in my_mainline_module_contributions
+				"sdklib.source_preferred_using_legacy_flags.stubs",
+				"sdklib.source_preferred_using_legacy_flags.stubs.system",
+
+			],
+		}
+	`
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("sdklib.source_preferred_using_legacy_flags", "sdklib.prebuilt_preferred_using_legacy_flags"),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contributions",
+			}
+		}),
+	).RunTestWithBp(t, bp)
+
+	// Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions
+	public := result.ModuleForTests("public", "android_common")
+	rule := public.Output("javac/public.jar")
+	inputs := rule.Implicits.Strings()
+	expectedInputs := []string{
+		// source
+		"out/soong/.intermediates/sdklib.prebuilt_preferred_using_legacy_flags.stubs/android_common/turbine-combined/sdklib.prebuilt_preferred_using_legacy_flags.stubs.jar",
+		"out/soong/.intermediates/sdklib.prebuilt_preferred_using_legacy_flags.stubs.system/android_common/turbine-combined/sdklib.prebuilt_preferred_using_legacy_flags.stubs.system.jar",
+
+		// prebuilt
+		"out/soong/.intermediates/prebuilt_sdklib.source_preferred_using_legacy_flags.stubs/android_common/combined/sdklib.source_preferred_using_legacy_flags.stubs.jar",
+		"out/soong/.intermediates/prebuilt_sdklib.source_preferred_using_legacy_flags.stubs.system/android_common/combined/sdklib.source_preferred_using_legacy_flags.stubs.system.jar",
+	}
+	for _, expected := range expectedInputs {
+		if !android.InList(expected, inputs) {
+			t.Errorf("expected %q to contain %q", inputs, expected)
+		}
+	}
 }
 
 func TestJavaSdkLibraryEnforce(t *testing.T) {
@@ -1081,7 +1230,6 @@
 		libraryType                string
 		fromPartition              string
 		toPartition                string
-		enforceVendorInterface     bool
 		enforceProductInterface    bool
 		enforceJavaSdkLibraryCheck bool
 		allowList                  []string
@@ -1116,9 +1264,6 @@
 			android.FixtureWithRootAndroidBp(bpFile),
 			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 				variables.EnforceProductPartitionInterface = proptools.BoolPtr(info.enforceProductInterface)
-				if info.enforceVendorInterface {
-					variables.DeviceVndkVersion = proptools.StringPtr("current")
-				}
 				variables.EnforceInterPartitionJavaSdkLibrary = proptools.BoolPtr(info.enforceJavaSdkLibraryCheck)
 				variables.InterPartitionJavaLibraryAllowList = info.allowList
 			}),
@@ -1146,7 +1291,6 @@
 		libraryType:                "java_library",
 		fromPartition:              "product",
 		toPartition:                "system",
-		enforceVendorInterface:     true,
 		enforceProductInterface:    true,
 		enforceJavaSdkLibraryCheck: false,
 	}, "")
@@ -1155,7 +1299,6 @@
 		libraryType:                "java_library",
 		fromPartition:              "product",
 		toPartition:                "system",
-		enforceVendorInterface:     true,
 		enforceProductInterface:    false,
 		enforceJavaSdkLibraryCheck: true,
 	}, "")
@@ -1164,7 +1307,6 @@
 		libraryType:                "java_library",
 		fromPartition:              "product",
 		toPartition:                "system",
-		enforceVendorInterface:     true,
 		enforceProductInterface:    true,
 		enforceJavaSdkLibraryCheck: true,
 	}, errorMessage)
@@ -1173,7 +1315,6 @@
 		libraryType:                "java_library",
 		fromPartition:              "vendor",
 		toPartition:                "system",
-		enforceVendorInterface:     true,
 		enforceProductInterface:    true,
 		enforceJavaSdkLibraryCheck: true,
 	}, errorMessage)
@@ -1182,7 +1323,6 @@
 		libraryType:                "java_library",
 		fromPartition:              "vendor",
 		toPartition:                "system",
-		enforceVendorInterface:     true,
 		enforceProductInterface:    true,
 		enforceJavaSdkLibraryCheck: true,
 		allowList:                  []string{"bar"},
@@ -1192,7 +1332,6 @@
 		libraryType:                "java_library",
 		fromPartition:              "vendor",
 		toPartition:                "product",
-		enforceVendorInterface:     true,
 		enforceProductInterface:    true,
 		enforceJavaSdkLibraryCheck: true,
 	}, errorMessage)
@@ -1201,7 +1340,6 @@
 		libraryType:                "java_sdk_library",
 		fromPartition:              "product",
 		toPartition:                "system",
-		enforceVendorInterface:     true,
 		enforceProductInterface:    true,
 		enforceJavaSdkLibraryCheck: true,
 	}, "")
@@ -1210,7 +1348,6 @@
 		libraryType:                "java_sdk_library",
 		fromPartition:              "vendor",
 		toPartition:                "system",
-		enforceVendorInterface:     true,
 		enforceProductInterface:    true,
 		enforceJavaSdkLibraryCheck: true,
 	}, "")
@@ -1219,7 +1356,6 @@
 		libraryType:                "java_sdk_library",
 		fromPartition:              "vendor",
 		toPartition:                "product",
-		enforceVendorInterface:     true,
 		enforceProductInterface:    true,
 		enforceJavaSdkLibraryCheck: true,
 	}, "")
@@ -1235,6 +1371,11 @@
 			"sdklib_group_foo",
 			"sdklib_owner_foo",
 			"foo"),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
 	).RunTestWithBp(t, `
 		java_sdk_library {
 			name: "sdklib_no_group",
@@ -1291,7 +1432,7 @@
 
 	for _, tt := range testCases {
 		t.Run(tt.module, func(t *testing.T) {
-			m := result.ModuleForTests(tt.module+".stubs", "android_common").Module().(*Library)
+			m := result.ModuleForTests(apiScopePublic.exportableStubsLibraryModuleName(tt.module), "android_common").Module().(*Library)
 			dists := m.Dists()
 			if len(dists) != 1 {
 				t.Fatalf("expected exactly 1 dist entry, got %d", len(dists))
@@ -1416,6 +1557,32 @@
 	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs, "bar-lib")
 }
 
+func TestJavaSdkLibrary_Scope_Libs_PassedToDroidstubs(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("foo"),
+	).RunTestWithBp(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["a.java"],
+			public: {
+				enabled: true,
+				libs: ["bar-lib"],
+			},
+		}
+
+		java_library {
+			name: "bar-lib",
+			srcs: ["b.java"],
+		}
+		`)
+
+	// The foo.stubs.source should depend on bar-lib
+	fooStubsSources := result.ModuleForTests("foo.stubs.source", "android_common").Module().(*Droidstubs)
+	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs, "bar-lib")
+}
+
 func TestJavaSdkLibrary_ApiLibrary(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForJavaTest,
@@ -1449,17 +1616,17 @@
 		{
 			scope:              apiScopePublic,
 			apiContributions:   []string{"foo.stubs.source.api.contribution"},
-			fullApiSurfaceStub: "android_stubs_current.from-text",
+			fullApiSurfaceStub: "android_stubs_current",
 		},
 		{
 			scope:              apiScopeSystem,
 			apiContributions:   []string{"foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
-			fullApiSurfaceStub: "android_system_stubs_current.from-text",
+			fullApiSurfaceStub: "android_system_stubs_current",
 		},
 		{
 			scope:              apiScopeTest,
 			apiContributions:   []string{"foo.stubs.source.test.api.contribution", "foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
-			fullApiSurfaceStub: "android_test_stubs_current.from-text",
+			fullApiSurfaceStub: "android_test_stubs_current",
 		},
 		{
 			scope:              apiScopeModuleLib,
@@ -1474,3 +1641,265 @@
 		android.AssertStringEquals(t, "Module expected to contain full api surface api library", c.fullApiSurfaceStub, *m.properties.Full_api_surface_stub)
 	}
 }
+
+func TestStaticDepStubLibrariesVisibility(t *testing.T) {
+	android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("foo"),
+		android.FixtureMergeMockFs(
+			map[string][]byte{
+				"A.java": nil,
+				"dir/Android.bp": []byte(
+					`
+					java_library {
+						name: "bar",
+						srcs: ["A.java"],
+						libs: ["foo.stubs.from-source"],
+					}
+					`),
+				"dir/A.java": nil,
+			},
+		).ExtendWithErrorHandler(
+			android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+				`module "bar" variant "android_common": depends on //.:foo.stubs.from-source which is not visible to this module`)),
+	).RunTestWithBp(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["A.java"],
+		}
+	`)
+}
+
+func TestSdkLibraryDependency(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithPrebuiltApis(map[string][]string{
+			"30": {"bar", "foo"},
+		}),
+	).RunTestWithBp(t,
+		`
+		java_sdk_library {
+			name: "foo",
+			srcs: ["a.java", "b.java"],
+			api_packages: ["foo"],
+		}
+
+		java_sdk_library {
+			name: "bar",
+			srcs: ["c.java", "b.java"],
+			libs: [
+				"foo",
+			],
+			uses_libs: [
+				"foo",
+			],
+		}
+`)
+
+	barPermissions := result.ModuleForTests("bar.xml", "android_common").Output("bar.xml")
+	barContents := android.ContentFromFileRuleForTests(t, result.TestContext, barPermissions)
+	android.AssertStringDoesContain(t, "bar.xml java_sdk_xml command", barContents, `dependency="foo"`)
+}
+
+func TestSdkLibraryExportableStubsLibrary(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("foo"),
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.SetApiLibraries([]string{"foo"})
+		}),
+	).RunTestWithBp(t, `
+		aconfig_declarations {
+			name: "bar",
+			package: "com.example.package",
+			srcs: [
+				"bar.aconfig",
+			],
+		}
+		java_sdk_library {
+			name: "foo",
+			srcs: ["a.java", "b.java"],
+			api_packages: ["foo"],
+			system: {
+				enabled: true,
+			},
+			module_lib: {
+				enabled: true,
+			},
+			test: {
+				enabled: true,
+			},
+			aconfig_declarations: [
+				"bar",
+			],
+		}
+	`)
+
+	exportableStubsLibraryModuleName := apiScopePublic.exportableStubsLibraryModuleName("foo")
+	exportableSourceStubsLibraryModuleName := apiScopePublic.exportableSourceStubsLibraryModuleName("foo")
+
+	// Check modules generation
+	topLevelModule := result.ModuleForTests(exportableStubsLibraryModuleName, "android_common")
+	result.ModuleForTests(exportableSourceStubsLibraryModuleName, "android_common")
+
+	// Check static lib dependency
+	android.AssertBoolEquals(t, "exportable top level stubs library module depends on the"+
+		"exportable source stubs library module", true,
+		CheckModuleHasDependency(t, result.TestContext, exportableStubsLibraryModuleName,
+			"android_common", exportableSourceStubsLibraryModuleName),
+	)
+	android.AssertArrayString(t, "exportable source stub library is a static lib of the"+
+		"top level exportable stubs library", []string{exportableSourceStubsLibraryModuleName},
+		topLevelModule.Module().(*Library).properties.Static_libs)
+}
+
+// For java libraries depending on java_sdk_library(_import) via libs, assert that
+// rdep gets stubs of source if source is listed in apex_contributions and prebuilt has prefer (legacy mechanism)
+func TestStubResolutionOfJavaSdkLibraryInLibs(t *testing.T) {
+	bp := `
+		apex_contributions {
+			name: "my_mainline_module_contributions",
+			api_domain: "my_mainline_module",
+			contents: ["sdklib"], // source is selected using apex_contributions, but prebuilt is selected using prefer
+		}
+		java_sdk_library {
+			name: "sdklib",
+			srcs: ["a.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			public: {
+				enabled: true,
+			},
+		}
+		java_sdk_library_import {
+			name: "sdklib",
+			public: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+			prefer: true, // Set prefer explicitly on the prebuilt. We will assert that rdep gets source in a test case.
+		}
+		// rdeps
+		java_library {
+			name: "mymodule",
+			srcs: ["a.java"],
+			sdk_version: "current",
+			libs: ["sdklib",], // this should be dynamically resolved to sdklib.stubs (source) or prebuilt_sdklib.stubs (prebuilt)
+		}
+	`
+
+	fixture := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("sdklib"),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				// We can use any of the apex contribution build flags from build/soong/android/config.go#mainlineApexContributionBuildFlags here
+				"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contributions",
+			}
+		}),
+	)
+
+	result := fixture.RunTestWithBp(t, bp)
+	// Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions
+	public := result.ModuleForTests("mymodule", "android_common")
+	rule := public.Output("javac/mymodule.jar")
+	inputs := rule.Implicits.Strings()
+	android.AssertStringListContains(t, "Could not find the expected stub on classpath", inputs, "out/soong/.intermediates/sdklib.stubs/android_common/turbine-combined/sdklib.stubs.jar")
+}
+
+// test that rdep gets resolved to the correct version of a java_sdk_library (source or a specific prebuilt)
+func TestMultipleSdkLibraryPrebuilts(t *testing.T) {
+	bp := `
+		apex_contributions {
+			name: "my_mainline_module_contributions",
+			api_domain: "my_mainline_module",
+			contents: ["%s"],
+		}
+		java_sdk_library {
+			name: "sdklib",
+			srcs: ["a.java"],
+			sdk_version: "none",
+			system_modules: "none",
+			public: {
+				enabled: true,
+			},
+		}
+		java_sdk_library_import {
+			name: "sdklib.v1", //prebuilt
+			source_module_name: "sdklib",
+			public: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+		}
+		java_sdk_library_import {
+			name: "sdklib.v2", //prebuilt
+			source_module_name: "sdklib",
+			public: {
+				jars: ["a.jar"],
+				stub_srcs: ["a.java"],
+				current_api: "current.txt",
+				removed_api: "removed.txt",
+				annotations: "annotations.zip",
+			},
+		}
+		// rdeps
+		java_library {
+			name: "mymodule",
+			srcs: ["a.java"],
+			libs: ["sdklib.stubs",],
+		}
+	`
+	testCases := []struct {
+		desc                   string
+		selectedDependencyName string
+		expectedStubPath       string
+	}{
+		{
+			desc:                   "Source library is selected using apex_contributions",
+			selectedDependencyName: "sdklib",
+			expectedStubPath:       "out/soong/.intermediates/sdklib.stubs/android_common/turbine-combined/sdklib.stubs.jar",
+		},
+		{
+			desc:                   "Prebuilt library v1 is selected using apex_contributions",
+			selectedDependencyName: "prebuilt_sdklib.v1",
+			expectedStubPath:       "out/soong/.intermediates/prebuilt_sdklib.v1.stubs/android_common/combined/sdklib.stubs.jar",
+		},
+		{
+			desc:                   "Prebuilt library v2 is selected using apex_contributions",
+			selectedDependencyName: "prebuilt_sdklib.v2",
+			expectedStubPath:       "out/soong/.intermediates/prebuilt_sdklib.v2.stubs/android_common/combined/sdklib.stubs.jar",
+		},
+	}
+
+	fixture := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("sdklib", "sdklib.v1", "sdklib.v2"),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contributions",
+			}
+		}),
+	)
+
+	for _, tc := range testCases {
+		result := fixture.RunTestWithBp(t, fmt.Sprintf(bp, tc.selectedDependencyName))
+
+		// Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions
+		public := result.ModuleForTests("mymodule", "android_common")
+		rule := public.Output("javac/mymodule.jar")
+		inputs := rule.Implicits.Strings()
+		android.AssertStringListContains(t, "Could not find the expected stub on classpath", inputs, tc.expectedStubPath)
+	}
+}
diff --git a/java/sdk_version_test.go b/java/sdk_version_test.go
new file mode 100644
index 0000000..88351d2
--- /dev/null
+++ b/java/sdk_version_test.go
@@ -0,0 +1,66 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+func stringPtr(v string) *string {
+	return &v
+}
+
+func TestSystemSdkFromVendor(t *testing.T) {
+	fixtures := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_sdk_version = intPtr(34)
+			variables.Platform_sdk_codename = stringPtr("VanillaIceCream")
+			variables.Platform_version_active_codenames = []string{"VanillaIceCream"}
+			variables.Platform_systemsdk_versions = []string{"33", "34", "VanillaIceCream"}
+			variables.DeviceSystemSdkVersions = []string{"VanillaIceCream"}
+		}),
+		FixtureWithPrebuiltApis(map[string][]string{
+			"33": {},
+			"34": {},
+			"35": {},
+		}),
+	)
+
+	fixtures.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern("incompatible sdk version")).
+		RunTestWithBp(t, `
+		android_app {
+			name: "foo",
+			srcs: ["a.java"],
+			vendor: true,
+			sdk_version: "system_35",
+		}`)
+
+	result := fixtures.RunTestWithBp(t, `
+		android_app {
+			name: "foo",
+			srcs: ["a.java"],
+			vendor: true,
+			sdk_version: "system_current",
+		}`)
+	fooModule := result.ModuleForTests("foo", "android_common")
+	fooClasspath := fooModule.Rule("javac").Args["classpath"]
+
+	android.AssertStringDoesContain(t, "foo classpath", fooClasspath, "prebuilts/sdk/34/system/android.jar")
+	android.AssertStringDoesNotContain(t, "foo classpath", fooClasspath, "prebuilts/sdk/35/system/android.jar")
+	android.AssertStringDoesNotContain(t, "foo classpath", fooClasspath, "prebuilts/sdk/current/system/android.jar")
+}
diff --git a/java/support_libraries.go b/java/support_libraries.go
index af7c3c2..c483fc1 100644
--- a/java/support_libraries.go
+++ b/java/support_libraries.go
@@ -32,7 +32,7 @@
 		dir := ctx.ModuleDir(module)
 		switch {
 		case strings.HasPrefix(dir, "prebuilts/sdk/current/extras"),
-			dir == "prebuilts/sdk/current/androidx",
+			strings.HasPrefix(dir, "prebuilts/sdk/current/androidx"),
 			dir == "prebuilts/sdk/current/car",
 			dir == "prebuilts/sdk/current/optional",
 			dir == "prebuilts/sdk/current/support":
diff --git a/java/system_modules.go b/java/system_modules.go
index 0efa1a4..8e2d5d8 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -19,6 +19,7 @@
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 )
@@ -55,13 +56,15 @@
 			`${config.MergeZipsCmd} -j ${workDir}/module.jar ${workDir}/classes.jar $in && ` +
 			// Note: The version of the java.base module created must match the version
 			// of the jlink tool which consumes it.
-			`${config.JmodCmd} create --module-version ${config.JlinkVersion} --target-platform android ` +
+			// Use LINUX-OTHER to be compatible with JDK 21+ (b/294137077)
+			`${config.JmodCmd} create --module-version ${config.JlinkVersion} --target-platform LINUX-OTHER ` +
 			`  --class-path ${workDir}/module.jar ${workDir}/jmod/java.base.jmod && ` +
 			`${config.JlinkCmd} --module-path ${workDir}/jmod --add-modules java.base --output ${outDir} ` +
 			// Note: The system-modules jlink plugin is disabled because (a) it is not
 			// useful on Android, and (b) it causes errors with later versions of jlink
 			// when the jdk.internal.module is absent from java.base (as it is here).
 			`  --disable-plugin system-modules && ` +
+			`rm -rf ${workDir} && ` +
 			`cp ${config.JrtFsJar} ${outDir}/lib/`,
 		CommandDeps: []string{
 			"${moduleInfoJavaPath}",
@@ -159,7 +162,7 @@
 	var jars android.Paths
 
 	ctx.VisitDirectDepsWithTag(systemModulesLibsTag, func(module android.Module) {
-		dep, _ := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+		dep, _ := android.OtherModuleProvider(ctx, module, JavaInfoProvider)
 		jars = append(jars, dep.HeaderJars...)
 	})
 
@@ -209,7 +212,7 @@
 // type and the one to use is selected at runtime.
 func systemModulesImportFactory() android.Module {
 	module := &systemModulesImport{}
-	module.AddProperties(&module.properties)
+	module.AddProperties(&module.properties, &module.prebuiltProperties)
 	android.InitPrebuiltModule(module, &module.properties.Libs)
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
@@ -218,13 +221,39 @@
 
 type systemModulesImport struct {
 	SystemModules
-	prebuilt android.Prebuilt
+	prebuilt           android.Prebuilt
+	prebuiltProperties prebuiltSystemModulesProperties
+}
+
+type prebuiltSystemModulesProperties struct {
+	// Name of the source soong module that gets shadowed by this prebuilt
+	// If unspecified, follows the naming convention that the source module of
+	// the prebuilt is Name() without "prebuilt_" prefix
+	Source_module_name *string
 }
 
 func (system *systemModulesImport) Name() string {
 	return system.prebuilt.Name(system.ModuleBase.Name())
 }
 
+// BaseModuleName returns the source module that will get shadowed by this prebuilt
+// e.g.
+//
+//	java_system_modules_import {
+//	   name: "my_system_modules.v1",
+//	   source_module_name: "my_system_modules",
+//	}
+//
+//	java_system_modules_import {
+//	   name: "my_system_modules.v2",
+//	   source_module_name: "my_system_modules",
+//	}
+//
+// `BaseModuleName` for both will return `my_system_modules`
+func (system *systemModulesImport) BaseModuleName() string {
+	return proptools.StringDefault(system.prebuiltProperties.Source_module_name, system.ModuleBase.Name())
+}
+
 func (system *systemModulesImport) Prebuilt() *android.Prebuilt {
 	return &system.prebuilt
 }
diff --git a/java/system_modules_test.go b/java/system_modules_test.go
index 7b5a386..336dd21 100644
--- a/java/system_modules_test.go
+++ b/java/system_modules_test.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"fmt"
 	"testing"
 
 	"android/soong/android"
@@ -24,7 +25,7 @@
 	paths := []string{}
 	for _, moduleName := range moduleNames {
 		module := result.Module(moduleName, "android_common")
-		info := result.ModuleProvider(module, JavaInfoProvider).(JavaInfo)
+		info, _ := android.SingletonModuleProvider(result, module, JavaInfoProvider)
 		paths = append(paths, info.HeaderJars.RelativeToTop().Strings()...)
 	}
 	return paths
@@ -111,3 +112,85 @@
 	expectedPrebuiltPaths := getModuleHeaderJarsAsRelativeToTopPaths(result, "prebuilt_system-module1", "prebuilt_system-module2")
 	android.AssertArrayString(t, "prebuilt system modules inputs", expectedPrebuiltPaths, prebuiltInputs.RelativeToTop().Strings())
 }
+
+func TestMultipleSystemModulesPrebuilts(t *testing.T) {
+	bp := `
+		// an rdep
+		java_library {
+			name: "foo",
+			sdk_version: "none",
+			system_modules: "my_system_modules",
+		}
+
+		// multiple variations of java_system_modules
+		// source
+		java_system_modules {
+			name: "my_system_modules",
+			libs: ["bar"],
+		}
+		java_library {
+			name: "bar",
+			srcs: ["bar.java"],
+		}
+		// prebuilt "v1"
+		java_system_modules_import {
+			name: "my_system_modules.v1",
+			source_module_name: "my_system_modules",
+			libs: ["bar.v1"],
+		}
+		java_import {
+			name: "bar.v1",
+			source_module_name: "bar",
+			jars: ["bar.v1.jar"],
+		}
+		// prebuilt "v2"
+		java_system_modules_import {
+			name: "my_system_modules.v2",
+			source_module_name: "my_system_modules",
+			libs: ["bar.v2"],
+		}
+		java_import {
+			name: "bar.v2",
+			source_module_name: "bar",
+			jars: ["bar.v2.jar"],
+		}
+
+		// selectors
+		apex_contributions {
+			name: "myapex_contributions",
+			contents: ["%v"],
+		}
+	`
+	testCases := []struct {
+		desc                   string
+		selectedDependencyName string
+	}{
+		{
+			desc:                   "Source system_modules is selected using apex_contributions",
+			selectedDependencyName: "my_system_modules",
+		},
+		{
+			desc:                   "Prebuilt system_modules v1 is selected using apex_contributions",
+			selectedDependencyName: "prebuilt_my_system_modules.v1",
+		},
+		{
+			desc:                   "Prebuilt system_modules v2 is selected using apex_contributions",
+			selectedDependencyName: "prebuilt_my_system_modules.v2",
+		},
+	}
+
+	for _, tc := range testCases {
+		res := android.GroupFixturePreparers(
+			prepareForJavaTest,
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "myapex_contributions",
+				}
+			}),
+		).RunTestWithBp(t, fmt.Sprintf(bp, tc.selectedDependencyName))
+
+		// check that rdep gets the correct variation of system_modules
+		hasDep := CheckModuleHasDependency(t, res.TestContext, "foo", "android_common", tc.selectedDependencyName)
+		android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from foo to %s\n", tc.selectedDependencyName), true, hasDep)
+	}
+}
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index 17d301b..b291e70 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -87,9 +87,6 @@
 	ClasspathFragmentBase
 
 	properties systemServerClasspathFragmentProperties
-
-	// Collect the module directory for IDE info in java/jdeps.go.
-	modulePaths []string
 }
 
 func (s *SystemServerClasspathModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
@@ -129,9 +126,6 @@
 	configuredJars = configuredJars.AppendList(&standaloneConfiguredJars)
 	classpathJars = append(classpathJars, standaloneClasspathJars...)
 	s.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars)
-
-	// Collect the module directory for IDE info in java/jdeps.go.
-	s.modulePaths = append(s.modulePaths, ctx.ModuleDir())
 }
 
 func (s *SystemServerClasspathModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList {
@@ -195,7 +189,7 @@
 		return javaSdkLibrarySdkMemberType
 	}
 
-	return javaSystemserverLibsSdkMemberType
+	return JavaSystemserverLibsSdkMemberType
 }
 
 func (b systemServerClasspathFragmentContentDependencyTag) ExportMember() bool {
@@ -242,7 +236,6 @@
 func (s *SystemServerClasspathModule) IDEInfo(dpInfo *android.IdeInfo) {
 	dpInfo.Deps = append(dpInfo.Deps, s.properties.Contents...)
 	dpInfo.Deps = append(dpInfo.Deps, s.properties.Standalone_contents...)
-	dpInfo.Paths = append(dpInfo.Paths, s.modulePaths...)
 }
 
 type systemServerClasspathFragmentMemberType struct {
@@ -320,6 +313,10 @@
 	return nil
 }
 
+func (module *prebuiltSystemServerClasspathModule) UseProfileGuidedDexpreopt() bool {
+	return false
+}
+
 var _ android.RequiredFilesFromPrebuiltApex = (*prebuiltSystemServerClasspathModule)(nil)
 
 func prebuiltSystemServerClasspathModuleFactory() android.Module {
diff --git a/java/test_spec_test.go b/java/test_spec_test.go
new file mode 100644
index 0000000..4144dad
--- /dev/null
+++ b/java/test_spec_test.go
@@ -0,0 +1,122 @@
+package java
+
+import (
+	"strings"
+	"testing"
+
+	"android/soong/android"
+	soongTesting "android/soong/testing"
+	"android/soong/testing/test_spec_proto"
+	"google.golang.org/protobuf/proto"
+)
+
+func TestTestSpec(t *testing.T) {
+	bp := `test_spec {
+		name: "module-name",
+		teamId: "12345",
+		tests: [
+			"java-test-module-name-one",
+			"java-test-module-name-two"
+		]
+	}
+
+	java_test {
+		name: "java-test-module-name-one",
+	}
+
+	java_test {
+		name: "java-test-module-name-two",
+	}`
+	result := runTestSpecTest(t, android.FixtureExpectsNoErrors, bp)
+
+	module := result.ModuleForTests("module-name", "")
+
+	// Check that the provider has the right contents
+	data, _ := android.SingletonModuleProvider(result, module.Module(), soongTesting.TestSpecProviderKey)
+	if !strings.HasSuffix(
+		data.IntermediatePath.String(), "/intermediateTestSpecMetadata.pb",
+	) {
+		t.Errorf(
+			"Missing intermediates path in provider: %s",
+			data.IntermediatePath.String(),
+		)
+	}
+
+	metadata := android.ContentFromFileRuleForTests(t, result.TestContext,
+		module.Output(data.IntermediatePath.String()))
+
+	metadataList := make([]*test_spec_proto.TestSpec_OwnershipMetadata, 0, 2)
+	teamId := "12345"
+	bpFilePath := "Android.bp"
+	targetNames := []string{
+		"java-test-module-name-one", "java-test-module-name-two",
+	}
+
+	for _, test := range targetNames {
+		targetName := test
+		metadata := test_spec_proto.TestSpec_OwnershipMetadata{
+			TrendyTeamId: &teamId,
+			TargetName:   &targetName,
+			Path:         &bpFilePath,
+		}
+		metadataList = append(metadataList, &metadata)
+	}
+	testSpecMetadata := test_spec_proto.TestSpec{OwnershipMetadataList: metadataList}
+	protoData, _ := proto.Marshal(&testSpecMetadata)
+	expectedMetadata := string(protoData)
+
+	if metadata != expectedMetadata {
+		t.Errorf(
+			"Retrieved metadata: %s doesn't contain expectedMetadata: %s", metadata,
+			expectedMetadata,
+		)
+	}
+
+	// Tests for all_test_spec singleton.
+	singleton := result.SingletonForTests("all_test_specs")
+	rule := singleton.Rule("all_test_specs_rule")
+	prebuiltOs := result.Config.PrebuiltOS()
+	expectedCmd := "out/soong/host/" + prebuiltOs + "/bin/metadata -rule test_spec -inputFile out/soong/all_test_spec_paths.rsp -outputFile out/soong/ownership/all_test_specs.pb"
+	expectedOutputFile := "out/soong/ownership/all_test_specs.pb"
+	expectedInputFile := "out/soong/.intermediates/module-name/intermediateTestSpecMetadata.pb"
+	if !strings.Contains(
+		strings.TrimSpace(rule.Output.String()),
+		expectedOutputFile,
+	) {
+		t.Errorf(
+			"Retrieved singletonOutputFile: %s is not equal to expectedSingletonOutputFile: %s",
+			rule.Output.String(), expectedOutputFile,
+		)
+	}
+
+	if !strings.Contains(
+		strings.TrimSpace(rule.Inputs[0].String()),
+		expectedInputFile,
+	) {
+		t.Errorf(
+			"Retrieved singletonInputFile: %s is not equal to expectedSingletonInputFile: %s",
+			rule.Inputs[0].String(), expectedInputFile,
+		)
+	}
+
+	if !strings.Contains(
+		strings.TrimSpace(rule.RuleParams.Command),
+		expectedCmd,
+	) {
+		t.Errorf(
+			"Retrieved cmd: %s is not equal to expectedCmd: %s",
+			rule.RuleParams.Command, expectedCmd,
+		)
+	}
+}
+
+func runTestSpecTest(
+	t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
+) *android.TestResult {
+	return android.GroupFixturePreparers(
+		soongTesting.PrepareForTestWithTestingBuildComponents,
+		PrepareForIntegrationTestWithJava,
+	).
+		ExtendWithErrorHandler(errorHandler).
+		RunTestWithBp(t, bp)
+}
diff --git a/java/testing.go b/java/testing.go
index 3a238d7..5ae326d 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -73,10 +73,15 @@
 		// Needed for various deps defined in GatherRequiredDepsForTest()
 		defaultJavaDir + "/a.java":                        nil,
 		defaultJavaDir + "/api/current.txt":               nil,
+		defaultJavaDir + "/api/removed.txt":               nil,
 		defaultJavaDir + "/api/system-current.txt":        nil,
+		defaultJavaDir + "/api/system-removed.txt":        nil,
 		defaultJavaDir + "/api/test-current.txt":          nil,
+		defaultJavaDir + "/api/test-removed.txt":          nil,
 		defaultJavaDir + "/api/module-lib-current.txt":    nil,
+		defaultJavaDir + "/api/module-lib-removed.txt":    nil,
 		defaultJavaDir + "/api/system-server-current.txt": nil,
+		defaultJavaDir + "/api/system-server-removed.txt": nil,
 
 		// Needed for R8 rules on apps
 		"build/make/core/proguard.flags":             nil,
@@ -113,8 +118,6 @@
 	dexpreopt.PrepareForTestByEnablingDexpreopt,
 )
 
-var PrepareForTestWithOverlayBuildComponents = android.FixtureRegisterWithContext(registerOverlayBuildComponents)
-
 // Prepare a fixture to use all java module types, mutators and singletons fully.
 //
 // This should only be used by tests that want to run with as much of the build enabled as possible.
@@ -225,6 +228,29 @@
 	)
 }
 
+func FixtureWithPrebuiltIncrementalApis(apiLevel2Modules map[string][]string) android.FixturePreparer {
+	mockFS := android.MockFS{}
+	path := "prebuilts/sdk/Android.bp"
+
+	bp := fmt.Sprintf(`
+			prebuilt_apis {
+				name: "sdk",
+				api_dirs: ["%s"],
+				allow_incremental_platform_api: true,
+				imports_sdk_version: "none",
+				imports_compile_dex: true,
+			}
+		`, strings.Join(android.SortedKeys(apiLevel2Modules), `", "`))
+
+	for release, modules := range apiLevel2Modules {
+		mockFS.Merge(prebuiltApisFilesForModules([]string{release}, modules))
+	}
+	return android.GroupFixturePreparers(
+		android.FixtureAddTextFile(path, bp),
+		android.FixtureMergeMockFs(mockFS),
+	)
+}
+
 func prebuiltApisFilesForModules(apiLevels []string, modules []string) map[string][]byte {
 	libs := append([]string{"android"}, modules...)
 
@@ -357,6 +383,7 @@
 	RegisterSystemModulesBuildComponents(ctx)
 	registerSystemserverClasspathBuildComponents(ctx)
 	registerLintBuildComponents(ctx)
+	android.RegisterApexContributionsBuildComponents(ctx)
 }
 
 // gatherRequiredDepsForTest gathers the module definitions used by
@@ -380,11 +407,22 @@
 		"legacy.core.platform.api.stubs",
 		"stable.core.platform.api.stubs",
 
+		"android_stubs_current_exportable",
+		"android_system_stubs_current_exportable",
+		"android_test_stubs_current_exportable",
+		"android_module_lib_stubs_current_exportable",
+		"android_system_server_stubs_current_exportable",
+		"core.current.stubs.exportable",
+		"legacy.core.platform.api.stubs.exportable",
+
 		"kotlin-stdlib",
 		"kotlin-stdlib-jdk7",
 		"kotlin-stdlib-jdk8",
 		"kotlin-annotations",
 		"stub-annotations",
+
+		"aconfig-annotations-lib",
+		"unsupportedappusage",
 	}
 
 	for _, extra := range extraModules {
@@ -399,30 +437,98 @@
 		`, extra)
 	}
 
-	extraApiLibraryModules := map[string]string{
-		"android_stubs_current.from-text":                  "api/current.txt",
-		"android_system_stubs_current.from-text":           "api/system-current.txt",
-		"android_test_stubs_current.from-text":             "api/test-current.txt",
-		"android_module_lib_stubs_current.from-text":       "api/module-lib-current.txt",
-		"android_module_lib_stubs_current_full.from-text":  "api/module-lib-current.txt",
-		"android_system_server_stubs_current.from-text":    "api/system-server-current.txt",
-		"core.current.stubs.from-text":                     "api/current.txt",
-		"legacy.core.platform.api.stubs.from-text":         "api/current.txt",
-		"stable.core.platform.api.stubs.from-text":         "api/current.txt",
-		"core-lambda-stubs.from-text":                      "api/current.txt",
-		"android-non-updatable.stubs.from-text":            "api/current.txt",
-		"android-non-updatable.stubs.system.from-text":     "api/system-current.txt",
-		"android-non-updatable.stubs.test.from-text":       "api/test-current.txt",
-		"android-non-updatable.stubs.module_lib.from-text": "api/module-lib-current.txt",
+	type droidstubsStruct struct {
+		name        string
+		apiSurface  string
+		apiFile     string
+		removedFile string
 	}
 
-	for libName, apiFile := range extraApiLibraryModules {
+	var publicDroidstubs = droidstubsStruct{
+		name:        "api-stubs-docs-non-updatable",
+		apiSurface:  "public",
+		apiFile:     "api/current.txt",
+		removedFile: "api/removed.txt",
+	}
+	var systemDroidstubs = droidstubsStruct{
+		name:        "system-api-stubs-docs-non-updatable",
+		apiSurface:  "system",
+		apiFile:     "api/system-current.txt",
+		removedFile: "api/system-removed.txt",
+	}
+	var testDroidstubs = droidstubsStruct{
+		name:        "test-api-stubs-docs-non-updatable",
+		apiSurface:  "test",
+		apiFile:     "api/test-current.txt",
+		removedFile: "api/test-removed.txt",
+	}
+	var moduleLibDroidstubs = droidstubsStruct{
+		name:        "module-lib-api-stubs-docs-non-updatable",
+		apiSurface:  "module-lib",
+		apiFile:     "api/module-lib-current.txt",
+		removedFile: "api/module-lib-removed.txt",
+	}
+	var systemServerDroidstubs = droidstubsStruct{
+		// This module does not exist but is named this way for consistency
+		name:        "system-server-api-stubs-docs-non-updatable",
+		apiSurface:  "system-server",
+		apiFile:     "api/system-server-current.txt",
+		removedFile: "api/system-server-removed.txt",
+	}
+	var droidstubsStructs = []droidstubsStruct{
+		publicDroidstubs,
+		systemDroidstubs,
+		testDroidstubs,
+		moduleLibDroidstubs,
+		systemServerDroidstubs,
+	}
+
+	extraApiLibraryModules := map[string]droidstubsStruct{
+		"android_stubs_current.from-text":                  publicDroidstubs,
+		"android_system_stubs_current.from-text":           systemDroidstubs,
+		"android_test_stubs_current.from-text":             testDroidstubs,
+		"android_module_lib_stubs_current.from-text":       moduleLibDroidstubs,
+		"android_module_lib_stubs_current_full.from-text":  moduleLibDroidstubs,
+		"android_system_server_stubs_current.from-text":    systemServerDroidstubs,
+		"core.current.stubs.from-text":                     publicDroidstubs,
+		"legacy.core.platform.api.stubs.from-text":         publicDroidstubs,
+		"stable.core.platform.api.stubs.from-text":         publicDroidstubs,
+		"core-lambda-stubs.from-text":                      publicDroidstubs,
+		"android-non-updatable.stubs.from-text":            publicDroidstubs,
+		"android-non-updatable.stubs.system.from-text":     systemDroidstubs,
+		"android-non-updatable.stubs.test.from-text":       testDroidstubs,
+		"android-non-updatable.stubs.module_lib.from-text": moduleLibDroidstubs,
+		"android-non-updatable.stubs.test_module_lib":      moduleLibDroidstubs,
+	}
+
+	for _, droidstubs := range droidstubsStructs {
 		bp += fmt.Sprintf(`
-            java_api_library {
-                name: "%s",
-                api_files: ["%s"],
-            }
-        `, libName, apiFile)
+			droidstubs {
+				name: "%s",
+				api_surface: "%s",
+				check_api: {
+					current: {
+						api_file: "%s",
+						removed_api_file: "%s",
+					}
+				}
+			}
+		`,
+			droidstubs.name,
+			droidstubs.apiSurface,
+			droidstubs.apiFile,
+			droidstubs.removedFile,
+		)
+	}
+
+	for libName, droidstubs := range extraApiLibraryModules {
+		bp += fmt.Sprintf(`
+		java_api_library {
+			name: "%s",
+			api_contributions: ["%s"],
+			stubs_type: "everything",
+		}
+        `, libName, droidstubs.name+".api.contribution")
 	}
 
 	bp += `
@@ -474,10 +580,15 @@
 		}
 `
 
+	bp += `
+		all_apex_contributions {
+			name: "all_apex_contributions",
+		}
+`
 	return bp
 }
 
-func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
+func getModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string) []string {
 	t.Helper()
 	module := ctx.ModuleForTests(name, variant).Module()
 	deps := []string{}
@@ -486,11 +597,29 @@
 	})
 	sort.Strings(deps)
 
+	return deps
+}
+
+// CheckModuleDependencies checks if the expected dependencies of the module are
+// identical to the actual dependencies.
+func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
+	deps := getModuleDependencies(t, ctx, name, variant)
+
 	if actual := deps; !reflect.DeepEqual(expected, actual) {
 		t.Errorf("expected %#q, found %#q", expected, actual)
 	}
 }
 
+// CheckModuleHasDependency returns true if the module depends on the expected dependency.
+func CheckModuleHasDependency(t *testing.T, ctx *android.TestContext, name, variant string, expected string) bool {
+	for _, dep := range getModuleDependencies(t, ctx, name, variant) {
+		if dep == expected {
+			return true
+		}
+	}
+	return false
+}
+
 // CheckPlatformBootclasspathModules returns the apex:module pair for the modules depended upon by
 // the platform-bootclasspath module.
 func CheckPlatformBootclasspathModules(t *testing.T, result *android.TestResult, name string, expected []string) {
@@ -503,7 +632,7 @@
 func CheckClasspathFragmentProtoContentInfoProvider(t *testing.T, result *android.TestResult, generated bool, contents, outputFilename, installDir string) {
 	t.Helper()
 	p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule)
-	info := result.ModuleProvider(p, ClasspathFragmentProtoContentInfoProvider).(ClasspathFragmentProtoContentInfo)
+	info, _ := android.SingletonModuleProvider(result, p, ClasspathFragmentProtoContentInfoProvider)
 
 	android.AssertBoolEquals(t, "classpath proto generated", generated, info.ClasspathFragmentProtoGenerated)
 	android.AssertStringEquals(t, "classpath proto contents", contents, info.ClasspathFragmentProtoContents.String())
@@ -523,7 +652,7 @@
 func apexNamePairFromModule(ctx *android.TestContext, module android.Module) string {
 	name := module.Name()
 	var apex string
-	apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.SingletonModuleProvider(ctx, module, android.ApexInfoProvider)
 	if apexInfo.IsForPlatform() {
 		apex = "platform"
 	} else {
@@ -582,7 +711,7 @@
 
 func registerFakeApexMutator(ctx android.RegistrationContext) {
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("apex", fakeApexMutator).Parallel()
+		ctx.Transition("apex", &fakeApexMutator{})
 	})
 }
 
@@ -597,16 +726,30 @@
 // `apex_available`. It helps us avoid a dependency on the real mutator defined in "soong-apex",
 // which will cause a cyclic dependency, and it provides an easy way to create an APEX variant for
 // testing without dealing with all the complexities in the real mutator.
-func fakeApexMutator(mctx android.BottomUpMutatorContext) {
-	switch mctx.Module().(type) {
+type fakeApexMutator struct{}
+
+func (f *fakeApexMutator) Split(ctx android.BaseModuleContext) []string {
+	switch ctx.Module().(type) {
 	case *Library, *SdkLibrary:
-		if len(mctx.Module().(apexModuleBase).ApexAvailable()) > 0 {
-			modules := mctx.CreateVariations("", "apex1000")
-			apexInfo := android.ApexInfo{
-				ApexVariationName: "apex1000",
-			}
-			mctx.SetVariationProvider(modules[1], android.ApexInfoProvider, apexInfo)
+		return []string{"", "apex1000"}
+	}
+	return []string{""}
+}
+
+func (f *fakeApexMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string {
+	return sourceVariation
+}
+
+func (f *fakeApexMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
+	return incomingVariation
+}
+
+func (f *fakeApexMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) {
+	if variation != "" {
+		apexInfo := android.ApexInfo{
+			ApexVariationName: "apex1000",
 		}
+		android.SetProvider(ctx, android.ApexInfoProvider, apexInfo)
 	}
 }
 
diff --git a/java/tradefed.go b/java/tradefed.go
index ebbdec1..349b327 100644
--- a/java/tradefed.go
+++ b/java/tradefed.go
@@ -30,8 +30,8 @@
 	return module
 }
 
-func tradefedJavaLibraryInstall(ctx android.ModuleContext, path android.Path) android.Paths {
+func tradefedJavaLibraryInstall(ctx android.ModuleContext, path android.Path) android.InstallPaths {
 	installedPath := ctx.InstallFile(android.PathForModuleInstall(ctx, "tradefed"),
 		ctx.ModuleName()+".jar", path)
-	return android.Paths{installedPath}
+	return android.InstallPaths{installedPath}
 }
diff --git a/kernel/prebuilt_kernel_modules.go b/kernel/prebuilt_kernel_modules.go
index 5bcca04..e200ee2 100644
--- a/kernel/prebuilt_kernel_modules.go
+++ b/kernel/prebuilt_kernel_modules.go
@@ -50,6 +50,9 @@
 	// Kernel version that these modules are for. Kernel modules are installed to
 	// /lib/modules/<kernel_version> directory in the corresponding partition. Default is "".
 	Kernel_version *string
+
+	// Whether this module is directly installable to one of the partitions. Default is true
+	Installable *bool
 }
 
 // prebuilt_kernel_modules installs a set of prebuilt kernel module files to the correct directory.
@@ -62,6 +65,10 @@
 	return module
 }
 
+func (pkm *prebuiltKernelModules) installable() bool {
+	return proptools.BoolDefault(pkm.properties.Installable, true)
+}
+
 func (pkm *prebuiltKernelModules) KernelVersion() string {
 	return proptools.StringDefault(pkm.properties.Kernel_version, "")
 }
@@ -71,6 +78,9 @@
 }
 
 func (pkm *prebuiltKernelModules) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if !pkm.installable() {
+		pkm.SkipInstall()
+	}
 	modules := android.PathsForModuleSrc(ctx, pkm.properties.Srcs)
 
 	depmodOut := runDepmod(ctx, modules)
diff --git a/licenses/Android.bp b/licenses/Android.bp
index d045725..e4e5da7 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -1126,6 +1126,12 @@
 }
 
 license_kind {
+    name: "SPDX-license-identifier-Unicode-3.0",
+    conditions: ["notice"],
+    url: "https://spdx.org/licenses/Unicode-3.0.html",
+}
+
+license_kind {
     name: "SPDX-license-identifier-Unicode-DFS-2015",
     conditions: ["notice"],
     url: "https://spdx.org/licenses/Unicode-DFS-2015.html",
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index 165697d..98aa408 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -19,11 +19,9 @@
 	"sort"
 	"strings"
 
-	"android/soong/ui/metrics/bp2build_metrics_proto"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/cc"
 	"android/soong/etc"
 )
@@ -54,7 +52,6 @@
 
 type linkerConfig struct {
 	android.ModuleBase
-	android.BazelModuleBase
 	properties linkerConfigProperties
 
 	outputFilePath android.OutputPath
@@ -92,7 +89,7 @@
 	output := android.PathForModuleOut(ctx, "linker.config.pb").OutputPath
 
 	builder := android.NewRuleBuilder(pctx, ctx)
-	BuildLinkerConfig(ctx, builder, input, nil, output)
+	BuildLinkerConfig(ctx, builder, input, nil, nil, output)
 	builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String())
 
 	l.outputFilePath = output
@@ -103,31 +100,8 @@
 	ctx.InstallFile(l.installDirPath, l.outputFilePath.Base(), l.outputFilePath)
 }
 
-type linkerConfigAttributes struct {
-	Src bazel.LabelAttribute
-}
-
-func (l *linkerConfig) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	if l.properties.Src == nil {
-		ctx.PropertyErrorf("src", "empty src is not supported")
-		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "")
-		return
-	}
-	src := android.BazelLabelForModuleSrcSingle(ctx, *l.properties.Src)
-	targetModuleProperties := bazel.BazelTargetModuleProperties{
-		Rule_class:        "linker_config",
-		Bzl_load_location: "//build/bazel/rules:linker_config.bzl",
-	}
-	ctx.CreateBazelTargetModule(
-		targetModuleProperties,
-		android.CommonAttributes{Name: l.Name()},
-		&linkerConfigAttributes{
-			Src: bazel.LabelAttribute{Value: &src},
-		})
-}
-
 func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder,
-	input android.Path, otherModules []android.Module, output android.OutputPath) {
+	input android.Path, provideModules []android.Module, requireModules []android.Module, output android.OutputPath) {
 
 	// First, convert the input json to protobuf format
 	interimOutput := android.PathForModuleOut(ctx, "temp.pb")
@@ -137,9 +111,9 @@
 		FlagWithInput("-s ", input).
 		FlagWithOutput("-o ", interimOutput)
 
-	// Secondly, if there's provideLibs gathered from otherModules, append them
+	// Secondly, if there's provideLibs gathered from provideModules, append them
 	var provideLibs []string
-	for _, m := range otherModules {
+	for _, m := range provideModules {
 		if c, ok := m.(*cc.Module); ok && cc.IsStubTarget(c) {
 			for _, ps := range c.PackagingSpecs() {
 				provideLibs = append(provideLibs, ps.FileName())
@@ -148,30 +122,56 @@
 	}
 	provideLibs = android.FirstUniqueStrings(provideLibs)
 	sort.Strings(provideLibs)
+
+	var requireLibs []string
+	for _, m := range requireModules {
+		if c, ok := m.(*cc.Module); ok && c.HasStubsVariants() && !c.Host() {
+			requireLibs = append(requireLibs, c.ImplementationModuleName(ctx)+".so")
+		}
+	}
+
+	requireLibs = android.FirstUniqueStrings(requireLibs)
+	sort.Strings(requireLibs)
+
 	if len(provideLibs) > 0 {
+		prevOutput := interimOutput
+		interimOutput = android.PathForModuleOut(ctx, "temp_provideLibs.pb")
 		builder.Command().
 			BuiltTool("conv_linker_config").
 			Flag("append").
-			FlagWithInput("-s ", interimOutput).
-			FlagWithOutput("-o ", output).
+			FlagWithInput("-s ", prevOutput).
+			FlagWithOutput("-o ", interimOutput).
 			FlagWithArg("--key ", "provideLibs").
 			FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(provideLibs, " ")))
-	} else {
-		// If nothing to add, just cp to the final output
-		builder.Command().Text("cp").Input(interimOutput).Output(output)
+		builder.Temporary(prevOutput)
 	}
+	if len(requireLibs) > 0 {
+		prevOutput := interimOutput
+		interimOutput = android.PathForModuleOut(ctx, "temp_requireLibs.pb")
+		builder.Command().
+			BuiltTool("conv_linker_config").
+			Flag("append").
+			FlagWithInput("-s ", prevOutput).
+			FlagWithOutput("-o ", interimOutput).
+			FlagWithArg("--key ", "requireLibs").
+			FlagWithArg("--value ", proptools.ShellEscapeIncludingSpaces(strings.Join(requireLibs, " ")))
+		builder.Temporary(prevOutput)
+	}
+
+	// cp to the final output
+	builder.Command().Text("cp").Input(interimOutput).Output(output)
+
 	builder.Temporary(interimOutput)
 	builder.DeleteTemporaryFiles()
 }
 
 // linker_config generates protobuf file from json file. This protobuf file will be used from
 // linkerconfig while generating ld.config.txt. Format of this file can be found from
-// https://android.googlesource.com/platform/system/linkerconfig/+/master/README.md
+// https://android.googlesource.com/platform/system/linkerconfig/+/main/README.md
 func LinkerConfigFactory() android.Module {
 	m := &linkerConfig{}
 	m.AddProperties(&m.properties)
 	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibFirst)
-	android.InitBazelModule(m)
 	return m
 }
 
diff --git a/linkerconfig/proto/linker_config.proto b/linkerconfig/proto/linker_config.proto
index dccf311..fcbd1c5 100644
--- a/linkerconfig/proto/linker_config.proto
+++ b/linkerconfig/proto/linker_config.proto
@@ -16,7 +16,7 @@
 
 // This format file defines configuration file for linkerconfig. Details on this
 // format can be found from
-// https://android.googlesource.com/platform/system/linkerconfig/+/master/README.md
+// https://android.googlesource.com/platform/system/linkerconfig/+/main/README.md
 
 syntax = "proto3";
 
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 8225df6..78ab771 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -635,6 +635,13 @@
 	case "+=":
 		asgn.flavor = asgnAppend
 	case "?=":
+		if _, ok := lhs.(*productConfigVariable); ok {
+			// Make sets all product configuration variables to empty strings before running product
+			// config makefiles. ?= will have no effect on a variable that has been assigned before,
+			// even if assigned to an empty string. So just skip emitting any code for this
+			// assignment.
+			return nil
+		}
 		asgn.flavor = asgnMaybeSet
 	default:
 		panic(fmt.Errorf("unexpected assignment type %s", a.Type))
@@ -941,6 +948,8 @@
 
 func (ctx *parseContext) handleInclude(v *mkparser.Directive) []starlarkNode {
 	loadAlways := v.Name[0] != '-'
+	v.Args.TrimRightSpaces()
+	v.Args.TrimLeftSpaces()
 	return ctx.handleSubConfig(v, ctx.parseMakeString(v, v.Args), loadAlways, func(im inheritedModule) starlarkNode {
 		return &includeNode{im, loadAlways}
 	})
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index 7e68026..0c4d213 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -193,6 +193,31 @@
 	},
 
 	{
+		desc:   "Include with trailing whitespace",
+		mkname: "product.mk",
+		in: `
+# has a trailing whitespace after cfg.mk
+include vendor/$(foo)/cfg.mk 
+`,
+		expected: `# has a trailing whitespace after cfg.mk
+load("//build/make/core:product_config.rbc", "rblf")
+load("//vendor/foo1:cfg.star|init", _cfg_init = "init")
+load("//vendor/bar/baz:cfg.star|init", _cfg1_init = "init")
+
+def init(g, handle):
+  cfg = rblf.cfg(handle)
+  _entry = {
+    "vendor/foo1/cfg.mk": ("vendor/foo1/cfg", _cfg_init),
+    "vendor/bar/baz/cfg.mk": ("vendor/bar/baz/cfg", _cfg1_init),
+  }.get("vendor/%s/cfg.mk" % _foo)
+  (_varmod, _varmod_init) = _entry if _entry else (None, None)
+  if not _varmod_init:
+    rblf.mkerror("product.mk", "Cannot find %s" % ("vendor/%s/cfg.mk" % _foo))
+  _varmod_init(g, handle)
+`,
+	},
+
+	{
 		desc:   "Synonymous inherited configurations",
 		mkname: "path/product.mk",
 		in: `
@@ -898,8 +923,6 @@
   cfg["PRODUCT_LIST2"] += ["a"]
   cfg["PRODUCT_LIST1"] += ["b"]
   cfg["PRODUCT_LIST2"] += ["b"]
-  if cfg.get("PRODUCT_LIST3") == None:
-    cfg["PRODUCT_LIST3"] = ["a"]
   cfg["PRODUCT_LIST1"] = ["c"]
   g.setdefault("PLATFORM_LIST", [])
   g["PLATFORM_LIST"] += ["x"]
@@ -941,9 +964,10 @@
 PRODUCT_LIST2 ?= a $(PRODUCT_LIST2)
 PRODUCT_LIST3 += a
 
-# Now doing them again should not have a setdefault because they've already been set
+# Now doing them again should not have a setdefault because they've already been set, except 2
+# which did not emit an assignment before
 PRODUCT_LIST1 = a $(PRODUCT_LIST1)
-PRODUCT_LIST2 ?= a $(PRODUCT_LIST2)
+PRODUCT_LIST2 = a $(PRODUCT_LIST2)
 PRODUCT_LIST3 += a
 `,
 		expected: `# All of these should have a setdefault because they're self-referential and not defined before
@@ -954,18 +978,15 @@
   rblf.setdefault(handle, "PRODUCT_LIST1")
   cfg["PRODUCT_LIST1"] = (["a"] +
       cfg.get("PRODUCT_LIST1", []))
-  if cfg.get("PRODUCT_LIST2") == None:
-    rblf.setdefault(handle, "PRODUCT_LIST2")
-    cfg["PRODUCT_LIST2"] = (["a"] +
-        cfg.get("PRODUCT_LIST2", []))
   rblf.setdefault(handle, "PRODUCT_LIST3")
   cfg["PRODUCT_LIST3"] += ["a"]
-  # Now doing them again should not have a setdefault because they've already been set
+  # Now doing them again should not have a setdefault because they've already been set, except 2
+  # which did not emit an assignment before
   cfg["PRODUCT_LIST1"] = (["a"] +
       cfg["PRODUCT_LIST1"])
-  if cfg.get("PRODUCT_LIST2") == None:
-    cfg["PRODUCT_LIST2"] = (["a"] +
-        cfg["PRODUCT_LIST2"])
+  rblf.setdefault(handle, "PRODUCT_LIST2")
+  cfg["PRODUCT_LIST2"] = (["a"] +
+      cfg.get("PRODUCT_LIST2", []))
   cfg["PRODUCT_LIST3"] += ["a"]
 `,
 	},
diff --git a/mk2rbc/test/version_defaults.mk.test b/mk2rbc/test/version_defaults.mk.test
index 1666392..3ce60bc 100644
--- a/mk2rbc/test/version_defaults.mk.test
+++ b/mk2rbc/test/version_defaults.mk.test
@@ -3,8 +3,8 @@
   include $(INTERNAL_BUILD_ID_MAKEFILE)
 endif
 
-DEFAULT_PLATFORM_VERSION := TP1A
-.KATI_READONLY := DEFAULT_PLATFORM_VERSION
+RELEASE_PLATFORM_VERSION := TP1A
+.KATI_READONLY := RELEASE_PLATFORM_VERSION
 MIN_PLATFORM_VERSION := TP1A
 MAX_PLATFORM_VERSION := TP1A
 PLATFORM_VERSION_LAST_STABLE := 12
diff --git a/mk2rbc/variable.go b/mk2rbc/variable.go
index 0a26ed8..95e1f8e 100644
--- a/mk2rbc/variable.go
+++ b/mk2rbc/variable.go
@@ -109,14 +109,11 @@
 		}
 		emitAppend()
 	case asgnMaybeSet:
-		gctx.writef("if cfg.get(%q) == None:", pcv.nam)
-		gctx.indentLevel++
-		gctx.newLine()
-		if needsSetDefault {
-			emitSetDefault()
-		}
-		emitAssignment()
-		gctx.indentLevel--
+		// In mk2rbc.go we never emit a maybeSet assignment for product config variables, because
+		// they are set to empty strings before running product config.
+		panic("Should never get here")
+	default:
+		panic("Unknown assignment flavor")
 	}
 
 	gctx.setHasBeenAssigned(&pcv)
diff --git a/multitree/api_imports.go b/multitree/api_imports.go
index 07ec7bc..51b9e07 100644
--- a/multitree/api_imports.go
+++ b/multitree/api_imports.go
@@ -64,7 +64,7 @@
 	SharedLibs, HeaderLibs, ApexSharedLibs map[string]string
 }
 
-var ApiImportsProvider = blueprint.NewMutatorProvider(ApiImportInfo{}, "deps")
+var ApiImportsProvider = blueprint.NewMutatorProvider[ApiImportInfo]("deps")
 
 // Store module lists into ApiImportInfo and share it over mutator provider.
 func (imports *ApiImports) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -81,7 +81,7 @@
 	headerLibs := generateNameMapWithSuffix(imports.properties.Header_libs)
 	apexSharedLibs := generateNameMapWithSuffix(imports.properties.Apex_shared_libs)
 
-	ctx.SetProvider(ApiImportsProvider, ApiImportInfo{
+	android.SetProvider(ctx, ApiImportsProvider, ApiImportInfo{
 		SharedLibs:     sharedLibs,
 		HeaderLibs:     headerLibs,
 		ApexSharedLibs: apexSharedLibs,
diff --git a/partner/androidmk/androidmk_test.go b/partner/androidmk/androidmk_test.go
index 6bae836..3ace750 100644
--- a/partner/androidmk/androidmk_test.go
+++ b/partner/androidmk/androidmk_test.go
@@ -54,6 +54,9 @@
 }
 
 func TestEndToEnd(t *testing.T) {
+	// Skip checking Android.mk path with cleaning "ANDROID_BUILD_TOP"
+	t.Setenv("ANDROID_BUILD_TOP", "")
+
 	for i, test := range testCases {
 		expected, err := bpfix.Reformat(test.expected)
 		if err != nil {
diff --git a/phony/phony.go b/phony/phony.go
index 760b79b..5469238 100644
--- a/phony/phony.go
+++ b/phony/phony.go
@@ -23,9 +23,17 @@
 )
 
 func init() {
-	android.RegisterModuleType("phony", PhonyFactory)
+	registerPhonyModuleTypes(android.InitRegistrationContext)
 }
 
+func registerPhonyModuleTypes(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("phony", PhonyFactory)
+	ctx.RegisterModuleType("phony_rule", PhonyRuleFactory)
+	ctx.RegisterModuleType("phony_rule_defaults", PhonyRuleDefaultsFactory)
+}
+
+var PrepareForTestWithPhony = android.FixtureRegisterWithContext(registerPhonyModuleTypes)
+
 type phony struct {
 	android.ModuleBase
 	requiredModuleNames       []string
@@ -52,7 +60,6 @@
 			fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)", " # phony.phony")
 			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
 			fmt.Fprintln(w, "LOCAL_MODULE :=", name)
-			data.Entries.WriteLicenseVariables(w)
 			if p.Host() {
 				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
 			}
@@ -68,7 +75,92 @@
 				fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES :=",
 					strings.Join(p.targetRequiredModuleNames, " "))
 			}
+			// AconfigUpdateAndroidMkData may have added elements to Extra.  Process them here.
+			for _, extra := range data.Extra {
+				extra(w, nil)
+			}
 			fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
 		},
 	}
 }
+
+type PhonyRule struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+
+	properties PhonyProperties
+}
+
+type PhonyProperties struct {
+	// The Phony_deps is the set of all dependencies for this target,
+	// and it can function similarly to .PHONY in a makefile.
+	// Additionally, dependencies within it can even include genrule.
+	Phony_deps []string
+}
+
+// The phony_rule provides functionality similar to the .PHONY in a makefile.
+// It can create a phony target and include relevant dependencies associated with it.
+func PhonyRuleFactory() android.Module {
+	module := &PhonyRule{}
+	android.InitAndroidModule(module)
+	module.AddProperties(&module.properties)
+	android.InitDefaultableModule(module)
+	return module
+}
+
+func (p *PhonyRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+}
+
+func (p *PhonyRule) AndroidMk() android.AndroidMkData {
+	return android.AndroidMkData{
+		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+			if len(p.properties.Phony_deps) > 0 {
+				depModulesStr := strings.Join(p.properties.Phony_deps, " ")
+				fmt.Fprintln(w, ".PHONY:", name)
+				fmt.Fprintln(w, name, ":", depModulesStr)
+			}
+		},
+	}
+}
+
+// PhonyRuleDefaults
+type PhonyRuleDefaults struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+}
+
+// phony_rule_defaults provides a set of properties that can be inherited by other phony_rules.
+//
+// A module can use the properties from a phony_rule_defaults module using `defaults: ["defaults_module_name"]`.  Each
+// property in the defaults module that exists in the depending module will be prepended to the depending module's
+// value for that property.
+//
+// Example:
+//
+//	phony_rule_defaults {
+//	    name: "add_module1_defaults",
+//	    phony_deps: [
+//	        "module1",
+//	    ],
+//	}
+//
+//	phony_rule {
+//	    name: "example",
+//	    defaults: ["add_module1_defaults"],
+//	}
+//
+// is functionally identical to:
+//
+//	phony_rule {
+//	    name: "example",
+//	    phony_deps: [
+//	        "module1",
+//	    ],
+//	}
+func PhonyRuleDefaultsFactory() android.Module {
+	module := &PhonyRuleDefaults{}
+	module.AddProperties(&PhonyProperties{})
+	android.InitDefaultsModule(module)
+
+	return module
+}
diff --git a/provenance/provenance_singleton.go b/provenance/provenance_singleton.go
index 5d27c0c..97345af 100644
--- a/provenance/provenance_singleton.go
+++ b/provenance/provenance_singleton.go
@@ -38,7 +38,9 @@
 			Command: `rm -rf $out && ` +
 				`echo "# proto-file: build/soong/provenance/proto/provenance_metadata.proto" > $out && ` +
 				`echo "# proto-message: ProvenanceMetaDataList" >> $out && ` +
-				`for file in $in; do echo '' >> $out; echo 'metadata {' | cat - $$file | grep -Ev "^#.*|^$$" >> $out; echo '}' >> $out; done`,
+				`cat $out.rsp | tr ' ' '\n' | while read -r file || [ -n "$$file" ]; do echo '' >> $out; echo 'metadata {' | cat - $$file | grep -Ev "^#.*|^$$" >> $out; echo '}' >> $out; done`,
+			Rspfile:        `$out.rsp`,
+			RspfileContent: `$in`,
 		})
 )
 
diff --git a/python/Android.bp b/python/Android.bp
index 7578673..14e83c1 100644
--- a/python/Android.bp
+++ b/python/Android.bp
@@ -10,10 +10,10 @@
         "soong-android",
         "soong-tradefed",
         "soong-cc",
+        "soong-testing",
     ],
     srcs: [
         "binary.go",
-        "bp2build.go",
         "builder.go",
         "defaults.go",
         "library.go",
diff --git a/python/binary.go b/python/binary.go
index a5db2f6..c84eeee 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -71,6 +71,9 @@
 	installedDest android.Path
 
 	androidMkSharedLibs []string
+
+	// Aconfig files for all transitive deps.  Also exposed via TransitiveDeclarationsInfo
+	mergedAconfigFiles map[string]android.Paths
 }
 
 var _ android.AndroidMkEntriesProvider = (*PythonBinaryModule)(nil)
@@ -95,7 +98,6 @@
 	p.AddProperties(&p.binaryProperties)
 	android.InitAndroidArchModule(p, p.hod, p.multilib)
 	android.InitDefaultableModule(p)
-	android.InitBazelModule(p)
 	return p
 }
 
@@ -104,6 +106,7 @@
 	p.buildBinary(ctx)
 	p.installedDest = ctx.InstallFile(installDir(ctx, "bin", "", ""),
 		p.installSource.Base(), p.installSource)
+	android.CollectDependencyAconfigFiles(ctx, &p.mergedAconfigFiles)
 }
 
 func (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) {
@@ -167,6 +170,7 @@
 			entries.SetString("LOCAL_MODULE_STEM", stem)
 			entries.AddStrings("LOCAL_SHARED_LIBRARIES", p.androidMkSharedLibs...)
 			entries.SetBool("LOCAL_CHECK_ELF_FILES", false)
+			android.SetAconfigFileMkEntries(&p.ModuleBase, entries, p.mergedAconfigFiles)
 		})
 
 	return []android.AndroidMkEntries{entries}
@@ -199,7 +203,7 @@
 }
 
 func (p *PythonBinaryModule) isEmbeddedLauncherEnabled() bool {
-	return Bool(p.properties.Embedded_launcher)
+	return BoolDefault(p.properties.Embedded_launcher, true)
 }
 
 func (b *PythonBinaryModule) autorun() bool {
diff --git a/python/bp2build.go b/python/bp2build.go
deleted file mode 100644
index 41e9f49..0000000
--- a/python/bp2build.go
+++ /dev/null
@@ -1,233 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package python
-
-import (
-	"path/filepath"
-	"strings"
-
-	"github.com/google/blueprint/proptools"
-
-	"android/soong/android"
-	"android/soong/bazel"
-)
-
-type bazelPythonLibraryAttributes struct {
-	Srcs         bazel.LabelListAttribute
-	Deps         bazel.LabelListAttribute
-	Imports      bazel.StringListAttribute
-	Srcs_version *string
-}
-
-type bazelPythonProtoLibraryAttributes struct {
-	Deps bazel.LabelListAttribute
-}
-
-type baseAttributes struct {
-	// TODO(b/200311466): Probably not translate b/c Bazel has no good equiv
-	//Pkg_path    bazel.StringAttribute
-	// TODO: Related to Pkg_bath and similarLy gated
-	//Is_internal bazel.BoolAttribute
-	// Combines Srcs and Exclude_srcs
-	Srcs bazel.LabelListAttribute
-	Deps bazel.LabelListAttribute
-	// Combines Data and Java_data (invariant)
-	Data    bazel.LabelListAttribute
-	Imports bazel.StringListAttribute
-}
-
-func (m *PythonLibraryModule) makeArchVariantBaseAttributes(ctx android.TopDownMutatorContext) baseAttributes {
-	var attrs baseAttributes
-	archVariantBaseProps := m.GetArchVariantProperties(ctx, &BaseProperties{})
-	for axis, configToProps := range archVariantBaseProps {
-		for config, props := range configToProps {
-			if baseProps, ok := props.(*BaseProperties); ok {
-				attrs.Srcs.SetSelectValue(axis, config,
-					android.BazelLabelForModuleSrcExcludes(ctx, baseProps.Srcs, baseProps.Exclude_srcs))
-				attrs.Deps.SetSelectValue(axis, config,
-					android.BazelLabelForModuleDeps(ctx, baseProps.Libs))
-				data := android.BazelLabelForModuleSrc(ctx, baseProps.Data)
-				data.Append(android.BazelLabelForModuleSrc(ctx, baseProps.Java_data))
-				attrs.Data.SetSelectValue(axis, config, data)
-			}
-		}
-	}
-
-	partitionedSrcs := bazel.PartitionLabelListAttribute(ctx, &attrs.Srcs, bazel.LabelPartitions{
-		"proto": android.ProtoSrcLabelPartition,
-		"py":    bazel.LabelPartition{Keep_remainder: true},
-	})
-	attrs.Srcs = partitionedSrcs["py"]
-
-	if !partitionedSrcs["proto"].IsEmpty() {
-		protoInfo, _ := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, partitionedSrcs["proto"])
-
-		pyProtoLibraryName := m.Name() + "_py_proto"
-		ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
-			Rule_class:        "py_proto_library",
-			Bzl_load_location: "//build/bazel/rules/python:py_proto.bzl",
-		}, android.CommonAttributes{
-			Name: pyProtoLibraryName,
-		}, &bazelPythonProtoLibraryAttributes{
-			Deps: bazel.MakeLabelListAttribute(protoInfo.Proto_libs),
-		})
-
-		attrs.Deps.Add(bazel.MakeLabelAttribute(":" + pyProtoLibraryName))
-	}
-
-	// Bazel normally requires `import path.from.top.of.tree` statements in
-	// python code, but with soong you can directly import modules from libraries.
-	// Add "imports" attributes to the bazel library so it matches soong's behavior.
-	imports := "."
-	if m.properties.Pkg_path != nil {
-		// TODO(b/215119317) This is a hack to handle the fact that we don't convert
-		// pkg_path properly right now. If the folder structure that contains this
-		// Android.bp file matches pkg_path, we can set imports to an appropriate
-		// number of ../..s to emulate moving the files under a pkg_path folder.
-		pkg_path := filepath.Clean(*m.properties.Pkg_path)
-		if strings.HasPrefix(pkg_path, "/") {
-			ctx.ModuleErrorf("pkg_path cannot start with a /: %s", pkg_path)
-		}
-
-		if !strings.HasSuffix(ctx.ModuleDir(), "/"+pkg_path) && ctx.ModuleDir() != pkg_path {
-			ctx.ModuleErrorf("Currently, bp2build only supports pkg_paths that are the same as the folders the Android.bp file is in. pkg_path: %s, module directory: %s", pkg_path, ctx.ModuleDir())
-		}
-		numFolders := strings.Count(pkg_path, "/") + 1
-		dots := make([]string, numFolders)
-		for i := 0; i < numFolders; i++ {
-			dots[i] = ".."
-		}
-		imports = strings.Join(dots, "/")
-	}
-	attrs.Imports = bazel.MakeStringListAttribute([]string{imports})
-
-	return attrs
-}
-
-func (m *PythonLibraryModule) bp2buildPythonVersion(ctx android.TopDownMutatorContext) *string {
-	py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, true)
-	py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false)
-	if py2Enabled && !py3Enabled {
-		return &pyVersion2
-	} else if !py2Enabled && py3Enabled {
-		return &pyVersion3
-	} else if !py2Enabled && !py3Enabled {
-		ctx.ModuleErrorf("bp2build converter doesn't understand having neither py2 nor py3 enabled")
-		return &pyVersion3
-	} else {
-		return &pyVersion2And3
-	}
-}
-
-type bazelPythonBinaryAttributes struct {
-	Main           *bazel.Label
-	Srcs           bazel.LabelListAttribute
-	Deps           bazel.LabelListAttribute
-	Python_version *string
-	Imports        bazel.StringListAttribute
-}
-
-func (p *PythonLibraryModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	// TODO(b/182306917): this doesn't fully handle all nested props versioned
-	// by the python version, which would have been handled by the version split
-	// mutator. This is sufficient for very simple python_library modules under
-	// Bionic.
-	baseAttrs := p.makeArchVariantBaseAttributes(ctx)
-	pyVersion := p.bp2buildPythonVersion(ctx)
-	if *pyVersion == pyVersion2And3 {
-		// Libraries default to python 2 and 3
-		pyVersion = nil
-	}
-
-	attrs := &bazelPythonLibraryAttributes{
-		Srcs:         baseAttrs.Srcs,
-		Deps:         baseAttrs.Deps,
-		Srcs_version: pyVersion,
-		Imports:      baseAttrs.Imports,
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		// Use the native py_library rule.
-		Rule_class: "py_library",
-	}
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-		Name: p.Name(),
-		Data: baseAttrs.Data,
-	}, attrs)
-}
-
-func (p *PythonBinaryModule) bp2buildBinaryProperties(ctx android.TopDownMutatorContext) (*bazelPythonBinaryAttributes, bazel.LabelListAttribute) {
-	// TODO(b/182306917): this doesn't fully handle all nested props versioned
-	// by the python version, which would have been handled by the version split
-	// mutator. This is sufficient for very simple python_binary_host modules
-	// under Bionic.
-
-	baseAttrs := p.makeArchVariantBaseAttributes(ctx)
-	pyVersion := p.bp2buildPythonVersion(ctx)
-	if *pyVersion == pyVersion3 {
-		// Binaries default to python 3
-		pyVersion = nil
-	} else if *pyVersion == pyVersion2And3 {
-		ctx.ModuleErrorf("error for '%s' module: bp2build's python_binary_host converter "+
-			"does not support converting a module that is enabled for both Python 2 and 3 at the "+
-			"same time.", p.Name())
-	}
-
-	attrs := &bazelPythonBinaryAttributes{
-		Main:           nil,
-		Srcs:           baseAttrs.Srcs,
-		Deps:           baseAttrs.Deps,
-		Python_version: pyVersion,
-		Imports:        baseAttrs.Imports,
-	}
-
-	// main is optional.
-	if p.binaryProperties.Main != nil {
-		main := android.BazelLabelForModuleSrcSingle(ctx, *p.binaryProperties.Main)
-		attrs.Main = &main
-	}
-	return attrs, baseAttrs.Data
-}
-
-func (p *PythonBinaryModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	attrs, data := p.bp2buildBinaryProperties(ctx)
-
-	props := bazel.BazelTargetModuleProperties{
-		// Use the native py_binary rule.
-		Rule_class: "py_binary",
-	}
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-		Name: p.Name(),
-		Data: data,
-	}, attrs)
-}
-
-func (p *PythonTestModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	// Python tests are currently exactly the same as binaries, but with a different module type
-	attrs, data := p.bp2buildBinaryProperties(ctx)
-
-	props := bazel.BazelTargetModuleProperties{
-		// Use the native py_binary rule.
-		Rule_class:        "py_test",
-		Bzl_load_location: "//build/bazel/rules/python:py_test.bzl",
-	}
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-		Name: p.Name(),
-		Data: data,
-	}, attrs)
-}
diff --git a/python/builder.go b/python/builder.go
index 1066493..2553a77 100644
--- a/python/builder.go
+++ b/python/builder.go
@@ -73,14 +73,14 @@
 
 	precompile = pctx.AndroidStaticRule("precompilePython", blueprint.RuleParams{
 		Command: `LD_LIBRARY_PATH="$ldLibraryPath" ` +
-			`PYTHONPATH=$stdlibZip/internal/stdlib ` +
+			`PYTHONPATH=$stdlibZip/internal/$stdlibPkg ` +
 			`$launcher build/soong/python/scripts/precompile_python.py $in $out`,
 		CommandDeps: []string{
 			"$stdlibZip",
 			"$launcher",
 			"build/soong/python/scripts/precompile_python.py",
 		},
-	}, "stdlibZip", "launcher", "ldLibraryPath")
+	}, "stdlibZip", "stdlibPkg", "launcher", "ldLibraryPath")
 )
 
 func init() {
diff --git a/python/proto.go b/python/proto.go
index 400e72c..ad2b786 100644
--- a/python/proto.go
+++ b/python/proto.go
@@ -19,7 +19,8 @@
 )
 
 func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.ProtoFlags) android.Path {
-	srcsZipFile := android.PathForModuleGen(ctx, protoFile.Base()+".srcszip")
+	// Using protoFile.Base() would generate duplicate source errors in some cases, so we use Rel() instead
+	srcsZipFile := android.PathForModuleGen(ctx, protoFile.Rel()+".srcszip")
 
 	outDir := srcsZipFile.ReplaceExtension(ctx, "tmp")
 	depFile := srcsZipFile.ReplaceExtension(ctx, "srcszip.d")
diff --git a/python/python.go b/python/python.go
index 8fde638..e14fdf3 100644
--- a/python/python.go
+++ b/python/python.go
@@ -59,7 +59,7 @@
 	// list of the Python libraries used only for this Python version.
 	Libs []string `android:"arch_variant"`
 
-	// whether the binary is required to be built with embedded launcher for this version, defaults to false.
+	// whether the binary is required to be built with embedded launcher for this version, defaults to true.
 	Embedded_launcher *bool // TODO(b/174041232): Remove this property
 }
 
@@ -129,7 +129,6 @@
 type PythonLibraryModule struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
-	android.BazelModuleBase
 
 	properties      BaseProperties
 	protoProperties android.ProtoProperties
@@ -152,6 +151,8 @@
 	// The zip file containing the current module's source/data files, with the
 	// source files precompiled.
 	precompiledSrcsZip android.Path
+
+	sourceProperties android.SourceProperties
 }
 
 // newModule generates new Python base module
@@ -169,6 +170,7 @@
 	getDataPathMappings() []pathMapping
 	getSrcsZip() android.Path
 	getPrecompiledSrcsZip() android.Path
+	getPkgPath() string
 }
 
 // getSrcsPathMappings gets this module's path mapping of src source path : runfiles destination
@@ -191,6 +193,11 @@
 	return p.precompiledSrcsZip
 }
 
+// getPkgPath returns the pkg_path value
+func (p *PythonLibraryModule) getPkgPath() string {
+	return String(p.properties.Pkg_path)
+}
+
 func (p *PythonLibraryModule) getBaseProperties() *BaseProperties {
 	return &p.properties
 }
@@ -198,10 +205,9 @@
 var _ pythonDependency = (*PythonLibraryModule)(nil)
 
 func (p *PythonLibraryModule) init() android.Module {
-	p.AddProperties(&p.properties, &p.protoProperties)
+	p.AddProperties(&p.properties, &p.protoProperties, &p.sourceProperties)
 	android.InitAndroidArchModule(p, p.hod, p.multilib)
 	android.InitDefaultableModule(p)
-	android.InitBazelModule(p)
 	return p
 }
 
@@ -370,7 +376,20 @@
 
 		launcherSharedLibDeps = append(launcherSharedLibDeps, "libc++")
 	case pyVersion3:
-		stdLib = "py3-stdlib"
+		var prebuiltStdLib bool
+		if targetForDeps.Os.Bionic() {
+			prebuiltStdLib = false
+		} else if ctx.Config().VendorConfig("cpython3").Bool("force_build_host") {
+			prebuiltStdLib = false
+		} else {
+			prebuiltStdLib = true
+		}
+
+		if prebuiltStdLib {
+			stdLib = "py3-stdlib-prebuilt"
+		} else {
+			stdLib = "py3-stdlib"
+		}
 
 		launcherModule = "py3-launcher"
 		if autorun {
@@ -403,6 +422,12 @@
 // GenerateAndroidBuildActions performs build actions common to all Python modules
 func (p *PythonLibraryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	expandedSrcs := android.PathsForModuleSrcExcludes(ctx, p.properties.Srcs, p.properties.Exclude_srcs)
+	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: expandedSrcs.Strings()})
+	// Keep before any early returns.
+	android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
+		TestOnly:       Bool(p.sourceProperties.Test_only),
+		TopLevelTarget: p.sourceProperties.Top_level_test_target,
+	})
 
 	// expand data files from "data" property.
 	expandedData := android.PathsForModuleSrc(ctx, p.properties.Data)
@@ -461,14 +486,19 @@
 	destToPySrcs := make(map[string]string)
 	destToPyData := make(map[string]string)
 
+	// Disable path checks for the stdlib, as it includes a "." in the version string
+	isInternal := proptools.BoolDefault(p.properties.Is_internal, false)
+
 	for _, s := range expandedSrcs {
 		if s.Ext() != pyExt && s.Ext() != protoExt {
 			ctx.PropertyErrorf("srcs", "found non (.py|.proto) file: %q!", s.String())
 			continue
 		}
 		runfilesPath := filepath.Join(pkgPath, s.Rel())
-		if err := isValidPythonPath(runfilesPath); err != nil {
-			ctx.PropertyErrorf("srcs", err.Error())
+		if !isInternal {
+			if err := isValidPythonPath(runfilesPath); err != nil {
+				ctx.PropertyErrorf("srcs", err.Error())
+			}
 		}
 		if !checkForDuplicateOutputPath(ctx, destToPySrcs, runfilesPath, s.String(), p.Name(), p.Name()) {
 			p.srcsPathMappings = append(p.srcsPathMappings, pathMapping{dest: runfilesPath, src: s})
@@ -522,7 +552,6 @@
 			var stagedProtoSrcs android.Paths
 			for _, srcFile := range protoSrcs {
 				stagedProtoSrc := pkgPathStagingDir.Join(ctx, pkgPath, srcFile.Rel())
-				rule.Command().Text("mkdir -p").Flag(filepath.Base(stagedProtoSrc.String()))
 				rule.Command().Text("cp -f").Input(srcFile).Output(stagedProtoSrc)
 				stagedProtoSrcs = append(stagedProtoSrcs, stagedProtoSrc)
 			}
@@ -591,13 +620,16 @@
 	// "cross compiling" for device here purely by virtue of host and device python bytecode
 	// being the same.
 	var stdLib android.Path
+	var stdLibPkg string
 	var launcher android.Path
-	if ctx.ModuleName() == "py3-stdlib" || ctx.ModuleName() == "py2-stdlib" {
+	if proptools.BoolDefault(p.properties.Is_internal, false) {
 		stdLib = p.srcsZip
+		stdLibPkg = p.getPkgPath()
 	} else {
 		ctx.VisitDirectDepsWithTag(hostStdLibTag, func(module android.Module) {
 			if dep, ok := module.(pythonDependency); ok {
 				stdLib = dep.getPrecompiledSrcsZip()
+				stdLibPkg = dep.getPkgPath()
 			}
 		})
 	}
@@ -636,6 +668,7 @@
 		Description: "Precompile the python sources of " + ctx.ModuleName(),
 		Args: map[string]string{
 			"stdlibZip":     stdLib.String(),
+			"stdlibPkg":     stdLibPkg,
 			"launcher":      launcher.String(),
 			"ldLibraryPath": strings.Join(ldLibraryPath, ":"),
 		},
diff --git a/python/python_test.go b/python/python_test.go
index 75a6a89..c0b7295 100644
--- a/python/python_test.go
+++ b/python/python_test.go
@@ -18,10 +18,13 @@
 	"fmt"
 	"os"
 	"path/filepath"
+	"strings"
 	"testing"
 
 	"android/soong/android"
 	"android/soong/cc"
+
+	"github.com/google/blueprint"
 )
 
 type pyModule struct {
@@ -360,6 +363,76 @@
 	}
 }
 
+func TestTestOnlyProvider(t *testing.T) {
+	t.Parallel()
+	ctx := android.GroupFixturePreparers(
+		PrepareForTestWithPythonBuildComponents,
+		android.PrepareForTestWithAllowMissingDependencies,
+	).RunTestWithBp(t, `
+                // These should be test-only
+                python_library { name: "py-lib-test", test_only: true }
+                python_library { name: "py-lib-test-host", test_only: true, host_supported: true }
+                python_test {    name: "py-test", srcs: ["py-test.py"] }
+                python_test_host { name: "py-test-host", srcs: ["py-test-host.py"] }
+                python_binary_host { name: "py-bin-test", srcs: ["py-bin-test.py"] }
+
+                // These should not be.
+                python_library { name: "py-lib" }
+                python_binary_host { name: "py-bin", srcs: ["py-bin.py"] }
+	`)
+
+	// Visit all modules and ensure only the ones that should
+	// marked as test-only are marked as test-only.
+
+	actualTestOnly := []string{}
+	ctx.VisitAllModules(func(m blueprint.Module) {
+		if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, android.TestOnlyProviderKey); ok {
+			if provider.TestOnly {
+				actualTestOnly = append(actualTestOnly, m.Name())
+			}
+		}
+	})
+	expectedTestOnlyModules := []string{
+		"py-lib-test",
+		"py-lib-test-host",
+		"py-test",
+		"py-test-host",
+	}
+
+	notEqual, left, right := android.ListSetDifference(expectedTestOnlyModules, actualTestOnly)
+	if notEqual {
+		t.Errorf("test-only: Expected but not found: %v, Found but not expected: %v", left, right)
+	}
+}
+
+// Don't allow setting test-only on things that are always tests or never tests.
+func TestInvalidTestOnlyTargets(t *testing.T) {
+	testCases := []string{
+		` python_test { name: "py-test", test_only: true, srcs: ["py-test.py"] } `,
+		` python_test_host { name: "py-test-host", test_only: true, srcs: ["py-test-host.py"] } `,
+		` python_defaults { name: "py-defaults", test_only: true, srcs: ["foo.py"] } `,
+	}
+
+	for i, bp := range testCases {
+		ctx := android.GroupFixturePreparers(
+			PrepareForTestWithPythonBuildComponents,
+			android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+
+				ctx.RegisterModuleType("python_defaults", DefaultsFactory)
+			}),
+			android.PrepareForTestWithAllowMissingDependencies).
+			ExtendWithErrorHandler(android.FixtureIgnoreErrors).
+			RunTestWithBp(t, bp)
+		if len(ctx.Errs) != 1 {
+			t.Errorf("Expected err setting test_only in testcase #%d: %d errs", i, len(ctx.Errs))
+			continue
+		}
+		if !strings.Contains(ctx.Errs[0].Error(), "unrecognized property \"test_only\"") {
+			t.Errorf("ERR: %s bad bp: %s", ctx.Errs[0], bp)
+		}
+	}
+}
+
 func expectModule(t *testing.T, ctx *android.TestContext, name, variant, expectedSrcsZip string, expectedPyRunfiles []string) {
 	module := ctx.ModuleForTests(name, variant)
 
diff --git a/python/scripts/precompile_python.py b/python/scripts/precompile_python.py
index e12e7d2..b3cf950 100644
--- a/python/scripts/precompile_python.py
+++ b/python/scripts/precompile_python.py
@@ -13,9 +13,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from __future__ import print_function
 import argparse
 import py_compile
 import os
+import sys
 import shutil
 import tempfile
 import zipfile
@@ -23,22 +25,35 @@
 # This file needs to support both python 2 and 3.
 
 
-def process_one_file(name, inf, outzip):
-    if not name.endswith('.py'):
-        outzip.writestr(name, inf.read())
+def process_one_file(name, infile, outzip):
+    # Create a ZipInfo instance with a fixed date to ensure a deterministic output.
+    # Date was chosen to be the same as
+    # https://cs.android.com/android/platform/superproject/main/+/main:build/soong/jar/jar.go;l=36;drc=2863e4535eb65e15f955dc8ed48fa99b1d2a1db5
+    info = zipfile.ZipInfo(filename=name, date_time=(2008, 1, 1, 0, 0, 0))
+    info.compress_type = zipfile.ZIP_DEFLATED
+
+    if not info.filename.endswith('.py'):
+        outzip.writestr(info, infile.read())
         return
 
     # Unfortunately py_compile requires the input/output files to be written
     # out to disk.
     with tempfile.NamedTemporaryFile(prefix="Soong_precompile_", delete=False) as tmp:
-        shutil.copyfileobj(inf, tmp)
+        shutil.copyfileobj(infile, tmp)
         in_name = tmp.name
     with tempfile.NamedTemporaryFile(prefix="Soong_precompile_", delete=False) as tmp:
         out_name = tmp.name
     try:
-        py_compile.compile(in_name, out_name, name, doraise=True)
+        # Ensure a deterministic .pyc output by using the hash rather than the timestamp.
+        # Only works on Python 3.7+
+        # See https://docs.python.org/3/library/py_compile.html#py_compile.PycInvalidationMode
+        if sys.version_info >= (3, 7):
+            py_compile.compile(in_name, out_name, info.filename, doraise=True, invalidation_mode=py_compile.PycInvalidationMode.CHECKED_HASH)
+        else:
+            py_compile.compile(in_name, out_name, info.filename, doraise=True)
         with open(out_name, 'rb') as f:
-            outzip.writestr(name + 'c', f.read())
+            info.filename = info.filename + 'c'
+            outzip.writestr(info, f.read())
     finally:
         os.remove(in_name)
         os.remove(out_name)
@@ -50,11 +65,23 @@
     parser.add_argument('dst_zip')
     args = parser.parse_args()
 
+    errors = []
     with open(args.dst_zip, 'wb') as outf, open(args.src_zip, 'rb') as inf:
         with zipfile.ZipFile(outf, mode='w') as outzip, zipfile.ZipFile(inf, mode='r') as inzip:
             for name in inzip.namelist():
                 with inzip.open(name, mode='r') as inzipf:
-                    process_one_file(name, inzipf, outzip)
+                    try:
+                        process_one_file(name, inzipf, outzip)
+                    except py_compile.PyCompileError as e:
+                        errors.append(e)
+
+    if errors:
+        for i, error in enumerate(errors):
+            # Print an empty line in between each error
+            if i > 0:
+                print(file=sys.stderr)
+            print(str(error).strip(), file=sys.stderr)
+        sys.exit(1)
 
 
 if __name__ == "__main__":
diff --git a/python/test.go b/python/test.go
index 6e23a44..2b939e7 100644
--- a/python/test.go
+++ b/python/test.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 
+	"android/soong/testing"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -35,7 +36,9 @@
 }
 
 func NewTest(hod android.HostOrDeviceSupported) *PythonTestModule {
-	return &PythonTestModule{PythonBinaryModule: *NewBinary(hod)}
+	p := &PythonTestModule{PythonBinaryModule: *NewBinary(hod)}
+	p.sourceProperties = android.SourceProperties{Test_only: proptools.BoolPtr(true), Top_level_test_target: true}
+	return p
 }
 
 func PythonTestHostFactory() android.Module {
@@ -101,7 +104,6 @@
 	p.AddProperties(&p.testProperties)
 	android.InitAndroidArchModule(p, p.hod, p.multilib)
 	android.InitDefaultableModule(p)
-	android.InitBazelModule(p)
 	if p.isTestHost() && p.testProperties.Test_options.Unit_test == nil {
 		p.testProperties.Test_options.Unit_test = proptools.BoolPtr(true)
 	}
@@ -149,6 +151,7 @@
 	// just use buildBinary() so that the binary is not installed into the location
 	// it would be for regular binaries.
 	p.PythonLibraryModule.GenerateAndroidBuildActions(ctx)
+	android.CollectDependencyAconfigFiles(ctx, &p.mergedAconfigFiles)
 	p.buildBinary(ctx)
 
 	var configs []tradefed.Option
@@ -157,37 +160,25 @@
 	}
 
 	runner := proptools.StringDefault(p.testProperties.Test_options.Runner, "tradefed")
-	if runner == "tradefed" {
-		p.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
-			TestConfigProp:          p.testProperties.Test_config,
-			TestConfigTemplateProp:  p.testProperties.Test_config_template,
-			TestSuites:              p.binaryProperties.Test_suites,
-			OptionsForAutogenerated: configs,
-			AutoGenConfig:           p.binaryProperties.Auto_gen_config,
-			DeviceTemplate:          "${PythonBinaryHostTestConfigTemplate}",
-			HostTemplate:            "${PythonBinaryHostTestConfigTemplate}",
-		})
-	} else if runner == "mobly" {
-		if p.testProperties.Test_config != nil || p.testProperties.Test_config_template != nil || p.binaryProperties.Auto_gen_config != nil {
-			panic(fmt.Errorf("cannot set test_config, test_config_template or auto_gen_config for mobly test"))
+	template := "${PythonBinaryHostTestConfigTemplate}"
+	if runner == "mobly" {
+		// Add tag to enable Atest mobly runner
+		if !android.InList("mobly", p.testProperties.Test_options.Tags) {
+			p.testProperties.Test_options.Tags = append(p.testProperties.Test_options.Tags, "mobly")
 		}
-
-		for _, testSuite := range p.binaryProperties.Test_suites {
-			if testSuite == "cts" {
-				configs = append(configs, tradefed.Option{Name: "test-suite-tag", Value: "cts"})
-				break
-			}
-		}
-		p.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
-			OptionsForAutogenerated: configs,
-			DeviceTemplate:          "${PythonBinaryHostMoblyTestConfigTemplate}",
-			HostTemplate:            "${PythonBinaryHostMoblyTestConfigTemplate}",
-		})
-	} else {
+		template = "${PythonBinaryHostMoblyTestConfigTemplate}"
+	} else if runner != "tradefed" {
 		panic(fmt.Errorf("unknown python test runner '%s', should be 'tradefed' or 'mobly'", runner))
 	}
-
-	p.installedDest = ctx.InstallFile(installDir(ctx, "nativetest", "nativetest64", ctx.ModuleName()), p.installSource.Base(), p.installSource)
+	p.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
+		TestConfigProp:          p.testProperties.Test_config,
+		TestConfigTemplateProp:  p.testProperties.Test_config_template,
+		TestSuites:              p.binaryProperties.Test_suites,
+		OptionsForAutogenerated: configs,
+		AutoGenConfig:           p.binaryProperties.Auto_gen_config,
+		DeviceTemplate:          template,
+		HostTemplate:            template,
+	})
 
 	for _, dataSrcPath := range android.PathsForModuleSrc(ctx, p.testProperties.Data) {
 		p.data = append(p.data, android.DataPath{SrcPath: dataSrcPath})
@@ -205,6 +196,12 @@
 			p.data = append(p.data, android.DataPath{SrcPath: javaDataSrcPath})
 		}
 	}
+
+	installDir := installDir(ctx, "nativetest", "nativetest64", ctx.ModuleName())
+	installedData := ctx.InstallTestData(installDir, p.data)
+	p.installedDest = ctx.InstallFile(installDir, p.installSource.Base(), p.installSource, installedData...)
+
+	android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 func (p *PythonTestModule) AndroidMkEntries() []android.AndroidMkEntries {
@@ -223,9 +220,14 @@
 				entries.SetString("LOCAL_FULL_TEST_CONFIG", p.testConfig.String())
 			}
 
-			entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(p.binaryProperties.Auto_gen_config, true))
+			// ATS 2.0 is the test harness for mobly tests and the test config is for ATS 2.0.
+			// Add "v2" suffix to test config name to distinguish it from the config for TF.
+			if proptools.String(p.testProperties.Test_options.Runner) == "mobly" {
+				entries.SetString("LOCAL_TEST_CONFIG_SUFFIX", "v2")
+			}
 
-			entries.AddStrings("LOCAL_TEST_DATA", android.AndroidMkDataPaths(p.data)...)
+			entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(p.binaryProperties.Auto_gen_config, true))
+			android.SetAconfigFileMkEntries(&p.ModuleBase, entries, p.mergedAconfigFiles)
 
 			p.testProperties.Test_options.SetAndroidMkEntries(entries)
 		})
diff --git a/python/tests/par_test.py b/python/tests/par_test.py
index 1e03f16..96b42ae 100644
--- a/python/tests/par_test.py
+++ b/python/tests/par_test.py
@@ -33,6 +33,8 @@
 assert_equal("os.path.basename(__file__)", fileName, "par_test.py")
 
 archive = os.path.dirname(__file__)
+major = sys.version_info.major
+minor = sys.version_info.minor
 
 assert_equal("__package__", __package__, "")
 assert_equal("sys.argv[0]", sys.argv[0], archive)
@@ -42,10 +44,11 @@
 assert_equal("__loader__.archive", __loader__.archive, archive)
 assert_equal("site.ENABLE_USER_SITE", site.ENABLE_USER_SITE, None)
 
-assert_equal("len(sys.path)", len(sys.path), 3)
+assert_equal("len(sys.path)", len(sys.path), 4)
 assert_equal("sys.path[0]", sys.path[0], archive)
-assert_equal("sys.path[1]", sys.path[1], os.path.join(archive, "internal"))
-assert_equal("sys.path[2]", sys.path[2], os.path.join(archive, "internal", "stdlib"))
+assert_equal("sys.path[1]", sys.path[1], os.path.join(archive, "internal", f"python{major}{minor}.zip"))
+assert_equal("sys.path[2]", sys.path[2], os.path.join(archive, "internal", f"python{major}.{minor}"))
+assert_equal("sys.path[3]", sys.path[3], os.path.join(archive, "internal", f"python{major}.{minor}", "lib-dynload"))
 
 if os.getenv('ARGTEST', False):
     assert_equal("len(sys.argv)", len(sys.argv), 3)
diff --git a/python/tests/py-cmd_test.py b/python/tests/py-cmd_test.py
index c7ba0ab..8aed782 100644
--- a/python/tests/py-cmd_test.py
+++ b/python/tests/py-cmd_test.py
@@ -55,22 +55,22 @@
 assert_equal("sys.prefix", sys.prefix, sys.executable)
 assert_equal("site.ENABLE_USER_SITE", site.ENABLE_USER_SITE, None)
 
-if sys.version_info[0] == 2:
+major = sys.version_info.major
+minor = sys.version_info.minor
+
+if major == 2:
     assert_equal("len(sys.path)", len(sys.path), 4)
     assert_equal("sys.path[0]", sys.path[0], os.path.abspath(os.path.dirname(__file__)))
     assert_equal("sys.path[1]", sys.path[1], "/extra")
     assert_equal("sys.path[2]", sys.path[2], os.path.join(sys.executable, "internal"))
     assert_equal("sys.path[3]", sys.path[3], os.path.join(sys.executable, "internal", "stdlib"))
 else:
-    assert_equal("len(sys.path)", len(sys.path), 8)
+    assert_equal("len(sys.path)", len(sys.path), 5)
     assert_equal("sys.path[0]", sys.path[0], os.path.abspath(os.path.dirname(__file__)))
     assert_equal("sys.path[1]", sys.path[1], "/extra")
-    assert_equal("sys.path[2]", sys.path[2], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + str(sys.version_info[1]) + '.zip'))
-    assert_equal("sys.path[3]", sys.path[3], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]), '..'))
-    assert_equal("sys.path[4]", sys.path[4], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1])))
-    assert_equal("sys.path[5]", sys.path[5], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]), 'lib-dynload'))
-    assert_equal("sys.path[6]", sys.path[6], os.path.join(sys.executable, "internal"))
-    assert_equal("sys.path[7]", sys.path[7], os.path.join(sys.executable, "internal", "stdlib"))
+    assert_equal("sys.path[2]", sys.path[2], os.path.join(sys.executable, 'internal', 'python' + str(sys.version_info[0]) + str(sys.version_info[1]) + '.zip'))
+    assert_equal("sys.path[3]", sys.path[3], os.path.join(sys.executable, 'internal', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1])))
+    assert_equal("sys.path[4]", sys.path[4], os.path.join(sys.executable, 'internal', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]), 'lib-dynload'))
 
 if failed:
     sys.exit(1)
diff --git a/python/tests/runtest.sh b/python/tests/runtest.sh
index f4abae5..c44ec58 100755
--- a/python/tests/runtest.sh
+++ b/python/tests/runtest.sh
@@ -24,11 +24,16 @@
 fi
 
 if [[ ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test/par_test ) ||
-      ( ! -f $ANDROID_HOST_OUT/bin/py2-cmd ) ||
       ( ! -f $ANDROID_HOST_OUT/bin/py3-cmd )]]; then
   echo "Run 'm par_test py2-cmd py3-cmd' first"
   exit 1
 fi
+if [ $(uname -s) = Linux ]; then
+  if [[ ! -f $ANDROID_HOST_OUT/bin/py2-cmd ]]; then
+    echo "Run 'm par_test py2-cmd py3-cmd' first"
+    exit 1
+  fi
+fi
 
 export LD_LIBRARY_PATH=$ANDROID_HOST_OUT/lib64
 
@@ -42,11 +47,15 @@
 
 cd $(dirname ${BASH_SOURCE[0]})
 
-PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py
+if [ $(uname -s) = Linux ]; then
+  PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py
+fi
 PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py
 
-ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py arg1 arg2
-ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py --arg1 arg2
+if [ $(uname -s) = Linux ]; then
+  ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py arg1 arg2
+  ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py --arg1 arg2
+fi
 
 ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py arg1 arg2
 ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py --arg1 arg2
diff --git a/remoteexec/remoteexec.go b/remoteexec/remoteexec.go
index 9e7a0f1..8294c3f 100644
--- a/remoteexec/remoteexec.go
+++ b/remoteexec/remoteexec.go
@@ -15,6 +15,7 @@
 package remoteexec
 
 import (
+	"fmt"
 	"sort"
 	"strings"
 )
@@ -29,7 +30,7 @@
 	// DefaultImage is the default container image used for Android remote execution. The
 	// image was built with the Dockerfile at
 	// https://android.googlesource.com/platform/prebuilts/remoteexecution-client/+/refs/heads/master/docker/Dockerfile
-	DefaultImage = "docker://gcr.io/androidbuild-re-dockerimage/android-build-remoteexec-image@sha256:582efb38f0c229ea39952fff9e132ccbe183e14869b39888010dacf56b360d62"
+	DefaultImage = "docker://gcr.io/androidbuild-re-dockerimage/android-build-remoteexec-image@sha256:1eb7f64b9e17102b970bd7a1af7daaebdb01c3fb777715899ef462d6c6d01a45"
 
 	// DefaultWrapperPath is the default path to the remote execution wrapper.
 	DefaultWrapperPath = "prebuilts/remoteexecution-client/live/rewrapper"
@@ -84,6 +85,14 @@
 	// EnvironmentVariables is a list of environment variables whose values should be passed through
 	// to the remote execution.
 	EnvironmentVariables []string
+	// Boolean indicating whether to compare chosen exec strategy with local execution.
+	Compare bool
+	// Number of times the action should be rerun locally.
+	NumLocalRuns int
+	// Number of times the action should be rerun remotely.
+	NumRemoteRuns int
+	// Boolean indicating whether to update remote cache entry. Rewrapper defaults to true, so the name is negated here.
+	NoRemoteUpdateCache bool
 }
 
 func init() {
@@ -135,6 +144,14 @@
 	}
 	args += " --exec_strategy=" + strategy
 
+	if r.Compare && r.NumLocalRuns >= 0 && r.NumRemoteRuns >= 0 {
+		args += fmt.Sprintf(" --compare=true --num_local_reruns=%d --num_remote_reruns=%d", r.NumLocalRuns, r.NumRemoteRuns)
+	}
+
+	if r.NoRemoteUpdateCache {
+		args += " --remote_update_cache=false"
+	}
+
 	if len(r.Inputs) > 0 {
 		args += " --inputs=" + strings.Join(r.Inputs, ",")
 	}
diff --git a/rust/Android.bp b/rust/Android.bp
index b01a94a..53c9462 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -7,11 +7,12 @@
     pkgPath: "android/soong/rust",
     deps: [
         "soong",
+        "soong-aconfig",
         "soong-android",
         "soong-bloaty",
         "soong-cc",
         "soong-rust-config",
-        "soong-snapshot",
+        "soong-testing",
     ],
     srcs: [
         "afdo.go",
@@ -34,8 +35,6 @@
         "rust.go",
         "sanitize.go",
         "source_provider.go",
-        "snapshot_prebuilt.go",
-        "snapshot_utils.go",
         "strip.go",
         "test.go",
         "testing.go",
@@ -60,7 +59,6 @@
         "sanitize_test.go",
         "source_provider_test.go",
         "test_test.go",
-        "vendor_snapshot_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/rust/afdo.go b/rust/afdo.go
index 3534ee6..6116c5e 100644
--- a/rust/afdo.go
+++ b/rust/afdo.go
@@ -44,14 +44,14 @@
 		if err != nil {
 			ctx.ModuleErrorf("%s", err.Error())
 		}
-		if fdoProfileName != nil {
+		if fdoProfileName != "" {
 			actx.AddFarVariationDependencies(
 				[]blueprint.Variation{
 					{Mutator: "arch", Variation: actx.Target().ArchVariation()},
 					{Mutator: "os", Variation: "android"},
 				},
 				cc.FdoProfileTag,
-				[]string{*fdoProfileName}...,
+				[]string{fdoProfileName}...,
 			)
 		}
 	}
@@ -67,8 +67,7 @@
 	}
 
 	ctx.VisitDirectDepsWithTag(cc.FdoProfileTag, func(m android.Module) {
-		if ctx.OtherModuleHasProvider(m, cc.FdoProfileProvider) {
-			info := ctx.OtherModuleProvider(m, cc.FdoProfileProvider).(cc.FdoProfileInfo)
+		if info, ok := android.OtherModuleProvider(ctx, m, cc.FdoProfileProvider); ok {
 			path := info.Path
 			profileUseFlag := fmt.Sprintf(afdoFlagFormat, path.String())
 			flags.RustFlags = append(flags.RustFlags, profileUseFlag)
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 5e680b0..021dd60 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -18,7 +18,6 @@
 	"path/filepath"
 
 	"android/soong/android"
-	"android/soong/cc"
 )
 
 type AndroidMkContext interface {
@@ -61,13 +60,16 @@
 				entries.AddStrings("LOCAL_RLIB_LIBRARIES", mod.Properties.AndroidMkRlibs...)
 				entries.AddStrings("LOCAL_DYLIB_LIBRARIES", mod.Properties.AndroidMkDylibs...)
 				entries.AddStrings("LOCAL_PROC_MACRO_LIBRARIES", mod.Properties.AndroidMkProcMacroLibs...)
-				entries.AddStrings("LOCAL_SHARED_LIBRARIES", mod.Properties.AndroidMkSharedLibs...)
+				entries.AddStrings("LOCAL_SHARED_LIBRARIES", mod.transitiveAndroidMkSharedLibs.ToList()...)
 				entries.AddStrings("LOCAL_STATIC_LIBRARIES", mod.Properties.AndroidMkStaticLibs...)
+				entries.AddStrings("LOCAL_HEADER_LIBRARIES", mod.Properties.AndroidMkHeaderLibs...)
 				entries.AddStrings("LOCAL_SOONG_LINK_TYPE", mod.makeLinkType)
-				if mod.UseVndk() {
-					entries.SetBool("LOCAL_USE_VNDK", true)
+				if mod.InVendor() {
+					entries.SetBool("LOCAL_IN_VENDOR", true)
+				} else if mod.InProduct() {
+					entries.SetBool("LOCAL_IN_PRODUCT", true)
 				}
-
+				android.SetAconfigFileMkEntries(mod.AndroidModuleBase(), entries, mod.mergedAconfigFiles)
 			},
 		},
 	}
@@ -114,8 +116,6 @@
 
 			test.Properties.Test_options.SetAndroidMkEntries(entries)
 		})
-
-	cc.AndroidMkWriteTestData(test.data, ret)
 }
 
 func (benchmark *benchmarkDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
@@ -155,11 +155,6 @@
 		})
 }
 
-func (library *snapshotLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
-	ctx.SubAndroidMk(ret, library.libraryDecorator)
-	ret.SubName = library.SnapshotAndroidMkSuffix()
-}
-
 func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
 	ctx.SubAndroidMk(ret, procMacro.baseCompiler)
 
@@ -216,33 +211,9 @@
 func (fuzz *fuzzDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
 	ctx.SubAndroidMk(ret, fuzz.binaryDecorator)
 
-	var fuzzFiles []string
-	for _, d := range fuzz.fuzzPackagedModule.Corpus {
-		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.fuzzPackagedModule.CorpusIntermediateDir.String())+":corpus/"+d.Base())
-	}
-
-	for _, d := range fuzz.fuzzPackagedModule.Data {
-		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.fuzzPackagedModule.DataIntermediateDir.String())+":data/"+d.Rel())
-	}
-
-	if fuzz.fuzzPackagedModule.Dictionary != nil {
-		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.fuzzPackagedModule.Dictionary.String())+":"+fuzz.fuzzPackagedModule.Dictionary.Base())
-	}
-
-	if fuzz.fuzzPackagedModule.Config != nil {
-		fuzzFiles = append(fuzzFiles,
-			filepath.Dir(fuzz.fuzzPackagedModule.Config.String())+":config.json")
-	}
-
 	ret.ExtraEntries = append(ret.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext,
 		entries *android.AndroidMkEntries) {
 		entries.SetBool("LOCAL_IS_FUZZ_TARGET", true)
-		if len(fuzzFiles) > 0 {
-			entries.AddStrings("LOCAL_TEST_DATA", fuzzFiles...)
-		}
 		if fuzz.installedSharedDeps != nil {
 			entries.AddStrings("LOCAL_FUZZ_INSTALLED_SHARED_DEPS", fuzz.installedSharedDeps...)
 		}
diff --git a/rust/binary.go b/rust/binary.go
index e6f1539..9969513 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -72,14 +72,11 @@
 func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
 	flags = binary.baseCompiler.compilerFlags(ctx, flags)
 
-	if ctx.Os().Linux() {
-		flags.LinkFlags = append(flags.LinkFlags, "-Wl,--gc-sections")
-	}
-
 	if ctx.toolchain().Bionic() {
 		// no-undefined-version breaks dylib compilation since __rust_*alloc* functions aren't defined,
 		// but we can apply this to binaries.
 		flags.LinkFlags = append(flags.LinkFlags,
+			"-Wl,--gc-sections",
 			"-Wl,-z,nocopyreloc",
 			"-Wl,--no-undefined-version")
 
@@ -133,13 +130,13 @@
 
 func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
 	fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
-	srcPath, _ := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs)
 	outputFile := android.PathForModuleOut(ctx, fileName)
 	ret := buildOutput{outputFile: outputFile}
+	crateRootPath := crateRootPath(ctx, binary)
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
-	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects.Strings()...)
+	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
 
 	if binary.stripper.NeedsStrip(ctx) {
 		strippedOutputFile := outputFile
@@ -150,7 +147,7 @@
 	}
 	binary.baseCompiler.unstrippedOutputFile = outputFile
 
-	ret.kytheFile = TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile).kytheFile
+	ret.kytheFile = TransformSrcToBinary(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	return ret
 }
 
diff --git a/rust/binary_test.go b/rust/binary_test.go
index dd4f993..ef93037 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -21,6 +21,27 @@
 	"android/soong/android"
 )
 
+// Test that rustlibs default linkage is always rlib for host binaries.
+func TestBinaryHostLinkage(t *testing.T) {
+	ctx := testRust(t, `
+		rust_binary_host {
+			name: "fizz-buzz",
+			srcs: ["foo.rs"],
+			rustlibs: ["libfoo"],
+		}
+		rust_library {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+			host_supported: true,
+		}
+	`)
+	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
+	if !android.InList("libfoo.rlib-std", fizzBuzz.Properties.AndroidMkRlibs) {
+		t.Errorf("rustlibs dependency libfoo should be an rlib dep for host binaries")
+	}
+}
+
 // Test that rustlibs default linkage is correct for binaries.
 func TestBinaryLinkage(t *testing.T) {
 	ctx := testRust(t, `
@@ -54,6 +75,12 @@
 	if !android.InList("libfoo", fizzBuzzDevice.Properties.AndroidMkDylibs) {
 		t.Errorf("rustlibs dependency libfoo should be an dylib dep for device modules")
 	}
+
+	rlibLinkDevice := ctx.ModuleForTests("rlib_linked", "android_arm64_armv8-a").Module().(*Module)
+
+	if !android.InList("libfoo.rlib-std", rlibLinkDevice.Properties.AndroidMkRlibs) {
+		t.Errorf("rustlibs dependency libfoo should be an rlib dep for device modules when prefer_rlib is set")
+	}
 }
 
 // Test that prefer_rlib links in libstd statically as well as rustlibs.
@@ -123,7 +150,7 @@
 			bootstrap: true,
 		}`)
 
-	foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustLink")
+	foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
 
 	flag := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker64"
 	if !strings.Contains(foo.Args["linkFlags"], flag) {
@@ -140,11 +167,10 @@
 		}`)
 
 	fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc")
-	fizzOutLink := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustLink")
 	fizzMod := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module)
 
 	flags := fizzOut.Args["rustcFlags"]
-	linkFlags := fizzOutLink.Args["linkFlags"]
+	linkFlags := fizzOut.Args["linkFlags"]
 	if !strings.Contains(flags, "-C relocation-model=static") {
 		t.Errorf("static binary missing '-C relocation-model=static' in rustcFlags, found: %#v", flags)
 	}
@@ -158,7 +184,7 @@
 	if !android.InList("libc", fizzMod.Properties.AndroidMkStaticLibs) {
 		t.Errorf("static binary not linking against libc as a static library")
 	}
-	if len(fizzMod.Properties.AndroidMkSharedLibs) > 0 {
+	if len(fizzMod.transitiveAndroidMkSharedLibs.ToList()) > 0 {
 		t.Errorf("static binary incorrectly linking against shared libraries")
 	}
 }
@@ -174,7 +200,7 @@
 			name: "libfoo",
 		}`)
 
-	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustLink")
+	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustc")
 	linkFlags := fizzBuzz.Args["linkFlags"]
 	if !strings.Contains(linkFlags, "/libfoo.so") {
 		t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags)
diff --git a/rust/bindgen.go b/rust/bindgen.go
index c2bf6af..eaed1b9 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -29,7 +29,7 @@
 	defaultBindgenFlags = []string{""}
 
 	// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
-	bindgenClangVersion = "clang-r498229"
+	bindgenClangVersion = "clang-r510928"
 
 	_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
@@ -101,6 +101,9 @@
 	//
 	// "my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]"
 	Custom_bindgen string
+
+	// flag to indicate if bindgen should handle `static inline` functions (default is false)
+	Handle_static_inline bool
 }
 
 type bindgenDecorator struct {
@@ -124,18 +127,20 @@
 		ctx.PropertyErrorf("c_std", "c_std and cpp_std cannot both be defined at the same time.")
 	}
 
-	if String(b.ClangProperties.Cpp_std) != "" {
+	if b.ClangProperties.Cpp_std != nil {
+		isCpp = true
 		if String(b.ClangProperties.Cpp_std) == "experimental" {
 			stdVersion = cc_config.ExperimentalCppStdVersion
-		} else if String(b.ClangProperties.Cpp_std) == "default" {
+		} else if String(b.ClangProperties.Cpp_std) == "default" || String(b.ClangProperties.Cpp_std) == "" {
 			stdVersion = cc_config.CppStdVersion
 		} else {
 			stdVersion = String(b.ClangProperties.Cpp_std)
 		}
 	} else if b.ClangProperties.C_std != nil {
+		isCpp = false
 		if String(b.ClangProperties.C_std) == "experimental" {
 			stdVersion = cc_config.ExperimentalCStdVersion
-		} else if String(b.ClangProperties.C_std) == "default" {
+		} else if String(b.ClangProperties.C_std) == "default" || String(b.ClangProperties.C_std) == "" {
 			stdVersion = cc_config.CStdVersion
 		} else {
 			stdVersion = String(b.ClangProperties.C_std)
@@ -168,10 +173,19 @@
 	cflags = append(cflags, strings.ReplaceAll(ccToolchain.Cflags(), "${config.", "${cc_config."))
 	cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainCflags(), "${config.", "${cc_config."))
 
-	if ctx.RustModule().UseVndk() {
+	if ctx.RustModule().InVendorOrProduct() {
 		cflags = append(cflags, "-D__ANDROID_VNDK__")
 		if ctx.RustModule().InVendor() {
 			cflags = append(cflags, "-D__ANDROID_VENDOR__")
+
+			vendorApiLevel := ctx.Config().VendorApiLevel()
+			if vendorApiLevel == "" {
+				// TODO(b/314036847): This is a fallback for UDC targets.
+				// This must be a build failure when UDC is no longer built
+				// from this source tree.
+				vendorApiLevel = ctx.Config().PlatformSdkVersion().String()
+			}
+			cflags = append(cflags, "-D__ANDROID_VENDOR_API__="+vendorApiLevel)
 		} else if ctx.RustModule().InProduct() {
 			cflags = append(cflags, "-D__ANDROID_PRODUCT__")
 		}
@@ -221,6 +235,9 @@
 
 	bindgenFlags := defaultBindgenFlags
 	bindgenFlags = append(bindgenFlags, esc(b.Properties.Bindgen_flags)...)
+	if b.Properties.Handle_static_inline {
+		bindgenFlags = append(bindgenFlags, "--experimental --wrap-static-fns")
+	}
 
 	// cat reads from stdin if its command line is empty,
 	// so we pass in /dev/null if there are no other flag files
@@ -252,10 +269,9 @@
 	// clang: error: '-x c' after last input file has no effect [-Werror,-Wunused-command-line-argument]
 	cflags = append(cflags, "-Wno-unused-command-line-argument")
 
-	// LLVM_NEXT may contain flags that bindgen doesn't recognise. Turn off unknown flags warning.
-	if ctx.Config().IsEnvTrue("LLVM_NEXT") {
-		cflags = append(cflags, "-Wno-unknown-warning-option")
-	}
+	// The Clang version used by CXX can be newer than the one used by Bindgen, and uses warning related flags that
+	// it cannot recognize. Turn off unknown warning flags warning.
+	cflags = append(cflags, "-Wno-unknown-warning-option")
 
 	outputFile := android.PathForModuleOut(ctx, b.BaseSourceProvider.getStem(ctx)+".rs")
 
@@ -294,7 +310,7 @@
 // rust_bindgen generates Rust FFI bindings to C libraries using bindgen given a wrapper header as the primary input.
 // Bindgen has a number of flags to control the generated source, and additional flags can be passed to clang to ensure
 // the header and generated source is appropriately handled. It is recommended to add it as a dependency in the
-// rlibs, dylibs or rustlibs property. It may also be added in the srcs property for external crates, using the ":"
+// rlibs or rustlibs property. It may also be added in the srcs property for external crates, using the ":"
 // prefix.
 func RustBindgenFactory() android.Module {
 	module, _ := NewRustBindgen(android.HostAndDeviceSupported)
@@ -336,6 +352,6 @@
 
 	deps.SharedLibs = append(deps.SharedLibs, b.ClangProperties.Shared_libs...)
 	deps.StaticLibs = append(deps.StaticLibs, b.ClangProperties.Static_libs...)
-	deps.HeaderLibs = append(deps.StaticLibs, b.ClangProperties.Header_libs...)
+	deps.HeaderLibs = append(deps.HeaderLibs, b.ClangProperties.Header_libs...)
 	return deps
 }
diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go
index 12cdb3c..11cfe4e 100644
--- a/rust/bindgen_test.go
+++ b/rust/bindgen_test.go
@@ -17,6 +17,8 @@
 import (
 	"strings"
 	"testing"
+
+	"android/soong/android"
 )
 
 func TestRustBindgen(t *testing.T) {
@@ -31,7 +33,21 @@
 			bindgen_flags: ["--bindgen-flag.*"],
 			cflags: ["--clang-flag()"],
 			shared_libs: ["libfoo_shared"],
+		}
+		rust_bindgen {
+			name: "libbindgen_staticlib",
+			wrapper_src: "src/any.h",
+			crate_name: "bindgen_staticlib",
+			stem: "libbindgen_staticlib",
+			source_stem: "bindings",
 			static_libs: ["libfoo_static"],
+		}
+		rust_bindgen {
+			name: "libbindgen_headerlib",
+			wrapper_src: "src/any.h",
+			crate_name: "bindgen_headerlib",
+			stem: "libbindgen_headerlib",
+			source_stem: "bindings",
 			header_libs: ["libfoo_header"],
 		}
 		cc_library_shared {
@@ -52,6 +68,9 @@
 		}
 	`)
 	libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs")
+	libbindgenStatic := ctx.ModuleForTests("libbindgen_staticlib", "android_arm64_armv8-a_source").Output("bindings.rs")
+	libbindgenHeader := ctx.ModuleForTests("libbindgen_headerlib", "android_arm64_armv8-a_source").Output("bindings.rs")
+	libbindgenHeaderModule := ctx.ModuleForTests("libbindgen_headerlib", "android_arm64_armv8-a_source").Module().(*Module)
 	// Ensure that the flags are present and escaped
 	if !strings.Contains(libbindgen.Args["flags"], "'--bindgen-flag.*'") {
 		t.Errorf("missing bindgen flags in rust_bindgen rule: flags %#v", libbindgen.Args["flags"])
@@ -62,12 +81,17 @@
 	if !strings.Contains(libbindgen.Args["cflags"], "-Ishared_include") {
 		t.Errorf("missing shared_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
 	}
-	if !strings.Contains(libbindgen.Args["cflags"], "-Istatic_include") {
-		t.Errorf("missing static_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
+	if !strings.Contains(libbindgenStatic.Args["cflags"], "-Istatic_include") {
+		t.Errorf("missing static_libs exported includes in rust_bindgen rule: cflags %#v", libbindgenStatic.Args["cflags"])
 	}
-	if !strings.Contains(libbindgen.Args["cflags"], "-Iheader_include") {
-		t.Errorf("missing static_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
+	if !strings.Contains(libbindgenHeader.Args["cflags"], "-Iheader_include") {
+		t.Errorf("missing header_libs exported includes in rust_bindgen rule: cflags %#v", libbindgenHeader.Args["cflags"])
 	}
+
+	if android.InList("libfoo_static", libbindgenHeaderModule.Properties.AndroidMkHeaderLibs) {
+		t.Errorf("Static library dependency should not be in HeaderLibs list")
+	}
+
 	if !strings.Contains(libbindgen.Args["cflags"], "--default-flag") {
 		t.Errorf("rust_bindgen missing cflags defined in cc_defaults: cflags %#v", libbindgen.Args["cflags"])
 	}
@@ -115,7 +139,7 @@
 	ctx := testRust(t, `
 		rust_bindgen {
 			name: "libbindgen_cstd",
-			wrapper_src: "src/any.h",
+			wrapper_src: "src/any.hpp",
 			crate_name: "bindgen",
 			stem: "libbindgen",
 			source_stem: "bindings",
@@ -141,6 +165,16 @@
 	if !strings.Contains(libbindgen_cppstd.Args["cflags"], "-std=foo") {
 		t.Errorf("cpp_std value not passed in to rust_bindgen as a clang flag")
 	}
+
+	// Make sure specifying cpp_std emits the '-x c++' flag
+	if !strings.Contains(libbindgen_cppstd.Args["cflags"], "-x c++") {
+		t.Errorf("Setting cpp_std should cause the '-x c++' flag to be emitted")
+	}
+
+	// Make sure specifying c_std omits the '-x c++' flag
+	if strings.Contains(libbindgen_cstd.Args["cflags"], "-x c++") {
+		t.Errorf("Setting c_std should not cause the '-x c++' flag to be emitted")
+	}
 }
 
 func TestBindgenDisallowedFlags(t *testing.T) {
@@ -193,3 +227,22 @@
 	// TODO: The best we can do right now is check $flagfiles. Once bindgen.go switches to RuleBuilder,
 	// we may be able to check libbinder.RuleParams.Command to see if it contains $(cat /dev/null flag_file.txt)
 }
+
+
+func TestBindgenHandleStaticInlining(t *testing.T) {
+	ctx := testRust(t, `
+		rust_bindgen {
+			name: "libbindgen",
+			wrapper_src: "src/any.h",
+			crate_name: "bindgen",
+			stem: "libbindgen",
+			source_stem: "bindings",
+			handle_static_inline: true
+		}
+	`)
+	libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs")
+	// Make sure the flag to support `static inline` functions is present
+	if !strings.Contains(libbindgen.Args["flags"], "--wrap-static-fns") {
+		t.Errorf("missing flag to handle static inlining in rust_bindgen rule: flags %#v", libbindgen.Args["flags"])
+	}
+}
diff --git a/rust/builder.go b/rust/builder.go
index b1f049d..4f45e33 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -26,14 +26,14 @@
 
 var (
 	_     = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc")
-	_     = pctx.SourcePathVariable("mkcraterspCmd", "build/soong/scripts/mkcratersp.py")
 	rustc = pctx.AndroidStaticRule("rustc",
 		blueprint.RuleParams{
 			Command: "$envVars $rustcCmd " +
-				"-C linker=$mkcraterspCmd " +
+				"-C linker=${config.RustLinker} " +
+				"-C link-args=\"${crtBegin} ${earlyLinkFlags} ${linkFlags} ${crtEnd}\" " +
 				"--emit link -o $out --emit dep-info=$out.d.raw $in ${libFlags} $rustcFlags" +
-				" && grep \"^$out:\" $out.d.raw > $out.d",
-			CommandDeps: []string{"$rustcCmd", "$mkcraterspCmd"},
+				" && grep ^$out: $out.d.raw > $out.d",
+			CommandDeps: []string{"$rustcCmd"},
 			// Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633
 			// Rustc emits unneeded dependency lines for the .d and input .rs files.
 			// Those extra lines cause ninja warning:
@@ -42,12 +42,7 @@
 			Deps:    blueprint.DepsGCC,
 			Depfile: "$out.d",
 		},
-		"rustcFlags", "libFlags", "envVars")
-	rustLink = pctx.AndroidStaticRule("rustLink",
-		blueprint.RuleParams{
-			Command: "${config.RustLinker} -o $out ${crtBegin} ${earlyLinkFlags} @$in ${linkFlags} ${crtEnd}",
-		},
-		"earlyLinkFlags", "linkFlags", "crtBegin", "crtEnd")
+		"rustcFlags", "earlyLinkFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars")
 
 	_       = pctx.SourcePathVariable("rustdocCmd", "${config.RustBin}/rustdoc")
 	rustdoc = pctx.AndroidStaticRule("rustdoc",
@@ -66,7 +61,7 @@
 				// Use the metadata output as it has the smallest footprint.
 				"--emit metadata -o $out --emit dep-info=$out.d.raw $in ${libFlags} " +
 				"$rustcFlags $clippyFlags" +
-				" && grep \"^$out:\" $out.d.raw > $out.d",
+				" && grep ^$out: $out.d.raw > $out.d",
 			CommandDeps: []string{"$clippyCmd"},
 			Deps:        blueprint.DepsGCC,
 			Depfile:     "$out.d",
@@ -106,13 +101,14 @@
 				`KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative ` +
 				`$rustExtractor $envVars ` +
 				`$rustcCmd ` +
-				`-C linker=true ` +
+				`-C linker=${config.RustLinker} ` +
+				`-C link-args="${crtBegin} ${linkFlags} ${crtEnd}" ` +
 				`$in ${libFlags} $rustcFlags`,
 			CommandDeps:    []string{"$rustExtractor", "$kytheVnames"},
 			Rspfile:        "${out}.rsp",
 			RspfileContent: "$in",
 		},
-		"rustcFlags", "libFlags", "envVars")
+		"rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars")
 )
 
 type buildOutput struct {
@@ -200,7 +196,7 @@
 	}
 
 	if len(deps.SrcDeps) > 0 {
-		moduleGenDir := ctx.RustModule().compiler.CargoOutDir()
+		moduleGenDir := ctx.RustModule().compiler.cargoOutDir()
 		// We must calculate an absolute path for OUT_DIR since Rust's include! macro (which normally consumes this)
 		// assumes that paths are relative to the source file.
 		var outDirPrefix string
@@ -219,13 +215,13 @@
 
 	envVars = append(envVars, "ANDROID_RUST_VERSION="+config.GetRustVersion(ctx))
 
-	if ctx.RustModule().compiler.CargoEnvCompat() {
+	if ctx.RustModule().compiler.cargoEnvCompat() {
 		if bin, ok := ctx.RustModule().compiler.(*binaryDecorator); ok {
 			envVars = append(envVars, "CARGO_BIN_NAME="+bin.getStem(ctx))
 		}
 		envVars = append(envVars, "CARGO_CRATE_NAME="+ctx.RustModule().CrateName())
 		envVars = append(envVars, "CARGO_PKG_NAME="+ctx.RustModule().CrateName())
-		pkgVersion := ctx.RustModule().compiler.CargoPkgVersion()
+		pkgVersion := ctx.RustModule().compiler.cargoPkgVersion()
 		if pkgVersion != "" {
 			envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion)
 
@@ -242,8 +238,6 @@
 		}
 	}
 
-	envVars = append(envVars, "AR=${cc_config.ClangBin}/llvm-ar")
-
 	if ctx.Darwin() {
 		envVars = append(envVars, "ANDROID_RUST_DARWIN=true")
 	}
@@ -255,7 +249,8 @@
 	outputFile android.WritablePath, crateType string) buildOutput {
 
 	var inputs android.Paths
-	var implicits, linkImplicits, linkOrderOnly android.Paths
+	var implicits android.Paths
+	var orderOnly android.Paths
 	var output buildOutput
 	var rustcFlags, linkFlags []string
 	var earlyLinkFlags string
@@ -287,11 +282,13 @@
 	if ctx.Config().IsEnvTrue("SOONG_RUSTC_INCREMENTAL") {
 		incrementalPath := android.PathForOutput(ctx, "rustc").String()
 
-		rustcFlags = append(rustcFlags, "-Cincremental="+incrementalPath)
+		rustcFlags = append(rustcFlags, "-C incremental="+incrementalPath)
+	} else {
+		rustcFlags = append(rustcFlags, "-C codegen-units=1")
 	}
 
 	// Disallow experimental features
-	modulePath := android.PathForModuleSrc(ctx).String()
+	modulePath := ctx.ModuleDir()
 	if !(android.IsThirdPartyPath(modulePath) || strings.HasPrefix(modulePath, "prebuilts")) {
 		rustcFlags = append(rustcFlags, "-Zallow-features=\"\"")
 	}
@@ -319,18 +316,18 @@
 	implicits = append(implicits, rustLibsToPaths(deps.RLibs)...)
 	implicits = append(implicits, rustLibsToPaths(deps.DyLibs)...)
 	implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...)
-	implicits = append(implicits, deps.AfdoProfiles...)
+	implicits = append(implicits, deps.StaticLibs...)
+	implicits = append(implicits, deps.SharedLibDeps...)
 	implicits = append(implicits, deps.srcProviderFiles...)
-	implicits = append(implicits, deps.WholeStaticLibs...)
+	implicits = append(implicits, deps.AfdoProfiles...)
 
-	linkImplicits = append(linkImplicits, deps.LibDeps...)
-	linkImplicits = append(linkImplicits, deps.CrtBegin...)
-	linkImplicits = append(linkImplicits, deps.CrtEnd...)
+	implicits = append(implicits, deps.CrtBegin...)
+	implicits = append(implicits, deps.CrtEnd...)
 
-	linkOrderOnly = append(linkOrderOnly, deps.linkObjects...)
+	orderOnly = append(orderOnly, deps.SharedLibs...)
 
 	if len(deps.SrcDeps) > 0 {
-		moduleGenDir := ctx.RustModule().compiler.CargoOutDir()
+		moduleGenDir := ctx.RustModule().compiler.cargoOutDir()
 		var outputs android.WritablePaths
 
 		for _, genSrc := range deps.SrcDeps {
@@ -356,11 +353,13 @@
 	if flags.Clippy {
 		clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
 		ctx.Build(pctx, android.BuildParams{
-			Rule:        clippyDriver,
-			Description: "clippy " + main.Rel(),
-			Output:      clippyFile,
-			Inputs:      inputs,
-			Implicits:   implicits,
+			Rule:            clippyDriver,
+			Description:     "clippy " + main.Rel(),
+			Output:          clippyFile,
+			ImplicitOutputs: nil,
+			Inputs:          inputs,
+			Implicits:       implicits,
+			OrderOnly:       orderOnly,
 			Args: map[string]string{
 				"rustcFlags":  strings.Join(rustcFlags, " "),
 				"libFlags":    strings.Join(libFlags, " "),
@@ -372,42 +371,24 @@
 		implicits = append(implicits, clippyFile)
 	}
 
-	rustcOutputFile := outputFile
-	usesLinker := crateType == "bin" || crateType == "dylib" || crateType == "cdylib" || crateType == "proc-macro"
-	if usesLinker {
-		rustcOutputFile = android.PathForModuleOut(ctx, outputFile.Base()+".rsp")
-	}
-
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rustc,
 		Description: "rustc " + main.Rel(),
-		Output:      rustcOutputFile,
+		Output:      outputFile,
 		Inputs:      inputs,
 		Implicits:   implicits,
+		OrderOnly:   orderOnly,
 		Args: map[string]string{
-			"rustcFlags": strings.Join(rustcFlags, " "),
-			"libFlags":   strings.Join(libFlags, " "),
-			"envVars":    strings.Join(envVars, " "),
+			"rustcFlags":     strings.Join(rustcFlags, " "),
+			"earlyLinkFlags": earlyLinkFlags,
+			"linkFlags":      strings.Join(linkFlags, " "),
+			"libFlags":       strings.Join(libFlags, " "),
+			"crtBegin":       strings.Join(deps.CrtBegin.Strings(), " "),
+			"crtEnd":         strings.Join(deps.CrtEnd.Strings(), " "),
+			"envVars":        strings.Join(envVars, " "),
 		},
 	})
 
-	if usesLinker {
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        rustLink,
-			Description: "rustLink " + main.Rel(),
-			Output:      outputFile,
-			Inputs:      android.Paths{rustcOutputFile},
-			Implicits:   linkImplicits,
-			OrderOnly:   linkOrderOnly,
-			Args: map[string]string{
-				"earlyLinkFlags": earlyLinkFlags,
-				"linkFlags":      strings.Join(linkFlags, " "),
-				"crtBegin":       strings.Join(deps.CrtBegin.Strings(), " "),
-				"crtEnd":         strings.Join(deps.CrtEnd.Strings(), " "),
-			},
-		})
-	}
-
 	if flags.EmitXrefs {
 		kytheFile := android.PathForModuleOut(ctx, outputFile.Base()+".kzip")
 		ctx.Build(pctx, android.BuildParams{
@@ -416,9 +397,13 @@
 			Output:      kytheFile,
 			Inputs:      inputs,
 			Implicits:   implicits,
+			OrderOnly:   orderOnly,
 			Args: map[string]string{
 				"rustcFlags": strings.Join(rustcFlags, " "),
+				"linkFlags":  strings.Join(linkFlags, " "),
 				"libFlags":   strings.Join(libFlags, " "),
+				"crtBegin":   strings.Join(deps.CrtBegin.Strings(), " "),
+				"crtEnd":     strings.Join(deps.CrtEnd.Strings(), " "),
 				"envVars":    strings.Join(envVars, " "),
 			},
 		})
@@ -451,7 +436,7 @@
 	docTimestampFile := android.PathForModuleOut(ctx, "rustdoc.timestamp")
 
 	// Silence warnings about renamed lints for third-party crates
-	modulePath := android.PathForModuleSrc(ctx).String()
+	modulePath := ctx.ModuleDir()
 	if android.IsThirdPartyPath(modulePath) {
 		rustdocFlags = append(rustdocFlags, " -A warnings")
 	}
diff --git a/rust/builder_test.go b/rust/builder_test.go
index 5c11cb7..639f6d4 100644
--- a/rust/builder_test.go
+++ b/rust/builder_test.go
@@ -14,7 +14,11 @@
 
 package rust
 
-import "testing"
+import (
+	"android/soong/android"
+	"sort"
+	"testing"
+)
 
 func TestSourceProviderCollision(t *testing.T) {
 	testRustError(t, "multiple source providers generate the same filename output: bindings.rs", `
@@ -40,3 +44,113 @@
 		}
 	`)
 }
+
+func TestCompilationOutputFiles(t *testing.T) {
+	ctx := testRust(t, `
+		rust_library {
+			name: "libfizz_buzz",
+			crate_name:"fizz_buzz",
+			srcs: ["lib.rs"],
+		}
+		rust_binary {
+			name: "fizz_buzz",
+			crate_name:"fizz_buzz",
+			srcs: ["lib.rs"],
+		}
+		rust_ffi {
+			name: "librust_ffi",
+			crate_name: "rust_ffi",
+			srcs: ["lib.rs"],
+		}
+	`)
+	testcases := []struct {
+		testName      string
+		moduleName    string
+		variant       string
+		expectedFiles []string
+	}{
+		{
+			testName:   "dylib",
+			moduleName: "libfizz_buzz",
+			variant:    "android_arm64_armv8-a_dylib",
+			expectedFiles: []string{
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so.clippy",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/unstripped/libfizz_buzz.dylib.so",
+				"out/soong/target/product/test_device/system/lib64/libfizz_buzz.dylib.so",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/meta_lic",
+			},
+		},
+		{
+			testName:   "rlib dylib-std",
+			moduleName: "libfizz_buzz",
+			variant:    "android_arm64_armv8-a_rlib_dylib-std",
+			expectedFiles: []string{
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_dylib-std/libfizz_buzz.rlib",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_dylib-std/libfizz_buzz.rlib.clippy",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_dylib-std/meta_lic",
+			},
+		},
+		{
+			testName:   "rlib rlib-std",
+			moduleName: "libfizz_buzz",
+			variant:    "android_arm64_armv8-a_rlib_rlib-std",
+			expectedFiles: []string{
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/libfizz_buzz.rlib",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/libfizz_buzz.rlib.clippy",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/meta_lic",
+				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/rustdoc.timestamp",
+			},
+		},
+		{
+			testName:   "rust_binary",
+			moduleName: "fizz_buzz",
+			variant:    "android_arm64_armv8-a",
+			expectedFiles: []string{
+				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz",
+				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz.clippy",
+				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/unstripped/fizz_buzz",
+				"out/soong/target/product/test_device/system/bin/fizz_buzz",
+				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/meta_lic",
+			},
+		},
+		{
+			testName:   "rust_ffi static",
+			moduleName: "librust_ffi",
+			variant:    "android_arm64_armv8-a_static",
+			expectedFiles: []string{
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_static/librust_ffi.a",
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_static/librust_ffi.a.clippy",
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_static/meta_lic",
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_static/rustdoc.timestamp",
+			},
+		},
+		{
+			testName:   "rust_ffi shared",
+			moduleName: "librust_ffi",
+			variant:    "android_arm64_armv8-a_shared",
+			expectedFiles: []string{
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/librust_ffi.so",
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/librust_ffi.so.clippy",
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/unstripped/librust_ffi.so",
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/unstripped/librust_ffi.so.toc",
+				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/meta_lic",
+				"out/soong/target/product/test_device/system/lib64/librust_ffi.so",
+			},
+		},
+	}
+	for _, tc := range testcases {
+		t.Run(tc.testName, func(t *testing.T) {
+			modOutputs := ctx.ModuleForTests(tc.moduleName, tc.variant).AllOutputs()
+			sort.Strings(tc.expectedFiles)
+			sort.Strings(modOutputs)
+			android.AssertStringPathsRelativeToTopEquals(
+				t,
+				"incorrect outputs from rust module",
+				ctx.Config(),
+				tc.expectedFiles,
+				modOutputs,
+			)
+		})
+	}
+}
diff --git a/rust/compiler.go b/rust/compiler.go
index 06ae12f..03fdf2b 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/cc"
+	"errors"
 	"fmt"
 	"path/filepath"
 	"strings"
@@ -34,6 +35,50 @@
 	DylibLinkage
 )
 
+type compiler interface {
+	initialize(ctx ModuleContext)
+	compilerFlags(ctx ModuleContext, flags Flags) Flags
+	cfgFlags(ctx ModuleContext, flags Flags) Flags
+	featureFlags(ctx ModuleContext, flags Flags) Flags
+	compilerProps() []interface{}
+	compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput
+	compilerDeps(ctx DepsContext, deps Deps) Deps
+	crateName() string
+	edition() string
+	features() []string
+	rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath
+
+	// Output directory in which source-generated code from dependencies is
+	// copied. This is equivalent to Cargo's OUT_DIR variable.
+	cargoOutDir() android.OptionalPath
+
+	// cargoPkgVersion returns the value of the Cargo_pkg_version property.
+	cargoPkgVersion() string
+
+	// cargoEnvCompat returns whether Cargo environment variables should be used.
+	cargoEnvCompat() bool
+
+	inData() bool
+	install(ctx ModuleContext)
+	relativeInstallPath() string
+	everInstallable() bool
+
+	nativeCoverage() bool
+
+	Disabled() bool
+	SetDisabled()
+
+	stdLinkage(ctx *depsContext) RustLinkage
+	noStdlibs() bool
+
+	unstrippedOutputFilePath() android.Path
+	strippedOutputFilePath() android.OptionalPath
+
+	checkedCrateRootPath() (android.Path, error)
+
+	Aliases() map[string]string
+}
+
 func (compiler *baseCompiler) edition() string {
 	return proptools.StringDefault(compiler.Properties.Edition, config.DefaultEdition)
 }
@@ -73,6 +118,15 @@
 	// If no source file is defined, a single generated source module can be defined to be used as the main source.
 	Srcs []string `android:"path,arch_variant"`
 
+	// Entry point that is passed to rustc to begin the compilation. E.g. main.rs or lib.rs.
+	// When this property is set,
+	//    * sandboxing is enabled for this module, and
+	//    * the srcs attribute is interpreted as a list of all source files potentially
+	//          used in compilation, including the entrypoint, and
+	//    * compile_data can be used to add additional files used in compilation that
+	//          not directly used as source files.
+	Crate_root *string `android:"path,arch_variant"`
+
 	// name of the lint set that should be used to validate this module.
 	//
 	// Possible values are "default" (for using a sensible set of lints
@@ -88,13 +142,17 @@
 	// flags to pass to the linker
 	Ld_flags []string `android:"arch_variant"`
 
+	// Rust crate dependencies to rename. Each entry should be a string of the form "dependencyname:alias".
+	//
+	// "dependencyname" here should be the name of the crate, not the Android module. This is
+	// equivalent to writing `alias = { package = "dependencyname" }` in a `Cargo.toml`.
+	Aliases []string
+
 	// list of rust rlib crate dependencies
 	Rlibs []string `android:"arch_variant"`
 
-	// list of rust dylib crate dependencies
-	Dylibs []string `android:"arch_variant"`
-
-	// list of rust automatic crate dependencies
+	// list of rust automatic crate dependencies.
+	// Rustlibs linkage is rlib for host targets and dylib for device targets.
 	Rustlibs []string `android:"arch_variant"`
 
 	// list of rust proc_macro crate dependencies
@@ -153,7 +211,7 @@
 	Relative_install_path *string `android:"arch_variant"`
 
 	// whether to suppress inclusion of standard crates - defaults to false
-	No_stdlibs *bool
+	No_stdlibs *bool `android:"arch_variant"`
 
 	// Change the rustlibs linkage to select rlib linkage by default for device targets.
 	// Also link libstd as an rlib as well on device targets.
@@ -189,6 +247,8 @@
 
 	distFile android.OptionalPath
 
+	installDeps android.InstallPaths
+
 	// unstripped output file.
 	unstrippedOutputFile android.Path
 
@@ -197,7 +257,16 @@
 
 	// If a crate has a source-generated dependency, a copy of the source file
 	// will be available in cargoOutDir (equivalent to Cargo OUT_DIR).
-	cargoOutDir android.ModuleOutPath
+	// This is stored internally because it may not be available during
+	// singleton-generation passes like rustdoc/rust_project.json, but should
+	// be stashed during initial generation.
+	cachedCargoOutDir android.ModuleOutPath
+	// Calculated crate root cached internally because ModuleContext is not
+	// available to singleton targets like rustdoc/rust_project.json
+	cachedCrateRootPath android.Path
+	// If cachedCrateRootPath is nil after initialization, this will contain
+	// an explanation of why
+	cachedCrateRootError error
 }
 
 func (compiler *baseCompiler) Disabled() bool {
@@ -220,6 +289,18 @@
 	return Bool(compiler.Properties.Prefer_rlib)
 }
 
+func (compiler *baseCompiler) Aliases() map[string]string {
+	aliases := map[string]string{}
+	for _, entry := range compiler.Properties.Aliases {
+		dep, alias, found := strings.Cut(entry, ":")
+		if !found {
+			panic(fmt.Errorf("invalid aliases entry %q missing ':'", entry))
+		}
+		aliases[dep] = alias
+	}
+	return aliases
+}
+
 func (compiler *baseCompiler) stdLinkage(ctx *depsContext) RustLinkage {
 	// For devices, we always link stdlibs in as dylibs by default.
 	if compiler.preferRlib() {
@@ -250,9 +331,13 @@
 	return flags
 }
 
+func (compiler *baseCompiler) features() []string {
+	return compiler.Properties.Features
+}
+
 func (compiler *baseCompiler) featuresToFlags() []string {
 	flags := []string{}
-	for _, feature := range compiler.Properties.Features {
+	for _, feature := range compiler.features() {
 		flags = append(flags, "--cfg 'feature=\""+feature+"\"'")
 	}
 
@@ -267,7 +352,7 @@
 }
 
 func (compiler *baseCompiler) cfgFlags(ctx ModuleContext, flags Flags) Flags {
-	if ctx.RustModule().UseVndk() {
+	if ctx.RustModule().InVendorOrProduct() {
 		compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_vndk")
 		if ctx.RustModule().InVendor() {
 			compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_vendor")
@@ -320,6 +405,20 @@
 		flags.LinkFlags = append(flags.LinkFlags, cc.RpathFlags(ctx)...)
 	}
 
+	if ctx.Os() == android.Linux {
+		// Add -lc, -lrt, -ldl, -lpthread, -lm and -lgcc_s to glibc builds to match
+		// the default behavior of device builds.
+		flags.LinkFlags = append(flags.LinkFlags, config.LinuxHostGlobalLinkFlags...)
+	} else if ctx.Os() == android.Darwin {
+		// Add -lc, -ldl, -lpthread and -lm to glibc darwin builds to match the default
+		// behavior of device builds.
+		flags.LinkFlags = append(flags.LinkFlags,
+			"-lc",
+			"-ldl",
+			"-lpthread",
+			"-lm",
+		)
+	}
 	return flags
 }
 
@@ -334,18 +433,24 @@
 }
 
 func (compiler *baseCompiler) initialize(ctx ModuleContext) {
-	compiler.cargoOutDir = android.PathForModuleOut(ctx, genSubDir)
+	compiler.cachedCargoOutDir = android.PathForModuleOut(ctx, genSubDir)
+	if compiler.Properties.Crate_root == nil {
+		compiler.cachedCrateRootPath, compiler.cachedCrateRootError = srcPathFromModuleSrcs(ctx, compiler.Properties.Srcs)
+	} else {
+		compiler.cachedCrateRootPath = android.PathForModuleSrc(ctx, *compiler.Properties.Crate_root)
+		compiler.cachedCrateRootError = nil
+	}
 }
 
-func (compiler *baseCompiler) CargoOutDir() android.OptionalPath {
-	return android.OptionalPathForPath(compiler.cargoOutDir)
+func (compiler *baseCompiler) cargoOutDir() android.OptionalPath {
+	return android.OptionalPathForPath(compiler.cachedCargoOutDir)
 }
 
-func (compiler *baseCompiler) CargoEnvCompat() bool {
+func (compiler *baseCompiler) cargoEnvCompat() bool {
 	return Bool(compiler.Properties.Cargo_env_compat)
 }
 
-func (compiler *baseCompiler) CargoPkgVersion() string {
+func (compiler *baseCompiler) cargoPkgVersion() string {
 	return String(compiler.Properties.Cargo_pkg_version)
 }
 
@@ -359,7 +464,6 @@
 
 func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
 	deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
-	deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...)
 	deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs...)
 	deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...)
 	deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...)
@@ -436,7 +540,7 @@
 		dir = filepath.Join(dir, ctx.Arch().ArchType.String())
 	}
 
-	if compiler.location == InstallInData && ctx.RustModule().UseVndk() {
+	if compiler.location == InstallInData && ctx.RustModule().InVendorOrProduct() {
 		if ctx.RustModule().InProduct() {
 			dir = filepath.Join(dir, "product")
 		} else if ctx.RustModule().InVendor() {
@@ -456,7 +560,12 @@
 
 func (compiler *baseCompiler) install(ctx ModuleContext) {
 	path := ctx.RustModule().OutputFile()
-	compiler.path = ctx.InstallFile(compiler.installDir(ctx), path.Path().Base(), path.Path())
+	compiler.path = ctx.InstallFile(compiler.installDir(ctx), path.Path().Base(), path.Path(), compiler.installDeps...)
+}
+
+func (compiler *baseCompiler) installTestData(ctx ModuleContext, data []android.DataPath) {
+	installedData := ctx.InstallTestData(compiler.installDir(ctx), data)
+	compiler.installDeps = append(compiler.installDeps, installedData...)
 }
 
 func (compiler *baseCompiler) getStem(ctx ModuleContext) string {
@@ -476,12 +585,20 @@
 	return String(compiler.Properties.Relative_install_path)
 }
 
-// Returns the Path for the main source file along with Paths for generated source files from modules listed in srcs.
-func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, android.Paths) {
-	if len(srcs) == 0 {
-		ctx.PropertyErrorf("srcs", "srcs must not be empty")
-	}
+func (compiler *baseCompiler) checkedCrateRootPath() (android.Path, error) {
+	return compiler.cachedCrateRootPath, compiler.cachedCrateRootError
+}
 
+func crateRootPath(ctx ModuleContext, compiler compiler) android.Path {
+	root, err := compiler.checkedCrateRootPath()
+	if err != nil {
+		ctx.PropertyErrorf("srcs", err.Error())
+	}
+	return root
+}
+
+// Returns the Path for the main source file along with Paths for generated source files from modules listed in srcs.
+func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, error) {
 	// The srcs can contain strings with prefix ":".
 	// They are dependent modules of this module, with android.SourceDepTag.
 	// They are not the main source file compiled by rustc.
@@ -494,17 +611,22 @@
 		}
 	}
 	if numSrcs > 1 {
-		ctx.PropertyErrorf("srcs", incorrectSourcesError)
+		return nil, errors.New(incorrectSourcesError)
 	}
 
 	// If a main source file is not provided we expect only a single SourceProvider module to be defined
 	// within srcs, with the expectation that the first source it provides is the entry point.
 	if srcIndex != 0 {
-		ctx.PropertyErrorf("srcs", "main source file must be the first in srcs")
+		return nil, errors.New("main source file must be the first in srcs")
 	} else if numSrcs > 1 {
-		ctx.PropertyErrorf("srcs", "only a single generated source module can be defined without a main source file.")
+		return nil, errors.New("only a single generated source module can be defined without a main source file.")
 	}
 
+	// TODO: b/297264540 - once all modules are sandboxed, we need to select the proper
+	// entry point file from Srcs rather than taking the first one
 	paths := android.PathsForModuleSrc(ctx, srcs)
-	return paths[srcIndex], paths[1:]
+	if len(paths) == 0 {
+		return nil, errors.New("srcs must not be empty")
+	}
+	return paths[srcIndex], nil
 }
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index ec6829a..89f4d1a 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -67,6 +67,7 @@
 func TestEnforceSingleSourceFile(t *testing.T) {
 
 	singleSrcError := "srcs can only contain one path for a rust file and source providers prefixed by \":\""
+	prebuiltSingleSrcError := "prebuilt libraries can only have one entry in srcs"
 
 	// Test libraries
 	testRustError(t, singleSrcError, `
@@ -90,7 +91,7 @@
 		}`)
 
 	// Test prebuilts
-	testRustError(t, singleSrcError, `
+	testRustError(t, prebuiltSingleSrcError, `
 		rust_prebuilt_dylib {
 			name: "foo-bar-prebuilt",
 			srcs: ["liby.so", "libz.so"],
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
index 08ac2ef..9850570 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -21,7 +21,9 @@
 )
 
 var (
-	Arm64RustFlags            = []string{}
+	Arm64RustFlags = []string{
+		"-C force-frame-pointers=y",
+	}
 	Arm64ArchFeatureRustFlags = map[string][]string{}
 	Arm64LinkFlags            = []string{}
 
@@ -52,6 +54,7 @@
 			strings.Join(rustFlags, " "))
 	}
 
+	pctx.StaticVariable("DEVICE_ARM64_RUSTC_FLAGS", strings.Join(Arm64RustFlags, " "))
 }
 
 type toolchainArm64 struct {
diff --git a/rust/config/arm_device.go b/rust/config/arm_device.go
index 42c1c02..5394e8a 100644
--- a/rust/config/arm_device.go
+++ b/rust/config/arm_device.go
@@ -44,6 +44,7 @@
 			strings.Join(rustFlags, " "))
 	}
 
+	pctx.StaticVariable("DEVICE_ARM_RUSTC_FLAGS", strings.Join(ArmRustFlags, " "))
 }
 
 type toolchainArm struct {
diff --git a/rust/config/global.go b/rust/config/global.go
index 86eb2d1..03333b8 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -21,10 +21,10 @@
 	_ "android/soong/cc/config"
 )
 
-var pctx = android.NewPackageContext("android/soong/rust/config")
-
 var (
-	RustDefaultVersion = "1.71.0"
+	pctx = android.NewPackageContext("android/soong/rust/config")
+
+	RustDefaultVersion = "1.77.1"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2021"
 	Stdlibs            = []string{
@@ -43,7 +43,6 @@
 	GlobalRustFlags = []string{
 		"-Z stack-protector=strong",
 		"-Z remap-cwd-prefix=.",
-		"-C codegen-units=1",
 		"-C debuginfo=2",
 		"-C opt-level=3",
 		"-C relocation-model=pic",
@@ -51,15 +50,30 @@
 		"-C force-unwind-tables=yes",
 		// Use v0 mangling to distinguish from C++ symbols
 		"-C symbol-mangling-version=v0",
-		"--color always",
-		"-Zdylib-lto",
+		"--color=always",
+		"-Z dylib-lto",
+		"-Z link-native-libraries=no",
+
+		// cfg flag to indicate that we are building in AOSP with Soong
+		"--cfg soong",
+	}
+
+	LinuxHostGlobalLinkFlags = []string{
+		"-lc",
+		"-lrt",
+		"-ldl",
+		"-lpthread",
+		"-lm",
+		"-lgcc_s",
+		"-Wl,--compress-debug-sections=zstd",
 	}
 
 	deviceGlobalRustFlags = []string{
 		"-C panic=abort",
-		"-Z link-native-libraries=no",
 		// Generate additional debug info for AutoFDO
 		"-Z debug-info-for-profiling",
+		// Android has ELF TLS on platform
+		"-Z tls-model=global-dynamic",
 	}
 
 	deviceGlobalLinkFlags = []string{
@@ -75,18 +89,13 @@
 		"-Wl,--use-android-relr-tags",
 		"-Wl,--no-undefined",
 		"-B${cc_config.ClangBin}",
+		"-Wl,--compress-debug-sections=zstd",
 	}
 )
 
 func init() {
 	pctx.SourcePathVariable("RustDefaultBase", RustDefaultBase)
-	pctx.VariableConfigMethod("HostPrebuiltTag", func(config android.Config) string {
-		if config.UseHostMusl() {
-			return "linux-musl-x86"
-		} else {
-			return config.PrebuiltOS()
-		}
-	})
+	pctx.VariableConfigMethod("HostPrebuiltTag", HostPrebuiltTag)
 
 	pctx.VariableFunc("RustBase", func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" {
@@ -105,6 +114,25 @@
 
 	pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " "))
 
+	pctx.StaticVariable("RUST_DEFAULT_VERSION", RustDefaultVersion)
+	pctx.StaticVariable("GLOBAL_RUSTC_FLAGS", strings.Join(GlobalRustFlags, " "))
+	pctx.StaticVariable("LINUX_HOST_GLOBAL_LINK_FLAGS", strings.Join(LinuxHostGlobalLinkFlags, " "))
+
+	pctx.StaticVariable("DEVICE_GLOBAL_RUSTC_FLAGS", strings.Join(deviceGlobalRustFlags, " "))
+	pctx.StaticVariable("DEVICE_GLOBAL_LINK_FLAGS",
+		strings.Join(android.RemoveListFromList(deviceGlobalLinkFlags, []string{
+			// The cc_config flags are retrieved from cc_toolchain by rust rules.
+			"${cc_config.DeviceGlobalLldflags}",
+			"-B${cc_config.ClangBin}",
+		}), " "))
+}
+
+func HostPrebuiltTag(config android.Config) string {
+	if config.UseHostMusl() {
+		return "linux-musl-x86"
+	} else {
+		return config.PrebuiltOS()
+	}
 }
 
 func getRustVersionPctx(ctx android.PackageVarContext) string {
diff --git a/rust/config/lints.go b/rust/config/lints.go
index ef6b315..735aa16 100644
--- a/rust/config/lints.go
+++ b/rust/config/lints.go
@@ -44,17 +44,23 @@
 	// Default Rust lints that applies to Google-authored modules.
 	defaultRustcLints = []string{
 		"-A deprecated",
+		"-A unknown_lints",
 		"-D missing-docs",
 		"-D warnings",
+		"-D unsafe_op_in_unsafe_fn",
 	}
 	// Default Clippy lints. These are applied on top of defaultRustcLints.
 	// It should be assumed that any warning lint will be promoted to a
 	// deny.
 	defaultClippyLints = []string{
+		// Let people hack in peace. ;)
+		"-A clippy::disallowed_names",
 		"-A clippy::type-complexity",
+		"-A clippy::unnecessary_fallible_conversions",
 		"-A clippy::unnecessary-wraps",
 		"-A clippy::unusual-byte-groupings",
 		"-A clippy::upper-case-acronyms",
+		"-D clippy::undocumented_unsafe_blocks",
 	}
 
 	// Rust lints for vendor code.
diff --git a/rust/config/riscv64_device.go b/rust/config/riscv64_device.go
index d014dbf..0a9c61a 100644
--- a/rust/config/riscv64_device.go
+++ b/rust/config/riscv64_device.go
@@ -21,9 +21,15 @@
 )
 
 var (
-	Riscv64RustFlags            = []string{}
-	Riscv64ArchFeatureRustFlags = map[string][]string{"": {}}
-	Riscv64LinkFlags            = []string{}
+	Riscv64RustFlags = []string{
+		"-C force-frame-pointers=y",
+	}
+	Riscv64ArchFeatureRustFlags = map[string][]string{
+		"riscv64": {
+			"-C target-feature=+V,+Zba,+Zbb,+Zbs",
+		},
+	}
+	Riscv64LinkFlags = []string{}
 
 	Riscv64ArchVariantRustFlags = map[string][]string{"": {}}
 )
diff --git a/rust/config/x86_64_device.go b/rust/config/x86_64_device.go
index 3458ec9..fee1923 100644
--- a/rust/config/x86_64_device.go
+++ b/rust/config/x86_64_device.go
@@ -21,20 +21,23 @@
 )
 
 var (
-	x86_64RustFlags            = []string{}
+	x86_64RustFlags = []string{
+		"-C force-frame-pointers=y",
+	}
 	x86_64ArchFeatureRustFlags = map[string][]string{}
 	x86_64LinkFlags            = []string{}
 
 	x86_64ArchVariantRustFlags = map[string][]string{
-		"":              []string{},
-		"broadwell":     []string{"-C target-cpu=broadwell"},
-		"goldmont":      []string{"-C target-cpu=goldmont"},
-		"goldmont-plus": []string{"-C target-cpu=goldmont-plus"},
-		"haswell":       []string{"-C target-cpu=haswell"},
-		"ivybridge":     []string{"-C target-cpu=ivybridge"},
-		"sandybridge":   []string{"-C target-cpu=sandybridge"},
-		"silvermont":    []string{"-C target-cpu=silvermont"},
-		"skylake":       []string{"-C target-cpu=skylake"},
+		"":                            []string{},
+		"broadwell":                   []string{"-C target-cpu=broadwell"},
+		"goldmont":                    []string{"-C target-cpu=goldmont"},
+		"goldmont-plus":               []string{"-C target-cpu=goldmont-plus"},
+		"goldmont-without-sha-xsaves": []string{"-C target-cpu=goldmont", "-C target-feature=-sha,-xsaves"},
+		"haswell":                     []string{"-C target-cpu=haswell"},
+		"ivybridge":                   []string{"-C target-cpu=ivybridge"},
+		"sandybridge":                 []string{"-C target-cpu=sandybridge"},
+		"silvermont":                  []string{"-C target-cpu=silvermont"},
+		"skylake":                     []string{"-C target-cpu=skylake"},
 		//TODO: Add target-cpu=stoneyridge when rustc supports it.
 		"stoneyridge": []string{""},
 		"tremont":     []string{"-C target-cpu=tremont"},
@@ -51,7 +54,7 @@
 		pctx.StaticVariable("X86_64"+variant+"VariantRustFlags",
 			strings.Join(rustFlags, " "))
 	}
-
+	pctx.StaticVariable("DEVICE_X86_64_RUSTC_FLAGS", strings.Join(x86_64RustFlags, " "))
 }
 
 type toolchainX86_64 struct {
diff --git a/rust/config/x86_device.go b/rust/config/x86_device.go
index 43f7340..5d9d88a 100644
--- a/rust/config/x86_device.go
+++ b/rust/config/x86_device.go
@@ -26,16 +26,17 @@
 	x86LinkFlags            = []string{}
 
 	x86ArchVariantRustFlags = map[string][]string{
-		"":              []string{},
-		"atom":          []string{"-C target-cpu=atom"},
-		"broadwell":     []string{"-C target-cpu=broadwell"},
-		"goldmont":      []string{"-C target-cpu=goldmont"},
-		"goldmont-plus": []string{"-C target-cpu=goldmont-plus"},
-		"haswell":       []string{"-C target-cpu=haswell"},
-		"ivybridge":     []string{"-C target-cpu=ivybridge"},
-		"sandybridge":   []string{"-C target-cpu=sandybridge"},
-		"silvermont":    []string{"-C target-cpu=silvermont"},
-		"skylake":       []string{"-C target-cpu=skylake"},
+		"":                            []string{},
+		"atom":                        []string{"-C target-cpu=atom"},
+		"broadwell":                   []string{"-C target-cpu=broadwell"},
+		"goldmont":                    []string{"-C target-cpu=goldmont"},
+		"goldmont-plus":               []string{"-C target-cpu=goldmont-plus"},
+		"goldmont-without-sha-xsaves": []string{"-C target-cpu=goldmont", "-C target-feature=-sha,-xsaves"},
+		"haswell":                     []string{"-C target-cpu=haswell"},
+		"ivybridge":                   []string{"-C target-cpu=ivybridge"},
+		"sandybridge":                 []string{"-C target-cpu=sandybridge"},
+		"silvermont":                  []string{"-C target-cpu=silvermont"},
+		"skylake":                     []string{"-C target-cpu=skylake"},
 		//TODO: Add target-cpu=stoneyridge when rustc supports it.
 		"stoneyridge": []string{""},
 		"tremont":     []string{"-C target-cpu=tremont"},
@@ -55,6 +56,7 @@
 			strings.Join(rustFlags, " "))
 	}
 
+	pctx.StaticVariable("DEVICE_X86_RUSTC_FLAGS", strings.Join(x86RustFlags, " "))
 }
 
 type toolchainX86 struct {
diff --git a/rust/coverage.go b/rust/coverage.go
index 5216d60..91a7806 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -39,9 +39,11 @@
 
 func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
 	if cov.Properties.NeedCoverageVariant {
-		ctx.AddVariationDependencies([]blueprint.Variation{
-			{Mutator: "link", Variation: "static"},
-		}, cc.CoverageDepTag, CovLibraryName)
+		if ctx.Device() {
+			ctx.AddVariationDependencies([]blueprint.Variation{
+				{Mutator: "link", Variation: "static"},
+			}, cc.CoverageDepTag, CovLibraryName)
+		}
 
 		// no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency.
 		if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() {
@@ -60,12 +62,14 @@
 
 	if cov.Properties.CoverageEnabled {
 		flags.Coverage = true
-		coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface)
 		flags.RustFlags = append(flags.RustFlags,
 			"-C instrument-coverage", "-g")
-		flags.LinkFlags = append(flags.LinkFlags,
-			profileInstrFlag, "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,open")
-		deps.LibDeps = append(deps.LibDeps, coverage.OutputFile().Path())
+		if ctx.Device() {
+			coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface)
+			flags.LinkFlags = append(flags.LinkFlags,
+				profileInstrFlag, "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,open")
+			deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path())
+		}
 
 		// no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency.
 		if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() {
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
index 64077cf..0f599d7 100644
--- a/rust/coverage_test.go
+++ b/rust/coverage_test.go
@@ -55,10 +55,6 @@
 	libbarNoCov := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc")
 	fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
 	buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
-	libfooCovLink := ctx.ModuleForTests("libfoo_cov", "android_arm64_armv8-a_dylib_cov").Rule("rustLink")
-	libbarNoCovLink := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustLink")
-	fizzCovLink := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustLink")
-	buzzNoCovLink := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustLink")
 
 	rustcCoverageFlags := []string{"-C instrument-coverage", " -g "}
 	for _, flag := range rustcCoverageFlags {
@@ -84,17 +80,17 @@
 		missingErrorStr := "missing rust linker flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
 		containsErrorStr := "contains rust linker flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
 
-		if !strings.Contains(fizzCovLink.Args["linkFlags"], flag) {
-			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCovLink.Args["linkFlags"])
+		if !strings.Contains(fizzCov.Args["linkFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["linkFlags"])
 		}
-		if !strings.Contains(libfooCovLink.Args["linkFlags"], flag) {
-			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCovLink.Args["linkFlags"])
+		if !strings.Contains(libfooCov.Args["linkFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["linkFlags"])
 		}
-		if strings.Contains(buzzNoCovLink.Args["linkFlags"], flag) {
-			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCovLink.Args["linkFlags"])
+		if strings.Contains(buzzNoCov.Args["linkFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["linkFlags"])
 		}
-		if strings.Contains(libbarNoCovLink.Args["linkFlags"], flag) {
-			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCovLink.Args["linkFlags"])
+		if strings.Contains(libbarNoCov.Args["linkFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["linkFlags"])
 		}
 	}
 
@@ -107,7 +103,7 @@
 			srcs: ["foo.rs"],
 		}`)
 
-	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustLink")
+	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustc")
 	if !strings.Contains(fizz.Args["linkFlags"], "libprofile-clang-extras.a") {
 		t.Fatalf("missing expected coverage 'libprofile-clang-extras' dependency in linkFlags: %#v", fizz.Args["linkFlags"])
 	}
diff --git a/rust/fuzz.go b/rust/fuzz.go
index c2b9405..1770d2e 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -15,16 +15,16 @@
 package rust
 
 import (
-	"path/filepath"
-
 	"android/soong/android"
 	"android/soong/cc"
 	"android/soong/fuzz"
 	"android/soong/rust/config"
+	"path/filepath"
 )
 
 func init() {
 	android.RegisterModuleType("rust_fuzz", RustFuzzFactory)
+	android.RegisterModuleType("rust_fuzz_host", RustFuzzHostFactory)
 }
 
 type fuzzDecorator struct {
@@ -43,6 +43,11 @@
 	return module.Init()
 }
 
+func RustFuzzHostFactory() android.Module {
+	module, _ := NewRustFuzz(android.HostSupported)
+	return module.Init()
+}
+
 func NewRustFuzz(hod android.HostOrDeviceSupported) (*Module, *fuzzDecorator) {
 	module, binary := NewRustBinary(hod)
 	fuzz := &fuzzDecorator{
@@ -54,6 +59,25 @@
 	fuzz.binaryDecorator.baseCompiler.dir64 = "fuzz"
 	fuzz.binaryDecorator.baseCompiler.location = InstallInData
 	module.sanitize.SetSanitizer(cc.Fuzzer, true)
+
+	// The fuzzer runtime is not present for darwin or bionic host modules, so disable rust_fuzz modules for these.
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+
+		extraProps := struct {
+			Target struct {
+				Darwin struct {
+					Enabled *bool
+				}
+				Linux_bionic struct {
+					Enabled *bool
+				}
+			}
+		}{}
+		extraProps.Target.Darwin.Enabled = cc.BoolPtr(false)
+		extraProps.Target.Linux_bionic.Enabled = cc.BoolPtr(false)
+		ctx.AppendProperties(&extraProps)
+	})
+
 	module.compiler = fuzz
 	return module, fuzz
 }
@@ -106,12 +130,6 @@
 }
 
 func (fuzz *fuzzDecorator) install(ctx ModuleContext) {
-	fuzz.binaryDecorator.baseCompiler.dir = filepath.Join(
-		"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
-	fuzz.binaryDecorator.baseCompiler.dir64 = filepath.Join(
-		"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
-	fuzz.binaryDecorator.baseCompiler.install(ctx)
-
 	fuzz.fuzzPackagedModule = cc.PackageFuzzModule(ctx, fuzz.fuzzPackagedModule, pctx)
 
 	installBase := "fuzz"
@@ -124,12 +142,38 @@
 
 		fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
 			cc.SharedLibraryInstallLocation(
-				install, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
+				install, ctx.Host(), ctx.InstallInVendor(), installBase, ctx.Arch().ArchType.String()))
 
 		// Also add the dependency on the shared library symbols dir.
 		if !ctx.Host() {
 			fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
-				cc.SharedLibrarySymbolsInstallLocation(install, installBase, ctx.Arch().ArchType.String()))
+				cc.SharedLibrarySymbolsInstallLocation(install, ctx.InstallInVendor(), installBase, ctx.Arch().ArchType.String()))
 		}
 	}
+
+	var fuzzData []android.DataPath
+	for _, d := range fuzz.fuzzPackagedModule.Corpus {
+		fuzzData = append(fuzzData, android.DataPath{SrcPath: d, RelativeInstallPath: "corpus", WithoutRel: true})
+	}
+
+	for _, d := range fuzz.fuzzPackagedModule.Data {
+		fuzzData = append(fuzzData, android.DataPath{SrcPath: d, RelativeInstallPath: "data"})
+	}
+
+	if d := fuzz.fuzzPackagedModule.Dictionary; d != nil {
+		fuzzData = append(fuzzData, android.DataPath{SrcPath: d, WithoutRel: true})
+	}
+
+	if d := fuzz.fuzzPackagedModule.Config; d != nil {
+		fuzzData = append(fuzzData, android.DataPath{SrcPath: d, WithoutRel: true})
+	}
+
+	fuzz.binaryDecorator.baseCompiler.dir = filepath.Join(
+		"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
+	fuzz.binaryDecorator.baseCompiler.dir64 = filepath.Join(
+		"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
+	fuzz.binaryDecorator.baseCompiler.installTestData(ctx, fuzzData)
+
+	fuzz.binaryDecorator.baseCompiler.install(ctx)
+
 }
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
index 0aecf61..ee28c6d 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -34,6 +34,10 @@
 				srcs: ["foo.rs"],
 				rustlibs: ["libtest_fuzzing"],
 			}
+			rust_fuzz_host {
+				name: "host_fuzzer",
+				srcs: ["foo.rs"],
+			}
 	`)
 
 	// Check that appropriate dependencies are added and that the rustlib linkage is correct.
@@ -50,7 +54,13 @@
 	if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov-module'") ||
 		!strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") {
 		t.Errorf("rust_fuzz module does not contain the expected flags (sancov-module, cfg fuzzing).")
+	}
 
+	// Check that host modules support fuzzing.
+	host_fuzzer := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc")
+	if !strings.Contains(host_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") ||
+		!strings.Contains(host_fuzzer.Args["rustcFlags"], "--cfg fuzzing") {
+		t.Errorf("rust_fuzz_host module does not contain the expected flags (sancov-module, cfg fuzzing).")
 	}
 
 	// Check that dependencies have 'fuzzer' variants produced for them as well.
diff --git a/rust/image.go b/rust/image.go
index c2e250c..e0d267d 100644
--- a/rust/image.go
+++ b/rust/image.go
@@ -117,20 +117,16 @@
 	return false
 }
 
-func (ctx *moduleContext) SocSpecific() bool {
+func (mod *Module) InstallInVendor() bool {
 	// Additionally check if this module is inVendor() that means it is a "vendor" variant of a
 	// module. As well as SoC specific modules, vendor variants must be installed to /vendor
 	// unless they have "odm_available: true".
-	return ctx.ModuleContext.SocSpecific() || (ctx.RustModule().InVendor() && !ctx.RustModule().VendorVariantToOdm())
+	return mod.InVendor() && !mod.VendorVariantToOdm()
 }
 
-func (ctx *moduleContext) DeviceSpecific() bool {
+func (mod *Module) InstallInOdm() bool {
 	// Some vendor variants want to be installed to /odm by setting "odm_available: true".
-	return ctx.ModuleContext.DeviceSpecific() || (ctx.RustModule().InVendor() && ctx.RustModule().VendorVariantToOdm())
-}
-
-func (ctx *moduleContext) SystemExtSpecific() bool {
-	return ctx.ModuleContext.SystemExtSpecific()
+	return mod.InVendor() && mod.VendorVariantToOdm()
 }
 
 // Returns true when this module creates a vendor variant and wants to install the vendor variant
@@ -188,12 +184,17 @@
 }
 
 func (mod *Module) InProduct() bool {
-	return mod.Properties.ImageVariationPrefix == cc.ProductVariationPrefix
+	return mod.Properties.ImageVariation == cc.ProductVariation
 }
 
 // Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor
 func (mod *Module) InVendor() bool {
-	return mod.Properties.ImageVariationPrefix == cc.VendorVariationPrefix
+	return mod.Properties.ImageVariation == cc.VendorVariation
+}
+
+// Returns true if the module is "vendor" or "product" variant.
+func (mod *Module) InVendorOrProduct() bool {
+	return mod.InVendor() || mod.InProduct()
 }
 
 func (mod *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
@@ -202,20 +203,16 @@
 		m.MakeAsPlatform()
 	} else if variant == android.RecoveryVariation {
 		m.MakeAsPlatform()
-	} else if strings.HasPrefix(variant, cc.VendorVariationPrefix) {
-		m.Properties.ImageVariationPrefix = cc.VendorVariationPrefix
-		m.Properties.VndkVersion = strings.TrimPrefix(variant, cc.VendorVariationPrefix)
-
-		// Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION.
-		// Hide other vendor variants to avoid collision.
-		vndkVersion := ctx.DeviceConfig().VndkVersion()
-		if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion {
-			m.Properties.HideFromMake = true
-			m.HideFromMake()
+	} else if strings.HasPrefix(variant, cc.VendorVariation) {
+		m.Properties.ImageVariation = cc.VendorVariation
+		if strings.HasPrefix(variant, cc.VendorVariationPrefix) {
+			m.Properties.VndkVersion = strings.TrimPrefix(variant, cc.VendorVariationPrefix)
 		}
-	} else if strings.HasPrefix(variant, cc.ProductVariationPrefix) {
-		m.Properties.ImageVariationPrefix = cc.ProductVariationPrefix
-		m.Properties.VndkVersion = strings.TrimPrefix(variant, cc.ProductVariationPrefix)
+	} else if strings.HasPrefix(variant, cc.ProductVariation) {
+		m.Properties.ImageVariation = cc.ProductVariation
+		if strings.HasPrefix(variant, cc.ProductVariationPrefix) {
+			m.Properties.VndkVersion = strings.TrimPrefix(variant, cc.ProductVariationPrefix)
+		}
 	}
 }
 
diff --git a/rust/image_test.go b/rust/image_test.go
index fb4d9c1..ba94906 100644
--- a/rust/image_test.go
+++ b/rust/image_test.go
@@ -24,7 +24,7 @@
 
 // Test that cc modules can link against vendor_available rust_ffi_static libraries.
 func TestVendorLinkage(t *testing.T) {
-	ctx := testRustVndk(t, `
+	ctx := testRust(t, `
 			cc_binary {
 				name: "fizz_vendor",
 				static_libs: ["libfoo_vendor"],
@@ -38,7 +38,7 @@
 			}
 		`)
 
-	vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_vendor.29_arm64_armv8-a").Module().(*cc.Module)
+	vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_vendor_arm64_armv8-a").Module().(*cc.Module)
 
 	if !android.InList("libfoo_vendor.vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
 		t.Errorf("vendorBinary should have a dependency on libfoo_vendor: %#v", vendorBinary.Properties.AndroidMkStaticLibs)
@@ -46,8 +46,8 @@
 }
 
 // Test that variants which use the vndk emit the appropriate cfg flag.
-func TestImageVndkCfgFlag(t *testing.T) {
-	ctx := testRustVndk(t, `
+func TestImageCfgFlag(t *testing.T) {
+	ctx := testRust(t, `
 			rust_ffi_static {
 				name: "libfoo",
 				crate_name: "foo",
@@ -57,7 +57,7 @@
 			}
 		`)
 
-	vendor := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_static").Rule("rustc")
+	vendor := ctx.ModuleForTests("libfoo", "android_vendor_arm64_armv8-a_static").Rule("rustc")
 
 	if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vndk'") {
 		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
@@ -69,7 +69,7 @@
 		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
 	}
 
-	product := ctx.ModuleForTests("libfoo", "android_product.29_arm64_armv8-a_static").Rule("rustc")
+	product := ctx.ModuleForTests("libfoo", "android_product_arm64_armv8-a_static").Rule("rustc")
 	if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vndk'") {
 		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
 	}
@@ -95,7 +95,7 @@
 
 // Test that cc modules can link against vendor_ramdisk_available rust_ffi_static libraries.
 func TestVendorRamdiskLinkage(t *testing.T) {
-	ctx := testRustVndk(t, `
+	ctx := testRust(t, `
 			cc_library_static {
 				name: "libcc_vendor_ramdisk",
 				static_libs: ["libfoo_vendor_ramdisk"],
@@ -119,7 +119,7 @@
 
 // Test that prebuilt libraries cannot be made vendor available.
 func TestForbiddenVendorLinkage(t *testing.T) {
-	testRustVndkError(t, "Rust prebuilt modules not supported for non-system images.", `
+	testRustError(t, "Rust prebuilt modules not supported for non-system images.", `
 		rust_prebuilt_library {
 			name: "librust_prebuilt",
 			crate_name: "rust_prebuilt",
diff --git a/rust/library.go b/rust/library.go
index 3f480a2..6be4917 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -15,6 +15,7 @@
 package rust
 
 import (
+	"errors"
 	"fmt"
 	"regexp"
 	"strings"
@@ -53,9 +54,13 @@
 	Shared VariantLibraryProperties `android:"arch_variant"`
 	Static VariantLibraryProperties `android:"arch_variant"`
 
-	// path to include directories to pass to cc_* modules, only relevant for static/shared variants.
+	// TODO: Remove this when all instances of Include_dirs have been removed from rust_ffi modules.
+	// path to include directories to pass to cc_* modules, only relevant for static/shared variants (deprecated, use export_include_dirs instead).
 	Include_dirs []string `android:"path,arch_variant"`
 
+	// path to include directories to export to cc_* modules, only relevant for static/shared variants.
+	Export_include_dirs []string `android:"path,arch_variant"`
+
 	// Whether this library is part of the Rust toolchain sysroot.
 	Sysroot *bool
 }
@@ -99,8 +104,6 @@
 	includeDirs       android.Paths
 	sourceProvider    SourceProvider
 
-	collectedSnapshotHeaders android.Paths
-
 	// table-of-contents file for cdylib crates to optimize out relinking when possible
 	tocFile android.OptionalPath
 }
@@ -464,9 +467,18 @@
 	flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
 	if library.shared() || library.static() {
 		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
+		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Export_include_dirs)...)
 	}
 	if library.shared() {
-		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx))
+		if ctx.Darwin() {
+			flags.LinkFlags = append(
+				flags.LinkFlags,
+				"-dynamic_lib",
+				"-install_name @rpath/"+library.sharedLibFilename(ctx),
+			)
+		} else {
+			flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx))
+		}
 	}
 
 	return flags
@@ -476,7 +488,7 @@
 	var outputFile android.ModuleOutPath
 	var ret buildOutput
 	var fileName string
-	srcPath := library.srcPath(ctx, deps)
+	crateRootPath := crateRootPath(ctx, library)
 
 	if library.sourceProvider != nil {
 		deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...)
@@ -512,7 +524,7 @@
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
-	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects.Strings()...)
+	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
 
 	if library.dylib() {
 		// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
@@ -523,23 +535,22 @@
 
 	// Call the appropriate builder for this library type
 	if library.rlib() {
-		ret.kytheFile = TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoRlib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.dylib() {
-		ret.kytheFile = TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoDylib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.static() {
-		ret.kytheFile = TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoStatic(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.shared() {
-		ret.kytheFile = TransformSrctoShared(ctx, srcPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoShared(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	}
 
 	if library.rlib() || library.dylib() {
 		library.flagExporter.exportLinkDirs(deps.linkDirs...)
 		library.flagExporter.exportLinkObjects(deps.linkObjects...)
-		library.flagExporter.exportLibDeps(deps.LibDeps...)
 	}
 
 	if library.static() || library.shared() {
-		ctx.SetProvider(cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
+		android.SetProvider(ctx, cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
 			IncludeDirs: library.includeDirs,
 		})
 	}
@@ -551,7 +562,7 @@
 		library.tocFile = android.OptionalPathForPath(tocFile)
 		cc.TransformSharedObjectToToc(ctx, outputFile, tocFile)
 
-		ctx.SetProvider(cc.SharedLibraryInfoProvider, cc.SharedLibraryInfo{
+		android.SetProvider(ctx, cc.SharedLibraryInfoProvider, cc.SharedLibraryInfo{
 			TableOfContents: android.OptionalPathForPath(tocFile),
 			SharedLibrary:   outputFile,
 			Target:          ctx.Target(),
@@ -560,7 +571,7 @@
 
 	if library.static() {
 		depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(outputFile).Build()
-		ctx.SetProvider(cc.StaticLibraryInfoProvider, cc.StaticLibraryInfo{
+		android.SetProvider(ctx, cc.StaticLibraryInfoProvider, cc.StaticLibraryInfo{
 			StaticLibrary: outputFile,
 
 			TransitiveStaticLibrariesForOrdering: depSet,
@@ -572,13 +583,16 @@
 	return ret
 }
 
-func (library *libraryDecorator) srcPath(ctx ModuleContext, _ PathDeps) android.Path {
+func (library *libraryDecorator) checkedCrateRootPath() (android.Path, error) {
 	if library.sourceProvider != nil {
+		srcs := library.sourceProvider.Srcs()
+		if len(srcs) == 0 {
+			return nil, errors.New("Source provider generated 0 sources")
+		}
 		// Assume the first source from the source provider is the library entry point.
-		return library.sourceProvider.Srcs()[0]
+		return srcs[0], nil
 	} else {
-		path, _ := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
-		return path
+		return library.baseCompiler.checkedCrateRootPath()
 	}
 }
 
@@ -593,7 +607,7 @@
 		return android.OptionalPath{}
 	}
 
-	return android.OptionalPathForPath(Rustdoc(ctx, library.srcPath(ctx, deps),
+	return android.OptionalPathForPath(Rustdoc(ctx, crateRootPath(ctx, library),
 		deps, flags))
 }
 
@@ -733,55 +747,3 @@
 		}
 	}
 }
-
-func (l *libraryDecorator) snapshotHeaders() android.Paths {
-	if l.collectedSnapshotHeaders == nil {
-		panic("snapshotHeaders() must be called after collectHeadersForSnapshot()")
-	}
-	return l.collectedSnapshotHeaders
-}
-
-// collectHeadersForSnapshot collects all exported headers from library.
-// It globs header files in the source tree for exported include directories,
-// and tracks generated header files separately.
-//
-// This is to be called from GenerateAndroidBuildActions, and then collected
-// header files can be retrieved by snapshotHeaders().
-func (l *libraryDecorator) collectHeadersForSnapshot(ctx android.ModuleContext, deps PathDeps) {
-	ret := android.Paths{}
-
-	// Glob together the headers from the modules include_dirs property
-	for _, path := range android.CopyOfPaths(l.includeDirs) {
-		dir := path.String()
-		globDir := dir + "/**/*"
-		glob, err := ctx.GlobWithDeps(globDir, nil)
-		if err != nil {
-			ctx.ModuleErrorf("glob of %q failed: %s", globDir, err)
-			return
-		}
-
-		for _, header := range glob {
-			// Filter out only the files with extensions that are headers.
-			found := false
-			for _, ext := range cc.HeaderExts {
-				if strings.HasSuffix(header, ext) {
-					found = true
-					break
-				}
-			}
-			if !found {
-				continue
-			}
-			ret = append(ret, android.PathForSource(ctx, header))
-		}
-	}
-
-	// Glob together the headers from C dependencies as well, starting with non-generated headers.
-	ret = append(ret, cc.GlobHeadersForSnapshot(ctx, append(android.CopyOfPaths(deps.depIncludePaths), deps.depSystemIncludePaths...))...)
-
-	// Collect generated headers from C dependencies.
-	ret = append(ret, cc.GlobGeneratedHeadersForSnapshot(ctx, deps.depGeneratedHeaders)...)
-
-	// TODO(185577950): If support for generated headers is added, they need to be collected here as well.
-	l.collectedSnapshotHeaders = ret
-}
diff --git a/rust/library_test.go b/rust/library_test.go
index add7173..7275b66 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -148,7 +148,7 @@
 
 	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared")
 
-	libfooOutput := libfoo.Rule("rustLink")
+	libfooOutput := libfoo.Rule("rustc")
 	if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
 		t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v",
 			libfooOutput.Args["linkFlags"])
@@ -196,6 +196,65 @@
 	}
 }
 
+func TestNativeDependencyOfRlib(t *testing.T) {
+	ctx := testRust(t, `
+		rust_ffi_static {
+			name: "libffi_static",
+			crate_name: "ffi_static",
+			rlibs: ["librust_rlib"],
+			srcs: ["foo.rs"],
+		}
+		rust_library_rlib {
+			name: "librust_rlib",
+			crate_name: "rust_rlib",
+			srcs: ["foo.rs"],
+			shared_libs: ["shared_cc_dep"],
+			static_libs: ["static_cc_dep"],
+		}
+		cc_library_shared {
+			name: "shared_cc_dep",
+			srcs: ["foo.cpp"],
+		}
+		cc_library_static {
+			name: "static_cc_dep",
+			srcs: ["foo.cpp"],
+		}
+		`)
+
+	rustRlibRlibStd := ctx.ModuleForTests("librust_rlib", "android_arm64_armv8-a_rlib_rlib-std")
+	rustRlibDylibStd := ctx.ModuleForTests("librust_rlib", "android_arm64_armv8-a_rlib_dylib-std")
+	ffiStatic := ctx.ModuleForTests("libffi_static", "android_arm64_armv8-a_static")
+
+	modules := []android.TestingModule{
+		rustRlibRlibStd,
+		rustRlibDylibStd,
+		ffiStatic,
+	}
+
+	// librust_rlib specifies -L flag to cc deps output directory on rustc command
+	// and re-export the cc deps to rdep libffi_static
+	// When building rlib crate, rustc doesn't link the native libraries
+	// The build system assumes the  cc deps will be at the final linkage (either a shared library or binary)
+	// Hence, these flags are no-op
+	// TODO: We could consider removing these flags
+	for _, module := range modules {
+		if !strings.Contains(module.Rule("rustc").Args["libFlags"],
+			"-L out/soong/.intermediates/shared_cc_dep/android_arm64_armv8-a_shared/") {
+			t.Errorf(
+				"missing -L flag for shared_cc_dep, rustcFlags: %#v",
+				rustRlibRlibStd.Rule("rustc").Args["libFlags"],
+			)
+		}
+		if !strings.Contains(module.Rule("rustc").Args["libFlags"],
+			"-L out/soong/.intermediates/static_cc_dep/android_arm64_armv8-a_static/") {
+			t.Errorf(
+				"missing -L flag for static_cc_dep, rustcFlags: %#v",
+				rustRlibRlibStd.Rule("rustc").Args["libFlags"],
+			)
+		}
+	}
+}
+
 // Test that variants pull in the right type of rustlib autodep
 func TestAutoDeps(t *testing.T) {
 
@@ -344,3 +403,22 @@
 	}
 
 }
+
+func TestRustFFIExportedIncludes(t *testing.T) {
+	ctx := testRust(t, `
+		rust_ffi {
+			name: "libbar",
+			srcs: ["foo.rs"],
+			crate_name: "bar",
+			export_include_dirs: ["rust_includes"],
+			host_supported: true,
+		}
+		cc_library_static {
+			name: "libfoo",
+			srcs: ["foo.cpp"],
+			shared_libs: ["libbar"],
+			host_supported: true,
+		}`)
+	libfooStatic := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_static").Rule("cc")
+	android.AssertStringDoesContain(t, "cFlags for lib module", libfooStatic.Args["cFlags"], " -Irust_includes ")
+}
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
index fe9d0b5..e35e510 100644
--- a/rust/prebuilt.go
+++ b/rust/prebuilt.go
@@ -76,6 +76,17 @@
 var _ exportedFlagsProducer = (*prebuiltProcMacroDecorator)(nil)
 var _ rustPrebuilt = (*prebuiltProcMacroDecorator)(nil)
 
+func prebuiltPath(ctx ModuleContext, prebuilt rustPrebuilt) android.Path {
+	srcs := android.PathsForModuleSrc(ctx, prebuilt.prebuiltSrcs())
+	if len(srcs) == 0 {
+		ctx.PropertyErrorf("srcs", "srcs must not be empty")
+	}
+	if len(srcs) > 1 {
+		ctx.PropertyErrorf("srcs", "prebuilt libraries can only have one entry in srcs (the prebuilt path)")
+	}
+	return srcs[0]
+}
+
 func PrebuiltLibraryFactory() android.Module {
 	module, _ := NewPrebuiltLibrary(android.HostAndDeviceSupported)
 	return module.Init()
@@ -148,11 +159,7 @@
 func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
 	prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...)
 	prebuilt.flagExporter.setProvider(ctx)
-
-	srcPath, paths := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs())
-	if len(paths) > 0 {
-		ctx.PropertyErrorf("srcs", "prebuilt libraries can only have one entry in srcs (the prebuilt path)")
-	}
+	srcPath := prebuiltPath(ctx, prebuilt)
 	prebuilt.baseCompiler.unstrippedOutputFile = srcPath
 	return buildOutput{outputFile: srcPath}
 }
@@ -205,11 +212,7 @@
 func (prebuilt *prebuiltProcMacroDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
 	prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...)
 	prebuilt.flagExporter.setProvider(ctx)
-
-	srcPath, paths := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs())
-	if len(paths) > 0 {
-		ctx.PropertyErrorf("srcs", "prebuilt libraries can only have one entry in srcs (the prebuilt path)")
-	}
+	srcPath := prebuiltPath(ctx, prebuilt)
 	prebuilt.baseCompiler.unstrippedOutputFile = srcPath
 	return buildOutput{outputFile: srcPath}
 }
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 832b62c..b491449 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -73,8 +73,7 @@
 func (procMacro *procMacroDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
 	fileName := procMacro.getStem(ctx) + ctx.toolchain().ProcMacroSuffix()
 	outputFile := android.PathForModuleOut(ctx, fileName)
-
-	srcPath, _ := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs)
+	srcPath := crateRootPath(ctx, procMacro)
 	ret := TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile)
 	procMacro.baseCompiler.unstrippedOutputFile = outputFile
 	return ret
diff --git a/rust/project_json.go b/rust/project_json.go
index 40aa7c7..05fc09b 100644
--- a/rust/project_json.go
+++ b/rust/project_json.go
@@ -17,7 +17,6 @@
 import (
 	"encoding/json"
 	"fmt"
-	"path"
 
 	"android/soong/android"
 )
@@ -60,8 +59,9 @@
 
 // crateInfo is used during the processing to keep track of the known crates.
 type crateInfo struct {
-	Idx  int            // Index of the crate in rustProjectJson.Crates slice.
-	Deps map[string]int // The keys are the module names and not the crate names.
+	Idx    int            // Index of the crate in rustProjectJson.Crates slice.
+	Deps   map[string]int // The keys are the module names and not the crate names.
+	Device bool           // True if the crate at idx was a device crate
 }
 
 type projectGeneratorSingleton struct {
@@ -77,85 +77,6 @@
 	android.RegisterParallelSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
 }
 
-// sourceProviderVariantSource returns the path to the source file if this
-// module variant should be used as a priority.
-//
-// SourceProvider modules may have multiple variants considered as source
-// (e.g., x86_64 and armv8). For a module available on device, use the source
-// generated for the target. For a host-only module, use the source generated
-// for the host.
-func sourceProviderVariantSource(ctx android.SingletonContext, rModule *Module) (string, bool) {
-	rustLib, ok := rModule.compiler.(*libraryDecorator)
-	if !ok {
-		return "", false
-	}
-	if rustLib.source() {
-		switch rModule.hod {
-		case android.HostSupported, android.HostSupportedNoCross:
-			if rModule.Target().String() == ctx.Config().BuildOSTarget.String() {
-				src := rustLib.sourceProvider.Srcs()[0]
-				return src.String(), true
-			}
-		default:
-			if rModule.Target().String() == ctx.Config().AndroidFirstDeviceTarget.String() {
-				src := rustLib.sourceProvider.Srcs()[0]
-				return src.String(), true
-			}
-		}
-	}
-	return "", false
-}
-
-// sourceProviderSource finds the main source file of a source-provider crate.
-func sourceProviderSource(ctx android.SingletonContext, rModule *Module) (string, bool) {
-	rustLib, ok := rModule.compiler.(*libraryDecorator)
-	if !ok {
-		return "", false
-	}
-	if rustLib.source() {
-		// This is a source-variant, check if we are the right variant
-		// depending on the module configuration.
-		if src, ok := sourceProviderVariantSource(ctx, rModule); ok {
-			return src, true
-		}
-	}
-	foundSource := false
-	sourceSrc := ""
-	// Find the variant with the source and return its.
-	ctx.VisitAllModuleVariants(rModule, func(variant android.Module) {
-		if foundSource {
-			return
-		}
-		// All variants of a source provider library are libraries.
-		rVariant, _ := variant.(*Module)
-		variantLib, _ := rVariant.compiler.(*libraryDecorator)
-		if variantLib.source() {
-			sourceSrc, ok = sourceProviderVariantSource(ctx, rVariant)
-			if ok {
-				foundSource = true
-			}
-		}
-	})
-	if !foundSource {
-		ctx.Errorf("No valid source for source provider found: %v\n", rModule)
-	}
-	return sourceSrc, foundSource
-}
-
-// crateSource finds the main source file (.rs) for a crate.
-func crateSource(ctx android.SingletonContext, rModule *Module, comp *baseCompiler) (string, bool) {
-	// Basic libraries, executables and tests.
-	srcs := comp.Properties.Srcs
-	if len(srcs) != 0 {
-		return path.Join(ctx.ModuleDir(rModule), srcs[0]), true
-	}
-	// SourceProvider libraries.
-	if rModule.sourceProvider != nil {
-		return sourceProviderSource(ctx, rModule)
-	}
-	return "", false
-}
-
 // mergeDependencies visits all the dependencies for module and updates crate and deps
 // with any new dependency.
 func (singleton *projectGeneratorSingleton) mergeDependencies(ctx android.SingletonContext,
@@ -167,7 +88,7 @@
 			return
 		}
 		// Skip unsupported modules.
-		rChild, compChild, ok := isModuleSupported(ctx, child)
+		rChild, ok := isModuleSupported(ctx, child)
 		if !ok {
 			return
 		}
@@ -175,7 +96,7 @@
 		var childId int
 		cInfo, known := singleton.knownCrates[rChild.Name()]
 		if !known {
-			childId, ok = singleton.addCrate(ctx, rChild, compChild)
+			childId, ok = singleton.addCrate(ctx, rChild)
 			if !ok {
 				return
 			}
@@ -191,41 +112,26 @@
 	})
 }
 
-// isModuleSupported returns the RustModule and baseCompiler if the module
+// isModuleSupported returns the RustModule if the module
 // should be considered for inclusion in rust-project.json.
-func isModuleSupported(ctx android.SingletonContext, module android.Module) (*Module, *baseCompiler, bool) {
+func isModuleSupported(ctx android.SingletonContext, module android.Module) (*Module, bool) {
 	rModule, ok := module.(*Module)
 	if !ok {
-		return nil, nil, false
+		return nil, false
 	}
-	if rModule.compiler == nil {
-		return nil, nil, false
+	if !rModule.Enabled() {
+		return nil, false
 	}
-	var comp *baseCompiler
-	switch c := rModule.compiler.(type) {
-	case *libraryDecorator:
-		comp = c.baseCompiler
-	case *binaryDecorator:
-		comp = c.baseCompiler
-	case *testDecorator:
-		comp = c.binaryDecorator.baseCompiler
-	case *procMacroDecorator:
-		comp = c.baseCompiler
-	case *toolchainLibraryDecorator:
-		comp = c.baseCompiler
-	default:
-		return nil, nil, false
-	}
-	return rModule, comp, true
+	return rModule, true
 }
 
 // addCrate adds a crate to singleton.project.Crates ensuring that required
 // dependencies are also added. It returns the index of the new crate in
 // singleton.project.Crates
-func (singleton *projectGeneratorSingleton) addCrate(ctx android.SingletonContext, rModule *Module, comp *baseCompiler) (int, bool) {
-	rootModule, ok := crateSource(ctx, rModule, comp)
-	if !ok {
-		ctx.Errorf("Unable to find source for valid module: %v", rModule)
+func (singleton *projectGeneratorSingleton) addCrate(ctx android.SingletonContext, rModule *Module) (int, bool) {
+	deps := make(map[string]int)
+	rootModule, err := rModule.compiler.checkedCrateRootPath()
+	if err != nil {
 		return 0, false
 	}
 
@@ -233,28 +139,33 @@
 
 	crate := rustProjectCrate{
 		DisplayName: rModule.Name(),
-		RootModule:  rootModule,
-		Edition:     comp.edition(),
+		RootModule:  rootModule.String(),
+		Edition:     rModule.compiler.edition(),
 		Deps:        make([]rustProjectDep, 0),
 		Cfg:         make([]string, 0),
 		Env:         make(map[string]string),
 		ProcMacro:   procMacro,
 	}
 
-	if comp.CargoOutDir().Valid() {
-		crate.Env["OUT_DIR"] = comp.CargoOutDir().String()
+	if rModule.compiler.cargoOutDir().Valid() {
+		crate.Env["OUT_DIR"] = rModule.compiler.cargoOutDir().String()
 	}
 
-	for _, feature := range comp.Properties.Features {
+	for _, feature := range rModule.compiler.features() {
 		crate.Cfg = append(crate.Cfg, "feature=\""+feature+"\"")
 	}
 
-	deps := make(map[string]int)
 	singleton.mergeDependencies(ctx, rModule, &crate, deps)
 
-	idx := len(singleton.project.Crates)
-	singleton.knownCrates[rModule.Name()] = crateInfo{Idx: idx, Deps: deps}
-	singleton.project.Crates = append(singleton.project.Crates, crate)
+	var idx int
+	if cInfo, ok := singleton.knownCrates[rModule.Name()]; ok {
+		idx = cInfo.Idx
+		singleton.project.Crates[idx] = crate
+	} else {
+		idx = len(singleton.project.Crates)
+		singleton.project.Crates = append(singleton.project.Crates, crate)
+	}
+	singleton.knownCrates[rModule.Name()] = crateInfo{Idx: idx, Deps: deps, Device: rModule.Device()}
 	return idx, true
 }
 
@@ -262,18 +173,23 @@
 // It visits the dependencies of the module depth-first so the dependency ID can be added to the current module. If the
 // current module is already in singleton.knownCrates, its dependencies are merged.
 func (singleton *projectGeneratorSingleton) appendCrateAndDependencies(ctx android.SingletonContext, module android.Module) {
-	rModule, comp, ok := isModuleSupported(ctx, module)
+	rModule, ok := isModuleSupported(ctx, module)
 	if !ok {
 		return
 	}
 	// If we have seen this crate already; merge any new dependencies.
 	if cInfo, ok := singleton.knownCrates[module.Name()]; ok {
+		// If we have a new device variant, override the old one
+		if !cInfo.Device && rModule.Device() {
+			singleton.addCrate(ctx, rModule)
+			return
+		}
 		crate := singleton.project.Crates[cInfo.Idx]
 		singleton.mergeDependencies(ctx, rModule, &crate, cInfo.Deps)
 		singleton.project.Crates[cInfo.Idx] = crate
 		return
 	}
-	singleton.addCrate(ctx, rModule, comp)
+	singleton.addCrate(ctx, rModule)
 }
 
 func (singleton *projectGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
diff --git a/rust/protobuf.go b/rust/protobuf.go
index 0cf6e8c..fab5259 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -16,9 +16,11 @@
 
 import (
 	"fmt"
+	"strconv"
 	"strings"
 
 	"android/soong/android"
+	"android/soong/cc"
 )
 
 var (
@@ -53,26 +55,22 @@
 	// List of libraries which export include paths required for this module
 	Header_libs []string `android:"arch_variant,variant_prepend"`
 
-	// Use protobuf version 3.x. This will be deleted once we migrate all current users
-	// of protobuf off of 2.x.
-	Use_protobuf3 *bool
+	// List of exported include paths containing proto files for dependent rust_protobuf modules.
+	Exported_include_dirs []string
 }
 
 type protobufDecorator struct {
 	*BaseSourceProvider
 
-	Properties ProtobufProperties
-	protoNames []string
-	grpcNames  []string
+	Properties       ProtobufProperties
+	protoNames       []string
+	additionalCrates []string
+	grpcNames        []string
 
 	grpcProtoFlags android.ProtoFlags
 	protoFlags     android.ProtoFlags
 }
 
-func (proto *protobufDecorator) useProtobuf3() bool {
-	return Bool(proto.Properties.Use_protobuf3)
-}
-
 func (proto *protobufDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
 	var protoFlags android.ProtoFlags
 	var grpcProtoFlags android.ProtoFlags
@@ -82,12 +80,7 @@
 	protoFiles := android.PathsForModuleSrc(ctx, proto.Properties.Protos)
 	grpcFiles := android.PathsForModuleSrc(ctx, proto.Properties.Grpc_protos)
 
-	// For now protobuf2 (the deprecated version) remains the default. This will change in the
-	// future as we update the various users.
-	protoPluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust-deprecated")
-	if proto.useProtobuf3() == true {
-		protoPluginPath = ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
-	}
+	protoPluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
 
 	commonProtoFlags = append(commonProtoFlags, defaultProtobufFlags...)
 	commonProtoFlags = append(commonProtoFlags, proto.Properties.Proto_flags...)
@@ -130,41 +123,65 @@
 	// stemFile must be first here as the first path in BaseSourceProvider.OutputFiles is the library entry-point.
 	var outputs android.WritablePaths
 
-	rule := android.NewRuleBuilder(pctx, ctx)
+	for i, shard := range android.ShardPaths(protoFiles, 50) {
+		rule := android.NewRuleBuilder(pctx, ctx)
 
-	for _, protoFile := range protoFiles {
-		// Since we're iterating over the protoFiles already, make sure they're not redeclared in grpcFiles
-		if android.InList(protoFile.String(), grpcFiles.Strings()) {
-			ctx.PropertyErrorf("protos",
-				"A proto can only be added once to either grpc_protos or protos. %q is declared in both properties",
-				protoFile.String())
+		for _, protoFile := range shard {
+			// Since we're iterating over the protoFiles already, make sure they're not redeclared in grpcFiles
+			if android.InList(protoFile.String(), grpcFiles.Strings()) {
+				ctx.PropertyErrorf("protos",
+					"A proto can only be added once to either grpc_protos or protos. %q is declared in both properties",
+					protoFile.String())
+			}
+
+			protoName := strings.TrimSuffix(protoFile.Base(), ".proto")
+			proto.protoNames = append(proto.protoNames, protoName)
+
+			protoOut := android.PathForModuleOut(ctx, protoName+".rs")
+			depFile := android.PathForModuleOut(ctx, protoName+".d")
+
+			ruleOutputs := android.WritablePaths{protoOut, depFile}
+
+			android.ProtoRule(rule, protoFile, protoFlags, protoFlags.Deps, outDir, depFile, ruleOutputs)
+			outputs = append(outputs, ruleOutputs...)
 		}
 
-		protoName := strings.TrimSuffix(protoFile.Base(), ".proto")
-		proto.protoNames = append(proto.protoNames, protoName)
+		ruleName := "protoc"
+		ruleDesc := "protoc"
+		if i > 0 {
+			ruleName += "_" + strconv.Itoa(i+1)
+			ruleDesc += " " + strconv.Itoa(i+1)
+		}
 
-		protoOut := android.PathForModuleOut(ctx, protoName+".rs")
-		depFile := android.PathForModuleOut(ctx, protoName+".d")
-
-		ruleOutputs := android.WritablePaths{protoOut, depFile}
-
-		android.ProtoRule(rule, protoFile, protoFlags, protoFlags.Deps, outDir, depFile, ruleOutputs)
-		outputs = append(outputs, ruleOutputs...)
+		rule.Build(ruleName, ruleDesc)
 	}
 
-	for _, grpcFile := range grpcFiles {
-		grpcName := strings.TrimSuffix(grpcFile.Base(), ".proto")
-		proto.grpcNames = append(proto.grpcNames, grpcName)
+	for i, shard := range android.ShardPaths(grpcFiles, 50) {
+		rule := android.NewRuleBuilder(pctx, ctx)
 
-		// GRPC protos produce two files, a proto.rs and a proto_grpc.rs
-		protoOut := android.WritablePath(android.PathForModuleOut(ctx, grpcName+".rs"))
-		grpcOut := android.WritablePath(android.PathForModuleOut(ctx, grpcName+grpcSuffix+".rs"))
-		depFile := android.PathForModuleOut(ctx, grpcName+".d")
+		for _, grpcFile := range shard {
+			grpcName := strings.TrimSuffix(grpcFile.Base(), ".proto")
+			proto.grpcNames = append(proto.grpcNames, grpcName)
 
-		ruleOutputs := android.WritablePaths{protoOut, grpcOut, depFile}
+			// GRPC protos produce two files, a proto.rs and a proto_grpc.rs
+			protoOut := android.WritablePath(android.PathForModuleOut(ctx, grpcName+".rs"))
+			grpcOut := android.WritablePath(android.PathForModuleOut(ctx, grpcName+grpcSuffix+".rs"))
+			depFile := android.PathForModuleOut(ctx, grpcName+".d")
 
-		android.ProtoRule(rule, grpcFile, grpcProtoFlags, grpcProtoFlags.Deps, outDir, depFile, ruleOutputs)
-		outputs = append(outputs, ruleOutputs...)
+			ruleOutputs := android.WritablePaths{protoOut, grpcOut, depFile}
+
+			android.ProtoRule(rule, grpcFile, grpcProtoFlags, grpcProtoFlags.Deps, outDir, depFile, ruleOutputs)
+			outputs = append(outputs, ruleOutputs...)
+		}
+
+		ruleName := "protoc_grpc"
+		ruleDesc := "protoc grpc"
+		if i > 0 {
+			ruleName += "_" + strconv.Itoa(i+1)
+			ruleDesc += " " + strconv.Itoa(i+1)
+		}
+
+		rule.Build(ruleName, ruleDesc)
 	}
 
 	// Check that all proto base filenames are unique as outputs are written to the same directory.
@@ -176,11 +193,13 @@
 
 	android.WriteFileRule(ctx, stemFile, proto.genModFileContents())
 
-	rule.Build("protoc_"+ctx.ModuleName(), "protoc "+ctx.ModuleName())
-
 	// stemFile must be first here as the first path in BaseSourceProvider.OutputFiles is the library entry-point.
 	proto.BaseSourceProvider.OutputFiles = append(android.Paths{stemFile}, outputs.Paths()...)
 
+	android.SetProvider(ctx, cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
+		IncludeDirs: android.PathsForModuleSrc(ctx, proto.Properties.Exported_include_dirs),
+	})
+
 	// mod_stem.rs is the entry-point for our library modules, so this is what we return.
 	return stemFile
 }
@@ -189,10 +208,16 @@
 	lines := []string{
 		"// @Soong generated Source",
 	}
+
 	for _, protoName := range proto.protoNames {
 		lines = append(lines, fmt.Sprintf("pub mod %s;", protoName))
 	}
 
+	for _, crate := range proto.additionalCrates {
+		lines = append(lines, fmt.Sprintf("pub use %s::*;", crate))
+
+	}
+
 	for _, grpcName := range proto.grpcNames {
 		lines = append(lines, fmt.Sprintf("pub mod %s;", grpcName))
 		lines = append(lines, fmt.Sprintf("pub mod %s%s;", grpcName, grpcSuffix))
@@ -201,13 +226,7 @@
 		lines = append(
 			lines,
 			"pub mod empty {",
-			"    pub use protobuf::well_known_types::Empty;",
-			"}",
-			"pub mod wrappers {",
-			"    pub use protobuf::well_known_types::{",
-			"        DoubleValue, FloatValue, Int64Value, UInt64Value, Int32Value, UInt32Value,",
-			"        BoolValue, StringValue, BytesValue",
-			"    };",
+			"    pub use protobuf::well_known_types::empty::Empty;",
 			"}")
 	}
 
@@ -220,20 +239,10 @@
 
 func (proto *protobufDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
 	deps = proto.BaseSourceProvider.SourceProviderDeps(ctx, deps)
-	useProtobuf3 := proto.useProtobuf3()
-	if useProtobuf3 == true {
-		deps.Rustlibs = append(deps.Rustlibs, "libprotobuf")
-	} else {
-		deps.Rustlibs = append(deps.Rustlibs, "libprotobuf_deprecated")
-	}
+	deps.Rustlibs = append(deps.Rustlibs, "libprotobuf")
 	deps.HeaderLibs = append(deps.SharedLibs, proto.Properties.Header_libs...)
 
 	if len(proto.Properties.Grpc_protos) > 0 {
-		if useProtobuf3 == true {
-			ctx.PropertyErrorf("protos", "rust_protobuf with grpc_protos defined must currently use "+
-				"`use_protobuf3: false,` in the Android.bp file. This is temporary until the "+
-				"grpcio crate is updated to use the current version of the protobuf crate.")
-		}
 		deps.Rustlibs = append(deps.Rustlibs, "libgrpcio", "libfutures")
 		deps.HeaderLibs = append(deps.HeaderLibs, "libprotobuf-cpp-full")
 	}
@@ -243,7 +252,7 @@
 
 // rust_protobuf generates protobuf rust code from the provided proto file. This uses the protoc-gen-rust plugin for
 // protoc. Additional flags to the protoc command can be passed via the proto_flags property. This module type will
-// create library variants that can be used as a crate dependency by adding it to the rlibs, dylibs, and rustlibs
+// create library variants that can be used as a crate dependency by adding it to the rlibs and rustlibs
 // properties of other modules.
 func RustProtobufFactory() android.Module {
 	module, _ := NewRustProtobuf(android.HostAndDeviceSupported)
diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go
index b723f3f..cae071b 100644
--- a/rust/protobuf_test.go
+++ b/rust/protobuf_test.go
@@ -21,54 +21,6 @@
 	"android/soong/android"
 )
 
-func TestRustProtobuf(t *testing.T) {
-	ctx := testRust(t, `
-		rust_protobuf {
-			name: "librust_proto",
-			protos: ["buf.proto", "proto.proto"],
-			crate_name: "rust_proto",
-			source_stem: "buf",
-			shared_libs: ["libfoo_shared"],
-			static_libs: ["libfoo_static"],
-		}
-		cc_library_shared {
-			name: "libfoo_shared",
-			export_include_dirs: ["shared_include"],
-		}
-		cc_library_static {
-			name: "libfoo_static",
-			export_include_dirs: ["static_include"],
-		}
-	`)
-	// Check that libprotobuf is added as a dependency.
-	librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module)
-	if !android.InList("libprotobuf_deprecated", librust_proto.Properties.AndroidMkDylibs) {
-		t.Errorf("libprotobuf_deprecated dependency missing for rust_protobuf (dependency missing from AndroidMkDylibs)")
-	}
-
-	// Make sure the correct plugin is being used.
-	librust_proto_out := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("buf.rs")
-	cmd := librust_proto_out.RuleParams.Command
-	if w := "protoc-gen-rust-deprecated"; !strings.Contains(cmd, w) {
-		t.Errorf("expected %q in %q", w, cmd)
-	}
-
-	// Check exported include directories
-	if w := "-Ishared_include"; !strings.Contains(cmd, w) {
-		t.Errorf("expected %q in %q", w, cmd)
-	}
-	if w := "-Istatic_include"; !strings.Contains(cmd, w) {
-		t.Errorf("expected %q in %q", w, cmd)
-	}
-
-	// Check proto.rs, the second protobuf, is listed as an output
-	librust_proto_outputs := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").AllOutputs()
-	if android.InList("proto.rs", librust_proto_outputs) {
-		t.Errorf("rust_protobuf is not producing multiple outputs; expected 'proto.rs' in list, got: %#v ",
-			librust_proto_outputs)
-	}
-}
-
 func TestRustProtobuf3(t *testing.T) {
 	ctx := testRust(t, `
 		rust_protobuf {
@@ -76,7 +28,6 @@
 			protos: ["buf.proto", "proto.proto"],
 			crate_name: "rust_proto",
 			source_stem: "buf",
-            use_protobuf3: true,
 			shared_libs: ["libfoo_shared"],
 			static_libs: ["libfoo_static"],
 		}
@@ -118,6 +69,56 @@
 	}
 }
 
+func TestRustProtobufInclude(t *testing.T) {
+	ctx := testRust(t, `
+		rust_protobuf {
+			name: "librust_proto",
+			protos: ["proto.proto"],
+			crate_name: "rust_proto",
+			source_stem: "proto",
+			rustlibs: ["librust_exported_proto", "libfoo"],
+		}
+		rust_protobuf {
+			name: "librust_exported_proto",
+			protos: ["proto.proto"],
+			crate_name: "rust_exported_proto",
+			source_stem: "exported_proto",
+			exported_include_dirs: ["proto"]
+		}
+		rust_library {
+			name: "libfoo",
+			crate_name: "foo",
+			srcs: ["foo.rs"],
+		}
+	`)
+	// Check that librust_exported_proto is added as additional crate to generate source.
+	librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Module().(*Module).sourceProvider.(*protobufDecorator)
+	if !android.InList("rust_exported_proto", librust_proto.additionalCrates) {
+		t.Errorf("librust_proto should have librust_exported_proto included as an additional crate for generated source, instead got: %#v", librust_proto.additionalCrates)
+	}
+
+	// Make sure the default crates aren't being included.
+	if android.InList("std", librust_proto.additionalCrates) {
+		t.Errorf("librust_proto should not have included libstd as an additional crate for generated source, instead got: %#v", librust_proto.additionalCrates)
+	}
+	if android.InList("protobuf", librust_proto.additionalCrates) {
+		t.Errorf("librust_proto should not have included libprotobuf as an additional crate for generated source, instead got: %#v", librust_proto.additionalCrates)
+	}
+
+	// And make sure that non-protobuf crates aren't getting included either.
+	if android.InList("foo", librust_proto.additionalCrates) {
+		t.Errorf("librust_proto should not have included libfoo as an additional crate for generated source, instead got: %#v", librust_proto.additionalCrates)
+	}
+
+	// Check librust_proto args includes -Iproto
+	librust_proto_rule := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("proto.rs")
+	cmd := librust_proto_rule.RuleParams.Command
+	if w := "-Iproto"; !strings.Contains(cmd, w) {
+		t.Errorf("expected %q in %q", w, cmd)
+	}
+
+}
+
 func TestRustGrpc(t *testing.T) {
 	ctx := testRust(t, `
 		rust_protobuf {
diff --git a/rust/rust.go b/rust/rust.go
index dab3532..c2b6151 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -15,10 +15,12 @@
 package rust
 
 import (
-	"android/soong/bloaty"
 	"fmt"
 	"strings"
 
+	"android/soong/bloaty"
+	"android/soong/testing"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -28,7 +30,6 @@
 	"android/soong/fuzz"
 	"android/soong/multitree"
 	"android/soong/rust/config"
-	"android/soong/snapshot"
 )
 
 var pctx = android.NewPackageContext("android/soong/rust")
@@ -66,12 +67,12 @@
 	AndroidMkRlibs         []string `blueprint:"mutated"`
 	AndroidMkDylibs        []string `blueprint:"mutated"`
 	AndroidMkProcMacroLibs []string `blueprint:"mutated"`
-	AndroidMkSharedLibs    []string `blueprint:"mutated"`
 	AndroidMkStaticLibs    []string `blueprint:"mutated"`
+	AndroidMkHeaderLibs    []string `blueprint:"mutated"`
 
-	ImageVariationPrefix string `blueprint:"mutated"`
-	VndkVersion          string `blueprint:"mutated"`
-	SubName              string `blueprint:"mutated"`
+	ImageVariation string `blueprint:"mutated"`
+	VndkVersion    string `blueprint:"mutated"`
+	SubName        string `blueprint:"mutated"`
 
 	// SubName is used by CC for tracking image variants / SDK versions. RustSubName is used for Rust-specific
 	// subnaming which shouldn't be visible to CC modules (such as the rlib stdlinkage subname). This should be
@@ -142,8 +143,9 @@
 
 	Properties BaseProperties
 
-	hod      android.HostOrDeviceSupported
-	multilib android.Multilib
+	hod        android.HostOrDeviceSupported
+	multilib   android.Multilib
+	testModule bool
 
 	makeLinkType string
 
@@ -168,6 +170,11 @@
 
 	// For apex variants, this is set as apex.min_sdk_version
 	apexSdkVersion android.ApiLevel
+
+	transitiveAndroidMkSharedLibs *android.DepSet[string]
+
+	// Aconfig files for all transitive deps.  Also exposed via TransitiveDeclarationsInfo
+	mergedAconfigFiles map[string]android.Paths
 }
 
 func (mod *Module) Header() bool {
@@ -261,6 +268,15 @@
 	return false
 }
 
+func (mod *Module) Source() bool {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok && mod.sourceProvider != nil {
+			return library.source()
+		}
+	}
+	return false
+}
+
 func (mod *Module) RlibStd() bool {
 	if mod.compiler != nil {
 		if library, ok := mod.compiler.(libraryInterface); ok && library.rlib() {
@@ -432,12 +448,13 @@
 }
 
 type PathDeps struct {
-	DyLibs          RustLibraries
-	RLibs           RustLibraries
-	LibDeps         android.Paths
-	WholeStaticLibs android.Paths
-	ProcMacros      RustLibraries
-	AfdoProfiles    android.Paths
+	DyLibs        RustLibraries
+	RLibs         RustLibraries
+	SharedLibs    android.Paths
+	SharedLibDeps android.Paths
+	StaticLibs    android.Paths
+	ProcMacros    RustLibraries
+	AfdoProfiles  android.Paths
 
 	// depFlags and depLinkFlags are rustc and linker (clang) flags.
 	depFlags     []string
@@ -446,7 +463,7 @@
 	// linkDirs are link paths passed via -L to rustc. linkObjects are objects passed directly to the linker.
 	// Both of these are exported and propagate to dependencies.
 	linkDirs    []string
-	linkObjects android.Paths
+	linkObjects []string
 
 	// Used by bindgen modules which call clang
 	depClangFlags         []string
@@ -469,47 +486,9 @@
 	CrateName string
 }
 
-type compiler interface {
-	initialize(ctx ModuleContext)
-	compilerFlags(ctx ModuleContext, flags Flags) Flags
-	cfgFlags(ctx ModuleContext, flags Flags) Flags
-	featureFlags(ctx ModuleContext, flags Flags) Flags
-	compilerProps() []interface{}
-	compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput
-	compilerDeps(ctx DepsContext, deps Deps) Deps
-	crateName() string
-	rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath
-
-	// Output directory in which source-generated code from dependencies is
-	// copied. This is equivalent to Cargo's OUT_DIR variable.
-	CargoOutDir() android.OptionalPath
-
-	// CargoPkgVersion returns the value of the Cargo_pkg_version property.
-	CargoPkgVersion() string
-
-	// CargoEnvCompat returns whether Cargo environment variables should be used.
-	CargoEnvCompat() bool
-
-	inData() bool
-	install(ctx ModuleContext)
-	relativeInstallPath() string
-	everInstallable() bool
-
-	nativeCoverage() bool
-
-	Disabled() bool
-	SetDisabled()
-
-	stdLinkage(ctx *depsContext) RustLinkage
-	noStdlibs() bool
-
-	unstrippedOutputFilePath() android.Path
-	strippedOutputFilePath() android.OptionalPath
-}
-
 type exportedFlagsProducer interface {
 	exportLinkDirs(...string)
-	exportLinkObjects(...android.Path)
+	exportLinkObjects(...string)
 }
 
 type xref interface {
@@ -518,27 +497,21 @@
 
 type flagExporter struct {
 	linkDirs    []string
-	linkObjects android.Paths
-	libDeps     android.Paths
+	linkObjects []string
 }
 
 func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) {
 	flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...))
 }
 
-func (flagExporter *flagExporter) exportLinkObjects(flags ...android.Path) {
-	flagExporter.linkObjects = android.FirstUniquePaths(append(flagExporter.linkObjects, flags...))
-}
-
-func (flagExporter *flagExporter) exportLibDeps(paths ...android.Path) {
-	flagExporter.libDeps = android.FirstUniquePaths(append(flagExporter.libDeps, paths...))
+func (flagExporter *flagExporter) exportLinkObjects(flags ...string) {
+	flagExporter.linkObjects = android.FirstUniqueStrings(append(flagExporter.linkObjects, flags...))
 }
 
 func (flagExporter *flagExporter) setProvider(ctx ModuleContext) {
-	ctx.SetProvider(FlagExporterInfoProvider, FlagExporterInfo{
+	android.SetProvider(ctx, FlagExporterInfoProvider, FlagExporterInfo{
 		LinkDirs:    flagExporter.linkDirs,
 		LinkObjects: flagExporter.linkObjects,
-		LibDeps:     flagExporter.libDeps,
 	})
 }
 
@@ -551,11 +524,10 @@
 type FlagExporterInfo struct {
 	Flags       []string
 	LinkDirs    []string // TODO: this should be android.Paths
-	LinkObjects android.Paths
-	LibDeps     android.Paths
+	LinkObjects []string // TODO: this should be android.Paths
 }
 
-var FlagExporterInfoProvider = blueprint.NewProvider(FlagExporterInfo{})
+var FlagExporterInfoProvider = blueprint.NewProvider[FlagExporterInfo]()
 
 func (mod *Module) isCoverageVariant() bool {
 	return mod.coverage.Properties.IsCoverageVariant
@@ -563,7 +535,7 @@
 
 var _ cc.Coverage = (*Module)(nil)
 
-func (mod *Module) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
+func (mod *Module) IsNativeCoverageNeeded(ctx android.IncomingTransitionContext) bool {
 	return mod.coverage != nil && mod.coverage.Properties.NeedCoverageVariant
 }
 
@@ -613,6 +585,7 @@
 		&cc.RustBindgenClangProperties{},
 		&ClippyProperties{},
 		&SanitizeProperties{},
+		&fuzz.FuzzProperties{},
 	)
 
 	android.InitDefaultsModule(module)
@@ -774,7 +747,8 @@
 }
 
 func (ctx moduleContext) apexVariationName() string {
-	return ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).ApexVariationName
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+	return apexInfo.ApexVariationName
 }
 
 var _ cc.LinkableInterface = (*Module)(nil)
@@ -924,7 +898,7 @@
 		ModuleContext: actx,
 	}
 
-	apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(actx, android.ApexInfoProvider)
 	if !apexInfo.IsForPlatform() {
 		mod.hideApexVariantFromMake = true
 	}
@@ -977,6 +951,7 @@
 			sourceLib := sourceMod.(*Module).compiler.(*libraryDecorator)
 			mod.sourceProvider.setOutputFiles(sourceLib.sourceProvider.Srcs())
 		}
+		android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: mod.sourceProvider.Srcs().Strings()})
 	}
 
 	if mod.compiler != nil && !mod.compiler.Disabled() {
@@ -996,15 +971,7 @@
 			ctx.CheckbuildFile(mod.docTimestampFile.Path())
 		}
 
-		// glob exported headers for snapshot, if BOARD_VNDK_VERSION is current or
-		// RECOVERY_SNAPSHOT_VERSION is current.
-		if lib, ok := mod.compiler.(snapshotLibraryInterface); ok {
-			if cc.ShouldCollectHeadersForSnapshot(ctx, mod, apexInfo) {
-				lib.collectHeadersForSnapshot(ctx, deps)
-			}
-		}
-
-		apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+		apexInfo, _ := android.ModuleProvider(actx, android.ApexInfoProvider)
 		if !proptools.BoolDefault(mod.Installable(), mod.EverInstallable()) && !mod.ProcMacro() {
 			// If the module has been specifically configure to not be installed then
 			// hide from make as otherwise it will break when running inside make as the
@@ -1028,6 +995,11 @@
 
 		ctx.Phony("rust", ctx.RustModule().OutputFile().Path())
 	}
+	if mod.testModule {
+		android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+	}
+
+	android.CollectDependencyAconfigFiles(ctx, &mod.mergedAconfigFiles)
 }
 
 func (mod *Module) deps(ctx DepsContext) Deps {
@@ -1083,6 +1055,12 @@
 	return nil
 }
 
+func (d dependencyTag) PropagateAconfigValidation() bool {
+	return d == rlibDepTag || d == sourceDepTag
+}
+
+var _ android.PropagateAconfigValidationDependencyTag = dependencyTag{}
+
 var _ android.LicenseAnnotationsDependencyTag = dependencyTag{}
 
 var (
@@ -1138,6 +1116,11 @@
 	return nil
 }
 
+func (mod *Module) Symlinks() []string {
+	// TODO update this to return the list of symlinks when Rust supports defining symlinks
+	return nil
+}
+
 func rustMakeLibName(ctx android.ModuleContext, c cc.LinkableInterface, dep cc.LinkableInterface, depName string) string {
 	if rustDep, ok := dep.(*Module); ok {
 		// Use base module name for snapshots when exporting to Makefile.
@@ -1149,6 +1132,14 @@
 	return cc.MakeLibName(ctx, c, dep, depName)
 }
 
+func collectIncludedProtos(mod *Module, dep *Module) {
+	if protoMod, ok := mod.sourceProvider.(*protobufDecorator); ok {
+		if _, ok := dep.sourceProvider.(*protobufDecorator); ok {
+			protoMod.additionalCrates = append(protoMod.additionalCrates, dep.CrateName())
+		}
+	}
+}
+
 func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
 	var depPaths PathDeps
 
@@ -1162,7 +1153,7 @@
 
 	// For the dependency from platform to apex, use the latest stubs
 	mod.apexSdkVersion = android.FutureApiLevel
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
 	if !apexInfo.IsForPlatform() {
 		mod.apexSdkVersion = apexInfo.MinSdkVersion
 	}
@@ -1181,7 +1172,7 @@
 
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		if dep.Name() == "api_imports" {
-			apiImportInfo = ctx.OtherModuleProvider(dep, multitree.ApiImportsProvider).(multitree.ApiImportInfo)
+			apiImportInfo, _ = android.OtherModuleProvider(ctx, dep, multitree.ApiImportsProvider)
 			hasApiImportInfo = true
 		}
 	})
@@ -1217,6 +1208,9 @@
 		})
 	}
 
+	var transitiveAndroidMkSharedLibs []*android.DepSet[string]
+	var directAndroidMkSharedLibs []string
+
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
@@ -1224,6 +1218,11 @@
 		if _, exists := skipModuleList[depName]; exists {
 			return
 		}
+
+		if depTag == android.DarwinUniversalVariantTag {
+			return
+		}
+
 		if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() {
 			//Handle Rust Modules
 			makeLibName := rustMakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName)
@@ -1253,8 +1252,15 @@
 			case procMacroDepTag:
 				directProcMacroDeps = append(directProcMacroDeps, rustDep)
 				mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName)
+
+			case sourceDepTag:
+				if _, ok := mod.sourceProvider.(*protobufDecorator); ok {
+					collectIncludedProtos(mod, rustDep)
+				}
 			}
 
+			transitiveAndroidMkSharedLibs = append(transitiveAndroidMkSharedLibs, rustDep.transitiveAndroidMkSharedLibs)
+
 			if android.IsSourceDepTagWithOutputTag(depTag, "") {
 				// Since these deps are added in path_properties.go via AddDependencies, we need to ensure the correct
 				// OS/Arch variant is used.
@@ -1277,11 +1283,10 @@
 
 			//Append the dependencies exportedDirs, except for proc-macros which target a different arch/OS
 			if depTag != procMacroDepTag {
-				exportedInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo)
+				exportedInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider)
 				depPaths.linkDirs = append(depPaths.linkDirs, exportedInfo.LinkDirs...)
 				depPaths.depFlags = append(depPaths.depFlags, exportedInfo.Flags...)
 				depPaths.linkObjects = append(depPaths.linkObjects, exportedInfo.LinkObjects...)
-				depPaths.LibDeps = append(depPaths.LibDeps, exportedInfo.LibDeps...)
 			}
 
 			if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
@@ -1291,7 +1296,14 @@
 					lib.exportLinkDirs(linkDir)
 				}
 			}
-
+			if depTag == sourceDepTag {
+				if _, ok := mod.sourceProvider.(*protobufDecorator); ok && mod.Source() {
+					if _, ok := rustDep.sourceProvider.(*protobufDecorator); ok {
+						exportedInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider)
+						depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
+					}
+				}
+			}
 		} else if ccDep, ok := dep.(cc.LinkableInterface); ok {
 			//Handle C dependencies
 			makeLibName := cc.MakeLibName(ctx, mod, ccDep, depName)
@@ -1330,7 +1342,6 @@
 						depPaths.depLinkFlags = append(depPaths.depLinkFlags, []string{"-Wl,--whole-archive", linkObject.Path().String(), "-Wl,--no-whole-archive"}...)
 					} else if libName, ok := libNameFromFilePath(linkObject.Path()); ok {
 						depPaths.depFlags = append(depPaths.depFlags, "-lstatic="+libName)
-						depPaths.WholeStaticLibs = append(depPaths.WholeStaticLibs, linkObject.Path())
 					} else {
 						ctx.ModuleErrorf("'%q' cannot be listed as a whole_static_library in Rust modules unless the output is prefixed by 'lib'", depName, ctx.ModuleName())
 					}
@@ -1338,10 +1349,10 @@
 
 				// Add this to linkObjects to pass the library directly to the linker as well. This propagates
 				// to dependencies to avoid having to redeclare static libraries for dependents of the dylib variant.
-				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.AsPaths()...)
+				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
 
-				exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
+				exportedInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider)
 				depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
 				depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...)
 				depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
@@ -1372,7 +1383,7 @@
 				linkPath = linkPathFromFilePath(linkObject.Path())
 
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
-				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.AsPaths()...)
+				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
 				depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
 				depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...)
 				depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
@@ -1382,13 +1393,14 @@
 				// Record baseLibName for snapshots.
 				mod.Properties.SnapshotSharedLibs = append(mod.Properties.SnapshotSharedLibs, cc.BaseLibName(depName))
 
-				mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, makeLibName)
+				directAndroidMkSharedLibs = append(directAndroidMkSharedLibs, makeLibName)
 				exportDep = true
 			case cc.IsHeaderDepTag(depTag):
-				exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
+				exportedInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider)
 				depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
 				depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...)
 				depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...)
+				mod.Properties.AndroidMkHeaderLibs = append(mod.Properties.AndroidMkHeaderLibs, makeLibName)
 			case depTag == cc.CrtBeginDepTag:
 				depPaths.CrtBegin = append(depPaths.CrtBegin, linkObject.Path())
 			case depTag == cc.CrtEndDepTag:
@@ -1398,9 +1410,7 @@
 			// Make sure these dependencies are propagated
 			if lib, ok := mod.compiler.(exportedFlagsProducer); ok && exportDep {
 				lib.exportLinkDirs(linkPath)
-				if linkObject.Valid() {
-					lib.exportLinkObjects(linkObject.Path())
-				}
+				lib.exportLinkObjects(linkObject.String())
 			}
 		} else {
 			switch {
@@ -1419,29 +1429,47 @@
 		}
 	})
 
+	mod.transitiveAndroidMkSharedLibs = android.NewDepSet[string](android.PREORDER, directAndroidMkSharedLibs, transitiveAndroidMkSharedLibs)
+
 	var rlibDepFiles RustLibraries
+	aliases := mod.compiler.Aliases()
 	for _, dep := range directRlibDeps {
-		rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
+		crateName := dep.CrateName()
+		if alias, aliased := aliases[crateName]; aliased {
+			crateName = alias
+		}
+		rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: crateName})
 	}
 	var dylibDepFiles RustLibraries
 	for _, dep := range directDylibDeps {
-		dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
+		crateName := dep.CrateName()
+		if alias, aliased := aliases[crateName]; aliased {
+			crateName = alias
+		}
+		dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: crateName})
 	}
 	var procMacroDepFiles RustLibraries
 	for _, dep := range directProcMacroDeps {
-		procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
+		crateName := dep.CrateName()
+		if alias, aliased := aliases[crateName]; aliased {
+			crateName = alias
+		}
+		procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: crateName})
 	}
 
-	var libDepFiles android.Paths
+	var staticLibDepFiles android.Paths
 	for _, dep := range directStaticLibDeps {
-		libDepFiles = append(libDepFiles, dep.OutputFile().Path())
+		staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile().Path())
 	}
 
+	var sharedLibFiles android.Paths
+	var sharedLibDepFiles android.Paths
 	for _, dep := range directSharedLibDeps {
+		sharedLibFiles = append(sharedLibFiles, dep.SharedLibrary)
 		if dep.TableOfContents.Valid() {
-			libDepFiles = append(libDepFiles, dep.TableOfContents.Path())
+			sharedLibDepFiles = append(sharedLibDepFiles, dep.TableOfContents.Path())
 		} else {
-			libDepFiles = append(libDepFiles, dep.SharedLibrary)
+			sharedLibDepFiles = append(sharedLibDepFiles, dep.SharedLibrary)
 		}
 	}
 
@@ -1457,13 +1485,15 @@
 
 	depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...)
 	depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...)
-	depPaths.LibDeps = append(depPaths.LibDeps, libDepFiles...)
+	depPaths.SharedLibs = append(depPaths.SharedLibs, sharedLibFiles...)
+	depPaths.SharedLibDeps = append(depPaths.SharedLibDeps, sharedLibDepFiles...)
+	depPaths.StaticLibs = append(depPaths.StaticLibs, staticLibDepFiles...)
 	depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...)
 	depPaths.SrcDeps = append(depPaths.SrcDeps, srcProviderDepFiles...)
 
 	// Dedup exported flags from dependencies
 	depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
-	depPaths.linkObjects = android.FirstUniquePaths(depPaths.linkObjects)
+	depPaths.linkObjects = android.FirstUniqueStrings(depPaths.linkObjects)
 	depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
 	depPaths.depClangFlags = android.FirstUniqueStrings(depPaths.depClangFlags)
 	depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths)
@@ -1512,7 +1542,6 @@
 
 	deps := mod.deps(ctx)
 	var commonDepVariations []blueprint.Variation
-	var snapshotInfo *cc.SnapshotInfo
 
 	apiImportInfo := cc.GetApiImports(mod, actx)
 	if mod.usePublicApi() || mod.useVendorApi() {
@@ -1522,7 +1551,7 @@
 	}
 
 	if ctx.Os() == android.Android {
-		deps.SharedLibs, _ = cc.RewriteLibs(mod, &snapshotInfo, actx, ctx.Config(), deps.SharedLibs)
+		deps.SharedLibs, _ = cc.FilterNdkLibs(mod, ctx.Config(), deps.SharedLibs)
 	}
 
 	stdLinkage := "dylib-std"
@@ -1541,53 +1570,64 @@
 	rlibDepVariations = append(rlibDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: rlibVariation})
 	for _, lib := range deps.Rlibs {
 		depTag := rlibDepTag
-		lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
-
 		actx.AddVariationDependencies(rlibDepVariations, depTag, lib)
 	}
 
 	// dylibs
 	dylibDepVariations := append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: dylibVariation})
 	for _, lib := range deps.Dylibs {
-		addDylibDependency(actx, lib, mod, &snapshotInfo, dylibDepVariations, dylibDepTag)
+		actx.AddVariationDependencies(dylibDepVariations, dylibDepTag, lib)
 	}
 
 	// rustlibs
-	if deps.Rustlibs != nil && !mod.compiler.Disabled() {
-		autoDep := mod.compiler.(autoDeppable).autoDep(ctx)
-		for _, lib := range deps.Rustlibs {
-			if autoDep.depTag == rlibDepTag {
-				// Handle the rlib deptag case
-				addRlibDependency(actx, lib, mod, &snapshotInfo, rlibDepVariations)
-			} else {
-				// autoDep.depTag is a dylib depTag. Not all rustlibs may be available as a dylib however.
-				// Check for the existence of the dylib deptag variant. Select it if available,
-				// otherwise select the rlib variant.
-				autoDepVariations := append(commonDepVariations,
-					blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation})
+	if deps.Rustlibs != nil {
+		if !mod.compiler.Disabled() {
+			for _, lib := range deps.Rustlibs {
+				autoDep := mod.compiler.(autoDeppable).autoDep(ctx)
+				if autoDep.depTag == rlibDepTag {
+					// Handle the rlib deptag case
+					actx.AddVariationDependencies(rlibDepVariations, rlibDepTag, lib)
 
-				replacementLib := cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Dylibs)
-
-				if actx.OtherModuleDependencyVariantExists(autoDepVariations, replacementLib) {
-					addDylibDependency(actx, lib, mod, &snapshotInfo, autoDepVariations, autoDep.depTag)
 				} else {
-					// If there's no dylib dependency available, try to add the rlib dependency instead.
-					addRlibDependency(actx, lib, mod, &snapshotInfo, rlibDepVariations)
+					// autoDep.depTag is a dylib depTag. Not all rustlibs may be available as a dylib however.
+					// Check for the existence of the dylib deptag variant. Select it if available,
+					// otherwise select the rlib variant.
+					autoDepVariations := append(commonDepVariations,
+						blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation})
+
+					if actx.OtherModuleDependencyVariantExists(autoDepVariations, lib) {
+						actx.AddVariationDependencies(autoDepVariations, autoDep.depTag, lib)
+
+					} else {
+						// If there's no dylib dependency available, try to add the rlib dependency instead.
+						actx.AddVariationDependencies(rlibDepVariations, rlibDepTag, lib)
+
+					}
+				}
+			}
+		} else if _, ok := mod.sourceProvider.(*protobufDecorator); ok {
+			for _, lib := range deps.Rustlibs {
+				srcProviderVariations := append(commonDepVariations,
+					blueprint.Variation{Mutator: "rust_libraries", Variation: "source"})
+
+				if actx.OtherModuleDependencyVariantExists(srcProviderVariations, lib) {
+					actx.AddVariationDependencies(srcProviderVariations, sourceDepTag, lib)
 				}
 			}
 		}
 	}
+
 	// stdlibs
 	if deps.Stdlibs != nil {
 		if mod.compiler.stdLinkage(ctx) == RlibLinkage {
 			for _, lib := range deps.Stdlibs {
-				lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
 				actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}...),
 					rlibDepTag, lib)
 			}
 		} else {
 			for _, lib := range deps.Stdlibs {
-				addDylibDependency(actx, lib, mod, &snapshotInfo, dylibDepVariations, dylibDepTag)
+				actx.AddVariationDependencies(dylibDepVariations, dylibDepTag, lib)
+
 			}
 		}
 	}
@@ -1612,7 +1652,6 @@
 
 	for _, lib := range deps.WholeStaticLibs {
 		depTag := cc.StaticDepTag(true)
-		lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).StaticLibs)
 
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
@@ -1621,7 +1660,6 @@
 
 	for _, lib := range deps.StaticLibs {
 		depTag := cc.StaticDepTag(false)
-		lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).StaticLibs)
 
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
@@ -1632,12 +1670,10 @@
 
 	crtVariations := cc.GetCrtVariations(ctx, mod)
 	for _, crt := range deps.CrtBegin {
-		actx.AddVariationDependencies(crtVariations, cc.CrtBeginDepTag,
-			cc.GetReplaceModuleName(crt, cc.GetSnapshot(mod, &snapshotInfo, actx).Objects))
+		actx.AddVariationDependencies(crtVariations, cc.CrtBeginDepTag, crt)
 	}
 	for _, crt := range deps.CrtEnd {
-		actx.AddVariationDependencies(crtVariations, cc.CrtEndDepTag,
-			cc.GetReplaceModuleName(crt, cc.GetSnapshot(mod, &snapshotInfo, actx).Objects))
+		actx.AddVariationDependencies(crtVariations, cc.CrtEndDepTag, crt)
 	}
 
 	if mod.sourceProvider != nil {
@@ -1660,17 +1696,6 @@
 	mod.afdo.addDep(ctx, actx)
 }
 
-// addRlibDependency will add an rlib dependency, rewriting to the snapshot library if available.
-func addRlibDependency(actx android.BottomUpMutatorContext, lib string, mod *Module, snapshotInfo **cc.SnapshotInfo, variations []blueprint.Variation) {
-	lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, snapshotInfo, actx).Rlibs)
-	actx.AddVariationDependencies(variations, rlibDepTag, lib)
-}
-
-func addDylibDependency(actx android.BottomUpMutatorContext, lib string, mod *Module, snapshotInfo **cc.SnapshotInfo, variations []blueprint.Variation, depTag dependencyTag) {
-	lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, snapshotInfo, actx).Dylibs)
-	actx.AddVariationDependencies(variations, depTag, lib)
-}
-
 func BeginMutator(ctx android.BottomUpMutatorContext) {
 	if mod, ok := ctx.Module().(*Module); ok && mod.Enabled() {
 		mod.beginMutator(ctx)
@@ -1702,7 +1727,6 @@
 }
 
 var _ android.HostToolProvider = (*Module)(nil)
-var _ snapshot.RelativeInstallPath = (*Module)(nil)
 
 func (mod *Module) HostToolPath() android.OptionalPath {
 	if !mod.Host() {
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 3f4e296..6d083f6 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -37,12 +37,7 @@
 
 	genrule.PrepareForTestWithGenRuleBuildComponents,
 
-	PrepareForTestWithRustIncludeVndk,
-	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-		variables.DeviceVndkVersion = StringPtr("current")
-		variables.ProductVndkVersion = StringPtr("current")
-		variables.Platform_vndk_version = StringPtr("29")
-	}),
+	PrepareForIntegrationTestWithRust,
 )
 
 var rustMockedFiles = android.MockFS{
@@ -74,61 +69,21 @@
 	return result.TestContext
 }
 
-func testRustVndk(t *testing.T, bp string) *android.TestContext {
-	return testRustVndkFs(t, bp, rustMockedFiles)
-}
-
 const (
-	sharedVendorVariant        = "android_vendor.29_arm64_armv8-a_shared"
-	rlibVendorVariant          = "android_vendor.29_arm64_armv8-a_rlib_rlib-std"
-	rlibDylibStdVendorVariant  = "android_vendor.29_arm64_armv8-a_rlib_rlib-std"
-	dylibVendorVariant         = "android_vendor.29_arm64_armv8-a_dylib"
+	sharedVendorVariant        = "android_vendor_arm64_armv8-a_shared"
+	rlibVendorVariant          = "android_vendor_arm64_armv8-a_rlib_rlib-std"
+	rlibDylibStdVendorVariant  = "android_vendor_arm64_armv8-a_rlib_rlib-std"
+	dylibVendorVariant         = "android_vendor_arm64_armv8-a_dylib"
 	sharedRecoveryVariant      = "android_recovery_arm64_armv8-a_shared"
 	rlibRecoveryVariant        = "android_recovery_arm64_armv8-a_rlib_dylib-std"
 	rlibRlibStdRecoveryVariant = "android_recovery_arm64_armv8-a_rlib_rlib-std"
 	dylibRecoveryVariant       = "android_recovery_arm64_armv8-a_dylib"
 	binaryCoreVariant          = "android_arm64_armv8-a"
-	binaryVendorVariant        = "android_vendor.29_arm64_armv8-a"
-	binaryProductVariant       = "android_product.29_arm64_armv8-a"
+	binaryVendorVariant        = "android_vendor_arm64_armv8-a"
+	binaryProductVariant       = "android_product_arm64_armv8-a"
 	binaryRecoveryVariant      = "android_recovery_arm64_armv8-a"
 )
 
-func testRustVndkFs(t *testing.T, bp string, fs android.MockFS) *android.TestContext {
-	return testRustVndkFsVersions(t, bp, fs, "current", "current", "29")
-}
-
-func testRustVndkFsVersions(t *testing.T, bp string, fs android.MockFS, device_version, product_version, vndk_version string) *android.TestContext {
-	skipTestIfOsNotSupported(t)
-	result := android.GroupFixturePreparers(
-		prepareForRustTest,
-		fs.AddToFixture(),
-		android.FixtureModifyProductVariables(
-			func(variables android.FixtureProductVariables) {
-				variables.DeviceVndkVersion = StringPtr(device_version)
-				variables.ProductVndkVersion = StringPtr(product_version)
-				variables.Platform_vndk_version = StringPtr(vndk_version)
-			},
-		),
-	).RunTestWithBp(t, bp)
-	return result.TestContext
-}
-
-func testRustRecoveryFsVersions(t *testing.T, bp string, fs android.MockFS, device_version, vndk_version, recovery_version string) *android.TestContext {
-	skipTestIfOsNotSupported(t)
-	result := android.GroupFixturePreparers(
-		prepareForRustTest,
-		fs.AddToFixture(),
-		android.FixtureModifyProductVariables(
-			func(variables android.FixtureProductVariables) {
-				variables.DeviceVndkVersion = StringPtr(device_version)
-				variables.RecoverySnapshotVersion = StringPtr(recovery_version)
-				variables.Platform_vndk_version = StringPtr(vndk_version)
-			},
-		),
-	).RunTestWithBp(t, bp)
-	return result.TestContext
-}
-
 // testRustCov returns a TestContext in which a basic environment has been
 // setup. This environment explicitly enables coverage.
 func testRustCov(t *testing.T, bp string) *android.TestContext {
@@ -160,28 +115,6 @@
 		RunTestWithBp(t, bp)
 }
 
-// testRustVndkError is similar to testRustError, but can be used to test VNDK-related errors.
-func testRustVndkError(t *testing.T, pattern string, bp string) {
-	testRustVndkFsError(t, pattern, bp, rustMockedFiles)
-}
-
-func testRustVndkFsError(t *testing.T, pattern string, bp string, fs android.MockFS) {
-	skipTestIfOsNotSupported(t)
-	android.GroupFixturePreparers(
-		prepareForRustTest,
-		fs.AddToFixture(),
-		android.FixtureModifyProductVariables(
-			func(variables android.FixtureProductVariables) {
-				variables.DeviceVndkVersion = StringPtr("current")
-				variables.ProductVndkVersion = StringPtr("current")
-				variables.Platform_vndk_version = StringPtr("VER")
-			},
-		),
-	).
-		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)).
-		RunTestWithBp(t, bp)
-}
-
 // testRustCtx is used to build a particular test environment. Unless your
 // tests requires a specific setup, prefer the wrapping functions: testRust,
 // testRustCov or testRustError.
@@ -232,11 +165,6 @@
 			srcs: ["foo.rs"],
 			crate_name: "shared",
 		}
-		rust_library_host_dylib {
-			name: "libdylib",
-			srcs: ["foo.rs"],
-			crate_name: "dylib",
-		}
 		rust_library_host_rlib {
 			name: "librlib",
 			srcs: ["foo.rs"],
@@ -252,7 +180,6 @@
 		}
 		rust_binary_host {
 			name: "fizz-buzz",
-			dylibs: ["libdylib"],
 			rlibs: ["librlib"],
 			proc_macros: ["libpm"],
 			static_libs: ["libstatic"],
@@ -262,13 +189,8 @@
 	`)
 	module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
 	rustc := ctx.ModuleForTests("librlib", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
-	rustLink := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustLink")
 
 	// Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up.
-	if !android.InList("libdylib", module.Properties.AndroidMkDylibs) {
-		t.Errorf("Dylib dependency not detected (dependency missing from AndroidMkDylibs)")
-	}
-
 	if !android.InList("librlib.rlib-std", module.Properties.AndroidMkRlibs) {
 		t.Errorf("Rlib dependency not detected (dependency missing from AndroidMkRlibs)")
 	}
@@ -277,7 +199,7 @@
 		t.Errorf("Proc_macro dependency not detected (dependency missing from AndroidMkProcMacroLibs)")
 	}
 
-	if !android.InList("libshared", module.Properties.AndroidMkSharedLibs) {
+	if !android.InList("libshared", module.transitiveAndroidMkSharedLibs.ToList()) {
 		t.Errorf("Shared library dependency not detected (dependency missing from AndroidMkSharedLibs)")
 	}
 
@@ -289,16 +211,16 @@
 		t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.Args["rustcFlags"])
 	}
 
-	if !strings.Contains(rustLink.Args["linkFlags"], "cc_stubs_dep.so") {
-		t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustLink.Args["linkFlags"])
+	if !strings.Contains(rustc.Args["linkFlags"], "cc_stubs_dep.so") {
+		t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustc.Args["linkFlags"])
 	}
 
-	if !android.SuffixInList(rustLink.OrderOnly.Strings(), "cc_stubs_dep.so") {
-		t.Errorf("shared cc dep not being passed as order-only to rustc %#v", rustLink.OrderOnly.Strings())
+	if !android.SuffixInList(rustc.OrderOnly.Strings(), "cc_stubs_dep.so") {
+		t.Errorf("shared cc dep not being passed as order-only to rustc %#v", rustc.OrderOnly.Strings())
 	}
 
-	if !android.SuffixInList(rustLink.Implicits.Strings(), "cc_stubs_dep.so.toc") {
-		t.Errorf("shared cc dep TOC not being passed as implicit to rustc %#v", rustLink.Implicits.Strings())
+	if !android.SuffixInList(rustc.Implicits.Strings(), "cc_stubs_dep.so.toc") {
+		t.Errorf("shared cc dep TOC not being passed as implicit to rustc %#v", rustc.Implicits.Strings())
 	}
 }
 
@@ -484,6 +406,35 @@
 	m.Output("libwaldo.dylib.so.bloaty.csv")
 }
 
+// Test that aliases are respected.
+func TestRustAliases(t *testing.T) {
+	ctx := testRust(t, `
+		rust_library {
+			name: "libbar",
+			crate_name: "bar",
+			srcs: ["src/lib.rs"],
+		}
+		rust_library {
+			name: "libbaz",
+			crate_name: "baz",
+			srcs: ["src/lib.rs"],
+		}
+		rust_binary {
+			name: "foo",
+			srcs: ["src/main.rs"],
+			rustlibs: ["libbar", "libbaz"],
+			aliases: ["bar:bar_renamed"],
+		}`)
+
+	fooRustc := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
+	if !strings.Contains(fooRustc.Args["libFlags"], "--extern bar_renamed=out/soong/.intermediates/libbar/android_arm64_armv8-a_dylib/unstripped/libbar.dylib.so") {
+		t.Errorf("--extern bar_renamed=out/soong/.intermediates/libbar/android_arm64_armv8-a_dylib/unstripped/libbar.dylib.so flag not being passed to rustc for rust_binary with aliases. libFlags: %#v", fooRustc.Args["libFlags"])
+	}
+	if !strings.Contains(fooRustc.Args["libFlags"], "--extern baz=out/soong/.intermediates/libbaz/android_arm64_armv8-a_dylib/unstripped/libbaz.dylib.so") {
+		t.Errorf("--extern baz=out/soong/.intermediates/libbaz/android_arm64_armv8-a_dylib/unstripped/libbaz.dylib.so flag not being passed to rustc for rust_binary with aliases. libFlags: %#v", fooRustc.Args["libFlags"])
+	}
+}
+
 func assertString(t *testing.T, got, expected string) {
 	t.Helper()
 	if got != expected {
diff --git a/rust/sanitize.go b/rust/sanitize.go
index 862baf7..bfd3971 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -56,6 +56,8 @@
 }
 
 var fuzzerFlags = []string{
+	"-Z external-clangrt=true",
+
 	"-C passes='sancov-module'",
 
 	"--cfg fuzzing",
@@ -73,11 +75,13 @@
 }
 
 var asanFlags = []string{
+	"-Z external-clangrt=true",
 	"-Z sanitizer=address",
 }
 
 // See cc/sanitize.go's hwasanGlobalOptions for global hwasan options.
 var hwasanFlags = []string{
+	"-Z external-clangrt=true",
 	"-Z sanitizer=hwaddress",
 	"-C target-feature=+tagged-globals",
 
@@ -208,9 +212,14 @@
 		s.Memtag_heap = nil
 	}
 
+	// Disable sanitizers for musl x86 modules, rustc does not support any sanitizers.
+	if ctx.Os() == android.LinuxMusl && ctx.Arch().ArchType == android.X86 {
+		s.Never = boolPtr(true)
+	}
+
 	// TODO:(b/178369775)
-	// For now sanitizing is only supported on devices
-	if ctx.Os() == android.Android && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap) || Bool(s.Fuzzer)) {
+	// For now sanitizing is only supported on non-windows targets
+	if ctx.Os() != android.Windows && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap) || Bool(s.Fuzzer)) {
 		sanitize.Properties.SanitizerEnabled = true
 	}
 }
@@ -234,6 +243,11 @@
 
 	if Bool(sanitize.Properties.Sanitize.Address) {
 		flags.RustFlags = append(flags.RustFlags, asanFlags...)
+		if ctx.Host() {
+			// -nodefaultlibs (provided with libc++) prevents the driver from linking
+			// libraries needed with -fsanitize=address. http://b/18650275 (WAI)
+			flags.LinkFlags = append(flags.LinkFlags, []string{"-Wl,--no-as-needed"}...)
+		}
 	}
 	return flags, deps
 }
@@ -253,12 +267,6 @@
 			if Bool(mod.sanitize.Properties.Sanitize.Diag.Memtag_heap) {
 				noteDep = "note_memtag_heap_sync"
 			}
-			// If we're using snapshots, redirect to snapshot whenever possible
-			// TODO(b/178470649): clean manual snapshot redirections
-			snapshot := mctx.Provider(cc.SnapshotInfoProvider).(cc.SnapshotInfo)
-			if lib, ok := snapshot.StaticLibs[noteDep]; ok {
-				noteDep = lib
-			}
 			depTag := cc.StaticDepTag(true)
 			variations := append(mctx.Target().Variations(),
 				blueprint.Variation{Mutator: "link", Variation: "static"})
@@ -273,10 +281,17 @@
 		var deps []string
 
 		if mod.IsSanitizerEnabled(cc.Asan) {
-			variations = append(variations,
-				blueprint.Variation{Mutator: "link", Variation: "shared"})
-			depTag = cc.SharedDepTag()
-			deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")}
+			if mod.Host() {
+				variations = append(variations,
+					blueprint.Variation{Mutator: "link", Variation: "static"})
+				depTag = cc.StaticDepTag(false)
+				deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan.static")}
+			} else {
+				variations = append(variations,
+					blueprint.Variation{Mutator: "link", Variation: "shared"})
+				depTag = cc.SharedDepTag()
+				deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")}
+			}
 		} else if mod.IsSanitizerEnabled(cc.Hwasan) {
 			// TODO(b/204776996): HWASan for static Rust binaries isn't supported yet.
 			if binary, ok := mod.compiler.(binaryInterface); ok {
@@ -391,7 +406,8 @@
 }
 
 func (mod *Module) SanitizerSupported(t cc.SanitizerType) bool {
-	if mod.Host() {
+	// Sanitizers are not supported on Windows targets.
+	if mod.Os() == android.Windows {
 		return false
 	}
 	switch t {
@@ -417,7 +433,8 @@
 }
 
 func (mod *Module) IsSanitizerExplicitlyDisabled(t cc.SanitizerType) bool {
-	if mod.Host() {
+	// Sanitizers are not supported on Windows targets.
+	if mod.Os() == android.Windows {
 		return true
 	}
 
diff --git a/rust/sanitize_test.go b/rust/sanitize_test.go
index 43e95f4..d6a14b2 100644
--- a/rust/sanitize_test.go
+++ b/rust/sanitize_test.go
@@ -35,7 +35,7 @@
 	note_sync := "note_memtag_heap_sync"
 
 	found := None
-	implicits := m.Rule("rustLink").Implicits
+	implicits := m.Rule("rustc").Implicits
 	for _, lib := range implicits {
 		if strings.Contains(lib.Rel(), note_async) {
 			found = Async
diff --git a/rust/snapshot_prebuilt.go b/rust/snapshot_prebuilt.go
deleted file mode 100644
index 32d3916..0000000
--- a/rust/snapshot_prebuilt.go
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package rust
-
-import (
-	"android/soong/android"
-	"android/soong/cc"
-
-	"github.com/google/blueprint/proptools"
-)
-
-type snapshotLibraryDecorator struct {
-	cc.BaseSnapshotDecorator
-	*libraryDecorator
-	properties          cc.SnapshotLibraryProperties
-	sanitizerProperties struct {
-		CfiEnabled bool `blueprint:"mutated"`
-
-		// Library flags for cfi variant.
-		Cfi cc.SnapshotLibraryProperties `android:"arch_variant"`
-	}
-}
-
-func init() {
-	registerRustSnapshotModules(android.InitRegistrationContext)
-}
-
-func registerRustSnapshotModules(ctx android.RegistrationContext) {
-	cc.VendorSnapshotImageSingleton.RegisterAdditionalModule(ctx,
-		"vendor_snapshot_rlib", VendorSnapshotRlibFactory)
-	cc.VendorSnapshotImageSingleton.RegisterAdditionalModule(ctx,
-		"vendor_snapshot_dylib", VendorSnapshotDylibFactory)
-	cc.RecoverySnapshotImageSingleton.RegisterAdditionalModule(ctx,
-		"recovery_snapshot_rlib", RecoverySnapshotRlibFactory)
-}
-
-func snapshotLibraryFactory(image cc.SnapshotImage, moduleSuffix string) (*Module, *snapshotLibraryDecorator) {
-	module, library := NewRustLibrary(android.DeviceSupported)
-
-	module.sanitize = nil
-	library.stripper.StripProperties.Strip.None = proptools.BoolPtr(true)
-
-	prebuilt := &snapshotLibraryDecorator{
-		libraryDecorator: library,
-	}
-
-	module.compiler = prebuilt
-
-	prebuilt.Init(module, image, moduleSuffix)
-	module.AddProperties(
-		&prebuilt.properties,
-		&prebuilt.sanitizerProperties,
-	)
-
-	return module, prebuilt
-}
-
-func (library *snapshotLibraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
-	var variant string
-	if library.static() {
-		variant = cc.SnapshotStaticSuffix
-	} else if library.shared() {
-		variant = cc.SnapshotSharedSuffix
-	} else if library.rlib() {
-		variant = cc.SnapshotRlibSuffix
-	} else if library.dylib() {
-		variant = cc.SnapshotDylibSuffix
-	}
-
-	library.SetSnapshotAndroidMkSuffix(ctx, variant)
-
-	if !library.MatchesWithDevice(ctx.DeviceConfig()) {
-		return buildOutput{}
-	}
-	outputFile := android.PathForModuleSrc(ctx, *library.properties.Src)
-	library.unstrippedOutputFile = outputFile
-	return buildOutput{outputFile: outputFile}
-}
-
-func (library *snapshotLibraryDecorator) rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath {
-	return android.OptionalPath{}
-}
-
-// vendor_snapshot_rlib is a special prebuilt rlib library which is auto-generated by
-// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_rlib
-// overrides the vendor variant of the rust rlib library with the same name, if BOARD_VNDK_VERSION
-// is set.
-func VendorSnapshotRlibFactory() android.Module {
-	module, prebuilt := snapshotLibraryFactory(cc.VendorSnapshotImageSingleton, cc.SnapshotRlibSuffix)
-	prebuilt.libraryDecorator.BuildOnlyRlib()
-	prebuilt.libraryDecorator.setNoStdlibs()
-	return module.Init()
-}
-
-// vendor_snapshot_dylib is a special prebuilt dylib library which is auto-generated by
-// development/vendor_snapshot/update.py. As a part of vendor snapshot, vendor_snapshot_dylib
-// overrides the vendor variant of the rust dylib library with the same name, if BOARD_VNDK_VERSION
-// is set.
-func VendorSnapshotDylibFactory() android.Module {
-	module, prebuilt := snapshotLibraryFactory(cc.VendorSnapshotImageSingleton, cc.SnapshotDylibSuffix)
-	prebuilt.libraryDecorator.BuildOnlyDylib()
-	prebuilt.libraryDecorator.setNoStdlibs()
-	return module.Init()
-}
-
-func RecoverySnapshotRlibFactory() android.Module {
-	module, prebuilt := snapshotLibraryFactory(cc.RecoverySnapshotImageSingleton, cc.SnapshotRlibSuffix)
-	prebuilt.libraryDecorator.BuildOnlyRlib()
-	prebuilt.libraryDecorator.setNoStdlibs()
-	return module.Init()
-}
-
-func (library *snapshotLibraryDecorator) MatchesWithDevice(config android.DeviceConfig) bool {
-	arches := config.Arches()
-	if len(arches) == 0 || arches[0].ArchType.String() != library.Arch() {
-		return false
-	}
-	if library.properties.Src == nil {
-		return false
-	}
-	return true
-}
-
-func (library *snapshotLibraryDecorator) IsSnapshotPrebuilt() bool {
-	return true
-}
-
-var _ cc.SnapshotInterface = (*snapshotLibraryDecorator)(nil)
diff --git a/rust/snapshot_utils.go b/rust/snapshot_utils.go
deleted file mode 100644
index 55c85e6..0000000
--- a/rust/snapshot_utils.go
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package rust
-
-import (
-	"android/soong/android"
-)
-
-// snapshotLibraryInterface is an interface for libraries captured to VNDK / vendor snapshots.
-type snapshotLibraryInterface interface {
-	libraryInterface
-
-	// collectHeadersForSnapshot is called in GenerateAndroidBuildActions for snapshot aware
-	// modules (See isSnapshotAware below).
-	// This function should gather all headers needed for snapshot.
-	collectHeadersForSnapshot(ctx android.ModuleContext, deps PathDeps)
-
-	// snapshotHeaders should return collected headers by collectHeadersForSnapshot.
-	// Calling snapshotHeaders before collectHeadersForSnapshot is an error.
-	snapshotHeaders() android.Paths
-}
-
-func (mod *Module) ExcludeFromVendorSnapshot() bool {
-	return Bool(mod.Properties.Exclude_from_vendor_snapshot)
-}
-
-func (mod *Module) ExcludeFromRecoverySnapshot() bool {
-	return Bool(mod.Properties.Exclude_from_recovery_snapshot)
-}
-
-func (mod *Module) IsSnapshotLibrary() bool {
-	if lib, ok := mod.compiler.(libraryInterface); ok {
-		return lib.shared() || lib.static() || lib.rlib() || lib.dylib()
-	}
-	return false
-}
-
-func (mod *Module) SnapshotRuntimeLibs() []string {
-	// TODO Rust does not yet support a runtime libs notion similar to CC
-	return []string{}
-}
-
-func (mod *Module) SnapshotSharedLibs() []string {
-	return mod.Properties.SnapshotSharedLibs
-}
-
-func (mod *Module) SnapshotStaticLibs() []string {
-	return mod.Properties.SnapshotStaticLibs
-}
-
-func (mod *Module) SnapshotRlibs() []string {
-	return mod.Properties.SnapshotRlibs
-}
-
-func (mod *Module) SnapshotDylibs() []string {
-	return mod.Properties.SnapshotDylibs
-}
-
-func (mod *Module) Symlinks() []string {
-	// TODO update this to return the list of symlinks when Rust supports defining symlinks
-	return nil
-}
-
-func (m *Module) SnapshotHeaders() android.Paths {
-	if l, ok := m.compiler.(snapshotLibraryInterface); ok {
-		return l.snapshotHeaders()
-	}
-	return android.Paths{}
-}
diff --git a/rust/test.go b/rust/test.go
index 4b5296e..2583893 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -117,7 +117,7 @@
 
 func (test *testDecorator) install(ctx ModuleContext) {
 	testInstallBase := "/data/local/tests/unrestricted"
-	if ctx.RustModule().InVendor() || ctx.RustModule().UseVndk() {
+	if ctx.RustModule().InVendorOrProduct() {
 		testInstallBase = "/data/local/tests/vendor"
 	}
 
@@ -189,6 +189,7 @@
 	if ctx.Host() && test.Properties.Test_options.Unit_test == nil {
 		test.Properties.Test_options.Unit_test = proptools.BoolPtr(true)
 	}
+	test.binaryDecorator.installTestData(ctx, test.data)
 	test.binaryDecorator.install(ctx)
 }
 
@@ -222,11 +223,13 @@
 	// rustTestHostMultilib load hook to set MultilibFirst for the
 	// host target.
 	android.AddLoadHook(module, rustTestHostMultilib)
+	module.testModule = true
 	return module.Init()
 }
 
 func RustTestHostFactory() android.Module {
 	module, _ := NewRustTest(android.HostSupported)
+	module.testModule = true
 	return module.Init()
 }
 
diff --git a/rust/test_test.go b/rust/test_test.go
index 8906f1c..6d0ebcf 100644
--- a/rust/test_test.go
+++ b/rust/test_test.go
@@ -38,7 +38,7 @@
 
 	dataPaths := testingModule.Module().(*Module).compiler.(*testDecorator).dataPaths()
 	if len(dataPaths) != 1 {
-		t.Errorf("expected exactly one test data file. test data files: [%s]", dataPaths)
+		t.Errorf("expected exactly one test data file. test data files: [%v]", dataPaths)
 		return
 	}
 }
@@ -116,7 +116,7 @@
 		t.Fatalf("expected exactly one output file. output files: [%s]", outputFiles)
 	}
 	if len(testBinary.dataPaths()) != 2 {
-		t.Fatalf("expected exactly two test data files. test data files: [%s]", testBinary.dataPaths())
+		t.Fatalf("expected exactly two test data files. test data files: [%v]", testBinary.dataPaths())
 	}
 
 	outputPath := outputFiles[0].String()
@@ -178,7 +178,7 @@
 		t.Fatalf("expected exactly one output file. output files: [%s]", outputFiles)
 	}
 	if len(testBinary.dataPaths()) != 3 {
-		t.Fatalf("expected exactly two test data files. test data files: [%s]", testBinary.dataPaths())
+		t.Fatalf("expected exactly two test data files. test data files: [%v]", testBinary.dataPaths())
 	}
 
 	outputPath := outputFiles[0].String()
diff --git a/rust/testing.go b/rust/testing.go
index 7f30569..5837dcc 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -43,11 +43,7 @@
 // Preparer that will allow use of all rust modules fully.
 var PrepareForIntegrationTestWithRust = android.GroupFixturePreparers(
 	PrepareForTestWithRustDefaultModules,
-)
-
-var PrepareForTestWithRustIncludeVndk = android.GroupFixturePreparers(
-	PrepareForIntegrationTestWithRust,
-	cc.PrepareForTestWithCcIncludeVndk,
+	cc.PrepareForIntegrationTestWithCc,
 )
 
 func GatherRequiredDepsForTest() string {
@@ -75,6 +71,7 @@
 			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
 			min_sdk_version: "29",
 			vendor_available: true,
+			host_supported: true,
 			recovery_available: true,
 			llndk: {
 				symbol_file: "liblog.map.txt",
@@ -133,12 +130,6 @@
 			host_supported: true,
 		}
 		rust_library {
-			name: "libprotobuf_deprecated",
-			crate_name: "protobuf",
-			srcs: ["foo.rs"],
-			host_supported: true,
-		}
-		rust_library {
 			name: "libgrpcio",
 			crate_name: "grpcio",
 			srcs: ["foo.rs"],
@@ -182,6 +173,7 @@
 	ctx.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
 	ctx.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
 	ctx.RegisterModuleType("rust_fuzz", RustFuzzFactory)
+	ctx.RegisterModuleType("rust_fuzz_host", RustFuzzHostFactory)
 	ctx.RegisterModuleType("rust_ffi", RustFFIFactory)
 	ctx.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
 	ctx.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory)
@@ -205,5 +197,4 @@
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
 	})
-	registerRustSnapshotModules(ctx)
 }
diff --git a/rust/toolchain_library.go b/rust/toolchain_library.go
index 326d529..054104c 100644
--- a/rust/toolchain_library.go
+++ b/rust/toolchain_library.go
@@ -18,9 +18,12 @@
 
 import (
 	"path"
+	"path/filepath"
 
 	"android/soong/android"
 	"android/soong/rust/config"
+
+	"github.com/google/blueprint/proptools"
 )
 
 // This module is used to compile the rust toolchain libraries
@@ -33,11 +36,15 @@
 		rustToolchainLibraryRlibFactory)
 	android.RegisterModuleType("rust_toolchain_library_dylib",
 		rustToolchainLibraryDylibFactory)
+	android.RegisterModuleType("rust_toolchain_rustc_prebuilt",
+		rustToolchainRustcPrebuiltFactory)
 }
 
 type toolchainLibraryProperties struct {
-	// path to the toolchain source, relative to the top of the toolchain source
-	Toolchain_src *string `android:"arch_variant"`
+	// path to the toolchain crate root, relative to the top of the toolchain source
+	Toolchain_crate_root *string `android:"arch_variant"`
+	// path to the rest of the toolchain srcs, relative to the top of the toolchain source
+	Toolchain_srcs []string `android:"arch_variant"`
 }
 
 type toolchainLibraryDecorator struct {
@@ -82,16 +89,21 @@
 
 func rustSetToolchainSource(ctx android.LoadHookContext) {
 	if toolchainLib, ok := ctx.Module().(*Module).compiler.(*toolchainLibraryDecorator); ok {
-		prefix := "linux-x86/" + GetRustPrebuiltVersion(ctx)
-		newSrcs := []string{path.Join(prefix, android.String(toolchainLib.Properties.Toolchain_src))}
+		prefix := filepath.Join("linux-x86", GetRustPrebuiltVersion(ctx))
+		versionedCrateRoot := path.Join(prefix, android.String(toolchainLib.Properties.Toolchain_crate_root))
+		versionedSrcs := make([]string, len(toolchainLib.Properties.Toolchain_srcs))
+		for i, src := range toolchainLib.Properties.Toolchain_srcs {
+			versionedSrcs[i] = path.Join(prefix, src)
+		}
 
 		type props struct {
-			Srcs []string
+			Crate_root *string
+			Srcs       []string
 		}
 		p := &props{}
-		p.Srcs = newSrcs
+		p.Crate_root = &versionedCrateRoot
+		p.Srcs = versionedSrcs
 		ctx.AppendProperties(p)
-
 	} else {
 		ctx.ModuleErrorf("Called rustSetToolchainSource on a non-Rust Module.")
 	}
@@ -101,3 +113,47 @@
 func GetRustPrebuiltVersion(ctx android.LoadHookContext) string {
 	return ctx.AConfig().GetenvWithDefault("RUST_PREBUILTS_VERSION", config.RustDefaultVersion)
 }
+
+type toolchainRustcPrebuiltProperties struct {
+	// path to rustc prebuilt, relative to the top of the toolchain source
+	Toolchain_prebuilt_src *string
+	// path to deps, relative to the top of the toolchain source
+	Toolchain_deps []string
+	// path to deps, relative to module directory
+	Deps []string
+}
+
+func rustToolchainRustcPrebuiltFactory() android.Module {
+	module := android.NewPrebuiltBuildTool()
+	module.AddProperties(&toolchainRustcPrebuiltProperties{})
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		var toolchainProps *toolchainRustcPrebuiltProperties
+		for _, p := range ctx.Module().GetProperties() {
+			toolchainProperties, ok := p.(*toolchainRustcPrebuiltProperties)
+			if ok {
+				toolchainProps = toolchainProperties
+			}
+		}
+
+		if toolchainProps.Toolchain_prebuilt_src == nil {
+			ctx.PropertyErrorf("toolchain_prebuilt_src", "must set path to rustc prebuilt")
+		}
+
+		prefix := filepath.Join(config.HostPrebuiltTag(ctx.Config()), GetRustPrebuiltVersion(ctx))
+		deps := make([]string, 0, len(toolchainProps.Toolchain_deps)+len(toolchainProps.Deps))
+		for _, d := range toolchainProps.Toolchain_deps {
+			deps = append(deps, path.Join(prefix, d))
+		}
+		deps = append(deps, toolchainProps.Deps...)
+
+		props := struct {
+			Src  *string
+			Deps []string
+		}{
+			Src:  proptools.StringPtr(path.Join(prefix, *toolchainProps.Toolchain_prebuilt_src)),
+			Deps: deps,
+		}
+		ctx.AppendProperties(&props)
+	})
+	return module
+}
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
deleted file mode 100644
index 387d170..0000000
--- a/rust/vendor_snapshot_test.go
+++ /dev/null
@@ -1,1568 +0,0 @@
-// Copyright 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package rust
-
-import (
-	"fmt"
-	"path/filepath"
-	"reflect"
-	"strings"
-	"testing"
-
-	"android/soong/android"
-	"android/soong/cc"
-)
-
-func TestVendorSnapshotCapture(t *testing.T) {
-	bp := `
-	rust_ffi {
-		name: "libffivendor_available",
-		crate_name: "ffivendor_available",
-		srcs: ["lib.rs"],
-		vendor_available: true,
-		include_dirs: ["rust_headers/"],
-	}
-
-	rust_ffi {
-		name: "libffivendor",
-		crate_name: "ffivendor",
-		srcs: ["lib.rs"],
-		vendor: true,
-		include_dirs: ["rust_headers/"],
-	}
-
-	rust_library {
-		name: "librustvendor_available",
-		crate_name: "rustvendor_available",
-		srcs: ["lib.rs"],
-		vendor_available: true,
-	}
-
-	rust_library {
-		name: "librustvendor",
-		crate_name: "rustvendor",
-		srcs: ["lib.rs"],
-		vendor: true,
-	}
-
-	rust_binary {
-		name: "vendor_available_bin",
-		vendor_available: true,
-		srcs: ["srcs/lib.rs"],
-	}
-
-	rust_binary {
-		name: "vendor_bin",
-		vendor: true,
-		srcs: ["srcs/lib.rs"],
-	}
-    `
-	skipTestIfOsNotSupported(t)
-	result := android.GroupFixturePreparers(
-		prepareForRustTest,
-		rustMockedFiles.AddToFixture(),
-		android.FixtureModifyProductVariables(
-			func(variables android.FixtureProductVariables) {
-				variables.DeviceVndkVersion = StringPtr("current")
-				variables.Platform_vndk_version = StringPtr("29")
-			},
-		),
-	).RunTestWithBp(t, bp)
-	ctx := result.TestContext
-
-	// Check Vendor snapshot output.
-
-	snapshotDir := "vendor-snapshot"
-	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
-	var jsonFiles []string
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-		[]string{"arm", "armv7-a-neon"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		// For shared libraries, only non-VNDK vendor_available modules are captured
-		sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "libffivendor_available", "libffivendor_available.so", sharedDir, sharedVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(sharedDir, "libffivendor_available.so.json"))
-
-		// For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
-		staticVariant := fmt.Sprintf("android_vendor.29_%s_%s_static", archType, archVariant)
-		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "libffivendor_available", "libffivendor_available.a", staticDir, staticVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "libffivendor", "libffivendor.a", staticDir, staticVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(staticDir, "libffivendor_available.a.json"))
-		jsonFiles = append(jsonFiles,
-			filepath.Join(staticDir, "libffivendor.a.json"))
-
-		// For rlib libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
-		rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_dylib-std", archType, archVariant)
-		rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib")
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.rlib", rlibDir, rlibVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor", "librustvendor.rlib", rlibDir, rlibVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(rlibDir, "librustvendor_available.rlib.json"))
-		jsonFiles = append(jsonFiles,
-			filepath.Join(rlibDir, "librustvendor.rlib.json"))
-
-		// For rlib libraries, all rlib-std variants vendor:true and vendor_available modules (including VNDK) are captured.
-		rlibStdVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.rlib-std.rlib", rlibDir, rlibStdVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor", "librustvendor.rlib-std.rlib", rlibDir, rlibStdVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(rlibDir, "librustvendor_available.rlib.json"))
-		jsonFiles = append(jsonFiles,
-			filepath.Join(rlibDir, "librustvendor.rlib.json"))
-
-		// For dylib libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
-		dylibVariant := fmt.Sprintf("android_vendor.29_%s_%s_dylib", archType, archVariant)
-		dylibDir := filepath.Join(snapshotVariantPath, archDir, "dylib")
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.dylib.so", dylibDir, dylibVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor", "librustvendor.dylib.so", dylibDir, dylibVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(dylibDir, "librustvendor_available.dylib.so.json"))
-		jsonFiles = append(jsonFiles,
-			filepath.Join(dylibDir, "librustvendor.dylib.so.json"))
-
-		// For binary executables, all vendor:true and vendor_available modules are captured.
-		if archType == "arm64" {
-			binaryVariant := fmt.Sprintf("android_vendor.29_%s_%s", archType, archVariant)
-			binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
-			cc.CheckSnapshot(t, ctx, snapshotSingleton, "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant)
-			cc.CheckSnapshot(t, ctx, snapshotSingleton, "vendor_bin", "vendor_bin", binaryDir, binaryVariant)
-			jsonFiles = append(jsonFiles,
-				filepath.Join(binaryDir, "vendor_available_bin.json"))
-			jsonFiles = append(jsonFiles,
-				filepath.Join(binaryDir, "vendor_bin.json"))
-		}
-	}
-
-	for _, jsonFile := range jsonFiles {
-		// verify all json files exist
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("%q expected but not found; #%v", jsonFile, jsonFiles)
-		}
-	}
-
-	// fake snapshot should have all outputs in the normal snapshot.
-	fakeSnapshotSingleton := ctx.SingletonForTests("vendor-fake-snapshot")
-
-	for _, output := range snapshotSingleton.AllOutputs() {
-		fakeOutput := strings.Replace(output, "/vendor-snapshot/", "/fake/vendor-snapshot/", 1)
-		if fakeSnapshotSingleton.MaybeOutput(fakeOutput).Rule == nil {
-			t.Errorf("%q expected but not found", fakeOutput)
-		}
-	}
-}
-
-func TestVendorSnapshotDirected(t *testing.T) {
-	bp := `
-	rust_ffi_shared {
-		name: "libffivendor_available",
-		crate_name: "ffivendor_available",
-		srcs: ["lib.rs"],
-		vendor_available: true,
-	}
-
-	rust_library {
-		name: "librustvendor_available",
-		crate_name: "rustvendor_available",
-		srcs: ["lib.rs"],
-		vendor_available: true,
-	}
-
-	rust_ffi_shared {
-		name: "libffivendor_exclude",
-		crate_name: "ffivendor_exclude",
-		srcs: ["lib.rs"],
-		vendor_available: true,
-	}
-
-	rust_library {
-		name: "librustvendor_exclude",
-		crate_name: "rustvendor_exclude",
-		srcs: ["lib.rs"],
-		vendor_available: true,
-	}
-`
-	ctx := testRustVndk(t, bp)
-	ctx.Config().TestProductVariables.VendorSnapshotModules = make(map[string]bool)
-	ctx.Config().TestProductVariables.VendorSnapshotModules["librustvendor_available"] = true
-	ctx.Config().TestProductVariables.VendorSnapshotModules["libffivendor_available"] = true
-	ctx.Config().TestProductVariables.DirectedVendorSnapshot = true
-
-	// Check Vendor snapshot output.
-
-	snapshotDir := "vendor-snapshot"
-	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
-
-	var includeJsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-		[]string{"arm", "armv7-a-neon"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
-		rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_dylib-std", archType, archVariant)
-		rlibRlibStdVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-		rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib")
-		dylibVariant := fmt.Sprintf("android_vendor.29_%s_%s_dylib", archType, archVariant)
-		dylibDir := filepath.Join(snapshotVariantPath, archDir, "dylib")
-
-		// Included modules
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.rlib", rlibDir, rlibVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.rlib-std.rlib", rlibDir, rlibRlibStdVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librustvendor_available", "librustvendor_available.dylib.so", dylibDir, dylibVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "libffivendor_available", "libffivendor_available.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librustvendor_available.rlib.json"))
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librustvendor_available.rlib-std.rlib.json"))
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(dylibDir, "librustvendor_available.dylib.so.json"))
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libffivendor_available.so.json"))
-
-		// Excluded modules. Modules not included in the directed vendor snapshot
-		// are still include as fake modules.
-		cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librustvendor_exclude", "librustvendor_exclude.rlib", rlibDir, rlibVariant)
-		cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librustvendor_exclude", "librustvendor_exclude.rlib-std.rlib", rlibDir, rlibRlibStdVariant)
-		cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librustvendor_exclude", "librustvendor_exclude.dylib.so", dylibDir, dylibVariant)
-		cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "libffivendor_exclude", "libffivendor_exclude.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librustvendor_exclude.rlib.json"))
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librustvendor_exclude.rlib-std.rlib.json"))
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(dylibDir, "librustvendor_exclude.dylib.so.json"))
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libffivendor_exclude.so.json"))
-	}
-
-	// Verify that each json file for an included module has a rule.
-	for _, jsonFile := range includeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("include json file %q not found", jsonFile)
-		}
-	}
-}
-
-func TestVendorSnapshotExclude(t *testing.T) {
-
-	// This test verifies that the exclude_from_vendor_snapshot property
-	// makes its way from the Android.bp source file into the module data
-	// structure. It also verifies that modules are correctly included or
-	// excluded in the vendor snapshot based on their path (framework or
-	// vendor) and the exclude_from_vendor_snapshot property.
-
-	frameworkBp := `
-		rust_ffi_shared {
-			name: "libinclude",
-			crate_name: "include",
-			srcs: ["include.rs"],
-			vendor_available: true,
-		}
-
-		rust_ffi_shared {
-			name: "libexclude",
-			crate_name: "exclude",
-			srcs: ["exclude.rs"],
-			vendor: true,
-			exclude_from_vendor_snapshot: true,
-		}
-
-		rust_ffi_shared {
-			name: "libavailable_exclude",
-			crate_name: "available_exclude",
-			srcs: ["lib.rs"],
-			vendor_available: true,
-			exclude_from_vendor_snapshot: true,
-		}
-
-		rust_library {
-			name: "librust_include",
-			crate_name: "rust_include",
-			srcs: ["include.rs"],
-			vendor_available: true,
-		}
-
-		rust_library {
-			name: "librust_exclude",
-			crate_name: "rust_exclude",
-			srcs: ["exclude.rs"],
-			vendor: true,
-			exclude_from_vendor_snapshot: true,
-		}
-
-		rust_library {
-			name: "librust_available_exclude",
-			crate_name: "rust_available_exclude",
-			srcs: ["lib.rs"],
-			vendor_available: true,
-			exclude_from_vendor_snapshot: true,
-		}
-	`
-
-	mockFS := map[string][]byte{
-		"framework/Android.bp": []byte(frameworkBp),
-		"framework/include.rs": nil,
-		"framework/exclude.rs": nil,
-	}
-
-	ctx := testRustVndkFs(t, "", mockFS)
-
-	// Test an include and exclude framework module.
-	cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "libinclude", false, sharedVendorVariant)
-	cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "libexclude", true, sharedVendorVariant)
-	cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "libavailable_exclude", true, sharedVendorVariant)
-
-	cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_include", false, rlibVendorVariant)
-	cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_exclude", true, rlibVendorVariant)
-	cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_available_exclude", true, rlibVendorVariant)
-
-	cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_include", false, rlibDylibStdVendorVariant)
-	cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_exclude", true, rlibDylibStdVendorVariant)
-	cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_available_exclude", true, rlibDylibStdVendorVariant)
-
-	cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_include", false, dylibVendorVariant)
-	cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_exclude", true, dylibVendorVariant)
-	cc.AssertExcludeFromVendorSnapshotIs(t, ctx, "librust_available_exclude", true, dylibVendorVariant)
-
-	// Verify the content of the vendor snapshot.
-
-	snapshotDir := "vendor-snapshot"
-	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
-
-	var includeJsonFiles []string
-	var excludeJsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-		[]string{"arm", "armv7-a-neon"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		sharedVariant := fmt.Sprintf("android_vendor.29_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-
-		rlibVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_dylib-std", archType, archVariant)
-		rlibRlibStdVariant := fmt.Sprintf("android_vendor.29_%s_%s_rlib_rlib-std", archType, archVariant)
-		rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib")
-		dylibVariant := fmt.Sprintf("android_vendor.29_%s_%s_dylib", archType, archVariant)
-		dylibDir := filepath.Join(snapshotVariantPath, archDir, "dylib")
-
-		// Included modules
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json"))
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librust_include", "librust_include.rlib", rlibDir, rlibVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librust_include.rlib.json"))
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librust_include", "librust_include.rlib-std.rlib", rlibDir, rlibRlibStdVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librust_include.rlib-std.rlib.json"))
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librust_include", "librust_include.dylib.so", dylibDir, dylibVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(dylibDir, "librust_include.dylib.so.json"))
-
-		// Excluded modules
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librust_exclude", "librust_exclude.rlib", rlibDir, rlibVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librust_exclude.rlib.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librust_available_exclude", "librust_available_exclude.rlib", rlibDir, rlibVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librust_available_exclude.rlib.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librust_available_exclude", "librust_available_exclude.rlib-std.rlib", rlibDir, rlibRlibStdVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librust_available_exclude.rlib.rlib-std.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librust_exclude", "librust_exclude.dylib.so", dylibDir, dylibVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(dylibDir, "librust_exclude.dylib.so.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librust_available_exclude", "librust_available_exclude.dylib.so", dylibDir, dylibVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(dylibDir, "librust_available_exclude.dylib.so.json"))
-	}
-
-	// Verify that each json file for an included module has a rule.
-	for _, jsonFile := range includeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("include json file %q not found", jsonFile)
-		}
-	}
-
-	// Verify that each json file for an excluded module has no rule.
-	for _, jsonFile := range excludeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
-			t.Errorf("exclude json file %q found", jsonFile)
-		}
-	}
-}
-
-func TestVendorSnapshotUse(t *testing.T) {
-	frameworkBp := `
-	cc_library {
-		name: "libvndk",
-		vendor_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		nocrt: true,
-	}
-
-	cc_library {
-		name: "libvendor",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-	}
-
-	cc_library {
-		name: "libvendor_available",
-		vendor_available: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-	}
-
-	cc_library {
-		name: "lib32",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-		compile_multilib: "32",
-	}
-
-	cc_library {
-		name: "lib64",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-		compile_multilib: "64",
-	}
-
-	rust_binary {
-		name: "bin",
-		vendor: true,
-		srcs: ["bin.rs"],
-	}
-
-	rust_binary {
-		name: "bin32",
-		vendor: true,
-		compile_multilib: "32",
-		srcs: ["bin.rs"],
-	}
-
-	rust_library {
-		name: "librust_vendor_available",
-		crate_name: "rust_vendor",
-		vendor_available: true,
-		srcs: ["client.rs"],
-	}
-
-`
-
-	vndkBp := `
-	vndk_prebuilt_shared {
-		name: "libvndk",
-		version: "30",
-		target_arch: "arm64",
-		vendor_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		arch: {
-			arm64: {
-				srcs: ["libvndk.so"],
-				export_include_dirs: ["include/libvndk"],
-			},
-			arm: {
-				srcs: ["libvndk.so"],
-				export_include_dirs: ["include/libvndk"],
-			},
-		},
-	}
-
-	// old snapshot module which has to be ignored
-	vndk_prebuilt_shared {
-		name: "libvndk",
-		version: "26",
-		target_arch: "arm64",
-		vendor_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		arch: {
-			arm64: {
-				srcs: ["libvndk.so"],
-				export_include_dirs: ["include/libvndk"],
-			},
-			arm: {
-				srcs: ["libvndk.so"],
-				export_include_dirs: ["include/libvndk"],
-			},
-		},
-	}
-
-	// different arch snapshot which has to be ignored
-	vndk_prebuilt_shared {
-		name: "libvndk",
-		version: "30",
-		target_arch: "arm",
-		vendor_available: true,
-		product_available: true,
-		vndk: {
-			enabled: true,
-		},
-		arch: {
-			arm: {
-				srcs: ["libvndk.so"],
-				export_include_dirs: ["include/libvndk"],
-			},
-		},
-	}
-`
-
-	vendorProprietaryBp := `
-	cc_library {
-		name: "libvendor_without_snapshot",
-		vendor: true,
-		nocrt: true,
-		no_libcrt: true,
-		stl: "none",
-		system_shared_libs: [],
-	}
-
-	rust_ffi_shared {
-		name: "libclient",
-		crate_name: "client",
-		vendor: true,
-		shared_libs: ["libvndk", "libvendor_available"],
-		static_libs: ["libvendor", "libvendor_without_snapshot"],
-		rustlibs: ["librust_vendor_available"],
-		arch: {
-			arm64: {
-				shared_libs: ["lib64"],
-			},
-			arm: {
-				shared_libs: ["lib32"],
-			},
-		},
-		srcs: ["client.rs"],
-	}
-
-	rust_library {
-		name: "libclient_rust",
-		crate_name: "client_rust",
-		vendor: true,
-		shared_libs: ["libvndk", "libvendor_available"],
-		static_libs: ["libvendor", "libvendor_without_snapshot"],
-		rustlibs: ["librust_vendor_available"],
-		arch: {
-			arm64: {
-				shared_libs: ["lib64"],
-			},
-			arm: {
-				shared_libs: ["lib32"],
-			},
-		},
-		srcs: ["client.rs"],
-	}
-
-	rust_binary {
-		name: "bin_without_snapshot",
-		vendor: true,
-		static_libs: ["libvndk"],
-		srcs: ["bin.rs"],
-		rustlibs: ["librust_vendor_available"],
-	}
-
-	vendor_snapshot {
-		name: "vendor_snapshot",
-		version: "30",
-		arch: {
-			arm64: {
-				vndk_libs: [
-					"libvndk",
-				],
-				static_libs: [
-					"libvendor",
-					"libvndk",
-					"libclang_rt.builtins",
-					"note_memtag_heap_sync",
-				],
-				shared_libs: [
-					"libvendor_available",
-					"lib64",
-				],
-				rlibs: [
-					"libstd",
-					"librust_vendor_available",
-					"librust_vendor_available.rlib-std"
-				],
-				dylibs: [
-					"libstd",
-					"librust_vendor_available",
-				],
-				binaries: [
-					"bin",
-				],
-                objects: [
-				    "crtend_so",
-					"crtbegin_so",
-					"crtbegin_dynamic",
-					"crtend_android"
-				],
-			},
-			arm: {
-				vndk_libs: [
-					"libvndk",
-				],
-				static_libs: [
-					"libvendor",
-					"libvndk",
-					"libclang_rt.builtins",
-				],
-				shared_libs: [
-					"libvendor_available",
-					"lib32",
-				],
-				rlibs: [
-					"libstd",
-					"librust_vendor_available",
-				],
-				dylibs: [
-					"libstd",
-					"librust_vendor_available",
-				],
-				binaries: [
-					"bin32",
-				],
-                objects: [
-				    "crtend_so",
-					"crtbegin_so",
-					"crtbegin_dynamic",
-					"crtend_android"
-				],
-
-			},
-		}
-	}
-
-	vendor_snapshot_object {
-		name: "crtend_so",
-		version: "30",
-		target_arch: "arm64",
-		vendor: true,
-		stl: "none",
-		crt: true,
-		arch: {
-			arm64: {
-				src: "crtend_so.o",
-			},
-			arm: {
-				src: "crtend_so.o",
-			},
-		},
-	}
-
-	vendor_snapshot_object {
-		name: "crtbegin_so",
-		version: "30",
-		target_arch: "arm64",
-		vendor: true,
-		stl: "none",
-		crt: true,
-		arch: {
-			arm64: {
-				src: "crtbegin_so.o",
-			},
-			arm: {
-				src: "crtbegin_so.o",
-			},
-		},
-	}
-
-	vendor_snapshot_rlib {
-		name: "libstd",
-		version: "30",
-		target_arch: "arm64",
-		vendor: true,
-		sysroot: true,
-		arch: {
-			arm64: {
-				src: "libstd.rlib",
-			},
-			arm: {
-				src: "libstd.rlib",
-			},
-		},
-	}
-
-	vendor_snapshot_rlib {
-		name: "librust_vendor_available",
-		version: "30",
-		target_arch: "arm64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "librust_vendor_available.rlib",
-			},
-			arm: {
-				src: "librust_vendor_available.rlib",
-			},
-		},
-	}
-
-	vendor_snapshot_rlib {
-		name: "librust_vendor_available.rlib-std",
-		version: "30",
-		target_arch: "arm64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "librust_vendor_available.rlib-std.rlib",
-			},
-			arm: {
-				src: "librust_vendor_available.rlib-std.rlib",
-			},
-		},
-	}
-
-	vendor_snapshot_dylib {
-		name: "libstd",
-		version: "30",
-		target_arch: "arm64",
-		vendor: true,
-		sysroot: true,
-		arch: {
-			arm64: {
-				src: "libstd.dylib.so",
-			},
-			arm: {
-				src: "libstd.dylib.so",
-			},
-		},
-	}
-
-	vendor_snapshot_dylib {
-		name: "librust_vendor_available",
-		version: "30",
-		target_arch: "arm64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "librust_vendor_available.dylib.so",
-			},
-			arm: {
-				src: "librust_vendor_available.dylib.so",
-			},
-		},
-	}
-
-	vendor_snapshot_object {
-		name: "crtend_android",
-		version: "30",
-		target_arch: "arm64",
-		vendor: true,
-		stl: "none",
-		crt: true,
-		arch: {
-			arm64: {
-				src: "crtend_so.o",
-			},
-			arm: {
-				src: "crtend_so.o",
-			},
-		},
-	}
-
-	vendor_snapshot_object {
-		name: "crtbegin_dynamic",
-		version: "30",
-		target_arch: "arm64",
-		vendor: true,
-		stl: "none",
-		crt: true,
-		arch: {
-			arm64: {
-				src: "crtbegin_so.o",
-			},
-			arm: {
-				src: "crtbegin_so.o",
-			},
-		},
-	}
-
-	vendor_snapshot_static {
-		name: "libvndk",
-		version: "30",
-		target_arch: "arm64",
-		compile_multilib: "both",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "libvndk.a",
-			},
-			arm: {
-				src: "libvndk.a",
-			},
-		},
-		shared_libs: ["libvndk"],
-		export_shared_lib_headers: ["libvndk"],
-	}
-
-	vendor_snapshot_static {
-		name: "libclang_rt.builtins",
-		version: "30",
-		target_arch: "arm64",
-		vendor: true,
-		arch: {
-			arm: {
-				src: "libclang_rt.builtins-arm-android.a",
-			},
-			arm64: {
-				src: "libclang_rt.builtins-aarch64-android.a",
-			},
-		},
-    }
-
-	vendor_snapshot_shared {
-		name: "lib32",
-		version: "30",
-		target_arch: "arm64",
-		compile_multilib: "32",
-		vendor: true,
-		arch: {
-			arm: {
-				src: "lib32.so",
-			},
-		},
-	}
-
-	vendor_snapshot_shared {
-		name: "lib64",
-		version: "30",
-		target_arch: "arm64",
-		compile_multilib: "64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "lib64.so",
-			},
-		},
-	}
-	vendor_snapshot_shared {
-		name: "liblog",
-		version: "30",
-		target_arch: "arm64",
-		compile_multilib: "64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "liblog.so",
-			},
-		},
-	}
-
-	vendor_snapshot_static {
-		name: "libvendor",
-		version: "30",
-		target_arch: "arm64",
-		compile_multilib: "both",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "libvendor.a",
-				export_include_dirs: ["include/libvendor"],
-			},
-			arm: {
-				src: "libvendor.a",
-				export_include_dirs: ["include/libvendor"],
-			},
-		},
-	}
-
-	vendor_snapshot_shared {
-		name: "libvendor_available",
-		version: "30",
-		target_arch: "arm64",
-		compile_multilib: "both",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "libvendor_available.so",
-				export_include_dirs: ["include/libvendor"],
-			},
-			arm: {
-				src: "libvendor_available.so",
-				export_include_dirs: ["include/libvendor"],
-			},
-		},
-	}
-
-	vendor_snapshot_binary {
-		name: "bin",
-		version: "30",
-		target_arch: "arm64",
-		compile_multilib: "64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "bin",
-			},
-		},
-	}
-
-	vendor_snapshot_binary {
-		name: "bin32",
-		version: "30",
-		target_arch: "arm64",
-		compile_multilib: "32",
-		vendor: true,
-		arch: {
-			arm: {
-				src: "bin32",
-			},
-		},
-	}
-
-	// Test sanitizers use the snapshot libraries
-	rust_binary {
-		name: "memtag_binary",
-		srcs: ["vendor/bin.rs"],
-		vendor: true,
-		compile_multilib: "64",
-		sanitize: {
-			memtag_heap: true,
-			diag: {
-				memtag_heap: true,
-			}
-		},
-	}
-
-	// old snapshot module which has to be ignored
-	vendor_snapshot_binary {
-		name: "bin",
-		version: "26",
-		target_arch: "arm64",
-		compile_multilib: "first",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "bin",
-			},
-		},
-	}
-
-	// different arch snapshot which has to be ignored
-	vendor_snapshot_binary {
-		name: "bin",
-		version: "30",
-		target_arch: "arm",
-		compile_multilib: "first",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "bin",
-			},
-		},
-	}
-
-	vendor_snapshot_static {
-		name: "note_memtag_heap_sync",
-		vendor: true,
-		target_arch: "arm64",
-		version: "30",
-		arch: {
-			arm64: {
-				src: "note_memtag_heap_sync.a",
-			},
-		},
-	}
-
-`
-
-	mockFS := android.MockFS{
-		"framework/Android.bp":                          []byte(frameworkBp),
-		"framework/bin.rs":                              nil,
-		"note_memtag_heap_sync.a":                       nil,
-		"vendor/Android.bp":                             []byte(vendorProprietaryBp),
-		"vendor/bin":                                    nil,
-		"vendor/bin32":                                  nil,
-		"vendor/bin.rs":                                 nil,
-		"vendor/client.rs":                              nil,
-		"vendor/include/libvndk/a.h":                    nil,
-		"vendor/include/libvendor/b.h":                  nil,
-		"vendor/libvndk.a":                              nil,
-		"vendor/libvendor.a":                            nil,
-		"vendor/libvendor.so":                           nil,
-		"vendor/lib32.so":                               nil,
-		"vendor/lib64.so":                               nil,
-		"vendor/liblog.so":                              nil,
-		"vendor/libstd.rlib":                            nil,
-		"vendor/librust_vendor_available.rlib":          nil,
-		"vendor/librust_vendor_available.rlib-std.rlib": nil,
-		"vendor/libstd.dylib.so":                        nil,
-		"vendor/librust_vendor_available.dylib.so":      nil,
-		"vendor/crtbegin_so.o":                          nil,
-		"vendor/crtend_so.o":                            nil,
-		"vendor/libclang_rt.builtins-aarch64-android.a": nil,
-		"vendor/libclang_rt.builtins-arm-android.a":     nil,
-		"vndk/Android.bp":                               []byte(vndkBp),
-		"vndk/include/libvndk/a.h":                      nil,
-		"vndk/libvndk.so":                               nil,
-	}
-
-	sharedVariant := "android_vendor.30_arm64_armv8-a_shared"
-	rlibVariant := "android_vendor.30_arm64_armv8-a_rlib_dylib-std"
-	rlibRlibStdVariant := "android_vendor.30_arm64_armv8-a_rlib_rlib-std"
-	dylibVariant := "android_vendor.30_arm64_armv8-a_dylib"
-	staticVariant := "android_vendor.30_arm64_armv8-a_static"
-	binaryVariant := "android_vendor.30_arm64_armv8-a"
-
-	shared32Variant := "android_vendor.30_arm_armv7-a-neon_shared"
-	binary32Variant := "android_vendor.30_arm_armv7-a-neon"
-
-	ctx := testRustVndkFsVersions(t, "", mockFS, "30", "current", "31")
-
-	// libclient uses libvndk.vndk.30.arm64, libvendor.vendor_static.30.arm64, libvendor_without_snapshot
-	libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustLink").Args["linkFlags"]
-	for _, input := range [][]string{
-		[]string{sharedVariant, "libvndk.vndk.30.arm64"},
-		[]string{staticVariant, "libvendor.vendor_static.30.arm64"},
-		[]string{staticVariant, "libvendor_without_snapshot"},
-	} {
-		outputPaths := cc.GetOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */)
-		if !strings.Contains(libclientLdFlags, outputPaths[0].String()) {
-			t.Errorf("libflags for libclient must contain %#v, but was %#v", outputPaths[0], libclientLdFlags)
-		}
-	}
-
-	libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkSharedLibs
-	if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib64", "liblog.vendor", "libc.vendor", "libm.vendor", "libdl.vendor"}; !reflect.DeepEqual(g, w) {
-		t.Errorf("wanted libclient AndroidMkSharedLibs %q, got %q", w, g)
-	}
-
-	libclientAndroidMkStaticLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkStaticLibs
-	if g, w := libclientAndroidMkStaticLibs, []string{"libvendor", "libvendor_without_snapshot", "libclang_rt.builtins.vendor"}; !reflect.DeepEqual(g, w) {
-		t.Errorf("wanted libclient AndroidMkStaticLibs %q, got %q", w, g)
-	}
-
-	libclientAndroidMkDylibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkDylibs
-	if g, w := libclientAndroidMkDylibs, []string{"librust_vendor_available.vendor", "libstd.vendor"}; !reflect.DeepEqual(g, w) {
-		t.Errorf("wanted libclient libclientAndroidMkDylibs %q, got %q", w, libclientAndroidMkDylibs)
-	}
-
-	libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).Properties.AndroidMkSharedLibs
-	if g, w := libclient32AndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib32", "liblog.vendor", "libc.vendor", "libm.vendor", "libdl.vendor"}; !reflect.DeepEqual(g, w) {
-		t.Errorf("wanted libclient32 AndroidMkSharedLibs %q, got %q", w, g)
-	}
-
-	libclientRustAndroidMkRlibs := ctx.ModuleForTests("libclient_rust", rlibVariant).Module().(*Module).Properties.AndroidMkRlibs
-	if g, w := libclientRustAndroidMkRlibs, []string{"librust_vendor_available.vendor"}; !reflect.DeepEqual(g, w) {
-		t.Errorf("wanted rlib libclient libclientAndroidMkRlibs %q, got %q", w, g)
-	}
-
-	libclientRlibStdRustAndroidMkRlibs := ctx.ModuleForTests("libclient_rust", rlibRlibStdVariant).Module().(*Module).Properties.AndroidMkRlibs
-	if g, w := libclientRlibStdRustAndroidMkRlibs, []string{"librust_vendor_available.vendor.rlib-std", "libstd.vendor"}; !reflect.DeepEqual(g, w) {
-		t.Errorf("wanted rlib libclient libclientAndroidMkRlibs %q, got %q", w, g)
-	}
-
-	libclientRustDylibAndroidMkDylibs := ctx.ModuleForTests("libclient_rust", dylibVariant).Module().(*Module).Properties.AndroidMkDylibs
-	if g, w := libclientRustDylibAndroidMkDylibs, []string{"librust_vendor_available.vendor", "libstd.vendor"}; !reflect.DeepEqual(g, w) {
-		t.Errorf("wanted dylib libclient libclientRustDylibAndroidMkDylibs %q, got %q", w, g)
-	}
-
-	// rust vendor snapshot must have ".vendor" suffix in AndroidMk
-	librustVendorAvailableSnapshotModule := ctx.ModuleForTests("librust_vendor_available.vendor_rlib.30.arm64", rlibVariant).Module()
-	librustVendorSnapshotMkName := android.AndroidMkEntriesForTest(t, ctx, librustVendorAvailableSnapshotModule)[0].EntryMap["LOCAL_MODULE"][0]
-	expectedRustVendorSnapshotName := "librust_vendor_available.vendor"
-	if librustVendorSnapshotMkName != expectedRustVendorSnapshotName {
-		t.Errorf("Unexpected rust vendor snapshot name in AndroidMk: %q, expected: %q\n", librustVendorSnapshotMkName, expectedRustVendorSnapshotName)
-	}
-
-	librustVendorAvailableDylibSnapshotModule := ctx.ModuleForTests("librust_vendor_available.vendor_dylib.30.arm64", dylibVariant).Module()
-	librustVendorSnapshotDylibMkName := android.AndroidMkEntriesForTest(t, ctx, librustVendorAvailableDylibSnapshotModule)[0].EntryMap["LOCAL_MODULE"][0]
-	expectedRustVendorDylibSnapshotName := "librust_vendor_available.vendor"
-	if librustVendorSnapshotDylibMkName != expectedRustVendorDylibSnapshotName {
-		t.Errorf("Unexpected rust vendor snapshot name in AndroidMk: %q, expected: %q\n", librustVendorSnapshotDylibMkName, expectedRustVendorDylibSnapshotName)
-	}
-
-	rustVendorBinModule := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Module()
-	rustVendorBinMkDylibName := android.AndroidMkEntriesForTest(t, ctx, rustVendorBinModule)[0].EntryMap["LOCAL_DYLIB_LIBRARIES"][0]
-	if rustVendorBinMkDylibName != expectedRustVendorSnapshotName {
-		t.Errorf("Unexpected rust rlib name in AndroidMk: %q, expected: %q\n", rustVendorBinMkDylibName, expectedRustVendorSnapshotName)
-	}
-
-	binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustLink").Args["linkFlags"]
-	libVndkStaticOutputPaths := cc.GetOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.30.arm64"})
-	if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) {
-		t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
-			libVndkStaticOutputPaths[0], binWithoutSnapshotLdFlags)
-	}
-
-	// bin is installed by bin.vendor_binary.30.arm64
-	ctx.ModuleForTests("bin.vendor_binary.30.arm64", binaryVariant).Output("bin")
-
-	// bin32 is installed by bin32.vendor_binary.30.arm64
-	ctx.ModuleForTests("bin32.vendor_binary.30.arm64", binary32Variant).Output("bin32")
-
-	// bin_without_snapshot is installed by bin_without_snapshot
-	ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot")
-
-	// libvendor, libvendor_available and bin don't have vendor.30 variant
-	libvendorVariants := ctx.ModuleVariantsForTests("libvendor")
-	if android.InList(sharedVariant, libvendorVariants) {
-		t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant)
-	}
-
-	libvendorAvailableVariants := ctx.ModuleVariantsForTests("libvendor_available")
-	if android.InList(sharedVariant, libvendorAvailableVariants) {
-		t.Errorf("libvendor_available must not have variant %#v, but it does", sharedVariant)
-	}
-
-	binVariants := ctx.ModuleVariantsForTests("bin")
-	if android.InList(binaryVariant, binVariants) {
-		t.Errorf("bin must not have variant %#v, but it does", sharedVariant)
-	}
-
-	memtagStaticLibs := ctx.ModuleForTests("memtag_binary", "android_vendor.30_arm64_armv8-a").Module().(*Module).Properties.AndroidMkStaticLibs
-	if g, w := memtagStaticLibs, []string{"libclang_rt.builtins.vendor", "note_memtag_heap_sync.vendor"}; !reflect.DeepEqual(g, w) {
-		t.Errorf("wanted memtag_binary AndroidMkStaticLibs %q, got %q", w, g)
-	}
-}
-
-func TestRecoverySnapshotCapture(t *testing.T) {
-	bp := `
-	rust_ffi {
-		name: "librecovery",
-		recovery: true,
-		srcs: ["foo.rs"],
-		crate_name: "recovery",
-	}
-
-	rust_ffi {
-		name: "librecovery_available",
-		recovery_available: true,
-		srcs: ["foo.rs"],
-		crate_name: "recovery_available",
-	}
-
-	rust_library {
-		name: "librecovery_rustlib",
-		recovery: true,
-		srcs: ["foo.rs"],
-		crate_name: "recovery_rustlib",
-	}
-
-	rust_library {
-		name: "librecovery_available_rustlib",
-		recovery_available: true,
-		srcs: ["foo.rs"],
-		crate_name: "recovery_available_rustlib",
-	}
-
-	rust_binary {
-		name: "recovery_bin",
-		recovery: true,
-		srcs: ["foo.rs"],
-	}
-
-	rust_binary {
-		name: "recovery_available_bin",
-		recovery_available: true,
-		srcs: ["foo.rs"],
-	}
-
-`
-	// Check Recovery snapshot output.
-
-	ctx := testRustRecoveryFsVersions(t, bp, rustMockedFiles, "", "29", "current")
-	snapshotDir := "recovery-snapshot"
-	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
-
-	var jsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		// For shared libraries, all recovery:true and recovery_available modules are captured.
-		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(sharedDir, "librecovery.so.json"),
-			filepath.Join(sharedDir, "librecovery_available.so.json"))
-
-		// For static libraries, all recovery:true and recovery_available modules are captured.
-		staticVariant := fmt.Sprintf("android_recovery_%s_%s_static", archType, archVariant)
-		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.a", staticDir, staticVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.a", staticDir, staticVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(staticDir, "librecovery.a.json"),
-			filepath.Join(staticDir, "librecovery_available.a.json"))
-
-		// For rlib libraries, all recovery:true and recovery_available modules are captured.
-		rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_dylib-std", archType, archVariant)
-		rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib")
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.rlib", rlibDir, rlibVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available_rustlib", "librecovery_available_rustlib.rlib", rlibDir, rlibVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(rlibDir, "librecovery_rustlib.rlib.json"),
-			filepath.Join(rlibDir, "librecovery_available_rustlib.rlib.json"))
-
-		rlibRlibStdVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available_rustlib", "librecovery_available_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(rlibDir, "librecovery_rustlib.rlib-std.rlib.json"),
-			filepath.Join(rlibDir, "librecovery_available_rustlib.rlib-std.rlib.json"))
-
-		// For dylib libraries, all recovery:true and recovery_available modules are captured.
-		dylibVariant := fmt.Sprintf("android_recovery_%s_%s_dylib", archType, archVariant)
-		dylibDir := filepath.Join(snapshotVariantPath, archDir, "dylib")
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.dylib.so", dylibDir, dylibVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available_rustlib", "librecovery_available_rustlib.dylib.so", dylibDir, dylibVariant)
-		jsonFiles = append(jsonFiles,
-			filepath.Join(dylibDir, "librecovery_rustlib.dylib.so.json"),
-			filepath.Join(dylibDir, "librecovery_available_rustlib.dylib.so.json"))
-
-		// For binary executables, all recovery:true and recovery_available modules are captured.
-		if archType == "arm64" {
-			binaryVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant)
-			binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
-			cc.CheckSnapshot(t, ctx, snapshotSingleton, "recovery_bin", "recovery_bin", binaryDir, binaryVariant)
-			cc.CheckSnapshot(t, ctx, snapshotSingleton, "recovery_available_bin", "recovery_available_bin", binaryDir, binaryVariant)
-			jsonFiles = append(jsonFiles,
-				filepath.Join(binaryDir, "recovery_bin.json"),
-				filepath.Join(binaryDir, "recovery_available_bin.json"))
-		}
-	}
-
-	for _, jsonFile := range jsonFiles {
-		// verify all json files exist
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("%q expected but not found", jsonFile)
-		}
-	}
-}
-
-func TestRecoverySnapshotExclude(t *testing.T) {
-	// This test verifies that the exclude_from_recovery_snapshot property
-	// makes its way from the Android.bp source file into the module data
-	// structure. It also verifies that modules are correctly included or
-	// excluded in the recovery snapshot based on their path (framework or
-	// vendor) and the exclude_from_recovery_snapshot property.
-
-	frameworkBp := `
-		rust_ffi_shared {
-			name: "libinclude",
-			srcs: ["src/include.rs"],
-			recovery_available: true,
-			crate_name: "include",
-		}
-		rust_ffi_shared {
-			name: "libexclude",
-			srcs: ["src/exclude.rs"],
-			recovery: true,
-			exclude_from_recovery_snapshot: true,
-			crate_name: "exclude",
-		}
-		rust_ffi_shared {
-			name: "libavailable_exclude",
-			srcs: ["src/exclude.rs"],
-			recovery_available: true,
-			exclude_from_recovery_snapshot: true,
-			crate_name: "available_exclude",
-		}
-		rust_library {
-			name: "libinclude_rustlib",
-			srcs: ["src/include.rs"],
-			recovery_available: true,
-			crate_name: "include_rustlib",
-		}
-		rust_library {
-			name: "libexclude_rustlib",
-			srcs: ["src/exclude.rs"],
-			recovery: true,
-			exclude_from_recovery_snapshot: true,
-			crate_name: "exclude_rustlib",
-		}
-		rust_library {
-			name: "libavailable_exclude_rustlib",
-			srcs: ["src/exclude.rs"],
-			recovery_available: true,
-			exclude_from_recovery_snapshot: true,
-			crate_name: "available_exclude_rustlib",
-		}
-	`
-
-	vendorProprietaryBp := `
-		rust_ffi_shared {
-			name: "librecovery",
-			srcs: ["recovery.rs"],
-			recovery: true,
-			crate_name: "recovery",
-		}
-		rust_library {
-			name: "librecovery_rustlib",
-			srcs: ["recovery.rs"],
-			recovery: true,
-			crate_name: "recovery_rustlib",
-		}
-	`
-
-	mockFS := map[string][]byte{
-		"framework/Android.bp": []byte(frameworkBp),
-		"framework/include.rs": nil,
-		"framework/exclude.rs": nil,
-		"device/Android.bp":    []byte(vendorProprietaryBp),
-		"device/recovery.rs":   nil,
-	}
-
-	ctx := testRustRecoveryFsVersions(t, "", mockFS, "", "29", "current")
-
-	// Test an include and exclude framework module.
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false, sharedRecoveryVariant)
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true, sharedRecoveryVariant)
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true, sharedRecoveryVariant)
-
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude_rustlib", false, rlibRecoveryVariant)
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude_rustlib", true, rlibRecoveryVariant)
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude_rustlib", true, rlibRlibStdRecoveryVariant)
-
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude_rustlib", false, rlibRlibStdRecoveryVariant)
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude_rustlib", true, rlibRlibStdRecoveryVariant)
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude_rustlib", true, rlibRlibStdRecoveryVariant)
-
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude_rustlib", false, dylibRecoveryVariant)
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude_rustlib", true, dylibRecoveryVariant)
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude_rustlib", true, dylibRecoveryVariant)
-
-	// A recovery module is excluded, but by its path not the exclude_from_recovery_snapshot property
-	// ('device/' and 'vendor/' are default excluded). See snapshot/recovery_snapshot.go for more detail.
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false, sharedRecoveryVariant)
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery_rustlib", false, rlibRecoveryVariant)
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery_rustlib", false, rlibRlibStdRecoveryVariant)
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery_rustlib", false, dylibRecoveryVariant)
-
-	// Verify the content of the recovery snapshot.
-
-	snapshotDir := "recovery-snapshot"
-	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
-
-	var includeJsonFiles []string
-	var excludeJsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
-		rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_dylib-std", archType, archVariant)
-		rlibRlibStdVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant)
-		dylibVariant := fmt.Sprintf("android_recovery_%s_%s_dylib", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-		rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib")
-		dylibDir := filepath.Join(snapshotVariantPath, archDir, "dylib")
-
-		// Included modules
-
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json"))
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude_rustlib", "libinclude_rustlib.rlib", rlibDir, rlibVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "libinclude_rustlib.rlib.json"))
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude_rustlib", "libinclude_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "libinclude_rustlib.rlib-std.rlib.json"))
-
-		// Excluded modules
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json"))
-
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude_rustlib", "libexclude_rustlib.rlib", rlibDir, rlibVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libexclude_rustlib.rlib.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.rlib", rlibDir, rlibVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librecovery_rustlib.rlib.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude_rustlib", "libavailable_exclude_rustlib.rlib", rlibDir, rlibVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libavailable_exclude_rustlib.rlib.json"))
-
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude_rustlib", "libexclude_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libexclude_rustlib.rlib-std.rlib.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librecovery_rustlib.rlib-std.rlib.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude_rustlib", "libavailable_exclude_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libavailable_exclude_rustlib.rlib-std.rlib.json"))
-
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude_rustlib", "libexclude_rustlib.dylib.so", dylibDir, dylibVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libexclude_rustlib.dylib.so.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.dylib.so", dylibDir, dylibVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librecovery_rustlib.dylib.so.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude_rustlib", "libavailable_exclude_rustlib.dylib.so", dylibDir, dylibVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libavailable_exclude_rustlib.dylib.so.json"))
-	}
-
-	// Verify that each json file for an included module has a rule.
-	for _, jsonFile := range includeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("include json file %q not found", jsonFile)
-		}
-	}
-
-	// Verify that each json file for an excluded module has no rule.
-	for _, jsonFile := range excludeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
-			t.Errorf("exclude json file %q found", jsonFile)
-		}
-	}
-}
-
-func TestRecoverySnapshotDirected(t *testing.T) {
-	bp := `
-	rust_ffi_shared {
-		name: "librecovery",
-		recovery: true,
-		crate_name: "recovery",
-		srcs: ["foo.rs"],
-	}
-
-	rust_ffi_shared {
-		name: "librecovery_available",
-		recovery_available: true,
-		crate_name: "recovery_available",
-		srcs: ["foo.rs"],
-	}
-
-	rust_library {
-		name: "librecovery_rustlib",
-		recovery: true,
-		crate_name: "recovery",
-		srcs: ["foo.rs"],
-	}
-
-	rust_library {
-		name: "librecovery_available_rustlib",
-		recovery_available: true,
-		crate_name: "recovery_available",
-		srcs: ["foo.rs"],
-	}
-
-	/* TODO: Uncomment when Rust supports the "prefer" property for prebuilts
-	rust_library_rlib {
-		name: "libfoo_rlib",
-		recovery: true,
-		crate_name: "foo",
-	}
-
-	rust_prebuilt_rlib {
-		name: "libfoo_rlib",
-		recovery: true,
-		prefer: true,
-		srcs: ["libfoo.rlib"],
-		crate_name: "foo",
-	}
-	*/
-`
-	ctx := testRustRecoveryFsVersions(t, bp, rustMockedFiles, "current", "29", "current")
-	ctx.Config().TestProductVariables.RecoverySnapshotModules = make(map[string]bool)
-	ctx.Config().TestProductVariables.RecoverySnapshotModules["librecovery"] = true
-	ctx.Config().TestProductVariables.RecoverySnapshotModules["librecovery_rustlib"] = true
-	ctx.Config().TestProductVariables.DirectedRecoverySnapshot = true
-
-	// Check recovery snapshot output.
-	snapshotDir := "recovery-snapshot"
-	snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64")
-	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
-
-	var includeJsonFiles []string
-
-	for _, arch := range [][]string{
-		[]string{"arm64", "armv8-a"},
-	} {
-		archType := arch[0]
-		archVariant := arch[1]
-		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
-
-		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
-		rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_dylib-std", archType, archVariant)
-		rlibRlibStdVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant)
-		dylibVariant := fmt.Sprintf("android_recovery_%s_%s_dylib", archType, archVariant)
-		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-		rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib")
-		dylibDir := filepath.Join(snapshotVariantPath, archDir, "dylib")
-
-		// Included modules
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.rlib", rlibDir, rlibVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_rustlib.rlib.json"))
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_rustlib.rlib-std.rlib.json"))
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rustlib", "librecovery_rustlib.dylib.so", dylibDir, dylibVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(dylibDir, "librecovery_rustlib.dylib.so.json"))
-
-		// TODO: When Rust supports the "prefer" property for prebuilts, perform this check.
-		/*
-			// Check that snapshot captures "prefer: true" prebuilt
-			cc.CheckSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo_rlib", "libfoo_rlib.rlib", rlibDir, rlibVariant)
-			includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo_rlib.rlib.json"))
-		*/
-
-		// Excluded modules. Modules not included in the directed recovery snapshot
-		// are still included as fake modules.
-		cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery_available.so.json"))
-		cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available_rustlib", "librecovery_available_rustlib.rlib", rlibDir, rlibVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_available_rustlib.rlib.json"))
-		cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available_rustlib", "librecovery_available_rustlib.rlib-std.rlib", rlibDir, rlibRlibStdVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_available_rustlib.rlib-std.rlib.json"))
-		cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available_rustlib", "librecovery_available_rustlib.dylib.so", dylibDir, dylibVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(dylibDir, "librecovery_available_rustlib.dylib.so.json"))
-	}
-
-	// Verify that each json file for an included module has a rule.
-	for _, jsonFile := range includeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
-			t.Errorf("include json file %q not found, %#v", jsonFile, includeJsonFiles)
-		}
-	}
-}
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 97f6ab4..d039a81 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -143,6 +143,39 @@
 }
 
 python_library_host {
+    name: "uffd_gc_utils",
+    srcs: [
+        "uffd_gc_utils.py",
+    ],
+    visibility: [
+        "//build/make/tools:__subpackages__",
+    ],
+}
+
+python_test_host {
+    name: "uffd_gc_utils_test",
+    main: "uffd_gc_utils_test.py",
+    srcs: [
+        "uffd_gc_utils_test.py",
+    ],
+    libs: [
+        "uffd_gc_utils",
+    ],
+    test_suites: ["general-tests"],
+}
+
+python_binary_host {
+    name: "construct_uffd_gc_flag",
+    main: "construct_uffd_gc_flag.py",
+    srcs: [
+        "construct_uffd_gc_flag.py",
+    ],
+    libs: [
+        "uffd_gc_utils",
+    ],
+}
+
+python_library_host {
     name: "ninja_rsp",
     srcs: ["ninja_rsp.py"],
 }
@@ -254,3 +287,32 @@
         "modify_permissions_allowlist.py",
     ],
 }
+
+sh_binary_host {
+    name: "keep-flagged-apis",
+    src: "keep-flagged-apis.sh",
+}
+
+python_binary_host {
+    name: "merge_directories",
+    main: "merge_directories.py",
+    srcs: [
+        "merge_directories.py",
+    ],
+    version: {
+        py3: {
+            embedded_launcher: true,
+        },
+    },
+}
+
+python_binary_host {
+    name: "buildinfo",
+    main: "buildinfo.py",
+    srcs: ["buildinfo.py"],
+    version: {
+        py3: {
+            embedded_launcher: true,
+        },
+    },
+}
diff --git a/scripts/build-ndk-prebuilts.sh b/scripts/build-ndk-prebuilts.sh
index 0d14019..ef0f44a 100755
--- a/scripts/build-ndk-prebuilts.sh
+++ b/scripts/build-ndk-prebuilts.sh
@@ -19,9 +19,11 @@
     exit 1
 fi
 
+# Note: NDK doesn't support flagging APIs, so we hardcode it to trunk_staging.
 # TODO: remove ALLOW_MISSING_DEPENDENCIES=true when all the riscv64
 # dependencies exist (currently blocked by http://b/273792258).
 # TODO: remove BUILD_BROKEN_DISABLE_BAZEL=1 when bazel supports riscv64 (http://b/262192655).
+TARGET_RELEASE=trunk_staging \
 ALLOW_MISSING_DEPENDENCIES=true \
 BUILD_BROKEN_DISABLE_BAZEL=1 \
     TARGET_PRODUCT=ndk build/soong/soong_ui.bash --make-mode --soong-only ${OUT_DIR}/soong/ndk.timestamp
diff --git a/scripts/buildinfo.py b/scripts/buildinfo.py
new file mode 100755
index 0000000..e4fb0da
--- /dev/null
+++ b/scripts/buildinfo.py
@@ -0,0 +1,156 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""A tool for generating buildinfo.prop"""
+
+import argparse
+import contextlib
+import subprocess
+
+def parse_args():
+  """Parse commandline arguments."""
+  parser = argparse.ArgumentParser()
+  parser.add_argument('--use-vbmeta-digest-in-fingerprint', action='store_true')
+  parser.add_argument('--build-flavor', required=True)
+  parser.add_argument('--build-hostname-file', required=True, type=argparse.FileType('r')),
+  parser.add_argument('--build-id', required=True)
+  parser.add_argument('--build-keys', required=True)
+  parser.add_argument('--build-number-file', required=True, type=argparse.FileType('r'))
+  parser.add_argument('--build-thumbprint-file', type=argparse.FileType('r'))
+  parser.add_argument('--build-type', required=True)
+  parser.add_argument('--build-username', required=True)
+  parser.add_argument('--build-variant', required=True)
+  parser.add_argument('--cpu-abis', action='append', required=True)
+  parser.add_argument('--date-file', required=True, type=argparse.FileType('r'))
+  parser.add_argument('--default-locale')
+  parser.add_argument('--default-wifi-channels', action='append', default=[])
+  parser.add_argument('--device', required=True)
+  parser.add_argument("--display-build-number", action='store_true')
+  parser.add_argument('--platform-base-os', required=True)
+  parser.add_argument('--platform-display-version', required=True)
+  parser.add_argument('--platform-min-supported-target-sdk-version', required=True)
+  parser.add_argument('--platform-preview-sdk-fingerprint-file',
+                      required=True,
+                      type=argparse.FileType('r'))
+  parser.add_argument('--platform-preview-sdk-version', required=True)
+  parser.add_argument('--platform-sdk-version', required=True)
+  parser.add_argument('--platform-security-patch', required=True)
+  parser.add_argument('--platform-version', required=True)
+  parser.add_argument('--platform-version-codename',required=True)
+  parser.add_argument('--platform-version-all-codenames', action='append', required=True)
+  parser.add_argument('--platform-version-known-codenames', required=True)
+  parser.add_argument('--platform-version-last-stable', required=True)
+  parser.add_argument('--product', required=True)
+
+  parser.add_argument('--out', required=True, type=argparse.FileType('w'))
+
+  return parser.parse_args()
+
+def main():
+  option = parse_args()
+
+  build_hostname = option.build_hostname_file.read().strip()
+  build_number = option.build_number_file.read().strip()
+  build_version_tags = option.build_keys
+  if option.build_type == "debug":
+    build_version_tags = "debug," + build_version_tags
+
+  raw_date = option.date_file.read().strip()
+  date = subprocess.check_output(["date", "-d", f"@{raw_date}"], text=True).strip()
+  date_utc = subprocess.check_output(["date", "-d", f"@{raw_date}", "+%s"], text=True).strip()
+
+  # build_desc is human readable strings that describe this build. This has the same info as the
+  # build fingerprint.
+  # e.g. "aosp_cf_x86_64_phone-userdebug VanillaIceCream MAIN eng.20240319.143939 test-keys"
+  build_desc = f"{option.product}-{option.build_variant} {option.platform_version} " \
+               f"{option.build_id} {build_number} {build_version_tags}"
+
+  platform_preview_sdk_fingerprint = option.platform_preview_sdk_fingerprint_file.read().strip()
+
+  with contextlib.redirect_stdout(option.out):
+    print("# begin build properties")
+    print("# autogenerated by buildinfo.py")
+
+    # The ro.build.id will be set dynamically by init, by appending the unique vbmeta digest.
+    if option.use_vbmeta_digest_in_fingerprint:
+      print(f"ro.build.legacy.id={option.build_id}")
+    else:
+      print(f"ro.build.id?={option.build_id}")
+
+    # ro.build.display.id is shown under Settings -> About Phone
+    if option.build_variant == "user":
+      # User builds should show:
+      # release build number or branch.buld_number non-release builds
+
+      # Dev. branches should have DISPLAY_BUILD_NUMBER set
+      if option.display_build_number:
+        print(f"ro.build.display.id?={option.build_id} {build_number} {option.build_keys}")
+      else:
+        print(f"ro.build.display.id?={option.build_id} {option.build_keys}")
+    else:
+      # Non-user builds should show detailed build information (See build desc above)
+      print(f"ro.build.display.id?={build_desc}")
+    print(f"ro.build.version.incremental={build_number}")
+    print(f"ro.build.version.sdk={option.platform_sdk_version}")
+    print(f"ro.build.version.preview_sdk={option.platform_preview_sdk_version}")
+    print(f"ro.build.version.preview_sdk_fingerprint={platform_preview_sdk_fingerprint}")
+    print(f"ro.build.version.codename={option.platform_version_codename}")
+    print(f"ro.build.version.all_codenames={','.join(option.platform_version_all_codenames)}")
+    print(f"ro.build.version.known_codenames={option.platform_version_known_codenames}")
+    print(f"ro.build.version.release={option.platform_version_last_stable}")
+    print(f"ro.build.version.release_or_codename={option.platform_version}")
+    print(f"ro.build.version.release_or_preview_display={option.platform_display_version}")
+    print(f"ro.build.version.security_patch={option.platform_security_patch}")
+    print(f"ro.build.version.base_os={option.platform_base_os}")
+    print(f"ro.build.version.min_supported_target_sdk={option.platform_min_supported_target_sdk_version}")
+    print(f"ro.build.date={date}")
+    print(f"ro.build.date.utc={date_utc}")
+    print(f"ro.build.type={option.build_variant}")
+    print(f"ro.build.user={option.build_username}")
+    print(f"ro.build.host={build_hostname}")
+    # TODO: Remove any tag-related optional property declarations once the goals
+    # from go/arc-android-sigprop-changes have been achieved.
+    print(f"ro.build.tags?={build_version_tags}")
+    # ro.build.flavor are used only by the test harness to distinguish builds.
+    # Only add _asan for a sanitized build if it isn't already a part of the
+    # flavor (via a dedicated lunch config for example).
+    print(f"ro.build.flavor={option.build_flavor}")
+
+    # These values are deprecated, use "ro.product.cpu.abilist"
+    # instead (see below).
+    print(f"# ro.product.cpu.abi and ro.product.cpu.abi2 are obsolete,")
+    print(f"# use ro.product.cpu.abilist instead.")
+    print(f"ro.product.cpu.abi={option.cpu_abis[0]}")
+    if len(option.cpu_abis) > 1:
+      print(f"ro.product.cpu.abi2={option.cpu_abis[1]}")
+
+    if option.default_locale:
+      print(f"ro.product.locale={option.default_locale}")
+    print(f"ro.wifi.channels={' '.join(option.default_wifi_channels)}")
+
+    print(f"# ro.build.product is obsolete; use ro.product.device")
+    print(f"ro.build.product={option.device}")
+
+    print(f"# Do not try to parse description or thumbprint")
+    print(f"ro.build.description?={build_desc}")
+    if option.build_thumbprint_file:
+      build_thumbprint = option.build_thumbprint_file.read().strip()
+      print(f"ro.build.thumbprint={build_thumbprint}")
+
+    print(f"# end build properties")
+
+if __name__ == "__main__":
+  main()
diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt
index dad2b47..47eae07 100644
--- a/scripts/check_boot_jars/package_allowed_list.txt
+++ b/scripts/check_boot_jars/package_allowed_list.txt
@@ -44,6 +44,7 @@
 java\.util\.jar
 java\.util\.logging
 java\.util\.prefs
+java\.util\.random
 java\.util\.regex
 java\.util\.spi
 java\.util\.stream
@@ -79,8 +80,10 @@
 jdk\.internal\.reflect
 jdk\.internal\.util
 jdk\.internal\.util\.jar
+jdk\.internal\.util\.random
 jdk\.internal\.vm\.annotation
 jdk\.net
+jdk\.random
 org\.w3c\.dom
 org\.w3c\.dom\.ls
 org\.w3c\.dom\.traversal
diff --git a/scripts/check_prebuilt_presigned_apk.py b/scripts/check_prebuilt_presigned_apk.py
new file mode 100755
index 0000000..abedfb7
--- /dev/null
+++ b/scripts/check_prebuilt_presigned_apk.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+
+import subprocess
+import argparse
+import re
+import sys
+import zipfile
+
+def check_target_sdk_less_than_30(args):
+    if not args.aapt2:
+        sys.exit('--aapt2 is required')
+    regex = re.compile(r"targetSdkVersion: *'([0-9]+)'")
+    output = subprocess.check_output([args.aapt2, "dump", "badging", args.apk], text=True)
+    targetSdkVersion = None
+    for line in output.splitlines():
+        match = regex.fullmatch(line.strip())
+        if match:
+            targetSdkVersion = int(match.group(1))
+            break
+
+    if targetSdkVersion is None or targetSdkVersion >= 30:
+        sys.exit(args.apk + ": Prebuilt, presigned apks with targetSdkVersion >= 30 (or a codename targetSdkVersion) must set preprocessed: true in the Android.bp definition (because they must be signed with signature v2, and the build system would wreck that signature otherwise)")
+
+def has_preprocessed_issues(args, *, fail=False):
+    if not args.zipalign:
+        sys.exit('--zipalign is required')
+    ret = subprocess.run([args.zipalign, '-c', '-p', '4', args.apk], stdout=subprocess.DEVNULL).returncode
+    if ret != 0:
+        if fail:
+            sys.exit(args.apk + ': Improper zip alignment')
+        return True
+
+    with zipfile.ZipFile(args.apk) as zf:
+        for info in zf.infolist():
+            if info.filename.startswith('lib/') and info.filename.endswith('.so') and info.compress_type != zipfile.ZIP_STORED:
+                if fail:
+                    sys.exit(args.apk + ': Contains compressed JNI libraries')
+                return True
+            # It's ok for non-privileged apps to have compressed dex files, see go/gms-uncompressed-jni-slides
+            if args.privileged:
+                if info.filename.endswith('.dex') and info.compress_type != zipfile.ZIP_STORED:
+                    if fail:
+                        sys.exit(args.apk + ': Contains compressed dex files and is privileged')
+                    return True
+    return False
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--aapt2', help = "the path to the aapt2 executable")
+    parser.add_argument('--zipalign', help = "the path to the zipalign executable")
+    parser.add_argument('--skip-preprocessed-apk-checks', action = 'store_true', help = "the value of the soong property with the same name")
+    parser.add_argument('--preprocessed', action = 'store_true', help = "the value of the soong property with the same name")
+    parser.add_argument('--privileged', action = 'store_true', help = "the value of the soong property with the same name")
+    parser.add_argument('apk', help = "the apk to check")
+    parser.add_argument('stampfile', help = "a file to touch if successful")
+    args = parser.parse_args()
+
+    if not args.preprocessed:
+        check_target_sdk_less_than_30(args)
+    elif args.skip_preprocessed_apk_checks:
+        if not has_preprocessed_issues(args):
+            sys.exit('This module sets `skip_preprocessed_apk_checks: true`, but does not actually have any issues. Please remove `skip_preprocessed_apk_checks`.')
+    else:
+        has_preprocessed_issues(args, fail=True)
+
+    subprocess.check_call(["touch", args.stampfile])
+
+if __name__ == "__main__":
+    main()
diff --git a/scripts/construct_uffd_gc_flag.py b/scripts/construct_uffd_gc_flag.py
new file mode 100644
index 0000000..f437961
--- /dev/null
+++ b/scripts/construct_uffd_gc_flag.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""A tool for constructing UFFD GC flag."""
+
+import argparse
+import os
+
+from uffd_gc_utils import should_enable_uffd_gc
+
+
+def parse_args():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('kernel_version_file')
+  parser.add_argument('output')
+  return parser.parse_args()
+
+def main():
+  args = parse_args()
+  enable_uffd_gc = should_enable_uffd_gc(args.kernel_version_file)
+  flag = '--runtime-arg -Xgc:CMC' if enable_uffd_gc else ''
+  # Prevent the file's mtime from being changed if the contents don't change.
+  # This avoids unnecessary dexpreopt reruns.
+  if os.path.isfile(args.output):
+    with open(args.output, 'r') as f:
+      if f.read() == flag:
+        return
+  with open(args.output, 'w') as f:
+    f.write(flag)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/scripts/conv_linker_config.py b/scripts/conv_linker_config.py
index 3ac1b7e..ed3fbb7 100644
--- a/scripts/conv_linker_config.py
+++ b/scripts/conv_linker_config.py
@@ -62,8 +62,8 @@
     if args.source:
         for input in args.source.split(':'):
             pb.MergeFrom(LoadJsonMessage(input))
-    with open(args.output, 'wb') as f:
-        f.write(pb.SerializeToString())
+
+    ValidateAndWriteAsPbFile(pb, args.output)
 
 
 def Print(args):
@@ -90,8 +90,8 @@
     for item in installed_libraries:
         if item not in getattr(pb, 'provideLibs'):
             getattr(pb, 'provideLibs').append(item)
-    with open(args.output, 'wb') as f:
-        f.write(pb.SerializeToString())
+
+    ValidateAndWriteAsPbFile(pb, args.output)
 
 
 def Append(args):
@@ -106,8 +106,8 @@
     else:
         setattr(pb, args.key, args.value)
 
-    with open(args.output, 'wb') as f:
-        f.write(pb.SerializeToString())
+    ValidateAndWriteAsPbFile(pb, args.output)
+
 
 
 def Merge(args):
@@ -116,10 +116,68 @@
         with open(other, 'rb') as f:
             pb.MergeFromString(f.read())
 
-    with open(args.out, 'wb') as f:
+    ValidateAndWriteAsPbFile(pb, args.output)
+
+
+def Validate(args):
+    if os.path.isdir(args.input):
+        config_file = os.path.join(args.input, 'etc/linker.config.pb')
+        if os.path.exists(config_file):
+            args.input = config_file
+            Validate(args)
+        # OK if there's no linker config file.
+        return
+
+    if not os.path.isfile(args.input):
+        sys.exit(f"{args.input} is not a file")
+
+    pb = linker_config_pb2.LinkerConfig()
+    with open(args.input, 'rb') as f:
+        pb.ParseFromString(f.read())
+
+    if args.type == 'apex':
+        # Shouldn't use provideLibs/requireLibs in APEX linker.config.pb
+        if getattr(pb, 'provideLibs'):
+            sys.exit(f'{args.input}: provideLibs is set. Use provideSharedLibs in apex_manifest')
+        if getattr(pb, 'requireLibs'):
+            sys.exit(f'{args.input}: requireLibs is set. Use requireSharedLibs in apex_manifest')
+    elif args.type == 'system':
+        if getattr(pb, 'visible'):
+            sys.exit(f'{args.input}: do not use visible, which is for APEX')
+        if getattr(pb, 'permittedPaths'):
+            sys.exit(f'{args.input}: do not use permittedPaths, which is for APEX')
+    else:
+        sys.exit(f'Unknown type: {args.type}')
+
+    # Reject contributions field at build time while keeping the runtime behavior for GRF.
+    if getattr(pb, 'contributions'):
+        sys.exit(f"{args.input}: 'contributions' is set. "
+                 "It's deprecated. Instead, make the APEX 'visible' and use android_dlopen_ext().")
+
+
+def ValidateAndWriteAsPbFile(pb, output_path):
+    ValidateConfiguration(pb)
+    with open(output_path, 'wb') as f:
         f.write(pb.SerializeToString())
 
 
+def ValidateConfiguration(pb):
+    """
+    Validate if the configuration is valid to be used as linker configuration
+    """
+
+    # Validate if provideLibs and requireLibs have common module
+    provideLibs = set(getattr(pb, 'provideLibs'))
+    requireLibs = set(getattr(pb, 'requireLibs'))
+
+    intersectLibs = provideLibs.intersection(requireLibs)
+
+    if intersectLibs:
+        for lib in intersectLibs:
+            print(f'{lib} exists both in requireLibs and provideLibs', file=sys.stderr)
+        sys.exit(1)
+
+
 def GetArgParser():
     parser = argparse.ArgumentParser()
     subparsers = parser.add_subparsers()
@@ -227,6 +285,18 @@
         help='Linker configuration files to merge.')
     append.set_defaults(func=Merge)
 
+    validate = subparsers.add_parser('validate', help='Validate configuration')
+    validate.add_argument(
+        '--type',
+        required=True,
+        choices=['apex', 'system'],
+        help='Type of linker configuration')
+    validate.add_argument(
+        'input',
+        help='Input can be a directory which has etc/linker.config.pb or a path'
+        ' to the linker config file')
+    validate.set_defaults(func=Validate)
+
     return parser
 
 
diff --git a/scripts/keep-flagged-apis.sh b/scripts/keep-flagged-apis.sh
new file mode 100755
index 0000000..9c48fdb
--- /dev/null
+++ b/scripts/keep-flagged-apis.sh
@@ -0,0 +1,46 @@
+#!/bin/bash -e
+#
+# Copyright 2023 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Convert a list of flags in the input file to a list of metalava options
+# that will keep the APIs for those flags will hiding all other flagged
+# APIs.
+
+FLAGS="$1"
+
+FLAGGED="android.annotation.FlaggedApi"
+
+# Convert the list of feature flags in the input file to Metalava options
+# of the form `--revert-annotation !android.annotation.FlaggedApi("<flag>")`
+# to prevent the annotated APIs from being hidden, i.e. include the annotated
+# APIs in the SDK snapshots. This also preserves the line comments, they will
+# be ignored by Metalava but might be useful when debugging.
+while read -r line; do
+  key=$(echo "$line" | cut -d= -f1)
+  value=$(echo "$line" | cut -d= -f2)
+
+  # Skip if value is not true and line does not start with '#'
+  if [[ ( $value != "true" ) && ( $line =~ ^[^#] )]]; then
+    continue
+  fi
+
+  # Escape and quote the key for sed
+  escaped_key=$(echo "$key" | sed "s/'/\\\'/g; s/ /\\ /g")
+
+  echo $line | sed "s|^[^#].*$|--revert-annotation '!$FLAGGED(\"$escaped_key\")'|"
+done < "$FLAGS"
+
+# Revert all flagged APIs, unless listed above.
+echo "--revert-annotation $FLAGGED"
diff --git a/scripts/lint_project_xml.py b/scripts/lint_project_xml.py
index 3b0158d..c40b07d 100755
--- a/scripts/lint_project_xml.py
+++ b/scripts/lint_project_xml.py
@@ -18,6 +18,7 @@
 """This file generates project.xml and lint.xml files used to drive the Android Lint CLI tool."""
 
 import argparse
+import sys
 from xml.dom import minidom
 
 from ninja_rsp import NinjaRspFileReader
@@ -159,8 +160,8 @@
   if args.baseline_path:
     baseline = minidom.parse(args.baseline_path)
     disallowed_issues = check_baseline_for_disallowed_issues(baseline, args.disallowed_issues)
-    if bool(disallowed_issues):
-      raise RuntimeError('disallowed issues %s found in lint baseline file %s for module %s'
+    if disallowed_issues:
+      sys.exit('disallowed issues %s found in lint baseline file %s for module %s'
                          % (disallowed_issues, args.baseline_path, args.name))
 
   if args.project_out:
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
index c8d4f76..b101259 100755
--- a/scripts/manifest_check.py
+++ b/scripts/manifest_check.py
@@ -52,6 +52,14 @@
         'required:false'
     )
     parser.add_argument(
+        '--missing-optional-uses-library',
+        dest='missing_optional_uses_libraries',
+        action='append',
+        help='specify uses-library entries missing from the build system with '
+        'required:false',
+        default=[]
+    )
+    parser.add_argument(
         '--enforce-uses-libraries',
         dest='enforce_uses_libraries',
         action='store_true',
@@ -91,7 +99,7 @@
 C_BOLD = "\033[1m"
 
 
-def enforce_uses_libraries(manifest, required, optional, relax, is_apk, path):
+def enforce_uses_libraries(manifest, required, optional, missing_optional, relax, is_apk, path):
     """Verify that the <uses-library> tags in the manifest match those provided
 
   by the build system.
@@ -119,7 +127,12 @@
     required = trim_namespace_parts(required)
     optional = trim_namespace_parts(optional)
 
-    if manifest_required == required and manifest_optional == optional:
+    existing_manifest_optional = [
+        lib for lib in manifest_optional if lib not in missing_optional]
+
+    # The order of the existing libraries matter, while the order of the missing
+    # ones doesn't.
+    if manifest_required == required and existing_manifest_optional == optional:
         return None
 
     #pylint: disable=line-too-long
@@ -129,6 +142,7 @@
         '\t- required libraries in build system: %s[%s]%s\n' % (C_RED, ', '.join(required), C_OFF),
         '\t                 vs. in the manifest: %s[%s]%s\n' % (C_RED, ', '.join(manifest_required), C_OFF),
         '\t- optional libraries in build system: %s[%s]%s\n' % (C_RED, ', '.join(optional), C_OFF),
+        '\t    and missing ones in build system: %s[%s]%s\n' % (C_RED, ', '.join(missing_optional), C_OFF),
         '\t                 vs. in the manifest: %s[%s]%s\n' % (C_RED, ', '.join(manifest_optional), C_OFF),
         '\t- tags in the manifest (%s):\n' % path,
         '\t\t%s\n' % '\t\t'.join(tags),
@@ -187,18 +201,17 @@
     return required, optional, tags
 
 
-def extract_uses_libs_xml(xml): #pylint: disable=inconsistent-return-statements
+def extract_uses_libs_xml(xml):
     """Extract <uses-library> tags from the manifest."""
 
     manifest = parse_manifest(xml)
     elems = get_children_with_tag(manifest, 'application')
-    application = elems[0] if len(elems) == 1 else None
-    if len(elems) > 1: #pylint: disable=no-else-raise
+    if len(elems) > 1:
         raise RuntimeError('found multiple <application> tags')
-    elif not elems:
-        if uses_libraries or optional_uses_libraries: #pylint: disable=undefined-variable
-            raise ManifestMismatchError('no <application> tag found')
-        return
+    if not elems:
+        return [], [], []
+
+    application = elems[0]
 
     libs = get_children_with_tag(application, 'uses-library')
 
@@ -341,11 +354,14 @@
 
         if args.enforce_uses_libraries:
             # Load dexpreopt.config files and build a mapping from module
-            # names to library names. This is necessary because build system
-            # addresses libraries by their module name (`uses_libs`,
-            # `optional_uses_libs`, `LOCAL_USES_LIBRARIES`,
-            # `LOCAL_OPTIONAL_LIBRARY_NAMES` all contain module names), while
-            # the manifest addresses libraries by their name.
+            # names to library names. This is for Make only and it's necessary
+            # because Make passes module names from `LOCAL_USES_LIBRARIES`,
+            # `LOCAL_OPTIONAL_LIBRARY_NAMES`, while the manifest addresses
+            # libraries by their name. Soong doesn't use it and doesn't need it
+            # because it converts the module names to the library names and
+            # passes the library names. There is no need to translate missing
+            # optional libs because they are missing and therefore there is no
+            # mapping for them.
             mod_to_lib = load_dexpreopt_configs(args.dexpreopt_configs)
             required = translate_libnames(args.uses_libraries, mod_to_lib)
             optional = translate_libnames(args.optional_uses_libraries,
@@ -355,8 +371,8 @@
             # those in the manifest. Raise an exception on mismatch, unless the
             # script was passed a special parameter to suppress exceptions.
             errmsg = enforce_uses_libraries(manifest, required, optional,
-                                            args.enforce_uses_libraries_relax,
-                                            is_apk, args.input)
+                args.missing_optional_uses_libraries,
+                args.enforce_uses_libraries_relax, is_apk, args.input)
 
             # Create a status file that is empty on success, or contains an
             # error message on failure. When exceptions are suppressed,
diff --git a/scripts/manifest_check_test.py b/scripts/manifest_check_test.py
index 3be7a30..8003b3e 100755
--- a/scripts/manifest_check_test.py
+++ b/scripts/manifest_check_test.py
@@ -44,15 +44,17 @@
 class EnforceUsesLibrariesTest(unittest.TestCase):
     """Unit tests for add_extract_native_libs function."""
 
-    def run_test(self, xml, apk, uses_libraries=[], optional_uses_libraries=[]): #pylint: disable=dangerous-default-value
+    def run_test(self, xml, apk, uses_libraries=[], optional_uses_libraries=[],
+                 missing_optional_uses_libraries=[]): #pylint: disable=dangerous-default-value
         doc = minidom.parseString(xml)
         try:
             relax = False
             manifest_check.enforce_uses_libraries(
-                doc, uses_libraries, optional_uses_libraries, relax, False,
-                'path/to/X/AndroidManifest.xml')
+                doc, uses_libraries, optional_uses_libraries, missing_optional_uses_libraries,
+                relax, False, 'path/to/X/AndroidManifest.xml')
             manifest_check.enforce_uses_libraries(apk, uses_libraries,
                                                   optional_uses_libraries,
+                                                  missing_optional_uses_libraries,
                                                   relax, True,
                                                   'path/to/X/X.apk')
             return True
@@ -102,6 +104,15 @@
         matches = self.run_test(xml, apk, optional_uses_libraries=['foo'])
         self.assertFalse(matches)
 
+    def test_expected_missing_optional_uses_library(self):
+        xml = self.xml_tmpl % (
+            uses_library_xml('foo') + uses_library_xml('missing') + uses_library_xml('bar'))
+        apk = self.apk_tmpl % (
+            uses_library_apk('foo') + uses_library_apk('missing') + uses_library_apk('bar'))
+        matches = self.run_test(xml, apk, optional_uses_libraries=['foo', 'bar'],
+                                missing_optional_uses_libraries=['missing'])
+        self.assertFalse(matches)
+
     def test_missing_uses_library(self):
         xml = self.xml_tmpl % ('')
         apk = self.apk_tmpl % ('')
diff --git a/scripts/merge_directories.py b/scripts/merge_directories.py
new file mode 100755
index 0000000..3f8631b
--- /dev/null
+++ b/scripts/merge_directories.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python3
+import argparse
+import os
+import shutil
+import sys
+
+def main():
+    parser = argparse.ArgumentParser(
+        description="Given a list of directories, this script will copy the contents of all of "
+        "them into the first directory, erroring out if any duplicate files are found."
+    )
+    parser.add_argument(
+        "--ignore-duplicates",
+        action="store_true",
+        help="Don't error out on duplicate files, just skip them. The file from the earliest "
+        "directory listed on the command line will be the winner."
+    )
+    parser.add_argument(
+        "--file-list",
+        help="Path to a text file containing paths relative to in_dir. Only these paths will be "
+        "copied out of in_dir."
+    )
+    parser.add_argument("out_dir")
+    parser.add_argument("in_dir")
+    args = parser.parse_args()
+
+    if not os.path.isdir(args.out_dir):
+        sys.exit(f"error: {args.out_dir} must be a directory")
+    if not os.path.isdir(args.in_dir):
+        sys.exit(f"error: {args.in_dir} must be a directory")
+
+    file_list = None
+    if args.file_list:
+        with open(file_list_file, "r") as f:
+            file_list = f.read().strip().splitlines()
+
+    in_dir = args.in_dir
+    for root, dirs, files in os.walk(in_dir):
+        rel_root = os.path.relpath(root, in_dir)
+        dst_root = os.path.join(args.out_dir, rel_root)
+        made_parent_dirs = False
+        for f in files:
+            src = os.path.join(root, f)
+            dst = os.path.join(dst_root, f)
+            p = os.path.normpath(os.path.join(rel_root, f))
+            if file_list is not None and p not in file_list:
+                continue
+            if os.path.lexists(dst):
+                if args.ignore_duplicates:
+                    continue
+                sys.exit(f"error: {p} exists in both {args.out_dir} and {in_dir}")
+
+            if not made_parent_dirs:
+                os.makedirs(dst_root, exist_ok=True)
+                made_parent_dirs = True
+
+            shutil.copy2(src, dst, follow_symlinks=False)
+
+if __name__ == "__main__":
+    main()
diff --git a/scripts/mkcratersp.py b/scripts/mkcratersp.py
deleted file mode 100755
index 6ef01eb..0000000
--- a/scripts/mkcratersp.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2023 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-"""
-This script is used as a replacement for the Rust linker. It converts a linker
-command line into a rspfile that can be used during the link phase.
-"""
-
-import os
-import shutil
-import subprocess
-import sys
-
-def create_archive(out, objects, archives):
-  mricmd = f'create {out}\n'
-  for o in objects:
-    mricmd += f'addmod {o}\n'
-  for a in archives:
-    mricmd += f'addlib {a}\n'
-  mricmd += 'save\nend\n'
-  subprocess.run([os.getenv('AR'), '-M'], encoding='utf-8', input=mricmd, check=True)
-
-objects = []
-archives = []
-linkdirs = []
-libs = []
-temp_archives = []
-version_script = None
-
-for i, arg in enumerate(sys.argv):
-  if arg == '-o':
-    out = sys.argv[i+1]
-  if arg == '-L':
-    linkdirs.append(sys.argv[i+1])
-  if arg.startswith('-l') or arg == '-shared':
-    libs.append(arg)
-  if os.getenv('ANDROID_RUST_DARWIN') and (arg == '-dylib' or arg == '-dynamiclib'):
-    libs.append(arg)
-  if arg.startswith('-Wl,--version-script='):
-    version_script = arg[21:]
-  if arg[0] == '-':
-    continue
-  if arg.endswith('.o') or arg.endswith('.rmeta'):
-    objects.append(arg)
-  if arg.endswith('.rlib'):
-    if arg.startswith(os.getenv('TMPDIR')):
-      temp_archives.append(arg)
-    else:
-      archives.append(arg)
-
-create_archive(f'{out}.whole.a', objects, [])
-create_archive(f'{out}.a', [], temp_archives)
-
-with open(out, 'w') as f:
-  if os.getenv("ANDROID_RUST_DARWIN"):
-    print(f'-force_load', file=f)
-    print(f'{out}.whole.a', file=f)
-  else:
-    print(f'-Wl,--whole-archive', file=f)
-    print(f'{out}.whole.a', file=f)
-    print(f'-Wl,--no-whole-archive', file=f)
-  print(f'{out}.a', file=f)
-  for a in archives:
-    print(a, file=f)
-  for linkdir in linkdirs:
-    print(f'-L{linkdir}', file=f)
-  for l in libs:
-    print(l, file=f)
-  if version_script:
-    shutil.copyfile(version_script, f'{out}.version_script')
-    print(f'-Wl,--version-script={out}.version_script', file=f)
diff --git a/scripts/run-soong-tests-with-go-tools.sh b/scripts/run-soong-tests-with-go-tools.sh
new file mode 100755
index 0000000..93c622e
--- /dev/null
+++ b/scripts/run-soong-tests-with-go-tools.sh
@@ -0,0 +1,79 @@
+#!/bin/bash -ex
+
+: "${OUT_DIR:?Must set OUT_DIR}"
+TOP=$(cd $(dirname $0)/../../..; pwd)
+cd ${TOP}
+
+UNAME="$(uname)"
+case "$UNAME" in
+Linux)
+    OS='linux'
+    ;;
+Darwin)
+    OS='darwin'
+    ;;
+*)
+    exit 1
+    ;;
+esac
+
+# Verify that go test and go build work on all the same projects that are parsed by
+# build/soong/build_kzip.bash
+declare -ar go_modules=(build/blueprint build/soong
+      build/make/tools/canoninja build/make/tools/compliance build/make/tools/rbcrun)
+export GOROOT=${TOP}/prebuilts/go/${OS}-x86
+export GOENV=off
+export GOPROXY=off
+abs_out_dir=$(cd ${OUT_DIR}; pwd)
+export GOPATH=${abs_out_dir}/gopath
+export GOCACHE=${abs_out_dir}/gocache
+export GOMODCACHE=${abs_out_dir}/gomodcache
+export TMPDIR=${abs_out_dir}/gotemp
+mkdir -p ${TMPDIR}
+${GOROOT}/bin/go env
+
+if [[ ${OS} = linux ]]; then
+    # Building with the race detector enabled uses the host linker, set the
+    # path to use the hermetic one.
+    CLANG_VERSION=$(build/soong/scripts/get_clang_version.py)
+    export CC="${TOP}/prebuilts/clang/host/${OS}-x86/${CLANG_VERSION}/bin/clang"
+    export CXX="${TOP}/prebuilts/clang/host/${OS}-x86/${CLANG_VERSION}/bin/clang++"
+fi
+
+# androidmk_test.go gets confused if ANDROID_BUILD_TOP is set.
+unset ANDROID_BUILD_TOP
+
+network_jail=""
+if [[ ${OS} = linux ]]; then
+    # The go tools often try to fetch dependencies from the network,
+    # wrap them in an nsjail to prevent network access.
+    network_jail=${TOP}/prebuilts/build-tools/linux-x86/bin/nsjail
+    # Quiet
+    network_jail="${network_jail} -q"
+    # No timeout
+    network_jail="${network_jail} -t 0"
+    # Set working directory
+    network_jail="${network_jail} --cwd=\$PWD"
+    # Pass environment variables through
+    network_jail="${network_jail} -e"
+    # Allow read-only access to everything
+    network_jail="${network_jail} -R /"
+    # Allow write access to the out directory
+    network_jail="${network_jail} -B ${abs_out_dir}"
+    # Allow write access to the /tmp directory
+    network_jail="${network_jail} -B /tmp"
+    # Set high values, as network_jail uses low defaults.
+    network_jail="${network_jail} --rlimit_as soft"
+    network_jail="${network_jail} --rlimit_core soft"
+    network_jail="${network_jail} --rlimit_cpu soft"
+    network_jail="${network_jail} --rlimit_fsize soft"
+    network_jail="${network_jail} --rlimit_nofile soft"
+fi
+
+for dir in "${go_modules[@]}"; do
+    (cd "$dir";
+     eval ${network_jail} -- ${GOROOT}/bin/go build ./...
+     eval ${network_jail} -- ${GOROOT}/bin/go test ./...
+     eval ${network_jail} -- ${GOROOT}/bin/go test -race -short ./...
+    )
+done
diff --git a/scripts/strip.sh b/scripts/strip.sh
index d09c187..8d69f0d 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -29,6 +29,7 @@
 #   --keep-symbols
 #   --keep-symbols-and-debug-frame
 #   --remove-build-id
+#   --windows
 
 set -o pipefail
 
@@ -43,6 +44,7 @@
         --keep-symbols                  Keep symbols in out-file
         --keep-symbols-and-debug-frame  Keep symbols and .debug_frame in out-file
         --remove-build-id               Remove the gnu build-id section in out-file
+        --windows                       Input file is Windows DLL or executable
 EOF
     exit 1
 }
@@ -50,7 +52,11 @@
 do_strip() {
     # GNU strip --strip-all does not strip .ARM.attributes,
     # so we tell llvm-strip to keep it too.
-    "${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes "${infile}" -o "${outfile}.tmp"
+    local keep_section=--keep-section=.ARM.attributes
+    if [ -n "${windows}" ]; then
+      keep_section=
+    fi
+    "${CLANG_BIN}/llvm-strip" --strip-all ${keep_section} "${infile}" -o "${outfile}.tmp"
 }
 
 do_strip_keep_symbols_and_debug_frame() {
@@ -98,9 +104,17 @@
     "${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes --remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true
 
     if [ -z $fail ]; then
-        "${CREATE_MINIDEBUGINFO}" "${infile}" "${outfile}.mini_debuginfo.xz"
+        # create_minidebuginfo has issues with compressed debug sections. Just
+        # decompress them for now using objcopy which understands compressed
+        # debug sections.
+        # b/306150780 tracks supporting this directly in create_minidebuginfo
+        decompressed="$(mktemp)"
+        "${CLANG_BIN}/llvm-objcopy" --decompress-debug-sections \
+                "${infile}" "${decompressed}"
+
+        "${CREATE_MINIDEBUGINFO}" "${decompressed}" "${outfile}.mini_debuginfo.xz"
         "${CLANG_BIN}/llvm-objcopy" --add-section .gnu_debugdata="${outfile}.mini_debuginfo.xz" "${outfile}.tmp"
-        rm -f "${outfile}.mini_debuginfo.xz"
+        rm -f "${outfile}.mini_debuginfo.xz" "${decompressed}"
     else
         cp -f "${infile}" "${outfile}.tmp"
     fi
@@ -141,6 +155,7 @@
                 keep-symbols) keep_symbols=true ;;
                 keep-symbols-and-debug-frame) keep_symbols_and_debug_frame=true ;;
                 remove-build-id) remove_build_id=true ;;
+                windows) windows=true ;;
                 *) echo "Unknown option --${OPTARG}"; usage ;;
             esac;;
         ?) usage ;;
diff --git a/scripts/test_config_fixer.py b/scripts/test_config_fixer.py
index 07e01a1..2876bcb 100644
--- a/scripts/test_config_fixer.py
+++ b/scripts/test_config_fixer.py
@@ -19,6 +19,7 @@
 from __future__ import print_function
 
 import argparse
+import json
 import sys
 from xml.dom import minidom
 
@@ -31,6 +32,8 @@
 KNOWN_PREPARERS = ['com.android.tradefed.targetprep.TestAppInstallSetup',
                    'com.android.tradefed.targetprep.suite.SuiteApkInstaller']
 
+KNOWN_TEST_RUNNERS = ['com.android.tradefed.testtype.AndroidJUnitTest']
+
 MAINLINE_CONTROLLER = 'com.android.tradefed.testtype.suite.module.MainlineTestModuleController'
 
 def parse_args():
@@ -43,8 +46,12 @@
                       help=('overwrite package fields in the test config'))
   parser.add_argument('--test-file-name', default='', dest='test_file_name',
                       help=('overwrite test file name in the test config'))
+  parser.add_argument('--orig-test-file-name', default='', dest='orig_test_file_name',
+                      help=('Use with test-file-name to only override a single apk'))
   parser.add_argument('--mainline-package-name', default='', dest='mainline_package_name',
                       help=('overwrite mainline module package name in the test config'))
+  parser.add_argument('--test-runner-options', default='', dest='test_runner_options',
+                      help=('Add test runner options in the test config'))
   parser.add_argument('input', help='input test config file')
   parser.add_argument('output', help='output test config file')
   return parser.parse_args()
@@ -76,6 +83,18 @@
         if option.getAttribute('name') == "test-file-name":
           option.setAttribute('value', test_file_name)
 
+def overwrite_single_test_file_name(test_config_doc, orig_test_file_name, new_test_file_name):
+
+  test_config = parse_test_config(test_config_doc)
+  tests = get_children_with_tag(test_config, 'target_preparer')
+
+  for test in tests:
+    if test.getAttribute('class') in KNOWN_PREPARERS:
+      options = get_children_with_tag(test, 'option')
+      for option in options:
+        if option.getAttribute('name') == "test-file-name" and option.getAttribute('value') == orig_test_file_name:
+          option.setAttribute('value', new_test_file_name)
+
 def overwrite_mainline_module_package_name(test_config_doc, mainline_package_name):
 
   test_config = parse_test_config(test_config_doc)
@@ -86,6 +105,31 @@
         if option.getAttribute('name') == "mainline-module-package-name":
           option.setAttribute('value', mainline_package_name)
 
+def add_test_runner_options_toplevel(test_config_doc, test_runner_options):
+
+  test_config = parse_test_config(test_config_doc)
+
+  test_config.appendChild(test_config_doc.createComment("Options from Android.bp"))
+  test_config.appendChild(test_config_doc.createTextNode("\n"))
+  for new_option in json.loads(test_runner_options):
+    option = test_config_doc.createElement("option")
+    # name and value are mandatory,
+    name = new_option.get('Name')
+    if not name:
+      raise RuntimeError('"name" must set in test_runner_option"')
+    value = new_option.get('Value')
+    if not value:
+      raise RuntimeError('"value" must set in test_runner_option"')
+    option.setAttribute('name', name) # 'include-filter')
+    option.setAttribute('value', value) # 'android.test.example.devcodelab.DevCodelabTest#testHelloFail')
+    key = new_option.get('Key')
+    if key:
+      option.setAttribute('key', key) # 'include-filter')
+    # add tab and newline for readability
+    test_config.appendChild(test_config_doc.createTextNode("    "))
+    test_config.appendChild(option)
+    test_config.appendChild(test_config_doc.createTextNode("\n"))
+
 def main():
   """Program entry point."""
   try:
@@ -100,11 +144,20 @@
       overwrite_package_name(doc, manifest_doc, args.package_name)
 
     if args.test_file_name:
-      overwrite_test_file_name(doc, args.test_file_name)
+      if args.orig_test_file_name:
+        overwrite_single_test_file_name(doc, args.orig_test_file_name, args.test_file_name)
+      else:
+        # You probably never want to override the test_file_name if there
+        # are several in the xml, but this is currently only used on generated
+        # AndroidTest.xml where there is only a single test-file-name (no data)
+        overwrite_test_file_name(doc, args.test_file_name)
 
     if args.mainline_package_name:
       overwrite_mainline_module_package_name(doc, args.mainline_package_name)
 
+    if args.test_runner_options:
+      add_test_runner_options_toplevel(doc, args.test_runner_options)
+
     with open(args.output, 'w') as f:
       write_xml(f, doc)
 
diff --git a/scripts/uffd_gc_utils.py b/scripts/uffd_gc_utils.py
new file mode 100644
index 0000000..2d35494
--- /dev/null
+++ b/scripts/uffd_gc_utils.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Utils to determine whether to enable UFFD GC."""
+
+import re
+import sys
+
+
+def should_enable_uffd_gc(kernel_version_file):
+  with open(kernel_version_file, 'r') as f:
+    kernel_version = f.read().strip()
+  return should_enable_uffd_gc_impl(kernel_version)
+
+def should_enable_uffd_gc_impl(kernel_version):
+  # See https://source.android.com/docs/core/architecture/kernel/gki-versioning#determine-release
+  p = r"^(?P<w>\d+)[.](?P<x>\d+)[.](?P<y>\d+)(-android(?P<z>\d+)-(?P<k>\d+).*$)?"
+  m = re.match(p, kernel_version)
+  if m is not None:
+    if m.group('z') is not None:
+      android_release = int(m.group('z'))
+      # No need to check w, x, y because all Android 12 kernels have backports.
+      return android_release >= 12
+    else:
+      # Old kernel or non-GKI kernel.
+      version = int(m.group('w'))
+      patch_level = int(m.group('x'))
+      if version < 5:
+        # Old kernel.
+        return False
+      elif (version == 5 and patch_level >= 7) or version >= 6:
+        # New non-GKI kernel. 5.7 supports MREMAP_DONTUNMAP without the need for
+        # backports.
+        return True
+      else:
+        # Non-GKI kernel between 5 and 5.6. It may have backports.
+        raise exit_with_error(kernel_version)
+  elif kernel_version == '<unknown-kernel>':
+    # The kernel information isn't available to the build system, probably
+    # because PRODUCT_OTA_ENFORCE_VINTF_KERNEL_REQUIREMENTS is set to false. We
+    # assume that the kernel supports UFFD GC because it is the case for most of
+    # the products today and it is the future.
+    return True
+  else:
+    # Unrecognizable non-GKI kernel.
+    raise exit_with_error(kernel_version)
+
+def exit_with_error(kernel_version):
+  sys.exit(f"""
+Unable to determine UFFD GC flag for kernel version "{kernel_version}".
+You can fix this by explicitly setting PRODUCT_ENABLE_UFFD_GC to "true" or
+"false" based on the kernel version.
+1. Set PRODUCT_ENABLE_UFFD_GC to "true" if the kernel supports userfaultfd(2)
+   and MREMAP_DONTUNMAP.
+2. Set PRODUCT_ENABLE_UFFD_GC to "false" otherwise.""")
diff --git a/scripts/uffd_gc_utils_test.py b/scripts/uffd_gc_utils_test.py
new file mode 100644
index 0000000..c86ab4b
--- /dev/null
+++ b/scripts/uffd_gc_utils_test.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Unit tests for uffd_gc_utils.py."""
+
+import unittest
+
+from uffd_gc_utils import should_enable_uffd_gc_impl
+
+
+class UffdGcUtilsTest(unittest.TestCase):
+  def test_should_enable_uffd_gc_impl(self):
+    # GKI kernels in new format.
+    self.assertTrue(should_enable_uffd_gc_impl(
+        "6.1.25-android14-11-g34fde9ec08a3-ab10675345"))
+    self.assertTrue(should_enable_uffd_gc_impl(
+        "5.4.42-android12-0-something"))
+    self.assertFalse(should_enable_uffd_gc_impl(
+        "5.4.42-android11-0-something"))
+    # GKI kernels in old format.
+    self.assertFalse(should_enable_uffd_gc_impl(
+        "4.19.282-g4b749a433956-ab10893502"))
+    # Non GKI kernels.
+    self.assertTrue(should_enable_uffd_gc_impl(
+        "6.1.25-foo"))
+    self.assertTrue(should_enable_uffd_gc_impl(
+        "6.1.25"))
+    self.assertTrue(should_enable_uffd_gc_impl(
+        "5.10.19-foo"))
+    self.assertTrue(should_enable_uffd_gc_impl(
+        "5.10.19"))
+    with self.assertRaises(SystemExit):
+        should_enable_uffd_gc_impl("5.4.42-foo")
+    with self.assertRaises(SystemExit):
+        should_enable_uffd_gc_impl("5.4.42")
+    self.assertFalse(should_enable_uffd_gc_impl(
+        "4.19.282-foo"))
+    self.assertFalse(should_enable_uffd_gc_impl(
+        "4.19.282"))
+    with self.assertRaises(SystemExit):
+        should_enable_uffd_gc_impl("foo")
+    # No kernel.
+    self.assertTrue(should_enable_uffd_gc_impl(
+        "<unknown-kernel>"))
+
+
+if __name__ == '__main__':
+  unittest.main(verbosity=2)
diff --git a/sdk/Android.bp b/sdk/Android.bp
index f42b478..f436320 100644
--- a/sdk/Android.bp
+++ b/sdk/Android.bp
@@ -18,6 +18,7 @@
         "bp.go",
         "build_release.go",
         "exports.go",
+        "genrule.go",
         "member_trait.go",
         "member_type.go",
         "sdk.go",
@@ -30,6 +31,7 @@
         "cc_sdk_test.go",
         "compat_config_sdk_test.go",
         "exports_test.go",
+        "genrule_test.go",
         "java_sdk_test.go",
         "license_sdk_test.go",
         "member_trait_test.go",
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index ee1b5db..8d3bbfa 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -152,6 +152,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [],
+}
+
 prebuilt_bootclasspath_fragment {
     name: "art-bootclasspath-fragment",
     prefer: false,
@@ -187,6 +192,7 @@
     apex_available: ["com.android.art"],
     jars: ["java_boot_libs/snapshot/jars/are/invalid/core2.jar"],
 }
+
 `),
 		checkAllCopyRules(`
 .intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
@@ -206,8 +212,8 @@
 			checkBootJarsPackageCheckRule(t, result,
 				append(
 					[]string{
-						"out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/core1.jar",
-						"out/soong/.intermediates/prebuilts/apex/com.android.art.deapexer/android_common/deapexer/javalib/core2.jar",
+						"out/soong/.intermediates/prebuilts/apex/prebuilt_com.android.art.deapexer/android_common/deapexer/javalib/core1.jar",
+						"out/soong/.intermediates/prebuilts/apex/prebuilt_com.android.art.deapexer/android_common/deapexer/javalib/core2.jar",
 						"out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar",
 					},
 					java.ApexBootJarDexJarPaths...,
@@ -270,6 +276,12 @@
 		// Add a platform_bootclasspath that depends on the fragment.
 		fixtureAddPlatformBootclasspathForBootclasspathFragment("myapex", "mybootclasspathfragment"),
 
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
+
 		android.FixtureWithRootAndroidBp(sdk+`
 			apex {
 				name: "myapex",
@@ -347,6 +359,15 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [
+        "prebuilt_myothersdklibrary",
+        "prebuilt_mysdklibrary",
+        "prebuilt_mycoreplatform",
+    ],
+}
+
 prebuilt_bootclasspath_fragment {
     name: "mybootclasspathfragment",
     prefer: false,
@@ -489,15 +510,15 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
 .intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
-.intermediates/myothersdklibrary.stubs/android_common/combined/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
-.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
-.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
-.intermediates/mysdklibrary.stubs/android_common/combined/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
-.intermediates/mycoreplatform.stubs/android_common/combined/mycoreplatform.stubs.jar -> sdk_library/public/mycoreplatform-stubs.jar
-.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_api.txt -> sdk_library/public/mycoreplatform.txt
-.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt
+.intermediates/myothersdklibrary.stubs.exportable/android_common/combined/myothersdklibrary.stubs.exportable.jar -> sdk_library/public/myothersdklibrary-stubs.jar
+.intermediates/myothersdklibrary.stubs.source/android_common/exportable/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
+.intermediates/myothersdklibrary.stubs.source/android_common/exportable/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
+.intermediates/mysdklibrary.stubs.exportable/android_common/combined/mysdklibrary.stubs.exportable.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/exportable/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/exportable/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+.intermediates/mycoreplatform.stubs.exportable/android_common/combined/mycoreplatform.stubs.exportable.jar -> sdk_library/public/mycoreplatform-stubs.jar
+.intermediates/mycoreplatform.stubs.source/android_common/exportable/mycoreplatform.stubs.source_api.txt -> sdk_library/public/mycoreplatform.txt
+.intermediates/mycoreplatform.stubs.source/android_common/exportable/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt
 `)
 	})
 
@@ -509,15 +530,15 @@
 .intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
 .intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
 .intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
-.intermediates/myothersdklibrary.stubs/android_common/combined/myothersdklibrary.stubs.jar -> sdk_library/public/myothersdklibrary-stubs.jar
-.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
-.intermediates/myothersdklibrary.stubs.source/android_common/metalava/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
-.intermediates/mysdklibrary.stubs/android_common/combined/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
-.intermediates/mycoreplatform.stubs/android_common/combined/mycoreplatform.stubs.jar -> sdk_library/public/mycoreplatform-stubs.jar
-.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_api.txt -> sdk_library/public/mycoreplatform.txt
-.intermediates/mycoreplatform.stubs.source/android_common/metalava/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt
+.intermediates/myothersdklibrary.stubs.exportable/android_common/combined/myothersdklibrary.stubs.exportable.jar -> sdk_library/public/myothersdklibrary-stubs.jar
+.intermediates/myothersdklibrary.stubs.source/android_common/exportable/myothersdklibrary.stubs.source_api.txt -> sdk_library/public/myothersdklibrary.txt
+.intermediates/myothersdklibrary.stubs.source/android_common/exportable/myothersdklibrary.stubs.source_removed.txt -> sdk_library/public/myothersdklibrary-removed.txt
+.intermediates/mysdklibrary.stubs.exportable/android_common/combined/mysdklibrary.stubs.exportable.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/exportable/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/exportable/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+.intermediates/mycoreplatform.stubs.exportable/android_common/combined/mycoreplatform.stubs.exportable.jar -> sdk_library/public/mycoreplatform-stubs.jar
+.intermediates/mycoreplatform.stubs.source/android_common/exportable/mycoreplatform.stubs.source_api.txt -> sdk_library/public/mycoreplatform.txt
+.intermediates/mycoreplatform.stubs.source/android_common/exportable/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt
 `
 	t.Run("added-via-apex", func(t *testing.T) {
 		testSnapshotWithBootClasspathFragment_Contents(t, `
@@ -636,6 +657,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mysdklibrary"],
+}
+
 prebuilt_bootclasspath_fragment {
     name: "mybootclasspathfragment",
     prefer: false,
@@ -760,6 +786,12 @@
 		// Add a platform_bootclasspath that depends on the fragment.
 		fixtureAddPlatformBootclasspathForBootclasspathFragment("myapex", "mybootclasspathfragment"),
 
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
+
 		android.MockFS{
 			"my-blocked.txt":                   nil,
 			"my-max-target-o-low-priority.txt": nil,
@@ -869,6 +901,14 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [
+        "prebuilt_mynewlibrary",
+        "prebuilt_mysdklibrary",
+    ],
+}
+
 prebuilt_bootclasspath_fragment {
     name: "mybootclasspathfragment",
     prefer: false,
@@ -963,12 +1003,12 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
 .intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/mybootlib.jar
-.intermediates/mynewlibrary.stubs/android_common/combined/mynewlibrary.stubs.jar -> sdk_library/public/mynewlibrary-stubs.jar
-.intermediates/mynewlibrary.stubs.source/android_common/metalava/mynewlibrary.stubs.source_api.txt -> sdk_library/public/mynewlibrary.txt
-.intermediates/mynewlibrary.stubs.source/android_common/metalava/mynewlibrary.stubs.source_removed.txt -> sdk_library/public/mynewlibrary-removed.txt
-.intermediates/mysdklibrary.stubs/android_common/combined/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+.intermediates/mynewlibrary.stubs.exportable/android_common/combined/mynewlibrary.stubs.exportable.jar -> sdk_library/public/mynewlibrary-stubs.jar
+.intermediates/mynewlibrary.stubs.source/android_common/exportable/mynewlibrary.stubs.source_api.txt -> sdk_library/public/mynewlibrary.txt
+.intermediates/mynewlibrary.stubs.source/android_common/exportable/mynewlibrary.stubs.source_removed.txt -> sdk_library/public/mynewlibrary-removed.txt
+.intermediates/mysdklibrary.stubs.exportable/android_common/combined/mysdklibrary.stubs.exportable.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/exportable/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/exportable/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
 `),
 		snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot),
 		snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot),
@@ -996,6 +1036,15 @@
 		android.FixtureMergeEnv(map[string]string{
 			"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": targetBuildRelease,
 		}),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_version_active_codenames = []string{"VanillaIceCream"}
+		}),
+
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
 
 		android.FixtureWithRootAndroidBp(`
 			sdk {
@@ -1095,15 +1144,15 @@
 .intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/index.csv -> hiddenapi/index.csv
 .intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/stub-flags.csv -> hiddenapi/stub-flags.csv
 .intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi-for-sdk-snapshot/all-flags.csv -> hiddenapi/all-flags.csv
-.intermediates/mysdklibrary.stubs/android_common/combined/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+.intermediates/mysdklibrary.stubs.exportable/android_common/combined/mysdklibrary.stubs.exportable.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/exportable/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/exportable/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
 `
 
 		// On S the stub flags should only be generated from mysdklibrary as mynewsdklibrary is not part
 		// of the snapshot.
 		expectedStubFlagsInputs := []string{
-			"out/soong/.intermediates/mysdklibrary.stubs/android_common/dex/mysdklibrary.stubs.jar",
+			"out/soong/.intermediates/mysdklibrary.stubs.exportable/android_common/dex/mysdklibrary.stubs.exportable.jar",
 			"out/soong/.intermediates/mysdklibrary/android_common/aligned/mysdklibrary.jar",
 		}
 
@@ -1173,20 +1222,20 @@
 .intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
 .intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
 .intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
-.intermediates/mysdklibrary.stubs/android_common/combined/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
-.intermediates/mynewsdklibrary.stubs/android_common/combined/mynewsdklibrary.stubs.jar -> sdk_library/public/mynewsdklibrary-stubs.jar
-.intermediates/mynewsdklibrary.stubs.source/android_common/metalava/mynewsdklibrary.stubs.source_api.txt -> sdk_library/public/mynewsdklibrary.txt
-.intermediates/mynewsdklibrary.stubs.source/android_common/metalava/mynewsdklibrary.stubs.source_removed.txt -> sdk_library/public/mynewsdklibrary-removed.txt
+.intermediates/mysdklibrary.stubs.exportable/android_common/combined/mysdklibrary.stubs.exportable.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/exportable/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/exportable/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+.intermediates/mynewsdklibrary.stubs.exportable/android_common/combined/mynewsdklibrary.stubs.exportable.jar -> sdk_library/public/mynewsdklibrary-stubs.jar
+.intermediates/mynewsdklibrary.stubs.source/android_common/exportable/mynewsdklibrary.stubs.source_api.txt -> sdk_library/public/mynewsdklibrary.txt
+.intermediates/mynewsdklibrary.stubs.source/android_common/exportable/mynewsdklibrary.stubs.source_removed.txt -> sdk_library/public/mynewsdklibrary-removed.txt
 `
 
 		// On tiramisu the stub flags should be generated from both mynewsdklibrary and mysdklibrary as
 		// they are both part of the snapshot.
 		expectedStubFlagsInputs := []string{
-			"out/soong/.intermediates/mynewsdklibrary.stubs/android_common/dex/mynewsdklibrary.stubs.jar",
+			"out/soong/.intermediates/mynewsdklibrary.stubs.exportable/android_common/dex/mynewsdklibrary.stubs.exportable.jar",
 			"out/soong/.intermediates/mynewsdklibrary/android_common/aligned/mynewsdklibrary.jar",
-			"out/soong/.intermediates/mysdklibrary.stubs/android_common/dex/mysdklibrary.stubs.jar",
+			"out/soong/.intermediates/mysdklibrary.stubs.exportable/android_common/dex/mysdklibrary.stubs.exportable.jar",
 			"out/soong/.intermediates/mysdklibrary/android_common/aligned/mysdklibrary.jar",
 		}
 
@@ -1208,6 +1257,9 @@
 		android.FixtureMergeEnv(map[string]string{
 			"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": "S",
 		}),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_version_active_codenames = []string{"VanillaIceCream"}
+		}),
 		android.FixtureWithRootAndroidBp(`
 			sdk {
 				name: "mysdk",
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 265579a..9490d12 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -123,6 +123,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_sdkmember"],
+}
+
 cc_prebuilt_library_shared {
     name: "sdkmember",
     prefer: false,
@@ -226,6 +231,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_crtobj"],
+}
+
 cc_prebuilt_object {
     name: "crtobj",
     prefer: false,
@@ -333,6 +343,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
@@ -406,6 +421,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
@@ -465,6 +485,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mymodule_exports.contributions",
+    contents: ["prebuilt_mynativebinary"],
+}
+
 cc_prebuilt_binary {
     name: "mynativebinary",
     prefer: false,
@@ -523,6 +548,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_mynativebinary"],
+}
+
 cc_prebuilt_binary {
     name: "mynativebinary",
     prefer: false,
@@ -621,6 +651,14 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: [
+        "prebuilt_mynativebinary",
+        "prebuilt_mynativelib",
+    ],
+}
+
 cc_prebuilt_binary {
     name: "mynativebinary",
     prefer: false,
@@ -696,6 +734,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mymodule_exports.contributions",
+    contents: ["prebuilt_linker"],
+}
+
 cc_prebuilt_binary {
     name: "linker",
     prefer: false,
@@ -755,6 +798,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
@@ -856,6 +904,15 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [
+        "prebuilt_mynativelib",
+        "prebuilt_myothernativelib",
+        "prebuilt_mysystemnativelib",
+    ],
+}
+
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
@@ -953,6 +1010,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
@@ -1029,6 +1091,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
@@ -1095,6 +1162,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_static {
     name: "mynativelib",
     prefer: false,
@@ -1158,6 +1230,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_static {
     name: "mynativelib",
     prefer: false,
@@ -1222,6 +1299,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library {
     name: "mynativelib",
     prefer: false,
@@ -1298,6 +1380,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library {
     name: "mynativelib",
     prefer: false,
@@ -1394,6 +1481,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library {
     name: "mynativelib",
     prefer: false,
@@ -1520,6 +1612,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_static {
     name: "mynativelib",
     prefer: false,
@@ -1572,6 +1669,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativeheaders"],
+}
+
 cc_prebuilt_library_headers {
     name: "mynativeheaders",
     prefer: false,
@@ -1594,6 +1696,9 @@
 		PrepareForTestWithSdkBuildComponents,
 		ccTestFs.AddToFixture(),
 		prepareForTestWithNativeBridgeTarget,
+		android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+			android.RegisterApexContributionsBuildComponents(ctx)
+		}),
 	).RunTestWithBp(t, `
 		sdk {
 			name: "mysdk",
@@ -1616,6 +1721,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativeheaders"],
+}
+
 cc_prebuilt_library_headers {
     name: "mynativeheaders",
     prefer: false,
@@ -1679,6 +1789,9 @@
 			cc.PrepareForTestWithCcDefaultModules,
 			PrepareForTestWithSdkBuildComponents,
 			ccTestFs.AddToFixture(),
+			android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+				android.RegisterApexContributionsBuildComponents(ctx)
+			}),
 		).RunTestWithBp(t, fmt.Sprintf(`
 		sdk {
 			name: "mysdk",
@@ -1701,6 +1814,11 @@
 			checkAndroidBpContents(fmt.Sprintf(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativeheaders"],
+}
+
 cc_prebuilt_library_headers {
     name: "mynativeheaders",
     prefer: false,
@@ -1750,6 +1868,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativeheaders"],
+}
+
 cc_prebuilt_library_headers {
     name: "mynativeheaders",
     prefer: false,
@@ -1807,6 +1930,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativeheaders"],
+}
+
 cc_prebuilt_library_headers {
     name: "mynativeheaders",
     prefer: false,
@@ -1870,6 +1998,15 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [
+        "prebuilt_sslnil",
+        "prebuilt_sslempty",
+        "prebuilt_sslnonempty",
+    ],
+}
+
 cc_prebuilt_library_shared {
     name: "sslnil",
     prefer: false,
@@ -1943,6 +2080,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_sslvariants"],
+}
+
 cc_prebuilt_library_shared {
     name: "sslvariants",
     prefer: false,
@@ -2002,6 +2144,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_stubslib"],
+}
+
 cc_prebuilt_library_shared {
     name: "stubslib",
     prefer: false,
@@ -2056,6 +2203,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_stubslib"],
+}
+
 cc_prebuilt_library_shared {
     name: "stubslib",
     prefer: false,
@@ -2114,6 +2266,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mylib"],
+}
+
 cc_prebuilt_library_shared {
     name: "mylib",
     prefer: false,
@@ -2178,6 +2335,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mynativelib"],
+}
+
 cc_prebuilt_library_shared {
     name: "mynativelib",
     prefer: false,
diff --git a/sdk/compat_config_sdk_test.go b/sdk/compat_config_sdk_test.go
index 45e8e0e..75b5229 100644
--- a/sdk/compat_config_sdk_test.go
+++ b/sdk/compat_config_sdk_test.go
@@ -36,6 +36,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myconfig"],
+}
+
 prebuilt_platform_compat_config {
     name: "myconfig",
     prefer: false,
diff --git a/sdk/exports_test.go b/sdk/exports_test.go
index 2605fd1..9d0a242 100644
--- a/sdk/exports_test.go
+++ b/sdk/exports_test.go
@@ -46,6 +46,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
diff --git a/sdk/genrule.go b/sdk/genrule.go
new file mode 100644
index 0000000..347ab05
--- /dev/null
+++ b/sdk/genrule.go
@@ -0,0 +1,44 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package sdk
+
+import (
+	"android/soong/android"
+	"android/soong/genrule"
+)
+
+func init() {
+	registerGenRuleBuildComponents(android.InitRegistrationContext)
+}
+
+func registerGenRuleBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("sdk_genrule", SdkGenruleFactory)
+}
+
+// sdk_genrule_host is a genrule that can depend on sdk and sdk_snapshot module types
+//
+// What this means is that it's a genrule with only the "common_os" variant.
+// sdk modules have 3 variants: host, android, and common_os. The common_os one depends
+// on the host/device ones and packages their result into a final snapshot zip.
+// Genrules probably want access to this snapshot zip when they depend on an sdk module,
+// which means they want to depend on the common_os variant and not the host/android
+// variants.
+func SdkGenruleFactory() android.Module {
+	module := genrule.NewGenRule()
+
+	android.InitCommonOSAndroidMultiTargetsArchModule(module, android.NeitherHostNorDeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+
+	return module
+}
diff --git a/sdk/genrule_test.go b/sdk/genrule_test.go
new file mode 100644
index 0000000..6e52a3d
--- /dev/null
+++ b/sdk/genrule_test.go
@@ -0,0 +1,52 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package sdk
+
+import (
+	"testing"
+
+	"android/soong/android"
+	"android/soong/genrule"
+	"android/soong/java"
+)
+
+func TestSdkGenrule(t *testing.T) {
+	// Test that an sdk_genrule can depend on an sdk, and that a genrule can depend on an sdk_genrule
+	bp := `
+				sdk {
+					name: "my_sdk",
+				}
+				sdk_genrule {
+					name: "my_sdk_genrule",
+					tool_files: ["tool"],
+					cmd: "$(location tool) $(in) $(out)",
+					srcs: [":my_sdk"],
+					out: ["out"],
+				}
+				genrule {
+					name: "my_regular_genrule",
+					srcs: [":my_sdk_genrule"],
+					out: ["out"],
+					cmd: "cp $(in) $(out)",
+				}
+			`
+	android.GroupFixturePreparers(
+		// if java components aren't registered, the sdk module doesn't create a snapshot for some reason.
+		java.PrepareForTestWithJavaBuildComponents,
+		genrule.PrepareForTestWithGenRuleBuildComponents,
+		PrepareForTestWithSdkBuildComponents,
+		android.FixtureRegisterWithContext(registerGenRuleBuildComponents),
+	).RunTestWithBp(t, bp)
+}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 680494f..0a5483b 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -45,6 +45,11 @@
 	java.PrepareForTestWithJavaDefaultModules,
 	java.PrepareForTestWithJavaSdkLibraryFiles,
 	java.FixtureWithLastReleaseApis("myjavalib"),
+	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+		variables.BuildFlags = map[string]string{
+			"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+		}
+	}),
 )
 
 // Contains tests for SDK members provided by the java package.
@@ -103,6 +108,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -149,6 +159,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -188,6 +203,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -240,6 +260,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -286,6 +311,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -308,6 +338,9 @@
 			android.FixtureMergeEnv(map[string]string{
 				"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": targetBuildRelease,
 			}),
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.Platform_version_active_codenames = []string{"VanillaIceCream"}
+			}),
 		).RunTestWithBp(t, `
 		sdk {
 			name: "mysdk",
@@ -390,6 +423,11 @@
 			checkAndroidBpContents(fmt.Sprintf(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mylib"],
+}
+
 java_import {
     name: "mylib",
     prefer: false,
@@ -454,6 +492,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: [],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -499,6 +542,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -537,6 +585,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_myjavatests"],
+}
+
 java_test_import {
     name: "myjavatests",
     prefer: false,
@@ -577,6 +630,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: ["prebuilt_myjavatests"],
+}
+
 java_test_import {
     name: "myjavatests",
     prefer: false,
@@ -608,6 +666,11 @@
 			"1": {"myjavalib"},
 			"2": {"myjavalib"},
 		}),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
 	).RunTestWithBp(t, `
 		sdk {
 			name: "mysdk",
@@ -625,6 +688,12 @@
 			public: {
 				enabled: true,
 			},
+			system: {
+				enabled: true,
+			},
+			module_lib: {
+				enabled: true,
+			},
 		}
 
 		java_system_modules {
@@ -651,6 +720,15 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [
+        "prebuilt_exported-system-module",
+        "prebuilt_myjavalib",
+        "prebuilt_my-system-modules",
+    ],
+}
+
 java_import {
     name: "exported-system-module",
     prefer: false,
@@ -680,6 +758,20 @@
         removed_api: "sdk_library/public/myjavalib-removed.txt",
         sdk_version: "current",
     },
+    system: {
+        jars: ["sdk_library/system/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/system/myjavalib_stub_sources"],
+        current_api: "sdk_library/system/myjavalib.txt",
+        removed_api: "sdk_library/system/myjavalib-removed.txt",
+        sdk_version: "system_current",
+    },
+    module_lib: {
+        jars: ["sdk_library/module-lib/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/module-lib/myjavalib_stub_sources"],
+        current_api: "sdk_library/module-lib/myjavalib.txt",
+        removed_api: "sdk_library/module-lib/myjavalib-removed.txt",
+        sdk_version: "module_current",
+    },
 }
 
 java_system_modules_import {
@@ -696,9 +788,15 @@
 		checkAllCopyRules(`
 .intermediates/exported-system-module/android_common/turbine-combined/exported-system-module.jar -> java/exported-system-module.jar
 .intermediates/system-module/android_common/turbine-combined/system-module.jar -> java/system-module.jar
-.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable.system/android_common/combined/myjavalib.stubs.exportable.system.jar -> sdk_library/system/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.system/android_common/exportable/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
+.intermediates/myjavalib.stubs.source.system/android_common/exportable/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable.module_lib/android_common/combined/myjavalib.stubs.exportable.module_lib.jar -> sdk_library/module-lib/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.module_lib/android_common/exportable/myjavalib.stubs.source.module_lib_api.txt -> sdk_library/module-lib/myjavalib.txt
+.intermediates/myjavalib.stubs.source.module_lib/android_common/exportable/myjavalib.stubs.source.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt
 `),
 		checkInfoContents(result.Config, `
 [
@@ -733,11 +831,23 @@
     "@name": "myjavalib",
     "dist_stem": "myjavalib",
     "scopes": {
+      "module-lib": {
+        "current_api": "sdk_library/module-lib/myjavalib.txt",
+        "latest_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib.api.module-lib.latest/gen/myjavalib.api.module-lib.latest",
+        "latest_removed_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib-removed.api.module-lib.latest/gen/myjavalib-removed.api.module-lib.latest",
+        "removed_api": "sdk_library/module-lib/myjavalib-removed.txt"
+      },
       "public": {
         "current_api": "sdk_library/public/myjavalib.txt",
         "latest_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib.api.public.latest/gen/myjavalib.api.public.latest",
         "latest_removed_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib-removed.api.public.latest/gen/myjavalib-removed.api.public.latest",
         "removed_api": "sdk_library/public/myjavalib-removed.txt"
+      },
+      "system": {
+        "current_api": "sdk_library/system/myjavalib.txt",
+        "latest_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib.api.system.latest/gen/myjavalib.api.system.latest",
+        "latest_removed_api": "out/soong/.intermediates/prebuilts/sdk/myjavalib-removed.api.system.latest/gen/myjavalib-removed.api.system.latest",
+        "removed_api": "sdk_library/system/myjavalib-removed.txt"
       }
     }
   },
@@ -780,6 +890,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_my-system-modules"],
+}
+
 java_import {
     name: "mysdk_system-module",
     prefer: false,
@@ -844,6 +959,15 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "myexports.contributions",
+    contents: [
+        "prebuilt_hostjavalib",
+        "prebuilt_androidjavalib",
+        "prebuilt_myjavalib",
+    ],
+}
+
 java_import {
     name: "hostjavalib",
     prefer: false,
@@ -910,6 +1034,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -941,15 +1070,15 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
-.intermediates/myjavalib.stubs.system/android_common/combined/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source.system/android_common/metalava/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
-.intermediates/myjavalib.stubs.source.system/android_common/metalava/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
-.intermediates/myjavalib.stubs.test/android_common/combined/myjavalib.stubs.test.jar -> sdk_library/test/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source.test/android_common/metalava/myjavalib.stubs.source.test_api.txt -> sdk_library/test/myjavalib.txt
-.intermediates/myjavalib.stubs.source.test/android_common/metalava/myjavalib.stubs.source.test_removed.txt -> sdk_library/test/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable.system/android_common/combined/myjavalib.stubs.exportable.system.jar -> sdk_library/system/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.system/android_common/exportable/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
+.intermediates/myjavalib.stubs.source.system/android_common/exportable/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable.test/android_common/combined/myjavalib.stubs.exportable.test.jar -> sdk_library/test/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.test/android_common/exportable/myjavalib.stubs.source.test_api.txt -> sdk_library/test/myjavalib.txt
+.intermediates/myjavalib.stubs.source.test/android_common/exportable/myjavalib.stubs.source.test_removed.txt -> sdk_library/test/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
@@ -983,6 +1112,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib-foo"],
+}
+
 java_sdk_library_import {
     name: "myjavalib-foo",
     prefer: false,
@@ -999,9 +1133,9 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib-foo.stubs/android_common/combined/myjavalib-foo.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib-foo.stubs.source/android_common/metalava/myjavalib-foo.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib-foo.stubs.source/android_common/metalava/myjavalib-foo.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib-foo.stubs.exportable/android_common/combined/myjavalib-foo.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib-foo.stubs.source/android_common/exportable/myjavalib-foo.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib-foo.stubs.source/android_common/exportable/myjavalib-foo.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
@@ -1036,6 +1170,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1052,10 +1191,10 @@
 }
 		`),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source-stubs.srcjar -> sdk_library/public/myjavalib.srcjar
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source-stubs.srcjar -> sdk_library/public/myjavalib.srcjar
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 		`),
 	)
 }
@@ -1083,6 +1222,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1100,10 +1244,10 @@
 }
 		`),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_annotations.zip -> sdk_library/public/myjavalib_annotations.zip
+.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_annotations.zip -> sdk_library/public/myjavalib_annotations.zip
 		`),
 		checkMergeZips(".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip"),
 	)
@@ -1137,6 +1281,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1153,16 +1302,23 @@
 }
 		`),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 		`),
 		checkMergeZips(".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip"),
 	)
 }
 
 func TestSnapshotWithJavaSdkLibrary_CompileDex(t *testing.T) {
-	result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, `
+	result := android.GroupFixturePreparers(
+		prepareForSdkTestWithJavaSdkLibrary,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
+	).RunTestWithBp(t, `
 		sdk {
 			name: "mysdk",
 			java_sdk_libs: ["myjavalib"],
@@ -1187,6 +1343,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1214,21 +1375,22 @@
 			ctx := android.ModuleInstallPathContextForTesting(result.Config)
 			dexJarBuildPath := func(name string, kind android.SdkKind) string {
 				dep := result.Module(name, "android_common").(java.SdkLibraryDependency)
-				path := dep.SdkApiStubDexJar(ctx, kind).Path()
+				path := dep.SdkApiExportableStubDexJar(ctx, kind).Path()
 				return path.RelativeToTop().String()
 			}
 
 			dexJarPath := dexJarBuildPath("myjavalib", android.SdkPublic)
-			android.AssertStringEquals(t, "source dex public stubs jar build path", "out/soong/.intermediates/myjavalib.stubs/android_common/dex/myjavalib.stubs.jar", dexJarPath)
+			android.AssertStringEquals(t, "source dex public stubs jar build path", "out/soong/.intermediates/myjavalib.stubs.exportable/android_common/dex/myjavalib.stubs.exportable.jar", dexJarPath)
 
 			dexJarPath = dexJarBuildPath("myjavalib", android.SdkSystem)
-			systemDexJar := "out/soong/.intermediates/myjavalib.stubs.system/android_common/dex/myjavalib.stubs.system.jar"
+			systemDexJar := "out/soong/.intermediates/myjavalib.stubs.exportable.system/android_common/dex/myjavalib.stubs.exportable.system.jar"
 			android.AssertStringEquals(t, "source dex system stubs jar build path", systemDexJar, dexJarPath)
 
 			// This should fall back to system as module is not available.
 			dexJarPath = dexJarBuildPath("myjavalib", android.SdkModule)
 			android.AssertStringEquals(t, "source dex module stubs jar build path", systemDexJar, dexJarPath)
 
+			// Prebuilt dex jar does not come from the exportable stubs.
 			dexJarPath = dexJarBuildPath(android.PrebuiltNameFromSource("myjavalib"), android.SdkPublic)
 			android.AssertStringEquals(t, "prebuilt dex public stubs jar build path", "out/soong/.intermediates/snapshot/prebuilt_myjavalib.stubs/android_common/dex/myjavalib.stubs.jar", dexJarPath)
 		}),
@@ -1254,6 +1416,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1270,9 +1437,9 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
@@ -1302,6 +1469,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1318,9 +1490,9 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
@@ -1353,6 +1525,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1376,12 +1553,12 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
-.intermediates/myjavalib.stubs.system/android_common/combined/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source.system/android_common/metalava/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
-.intermediates/myjavalib.stubs.source.system/android_common/metalava/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable.system/android_common/combined/myjavalib.stubs.exportable.system.jar -> sdk_library/system/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.system/android_common/exportable/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
+.intermediates/myjavalib.stubs.source.system/android_common/exportable/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
@@ -1418,6 +1595,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1448,15 +1630,15 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
-.intermediates/myjavalib.stubs.system/android_common/combined/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source.system/android_common/metalava/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
-.intermediates/myjavalib.stubs.source.system/android_common/metalava/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
-.intermediates/myjavalib.stubs.module_lib/android_common/combined/myjavalib.stubs.module_lib.jar -> sdk_library/module-lib/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source.module_lib/android_common/metalava/myjavalib.stubs.source.module_lib_api.txt -> sdk_library/module-lib/myjavalib.txt
-.intermediates/myjavalib.stubs.source.module_lib/android_common/metalava/myjavalib.stubs.source.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable.system/android_common/combined/myjavalib.stubs.exportable.system.jar -> sdk_library/system/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.system/android_common/exportable/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
+.intermediates/myjavalib.stubs.source.system/android_common/exportable/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable.module_lib/android_common/combined/myjavalib.stubs.exportable.module_lib.jar -> sdk_library/module-lib/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.module_lib/android_common/exportable/myjavalib.stubs.source.module_lib_api.txt -> sdk_library/module-lib/myjavalib.txt
+.intermediates/myjavalib.stubs.source.module_lib/android_common/exportable/myjavalib.stubs.source.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/module-lib/myjavalib_stub_sources.zip",
@@ -1491,6 +1673,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1514,12 +1701,12 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
-.intermediates/myjavalib.stubs.system_server/android_common/combined/myjavalib.stubs.system_server.jar -> sdk_library/system-server/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source.system_server/android_common/metalava/myjavalib.stubs.source.system_server_api.txt -> sdk_library/system-server/myjavalib.txt
-.intermediates/myjavalib.stubs.source.system_server/android_common/metalava/myjavalib.stubs.source.system_server_removed.txt -> sdk_library/system-server/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable.system_server/android_common/combined/myjavalib.stubs.exportable.system_server.jar -> sdk_library/system-server/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.system_server/android_common/exportable/myjavalib.stubs.source.system_server_api.txt -> sdk_library/system-server/myjavalib.txt
+.intermediates/myjavalib.stubs.source.system_server/android_common/exportable/myjavalib.stubs.source.system_server_removed.txt -> sdk_library/system-server/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
@@ -1551,6 +1738,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1568,9 +1760,9 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
@@ -1608,6 +1800,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_sdk_library_import {
     name: "myjavalib",
     prefer: false,
@@ -1625,9 +1822,9 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/combined/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/metalava/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.exportable/android_common/combined/myjavalib.stubs.exportable.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/exportable/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 docs/known_doctags -> doctags/docs/known_doctags
 `),
 	)
diff --git a/sdk/license_sdk_test.go b/sdk/license_sdk_test.go
index 829edf1..754f019 100644
--- a/sdk/license_sdk_test.go
+++ b/sdk/license_sdk_test.go
@@ -69,6 +69,11 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
diff --git a/sdk/member_trait_test.go b/sdk/member_trait_test.go
index 99caf13..673d6fb 100644
--- a/sdk/member_trait_test.go
+++ b/sdk/member_trait_test.go
@@ -137,6 +137,11 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -202,6 +207,17 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [
+        "prebuilt_myjavalib",
+        "prebuilt_myjavalib_extra",
+        "prebuilt_myjavalib_special",
+        "prebuilt_anotherjavalib",
+        "prebuilt_anotherjavalib_special",
+    ],
+}
+
 java_test_import {
     name: "myjavalib",
     prefer: false,
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 4d4a2a2..fd16ab6 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -222,6 +222,18 @@
 	}}
 }
 
+func (s *sdk) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		if s.snapshotFile.Valid() {
+			return []android.Path{s.snapshotFile.Path()}, nil
+		}
+		return nil, fmt.Errorf("snapshot file not defined. This is most likely because this isn't the common_os variant of this module")
+	default:
+		return nil, fmt.Errorf("unknown tag %q", tag)
+	}
+}
+
 // gatherTraits gathers the traits from the dynamically generated trait specific properties.
 //
 // Returns a map from member name to the set of required traits.
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 5a25146..f9d49d9 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -118,6 +118,16 @@
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: [
+        "prebuilt_myjavalib",
+        "prebuilt_mypublicjavalib",
+        "prebuilt_mydefaultedjavalib",
+        "prebuilt_myprivatejavalib",
+    ],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -398,6 +408,11 @@
 			checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_myjavalib"],
+}
+
 java_import {
     name: "myjavalib",
     prefer: false,
@@ -442,12 +457,22 @@
 			android.FixtureMergeEnv(map[string]string{
 				"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": "S",
 			}),
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				variables.BuildFlags = map[string]string{
+					"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+				}
+			}),
 		).RunTest(t)
 
 		CheckSnapshot(t, result, "mysdk", "",
 			checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mysdklibrary"],
+}
+
 prebuilt_bootclasspath_fragment {
     name: "mybootclasspathfragment",
     prefer: false,
@@ -487,9 +512,9 @@
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/stub-flags.csv -> hiddenapi/stub-flags.csv
 .intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/all-flags.csv -> hiddenapi/all-flags.csv
-.intermediates/mysdklibrary.stubs/android_common/combined/mysdklibrary.stubs.jar -> sdk_library/public/mysdklibrary-stubs.jar
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
-.intermediates/mysdklibrary.stubs.source/android_common/metalava/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
+.intermediates/mysdklibrary.stubs.exportable/android_common/combined/mysdklibrary.stubs.exportable.jar -> sdk_library/public/mysdklibrary-stubs.jar
+.intermediates/mysdklibrary.stubs.source/android_common/exportable/mysdklibrary.stubs.source_api.txt -> sdk_library/public/mysdklibrary.txt
+.intermediates/mysdklibrary.stubs.source/android_common/exportable/mysdklibrary.stubs.source_removed.txt -> sdk_library/public/mysdklibrary-removed.txt
 `),
 		)
 	})
diff --git a/sdk/systemserverclasspath_fragment_sdk_test.go b/sdk/systemserverclasspath_fragment_sdk_test.go
index 7ccc114..c1c4ed6 100644
--- a/sdk/systemserverclasspath_fragment_sdk_test.go
+++ b/sdk/systemserverclasspath_fragment_sdk_test.go
@@ -34,6 +34,9 @@
 				env["SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE"] = targetBuildRelease
 			}
 		}),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_version_active_codenames = []string{"VanillaIceCream"}
+		}),
 		prepareForSdkTestWithApex,
 
 		android.FixtureWithRootAndroidBp(sdk+`
@@ -86,6 +89,98 @@
 	)
 }
 
+func TestSnapshotWithPartialSystemServerClasspathFragment(t *testing.T) {
+	commonSdk := `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			min_sdk_version: "Tiramisu",
+			systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
+		}
+		systemserverclasspath_fragment {
+			name: "mysystemserverclasspathfragment",
+			apex_available: ["myapex"],
+			contents: [
+				"mysdklibrary",
+				"mysdklibrary-future",
+			],
+		}
+		java_sdk_library {
+			name: "mysdklibrary",
+			apex_available: ["myapex"],
+			srcs: ["Test.java"],
+			min_sdk_version: "33", // Tiramisu
+		}
+		java_sdk_library {
+			name: "mysdklibrary-future",
+			apex_available: ["myapex"],
+			srcs: ["Test.java"],
+			min_sdk_version: "34", // UpsideDownCake
+		}
+		sdk {
+			name: "mysdk",
+			apexes: ["myapex"],
+		}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForSdkTestWithJava,
+		java.PrepareForTestWithJavaDefaultModules,
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		java.FixtureWithLastReleaseApis("mysdklibrary", "mysdklibrary-future"),
+		dexpreopt.FixtureSetApexSystemServerJars("myapex:mysdklibrary", "myapex:mysdklibrary-future"),
+		android.FixtureModifyEnv(func(env map[string]string) {
+			// targeting Tiramisu here means that we won't export mysdklibrary-future
+			env["SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE"] = "Tiramisu"
+		}),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_version_active_codenames = []string{"UpsideDownCake"}
+		}),
+		prepareForSdkTestWithApex,
+		android.FixtureWithRootAndroidBp(commonSdk),
+	).RunTest(t)
+
+	CheckSnapshot(t, result, "mysdk", "", checkAndroidBpContents(
+		`// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+    name: "mysdklibrary",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    shared_library: true,
+    public: {
+        jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/public/mysdklibrary.txt",
+        removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+        sdk_version: "current",
+    },
+    system: {
+        jars: ["sdk_library/system/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/system/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/system/mysdklibrary.txt",
+        removed_api: "sdk_library/system/mysdklibrary-removed.txt",
+        sdk_version: "system_current",
+    },
+    test: {
+        jars: ["sdk_library/test/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/test/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/test/mysdklibrary.txt",
+        removed_api: "sdk_library/test/mysdklibrary-removed.txt",
+        sdk_version: "test_current",
+    },
+}
+
+prebuilt_systemserverclasspath_fragment {
+    name: "mysystemserverclasspathfragment",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    contents: ["mysdklibrary"],
+} `))
+}
+
 func TestSnapshotWithEmptySystemServerClasspathFragment(t *testing.T) {
 	commonSdk := `
 		apex {
@@ -150,6 +245,11 @@
 	expectedLatestSnapshot := `
 // This is auto-generated. DO NOT EDIT.
 
+apex_contributions_defaults {
+    name: "mysdk.contributions",
+    contents: ["prebuilt_mysdklibrary"],
+}
+
 java_sdk_library_import {
     name: "mysdklibrary",
     prefer: false,
diff --git a/sdk/update.go b/sdk/update.go
index 4c39fae..afecf9f 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -24,6 +24,7 @@
 
 	"android/soong/apex"
 	"android/soong/cc"
+	"android/soong/java"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -89,19 +90,6 @@
 	indentLevel int
 }
 
-// generatedFile abstracts operations for writing contents into a file and emit a build rule
-// for the file.
-type generatedFile struct {
-	generatedContents
-	path android.OutputPath
-}
-
-func newGeneratedFile(ctx android.ModuleContext, path ...string) *generatedFile {
-	return &generatedFile{
-		path: android.PathForModuleOut(ctx, path...).OutputPath,
-	}
-}
-
 func (gc *generatedContents) Indent() {
 	gc.indentLevel++
 }
@@ -122,26 +110,6 @@
 	_, _ = fmt.Fprintf(&(gc.content), format, args...)
 }
 
-func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderContext, implicits android.Paths) {
-	rb := android.NewRuleBuilder(pctx, ctx)
-
-	content := gf.content.String()
-
-	// ninja consumes newline characters in rspfile_content. Prevent it by
-	// escaping the backslash in the newline character. The extra backslash
-	// is removed when the rspfile is written to the actual script file
-	content = strings.ReplaceAll(content, "\n", "\\n")
-
-	rb.Command().
-		Implicits(implicits).
-		Text("echo -n").Text(proptools.ShellEscape(content)).
-		// convert \\n to \n
-		Text("| sed 's/\\\\n/\\n/g' >").Output(gf.path)
-	rb.Command().
-		Text("chmod a+x").Output(gf.path)
-	rb.Build(gf.path.Base(), "Build "+gf.path.Base())
-}
-
 // Collect all the members.
 //
 // Updates the sdk module with a list of sdkMemberVariantDep instances and details as to which
@@ -166,14 +134,11 @@
 			// Keep track of which multilib variants are used by the sdk.
 			s.multilibUsages = s.multilibUsages.addArchType(child.Target().Arch.ArchType)
 
-			var exportedComponentsInfo android.ExportedComponentsInfo
-			if ctx.OtherModuleHasProvider(child, android.ExportedComponentsInfoProvider) {
-				exportedComponentsInfo = ctx.OtherModuleProvider(child, android.ExportedComponentsInfoProvider).(android.ExportedComponentsInfo)
-			}
+			exportedComponentsInfo, _ := android.OtherModuleProvider(ctx, child, android.ExportedComponentsInfoProvider)
 
 			var container android.Module
 			if parent != ctx.Module() {
-				container = parent.(android.Module)
+				container = parent
 			}
 
 			minApiLevel := android.MinApiLevelForSdkSnapshot(ctx, child)
@@ -182,7 +147,7 @@
 			s.memberVariantDeps = append(s.memberVariantDeps, sdkMemberVariantDep{
 				sdkVariant:             s,
 				memberType:             memberType,
-				variant:                child.(android.Module),
+				variant:                child,
 				minApiLevel:            minApiLevel,
 				container:              container,
 				export:                 export,
@@ -198,6 +163,20 @@
 	})
 }
 
+// A denylist of modules whose host variants will be removed from the generated snapshots above the ApiLevel
+// even if they are listed in the corresponding `sdk`.
+// The key is the module name
+// The value is the _last_ dessert where the host variant of the module will be present
+// This is a workaround to ensure that these modules are generated in <=$ApiLevel, but not in in >=$ApiLevel
+var ignoreHostModuleVariantsAboveDessert = map[string]android.ApiLevel{
+	// ignore host variant of libdexfile and its transitive dependencies.
+	// The platform test that depends on them (`libunwindstack_unit_test` at the time of writing)
+	// no longer requires a prebuilt variant of libdexfile.
+	"libdexfile":    android.ApiLevelUpsideDownCake,
+	"libartpalette": android.ApiLevelUpsideDownCake,
+	"libartbase":    android.ApiLevelUpsideDownCake,
+}
+
 // groupMemberVariantsByMemberThenType groups the member variant dependencies so that all the
 // variants of each member are grouped together within an sdkMember instance.
 //
@@ -216,6 +195,14 @@
 		variant := memberVariantDep.variant
 
 		name := ctx.OtherModuleName(variant)
+		targetApiLevel, err := android.ApiLevelFromUser(ctx, targetBuildRelease.name)
+		if err != nil {
+			targetApiLevel = android.FutureApiLevel
+		}
+		if lastApiLevel, exists := ignoreHostModuleVariantsAboveDessert[name]; exists && targetApiLevel.GreaterThan(lastApiLevel) && memberVariantDep.Host() {
+			// ignore host variant of this module if the targetApiLevel is V and above.
+			continue
+		}
 		member := byName[name]
 		if member == nil {
 			member = &sdkMember{memberType: memberType, name: name}
@@ -378,7 +365,7 @@
 
 	snapshotDir := android.PathForModuleOut(ctx, "snapshot")
 
-	bp := newGeneratedFile(ctx, "snapshot", "Android.bp")
+	bp := android.PathForModuleOut(ctx, "snapshot", "Android.bp")
 
 	bpFile := &bpFile{
 		modules: make(map[string]*bpModule),
@@ -392,7 +379,7 @@
 		sdk:                   s,
 		snapshotDir:           snapshotDir.OutputPath,
 		copies:                make(map[string]string),
-		filesToZip:            []android.Path{bp.path},
+		filesToZip:            []android.Path{bp},
 		bpFile:                bpFile,
 		prebuiltModules:       make(map[string]*bpModule),
 		allMembersByName:      allMembersByName,
@@ -424,6 +411,7 @@
 
 	// Create the prebuilt modules for each of the member modules.
 	traits := s.gatherTraits()
+	memberNames := []string{} // soong module names of the members. contains the prebuilt_ prefix.
 	for _, member := range members {
 		memberType := member.memberType
 		if !memberType.ArePrebuiltsRequired() {
@@ -445,6 +433,38 @@
 
 		prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member)
 		s.createMemberSnapshot(memberCtx, member, prebuiltModule.(*bpModule))
+
+		if member.memberType != android.LicenseModuleSdkMemberType && !builder.isInternalMember(member.name) {
+			// More exceptions
+			// 1. Skip BCP and SCCP fragments
+			// 2. Skip non-sdk contents of BCP and SCCP fragments
+			//
+			// The non-sdk contents of BCP/SSCP fragments should only be used for dexpreopt and hiddenapi,
+			// and are not available to the rest of the build.
+			if android.InList(member.memberType,
+				[]android.SdkMemberType{
+					// bcp
+					java.BootclasspathFragmentSdkMemberType,
+					java.JavaBootLibsSdkMemberType,
+					// sscp
+					java.SystemServerClasspathFragmentSdkMemberType,
+					java.JavaSystemserverLibsSdkMemberType,
+				},
+			) {
+				continue
+			}
+
+			memberNames = append(memberNames, android.PrebuiltNameFromSource(member.name))
+		}
+	}
+
+	// create an apex_contributions_defaults for this module's sdk.
+	// this module type is supported in V and above.
+	if targetApiLevel.GreaterThan(android.ApiLevelUpsideDownCake) {
+		ac := newModule("apex_contributions_defaults")
+		ac.AddProperty("name", s.Name()+".contributions")
+		ac.AddProperty("contents", memberNames)
+		bpFile.AddModule(ac)
 	}
 
 	// Create a transformer that will transform a module by replacing any references
@@ -466,17 +486,14 @@
 	}
 
 	// generate Android.bp
-	bp = newGeneratedFile(ctx, "snapshot", "Android.bp")
-	generateBpContents(&bp.generatedContents, bpFile)
-
-	contents := bp.content.String()
+	contents := generateBpContents(bpFile)
 	// If the snapshot is being generated for the current build release then check the syntax to make
 	// sure that it is compatible.
 	if targetBuildRelease == buildReleaseCurrent {
 		syntaxCheckSnapshotBpFile(ctx, contents)
 	}
 
-	bp.build(pctx, ctx, nil)
+	android.WriteFileRuleVerbatim(ctx, bp, contents)
 
 	// Copy the build number file into the snapshot.
 	builder.CopyToSnapshot(ctx.Config().BuildNumberFile(ctx), BUILD_NUMBER_FILE)
@@ -525,16 +542,14 @@
 	modules := s.generateInfoData(ctx, memberVariantDeps)
 
 	// Output the modules information as pretty printed JSON.
-	info := newGeneratedFile(ctx, fmt.Sprintf("%s%s.info", ctx.ModuleName(), snapshotFileSuffix))
+	info := android.PathForModuleOut(ctx, fmt.Sprintf("%s%s.info", ctx.ModuleName(), snapshotFileSuffix))
 	output, err := json.MarshalIndent(modules, "", "  ")
 	if err != nil {
 		ctx.ModuleErrorf("error generating %q: %s", info, err)
 	}
 	builder.infoContents = string(output)
-	info.generatedContents.UnindentedPrintf("%s", output)
-	info.build(pctx, ctx, nil)
-	infoPath := info.path
-	installedInfo := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), infoPath.Base(), infoPath)
+	android.WriteFileRuleVerbatim(ctx, info, builder.infoContents)
+	installedInfo := ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), info.Base(), info)
 	s.infoFile = android.OptionalPathForPath(installedInfo)
 
 	// Install the zip, making sure that the info file has been installed as well.
@@ -607,7 +622,7 @@
 				name:       name,
 			}
 
-			additionalSdkInfo := ctx.OtherModuleProvider(module, android.AdditionalSdkInfoProvider).(android.AdditionalSdkInfo)
+			additionalSdkInfo, _ := android.OtherModuleProvider(ctx, module, android.AdditionalSdkInfoProvider)
 			info.memberSpecific = additionalSdkInfo.Properties
 
 			name2Info[name] = info
@@ -721,105 +736,6 @@
 	}
 }
 
-// snapshotModuleStaticProperties contains snapshot static (i.e. not dynamically generated) properties.
-type snapshotModuleStaticProperties struct {
-	Compile_multilib string `android:"arch_variant"`
-}
-
-// combinedSnapshotModuleProperties are the properties that are associated with the snapshot module.
-type combinedSnapshotModuleProperties struct {
-	// The sdk variant from which this information was collected.
-	sdkVariant *sdk
-
-	// Static snapshot module properties.
-	staticProperties *snapshotModuleStaticProperties
-
-	// The dynamically generated member list properties.
-	dynamicProperties interface{}
-}
-
-// collateSnapshotModuleInfo collates all the snapshot module info from supplied sdk variants.
-func (s *sdk) collateSnapshotModuleInfo(ctx android.BaseModuleContext, sdkVariants []*sdk, memberVariantDeps []sdkMemberVariantDep) []*combinedSnapshotModuleProperties {
-	sdkVariantToCombinedProperties := map[*sdk]*combinedSnapshotModuleProperties{}
-	var list []*combinedSnapshotModuleProperties
-	for _, sdkVariant := range sdkVariants {
-		staticProperties := &snapshotModuleStaticProperties{
-			Compile_multilib: sdkVariant.multilibUsages.String(),
-		}
-		dynamicProperties := s.dynamicSdkMemberTypes.createMemberTypeListProperties()
-
-		combinedProperties := &combinedSnapshotModuleProperties{
-			sdkVariant:        sdkVariant,
-			staticProperties:  staticProperties,
-			dynamicProperties: dynamicProperties,
-		}
-		sdkVariantToCombinedProperties[sdkVariant] = combinedProperties
-
-		list = append(list, combinedProperties)
-	}
-
-	for _, memberVariantDep := range memberVariantDeps {
-		// If the member dependency is internal then do not add the dependency to the snapshot member
-		// list properties.
-		if !memberVariantDep.export {
-			continue
-		}
-
-		combined := sdkVariantToCombinedProperties[memberVariantDep.sdkVariant]
-		memberListProperty := s.memberTypeListProperty(memberVariantDep.memberType)
-		memberName := ctx.OtherModuleName(memberVariantDep.variant)
-
-		if memberListProperty.getter == nil {
-			continue
-		}
-
-		// Append the member to the appropriate list, if it is not already present in the list.
-		memberList := memberListProperty.getter(combined.dynamicProperties)
-		if !android.InList(memberName, memberList) {
-			memberList = append(memberList, memberName)
-		}
-		memberListProperty.setter(combined.dynamicProperties, memberList)
-	}
-
-	return list
-}
-
-func (s *sdk) optimizeSnapshotModuleProperties(ctx android.ModuleContext, list []*combinedSnapshotModuleProperties) *combinedSnapshotModuleProperties {
-
-	// Extract the dynamic properties and add them to a list of propertiesContainer.
-	propertyContainers := []propertiesContainer{}
-	for _, i := range list {
-		propertyContainers = append(propertyContainers, sdkVariantPropertiesContainer{
-			sdkVariant: i.sdkVariant,
-			properties: i.dynamicProperties,
-		})
-	}
-
-	// Extract the common members, removing them from the original properties.
-	commonDynamicProperties := s.dynamicSdkMemberTypes.createMemberTypeListProperties()
-	extractor := newCommonValueExtractor(commonDynamicProperties)
-	extractCommonProperties(ctx, extractor, commonDynamicProperties, propertyContainers)
-
-	// Extract the static properties and add them to a list of propertiesContainer.
-	propertyContainers = []propertiesContainer{}
-	for _, i := range list {
-		propertyContainers = append(propertyContainers, sdkVariantPropertiesContainer{
-			sdkVariant: i.sdkVariant,
-			properties: i.staticProperties,
-		})
-	}
-
-	commonStaticProperties := &snapshotModuleStaticProperties{}
-	extractor = newCommonValueExtractor(commonStaticProperties)
-	extractCommonProperties(ctx, extractor, &commonStaticProperties, propertyContainers)
-
-	return &combinedSnapshotModuleProperties{
-		sdkVariant:        nil,
-		staticProperties:  commonStaticProperties,
-		dynamicProperties: commonDynamicProperties,
-	}
-}
-
 type propertyTag struct {
 	name string
 }
@@ -888,7 +804,8 @@
 	}
 }
 
-func generateBpContents(contents *generatedContents, bpFile *bpFile) {
+func generateBpContents(bpFile *bpFile) string {
+	contents := &generatedContents{}
 	contents.IndentedPrintf("// This is auto-generated. DO NOT EDIT.\n")
 	for _, bpModule := range bpFile.order {
 		contents.IndentedPrintf("\n")
@@ -896,6 +813,7 @@
 		outputPropertySet(contents, bpModule.bpPropertySet)
 		contents.IndentedPrintf("}\n")
 	}
+	return contents.content.String()
 }
 
 func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
@@ -1010,7 +928,7 @@
 		contents.IndentedPrintf("}")
 
 	default:
-		panic(fmt.Errorf("Unknown type: %T of value %#v", value, value))
+		panic(fmt.Errorf("unknown type: %T of value %#v", value, value))
 	}
 }
 
@@ -1021,9 +939,7 @@
 }
 
 func (s *sdk) GetAndroidBpContentsForTests() string {
-	contents := &generatedContents{}
-	generateBpContents(contents, s.builderForTests.bpFile)
-	return contents.content.String()
+	return generateBpContents(s.builderForTests.bpFile)
 }
 
 func (s *sdk) GetInfoContentsForTests() string {
@@ -1171,7 +1087,7 @@
 
 	// The licenses are the same for all variants.
 	mctx := s.ctx
-	licenseInfo := mctx.OtherModuleProvider(variant, android.LicenseInfoProvider).(android.LicenseInfo)
+	licenseInfo, _ := android.OtherModuleProvider(mctx, variant, android.LicenseInfoProvider)
 	if len(licenseInfo.Licenses) > 0 {
 		m.AddPropertyWithTag("licenses", licenseInfo.Licenses, s.OptionalSdkMemberReferencePropertyTag())
 	}
@@ -1337,7 +1253,7 @@
 	case "lib64":
 		return m | multilib64
 	default:
-		panic(fmt.Errorf("Unknown Multilib field in ArchType, expected 'lib32' or 'lib64', found %q", multilib))
+		panic(fmt.Errorf("unknown Multilib field in ArchType, expected 'lib32' or 'lib64', found %q", multilib))
 	}
 }
 
@@ -1352,7 +1268,7 @@
 	case multilibBoth:
 		return "both"
 	default:
-		panic(fmt.Errorf("Unknown multilib value, found %b, expected one of %b, %b, %b or %b",
+		panic(fmt.Errorf("unknown multilib value, found %b, expected one of %b, %b, %b or %b",
 			m, multilibNone, multilib32, multilib64, multilibBoth))
 	}
 }
@@ -1417,7 +1333,7 @@
 		variantsByApex := make(map[string]android.Module)
 		conflictDetected := false
 		for _, variant := range list {
-			apexInfo := moduleCtx.OtherModuleProvider(variant, android.ApexInfoProvider).(android.ApexInfo)
+			apexInfo, _ := android.OtherModuleProvider(moduleCtx, variant, android.ApexInfoProvider)
 			apexVariationName := apexInfo.ApexVariationName
 			// If there are two variants for a specific APEX variation then there is conflict.
 			if _, ok := variantsByApex[apexVariationName]; ok {
@@ -2305,20 +2221,6 @@
 	optimizableProperties() interface{}
 }
 
-// A wrapper for sdk variant related properties to allow them to be optimized.
-type sdkVariantPropertiesContainer struct {
-	sdkVariant *sdk
-	properties interface{}
-}
-
-func (c sdkVariantPropertiesContainer) optimizableProperties() interface{} {
-	return c.properties
-}
-
-func (c sdkVariantPropertiesContainer) String() string {
-	return c.sdkVariant.String()
-}
-
 // Extract common properties from a slice of property structures of the same type.
 //
 // All the property structures must be of the same type.
diff --git a/sh/Android.bp b/sh/Android.bp
index f9198dc..930fcf5 100644
--- a/sh/Android.bp
+++ b/sh/Android.bp
@@ -10,6 +10,8 @@
         "soong",
         "soong-android",
         "soong-cc",
+        "soong-java",
+        "soong-testing",
         "soong-tradefed",
     ],
     srcs: [
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index d2eede6..3cbbc45 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -17,16 +17,15 @@
 import (
 	"fmt"
 	"path/filepath"
-	"sort"
 	"strings"
 
+	"android/soong/testing"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/cc"
-	"android/soong/snapshot"
 	"android/soong/tradefed"
 )
 
@@ -143,6 +142,9 @@
 	// Only available for host sh_test modules.
 	Data_device_libs []string `android:"path,arch_variant"`
 
+	// list of java modules that provide data that should be installed alongside the test.
+	Java_data []string
+
 	// Install the test into a folder named for the module in all test suites.
 	Per_testcase_directory *bool
 
@@ -152,7 +154,6 @@
 
 type ShBinary struct {
 	android.ModuleBase
-	android.BazelModuleBase
 
 	properties shBinaryProperties
 
@@ -170,7 +171,7 @@
 
 	installDir android.InstallPath
 
-	data       android.Paths
+	data       []android.DataPath
 	testConfig android.Path
 
 	dataModules map[string]android.Path
@@ -187,6 +188,15 @@
 	return s.outputFilePath
 }
 
+func (s *ShBinary) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		return android.Paths{s.outputFilePath}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
+}
+
 func (s *ShBinary) SubDir() string {
 	return proptools.String(s.properties.Sub_dir)
 }
@@ -260,6 +270,7 @@
 		Output: s.outputFilePath,
 		Input:  s.sourceFilePath,
 	})
+	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: []string{s.sourceFilePath.String()}})
 }
 
 func (s *ShBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -307,6 +318,7 @@
 	shTestDataLibsTag       = dependencyTag{name: "dataLibs"}
 	shTestDataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"}
 	shTestDataDeviceLibsTag = dependencyTag{name: "dataDeviceLibs"}
+	shTestJavaDataTag       = dependencyTag{name: "javaData"}
 )
 
 var sharedLibVariations = []blueprint.Variation{{Mutator: "link", Variation: "shared"}}
@@ -322,6 +334,10 @@
 		ctx.AddFarVariationDependencies(deviceVariations, shTestDataDeviceBinsTag, s.testProperties.Data_device_bins...)
 		ctx.AddFarVariationDependencies(append(deviceVariations, sharedLibVariations...),
 			shTestDataDeviceLibsTag, s.testProperties.Data_device_libs...)
+
+		javaDataVariation := []blueprint.Variation{{"arch", android.Common.String()}}
+		ctx.AddVariationDependencies(javaDataVariation, shTestJavaDataTag, s.testProperties.Java_data...)
+
 	} else if ctx.Target().Os.Class != android.Host {
 		if len(s.testProperties.Data_device_bins) > 0 {
 			ctx.PropertyErrorf("data_device_bins", "only available for host modules")
@@ -329,6 +345,9 @@
 		if len(s.testProperties.Data_device_libs) > 0 {
 			ctx.PropertyErrorf("data_device_libs", "only available for host modules")
 		}
+		if len(s.testProperties.Java_data) > 0 {
+			ctx.PropertyErrorf("Java_data", "only available for host modules")
+		}
 	}
 }
 
@@ -339,10 +358,21 @@
 		return
 	}
 	s.dataModules[relPath] = path
+	s.data = append(s.data, android.DataPath{SrcPath: path})
 }
 
 func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	s.ShBinary.generateAndroidBuildActions(ctx)
+
+	expandedData := android.PathsForModuleSrc(ctx, s.testProperties.Data)
+	// Emulate the data property for java_data dependencies.
+	for _, javaData := range ctx.GetDirectDepsWithTag(shTestJavaDataTag) {
+		expandedData = append(expandedData, android.OutputFilesForModule(ctx, javaData, "")...)
+	}
+	for _, d := range expandedData {
+		s.data = append(s.data, android.DataPath{SrcPath: d})
+	}
+
 	testDir := "nativetest"
 	if ctx.Target().Arch.ArchType.Multilib == "lib64" {
 		testDir = "nativetest64"
@@ -359,9 +389,6 @@
 	} else {
 		s.installDir = android.PathForModuleInstall(ctx, testDir, s.Name())
 	}
-	s.installedFile = ctx.InstallExecutable(s.installDir, s.outputFilePath.Base(), s.outputFilePath)
-
-	s.data = android.PathsForModuleSrc(ctx, s.testProperties.Data)
 
 	var configs []tradefed.Config
 	if Bool(s.testProperties.Require_root) {
@@ -410,7 +437,7 @@
 				if _, exist := s.dataModules[relPath]; exist {
 					return
 				}
-				relocatedLib := android.PathForModuleOut(ctx, "relocated", relPath)
+				relocatedLib := android.PathForModuleOut(ctx, "relocated").Join(ctx, relPath)
 				ctx.Build(pctx, android.BuildParams{
 					Rule:   android.Cp,
 					Input:  cc.OutputFile().Path(),
@@ -426,6 +453,11 @@
 			ctx.PropertyErrorf(property, "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
 		}
 	})
+
+	installedData := ctx.InstallTestData(s.installDir, s.data)
+	s.installedFile = ctx.InstallExecutable(s.installDir, s.outputFilePath.Base(), s.outputFilePath, installedData...)
+
+	android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 func (s *ShTest) InstallInData() bool {
@@ -445,24 +477,6 @@
 				if s.testConfig != nil {
 					entries.SetPath("LOCAL_FULL_TEST_CONFIG", s.testConfig)
 				}
-				for _, d := range s.data {
-					rel := d.Rel()
-					path := d.String()
-					if !strings.HasSuffix(path, rel) {
-						panic(fmt.Errorf("path %q does not end with %q", path, rel))
-					}
-					path = strings.TrimSuffix(path, rel)
-					entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel)
-				}
-				relPaths := make([]string, 0)
-				for relPath, _ := range s.dataModules {
-					relPaths = append(relPaths, relPath)
-				}
-				sort.Strings(relPaths)
-				for _, relPath := range relPaths {
-					dir := strings.TrimSuffix(s.dataModules[relPath].String(), relPath)
-					entries.AddStrings("LOCAL_TEST_DATA", dir+":"+relPath)
-				}
 				if s.testProperties.Data_bins != nil {
 					entries.AddStrings("LOCAL_TEST_DATA_BINS", s.testProperties.Data_bins...)
 				}
@@ -474,18 +488,15 @@
 	}}
 }
 
-func initShBinaryModule(s *ShBinary, useBazel bool) {
+func initShBinaryModule(s *ShBinary) {
 	s.AddProperties(&s.properties)
-	if useBazel {
-		android.InitBazelModule(s)
-	}
 }
 
 // sh_binary is for a shell script or batch file to be installed as an
 // executable binary to <partition>/bin.
 func ShBinaryFactory() android.Module {
 	module := &ShBinary{}
-	initShBinaryModule(module, true)
+	initShBinaryModule(module)
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst)
 	return module
 }
@@ -494,7 +505,7 @@
 // to $(HOST_OUT)/bin.
 func ShBinaryHostFactory() android.Module {
 	module := &ShBinary{}
-	initShBinaryModule(module, true)
+	initShBinaryModule(module)
 	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
 	return module
 }
@@ -502,7 +513,7 @@
 // sh_test defines a shell script based test module.
 func ShTestFactory() android.Module {
 	module := &ShTest{}
-	initShBinaryModule(&module.ShBinary, false)
+	initShBinaryModule(&module.ShBinary)
 	module.AddProperties(&module.testProperties)
 
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst)
@@ -512,7 +523,7 @@
 // sh_test_host defines a shell script based test module that runs on a host.
 func ShTestHostFactory() android.Module {
 	module := &ShTest{}
-	initShBinaryModule(&module.ShBinary, false)
+	initShBinaryModule(&module.ShBinary)
 	module.AddProperties(&module.testProperties)
 	// Default sh_test_host to unit_tests = true
 	if module.testProperties.Test_options.Unit_test == nil {
@@ -523,59 +534,4 @@
 	return module
 }
 
-type bazelShBinaryAttributes struct {
-	Srcs     bazel.LabelListAttribute
-	Filename *string
-	Sub_dir  *string
-	// Bazel also supports the attributes below, but (so far) these are not required for Bionic
-	// deps
-	// data
-	// args
-	// compatible_with
-	// deprecation
-	// distribs
-	// env
-	// exec_compatible_with
-	// exec_properties
-	// features
-	// licenses
-	// output_licenses
-	// restricted_to
-	// tags
-	// target_compatible_with
-	// testonly
-	// toolchains
-	// visibility
-}
-
-func (m *ShBinary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	srcs := bazel.MakeLabelListAttribute(
-		android.BazelLabelForModuleSrc(ctx, []string{*m.properties.Src}))
-
-	var filename *string
-	if m.properties.Filename != nil {
-		filename = m.properties.Filename
-	}
-
-	var subDir *string
-	if m.properties.Sub_dir != nil {
-		subDir = m.properties.Sub_dir
-	}
-
-	attrs := &bazelShBinaryAttributes{
-		Srcs:     srcs,
-		Filename: filename,
-		Sub_dir:  subDir,
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "sh_binary",
-		Bzl_load_location: "//build/bazel/rules:sh_binary.bzl",
-	}
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
-}
-
 var Bool = proptools.Bool
-
-var _ snapshot.RelativeInstallPath = (*ShBinary)(nil)
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 89b8126..37450b0 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -9,6 +9,7 @@
 
 	"android/soong/android"
 	"android/soong/cc"
+	"android/soong/java"
 )
 
 func TestMain(m *testing.M) {
@@ -17,6 +18,7 @@
 
 var prepareForShTest = android.GroupFixturePreparers(
 	cc.PrepareForTestWithCcBuildComponents,
+	java.PrepareForTestWithJavaDefaultModules,
 	PrepareForTestWithShBuildComponents,
 	android.FixtureMergeMockFs(android.MockFS{
 		"test.sh":            nil,
@@ -133,7 +135,7 @@
 		if arch == "darwin_x86_64" {
 			libExt = ".dylib"
 		}
-		relocated := variant.Output("relocated/lib64/libbar" + libExt)
+		relocated := variant.Output(filepath.Join("out/soong/.intermediates/foo", arch, "relocated/lib64/libbar"+libExt))
 		expectedInput := "out/soong/.intermediates/libbar/" + arch + "_shared/libbar" + libExt
 		android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input)
 
@@ -202,18 +204,19 @@
 	`)
 
 	buildOS := config.BuildOS.String()
-	variant := ctx.ModuleForTests("foo", buildOS+"_x86_64")
+	variant := buildOS + "_x86_64"
+	foo := ctx.ModuleForTests("foo", variant)
 
-	relocated := variant.Output("relocated/lib64/libbar.so")
+	relocated := foo.Output(filepath.Join("out/soong/.intermediates/foo", variant, "relocated/lib64/libbar.so"))
 	expectedInput := "out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so"
 	android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input)
 
-	mod := variant.Module().(*ShTest)
+	mod := foo.Module().(*ShTest)
 	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
 	expectedData := []string{
 		"out/soong/.intermediates/bar/android_arm64_armv8-a/:bar",
 		// libbar has been relocated, and so has a variant that matches the host arch.
-		"out/soong/.intermediates/foo/" + buildOS + "_x86_64/relocated/:lib64/libbar.so",
+		"out/soong/.intermediates/foo/" + variant + "/relocated/:lib64/libbar.so",
 	}
 	actualData := entries.EntryMap["LOCAL_TEST_DATA"]
 	android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
@@ -255,3 +258,39 @@
 		t.Errorf("foo extraConfings %v does not contain %q", autogen.Args["extraConfigs"], expectedBinAutogenConfig)
 	}
 }
+
+func TestShTestHost_javaData(t *testing.T) {
+	ctx, config := testShBinary(t, `
+		sh_test_host {
+			name: "foo",
+			src: "test.sh",
+			filename: "test.sh",
+			data: [
+				"testdata/data1",
+				"testdata/sub/data2",
+			],
+			java_data: [
+				"javalib",
+			],
+		}
+
+		java_library_host {
+			name: "javalib",
+			srcs: [],
+		}
+	`)
+	buildOS := ctx.Config().BuildOS.String()
+	mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest)
+	if !mod.Host() {
+		t.Errorf("host bit is not set for a sh_test_host module.")
+	}
+	expectedData := []string{
+		":testdata/data1",
+		":testdata/sub/data2",
+		"out/soong/.intermediates/javalib/" + buildOS + "_common/combined/:javalib.jar",
+	}
+
+	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
+	actualData := entries.EntryMap["LOCAL_TEST_DATA"]
+	android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
+}
diff --git a/snapshot/Android.bp b/snapshot/Android.bp
index 3354993..6cb318e 100644
--- a/snapshot/Android.bp
+++ b/snapshot/Android.bp
@@ -16,15 +16,11 @@
     srcs: [
         "host_fake_snapshot.go",
         "host_snapshot.go",
-        "recovery_snapshot.go",
-        "snapshot.go",
         "snapshot_base.go",
         "util.go",
-        "vendor_snapshot.go",
     ],
     testSrcs: [
         "host_test.go",
-        "test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/snapshot/host_fake_snapshot.go b/snapshot/host_fake_snapshot.go
index c4cfbb5..63cd4e1 100644
--- a/snapshot/host_fake_snapshot.go
+++ b/snapshot/host_fake_snapshot.go
@@ -119,7 +119,7 @@
 		if !module.Enabled() || module.IsHideFromMake() {
 			return
 		}
-		apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+		apexInfo, _ := android.SingletonModuleProvider(ctx, module, android.ApexInfoProvider)
 		if !apexInfo.IsForPlatform() {
 			return
 		}
diff --git a/snapshot/recovery_snapshot.go b/snapshot/recovery_snapshot.go
deleted file mode 100644
index 8ff59cb..0000000
--- a/snapshot/recovery_snapshot.go
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package snapshot
-
-import "android/soong/android"
-
-// Interface for modules which can be captured in the recovery snapshot.
-type RecoverySnapshotModuleInterface interface {
-	SnapshotModuleInterfaceBase
-	InRecovery() bool
-	ExcludeFromRecoverySnapshot() bool
-}
-
-var recoverySnapshotSingleton = SnapshotSingleton{
-	"recovery",                     // name
-	"SOONG_RECOVERY_SNAPSHOT_ZIP",  // makeVar
-	android.OptionalPath{},         // snapshotZipFile
-	RecoverySnapshotImageSingleton, // Image
-	false,                          // Fake
-}
-
-func RecoverySnapshotSingleton() android.Singleton {
-	return &recoverySnapshotSingleton
-}
-
-// Determine if a dir under source tree is an SoC-owned proprietary directory based
-// on recovery snapshot configuration
-// Examples: device/, vendor/
-func isRecoveryProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
-	return RecoverySnapshotSingleton().(*SnapshotSingleton).Image.IsProprietaryPath(dir, deviceConfig)
-}
-
-func IsRecoveryProprietaryModule(ctx android.BaseModuleContext) bool {
-
-	// Any module in a recovery proprietary path is a recovery proprietary
-	// module.
-	if isRecoveryProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) {
-		return true
-	}
-
-	// However if the module is not in a recovery proprietary path, it may
-	// still be a recovery proprietary module. This happens for cc modules
-	// that are excluded from the recovery snapshot, and it means that the
-	// vendor has assumed control of the framework-provided module.
-
-	if c, ok := ctx.Module().(RecoverySnapshotModuleInterface); ok {
-		if c.ExcludeFromRecoverySnapshot() {
-			return true
-		}
-	}
-
-	return false
-}
-
-var RecoverySnapshotImageName = "recovery"
-
-type RecoverySnapshotImage struct{}
-
-func (RecoverySnapshotImage) Init(ctx android.RegistrationContext) {
-	ctx.RegisterParallelSingletonType("recovery-snapshot", RecoverySnapshotSingleton)
-}
-
-func (RecoverySnapshotImage) RegisterAdditionalModule(ctx android.RegistrationContext, name string, factory android.ModuleFactory) {
-	ctx.RegisterModuleType(name, factory)
-}
-
-func (RecoverySnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool {
-	// RECOVERY_SNAPSHOT_VERSION must be set to 'current' in order to generate a
-	// snapshot.
-	return ctx.DeviceConfig().RecoverySnapshotVersion() == "current"
-}
-
-func (RecoverySnapshotImage) InImage(m SnapshotModuleInterfaceBase) func() bool {
-	r, ok := m.(RecoverySnapshotModuleInterface)
-
-	if !ok {
-		// This module does not support recovery snapshot
-		return func() bool { return false }
-	}
-	return r.InRecovery
-}
-
-func (RecoverySnapshotImage) IsProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
-	return isDirectoryExcluded(dir, deviceConfig.RecoverySnapshotDirsExcludedMap(), deviceConfig.RecoverySnapshotDirsIncludedMap())
-}
-
-func (RecoverySnapshotImage) ExcludeFromSnapshot(m SnapshotModuleInterfaceBase) bool {
-	r, ok := m.(RecoverySnapshotModuleInterface)
-
-	if !ok {
-		// This module does not support recovery snapshot
-		return true
-	}
-	return r.ExcludeFromRecoverySnapshot()
-}
-
-func (RecoverySnapshotImage) IsUsingSnapshot(cfg android.DeviceConfig) bool {
-	recoverySnapshotVersion := cfg.RecoverySnapshotVersion()
-	return recoverySnapshotVersion != "current" && recoverySnapshotVersion != ""
-}
-
-func (RecoverySnapshotImage) TargetSnapshotVersion(cfg android.DeviceConfig) string {
-	return cfg.RecoverySnapshotVersion()
-}
-
-func (RecoverySnapshotImage) ExcludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool {
-	// If we're using full snapshot, not directed snapshot, capture every module
-	if !cfg.DirectedRecoverySnapshot() {
-		return false
-	}
-	// Else, checks if name is in RECOVERY_SNAPSHOT_MODULES.
-	return !cfg.RecoverySnapshotModules()[name]
-}
-
-func (RecoverySnapshotImage) ImageName() string {
-	return RecoverySnapshotImageName
-}
-
-var RecoverySnapshotImageSingleton RecoverySnapshotImage
-
-func init() {
-	RecoverySnapshotImageSingleton.Init(android.InitRegistrationContext)
-}
diff --git a/snapshot/snapshot.go b/snapshot/snapshot.go
deleted file mode 100644
index c95a537..0000000
--- a/snapshot/snapshot.go
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package snapshot
-
-import (
-	"path/filepath"
-	"sort"
-
-	"android/soong/android"
-)
-
-// This file contains singletons to capture snapshots. This singleton will generate snapshot of each target
-// image, and capturing snapshot module will be delegated to each module which implements GenerateSnapshotAction
-// function and register with RegisterSnapshotAction.
-
-var pctx = android.NewPackageContext("android/soong/snapshot")
-
-func init() {
-	pctx.Import("android/soong/android")
-}
-
-type SnapshotSingleton struct {
-	// Name, e.g., "vendor", "recovery", "ramdisk".
-	name string
-
-	// Make variable that points to the snapshot file, e.g.,
-	// "SOONG_RECOVERY_SNAPSHOT_ZIP".
-	makeVar string
-
-	// Path to the snapshot zip file.
-	snapshotZipFile android.OptionalPath
-
-	// Implementation of the image interface specific to the image
-	// associated with this snapshot (e.g., specific to the vendor image,
-	// recovery image, etc.).
-	Image SnapshotImage
-
-	// Whether this singleton is for fake snapshot or not.
-	// Fake snapshot is a snapshot whose prebuilt binaries and headers are empty.
-	// It is much faster to generate, and can be used to inspect dependencies.
-	Fake bool
-}
-
-// The output files to be included in the snapshot.
-type SnapshotPaths struct {
-	// All files to be included in the snapshot
-	OutputFiles android.Paths
-
-	// Notice files of the snapshot output files
-	NoticeFiles android.Paths
-}
-
-// Interface of function to capture snapshot from each module
-// Returns snapshot ouputs and notice files.
-type GenerateSnapshotAction func(snapshot SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) SnapshotPaths
-
-var snapshotActionList []GenerateSnapshotAction
-
-// Register GenerateSnapshotAction function so it can be called while generating snapshot
-func RegisterSnapshotAction(x GenerateSnapshotAction) {
-	snapshotActionList = append(snapshotActionList, x)
-}
-
-func (c *SnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	if !c.Image.shouldGenerateSnapshot(ctx) {
-		return
-	}
-
-	var snapshotOutputs android.Paths
-
-	// Snapshot zipped artifacts will be captured under {SNAPSHOT_ARCH} directory
-
-	snapshotDir := c.name + "-snapshot"
-	if c.Fake {
-		// If this is a fake snapshot singleton, place all files under fake/ subdirectory to avoid
-		// collision with real snapshot files
-		snapshotDir = filepath.Join("fake", snapshotDir)
-	}
-	snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
-	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
-	installedNotices := make(map[string]bool)
-
-	for _, f := range snapshotActionList {
-		snapshotPaths := f(*c, ctx, snapshotArchDir)
-		snapshotOutputs = append(snapshotOutputs, snapshotPaths.OutputFiles...)
-		for _, notice := range snapshotPaths.NoticeFiles {
-			if _, ok := installedNotices[notice.String()]; !ok {
-				installedNotices[notice.String()] = true
-				snapshotOutputs = append(snapshotOutputs, CopyFileRule(
-					pctx, ctx, notice, filepath.Join(noticeDir, notice.String())))
-			}
-		}
-	}
-
-	// All artifacts are ready. Sort them to normalize ninja and then zip.
-	sort.Slice(snapshotOutputs, func(i, j int) bool {
-		return snapshotOutputs[i].String() < snapshotOutputs[j].String()
-	})
-
-	zipPath := android.PathForOutput(
-		ctx,
-		snapshotDir,
-		c.name+"-"+ctx.Config().DeviceName()+".zip")
-	zipRule := android.NewRuleBuilder(pctx, ctx)
-
-	// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr
-	snapshotOutputList := android.PathForOutput(
-		ctx,
-		snapshotDir,
-		c.name+"-"+ctx.Config().DeviceName()+"_list")
-	rspFile := snapshotOutputList.ReplaceExtension(ctx, "rsp")
-	zipRule.Command().
-		Text("tr").
-		FlagWithArg("-d ", "\\'").
-		FlagWithRspFileInputList("< ", rspFile, snapshotOutputs).
-		FlagWithOutput("> ", snapshotOutputList)
-
-	zipRule.Temporary(snapshotOutputList)
-
-	zipRule.Command().
-		BuiltTool("soong_zip").
-		FlagWithOutput("-o ", zipPath).
-		FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()).
-		FlagWithInput("-l ", snapshotOutputList)
-
-	zipRule.Build(zipPath.String(), c.name+" snapshot "+zipPath.String())
-	zipRule.DeleteTemporaryFiles()
-	c.snapshotZipFile = android.OptionalPathForPath(zipPath)
-}
-
-func (c *SnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
-	ctx.Strict(
-		c.makeVar,
-		c.snapshotZipFile.String())
-}
diff --git a/snapshot/snapshot_base.go b/snapshot/snapshot_base.go
index fb4ee0c..6bf3c87 100644
--- a/snapshot/snapshot_base.go
+++ b/snapshot/snapshot_base.go
@@ -15,92 +15,12 @@
 
 import (
 	"android/soong/android"
-	"path/filepath"
 )
 
-// Interface for modules which can be captured in the snapshot.
-type SnapshotModuleInterfaceBase interface{}
+var pctx = android.NewPackageContext("android/soong/snapshot")
 
-// Defines the specifics of different images to which the snapshot process is applicable, e.g.,
-// vendor, recovery, ramdisk.
-type SnapshotImage interface {
-	// Returns true if a snapshot should be generated for this image.
-	shouldGenerateSnapshot(ctx android.SingletonContext) bool
-
-	// Function that returns true if the module is included in this image.
-	// Using a function return instead of a value to prevent early
-	// evalution of a function that may be not be defined.
-	InImage(m SnapshotModuleInterfaceBase) func() bool
-
-	// Returns true if a dir under source tree is an SoC-owned proprietary
-	// directory, such as device/, vendor/, etc.
-	//
-	// For a given snapshot (e.g., vendor, recovery, etc.) if
-	// isProprietaryPath(dir, deviceConfig) returns true, then the module in dir
-	// will be built from sources.
-	IsProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool
-
-	// Whether a given module has been explicitly excluded from the
-	// snapshot, e.g., using the exclude_from_vendor_snapshot or
-	// exclude_from_recovery_snapshot properties.
-	ExcludeFromSnapshot(m SnapshotModuleInterfaceBase) bool
-
-	// Returns true if the build is using a snapshot for this image.
-	IsUsingSnapshot(cfg android.DeviceConfig) bool
-
-	// Returns a version of which the snapshot should be used in this target.
-	// This will only be meaningful when isUsingSnapshot is true.
-	TargetSnapshotVersion(cfg android.DeviceConfig) string
-
-	// Whether to exclude a given module from the directed snapshot or not.
-	// If the makefile variable DIRECTED_{IMAGE}_SNAPSHOT is true, directed snapshot is turned on,
-	// and only modules listed in {IMAGE}_SNAPSHOT_MODULES will be captured.
-	ExcludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool
-
-	// Returns target image name
-	ImageName() string
-}
-
-type directoryMap map[string]bool
-
-var (
-	// Modules under following directories are ignored. They are OEM's and vendor's
-	// proprietary modules(device/, kernel/, vendor/, and hardware/).
-	defaultDirectoryExcludedMap = directoryMap{
-		"device":   true,
-		"hardware": true,
-		"kernel":   true,
-		"vendor":   true,
-	}
-
-	// Modules under following directories are included as they are in AOSP,
-	// although hardware/ and kernel/ are normally for vendor's own.
-	defaultDirectoryIncludedMap = directoryMap{
-		"kernel/configs":              true,
-		"kernel/prebuilts":            true,
-		"kernel/tests":                true,
-		"hardware/interfaces":         true,
-		"hardware/libhardware":        true,
-		"hardware/libhardware_legacy": true,
-		"hardware/ril":                true,
-	}
-)
-
-func isDirectoryExcluded(dir string, excludedMap directoryMap, includedMap directoryMap) bool {
-	if dir == "." || dir == "/" {
-		return false
-	}
-	if includedMap[dir] {
-		return false
-	} else if excludedMap[dir] {
-		return true
-	} else if defaultDirectoryIncludedMap[dir] {
-		return false
-	} else if defaultDirectoryExcludedMap[dir] {
-		return true
-	} else {
-		return isDirectoryExcluded(filepath.Dir(dir), excludedMap, includedMap)
-	}
+func init() {
+	pctx.Import("android/soong/android")
 }
 
 // This is to be saved as .json files, which is for development/vendor_snapshot/update.py.
diff --git a/snapshot/vendor_snapshot.go b/snapshot/vendor_snapshot.go
deleted file mode 100644
index 4484c85..0000000
--- a/snapshot/vendor_snapshot.go
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package snapshot
-
-import "android/soong/android"
-
-// Interface for modules which can be captured in the vendor snapshot.
-type VendorSnapshotModuleInterface interface {
-	SnapshotModuleInterfaceBase
-	InVendor() bool
-	ExcludeFromVendorSnapshot() bool
-}
-
-var vendorSnapshotSingleton = SnapshotSingleton{
-	"vendor",                     // name
-	"SOONG_VENDOR_SNAPSHOT_ZIP",  // makeVar
-	android.OptionalPath{},       // snapshotZipFile
-	VendorSnapshotImageSingleton, // Image
-	false,                        // Fake
-}
-
-var vendorFakeSnapshotSingleton = SnapshotSingleton{
-	"vendor",                         // name
-	"SOONG_VENDOR_FAKE_SNAPSHOT_ZIP", // makeVar
-	android.OptionalPath{},           // snapshotZipFile
-	VendorSnapshotImageSingleton,     // Image
-	true,                             // Fake
-}
-
-func VendorSnapshotSingleton() android.Singleton {
-	return &vendorSnapshotSingleton
-}
-
-func VendorFakeSnapshotSingleton() android.Singleton {
-	return &vendorFakeSnapshotSingleton
-}
-
-// Determine if a dir under source tree is an SoC-owned proprietary directory based
-// on vendor snapshot configuration
-// Examples: device/, vendor/
-func isVendorProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
-	return VendorSnapshotSingleton().(*SnapshotSingleton).Image.IsProprietaryPath(dir, deviceConfig)
-}
-
-func IsVendorProprietaryModule(ctx android.BaseModuleContext) bool {
-	// Any module in a vendor proprietary path is a vendor proprietary
-	// module.
-	if isVendorProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) {
-		return true
-	}
-
-	// However if the module is not in a vendor proprietary path, it may
-	// still be a vendor proprietary module. This happens for cc modules
-	// that are excluded from the vendor snapshot, and it means that the
-	// vendor has assumed control of the framework-provided module.
-	if c, ok := ctx.Module().(VendorSnapshotModuleInterface); ok {
-		if c.ExcludeFromVendorSnapshot() {
-			return true
-		}
-	}
-
-	return false
-}
-
-var VendorSnapshotImageName = "vendor"
-
-type VendorSnapshotImage struct{}
-
-func (VendorSnapshotImage) Init(ctx android.RegistrationContext) {
-	ctx.RegisterParallelSingletonType("vendor-snapshot", VendorSnapshotSingleton)
-	ctx.RegisterParallelSingletonType("vendor-fake-snapshot", VendorFakeSnapshotSingleton)
-}
-
-func (VendorSnapshotImage) RegisterAdditionalModule(ctx android.RegistrationContext, name string, factory android.ModuleFactory) {
-	ctx.RegisterModuleType(name, factory)
-}
-
-func (VendorSnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool {
-	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a snapshot.
-	return ctx.DeviceConfig().VndkVersion() == "current"
-}
-
-func (VendorSnapshotImage) InImage(m SnapshotModuleInterfaceBase) func() bool {
-	v, ok := m.(VendorSnapshotModuleInterface)
-
-	if !ok {
-		// This module does not support Vendor snapshot
-		return func() bool { return false }
-	}
-
-	return v.InVendor
-}
-
-func (VendorSnapshotImage) IsProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
-	return isDirectoryExcluded(dir, deviceConfig.VendorSnapshotDirsExcludedMap(), deviceConfig.VendorSnapshotDirsIncludedMap())
-}
-
-func (VendorSnapshotImage) ExcludeFromSnapshot(m SnapshotModuleInterfaceBase) bool {
-	v, ok := m.(VendorSnapshotModuleInterface)
-
-	if !ok {
-		// This module does not support Vendor snapshot
-		return true
-	}
-
-	return v.ExcludeFromVendorSnapshot()
-}
-
-func (VendorSnapshotImage) IsUsingSnapshot(cfg android.DeviceConfig) bool {
-	vndkVersion := cfg.VndkVersion()
-	return vndkVersion != "current" && vndkVersion != ""
-}
-
-func (VendorSnapshotImage) TargetSnapshotVersion(cfg android.DeviceConfig) string {
-	return cfg.VndkVersion()
-}
-
-// returns true iff a given module SHOULD BE EXCLUDED, false if included
-func (VendorSnapshotImage) ExcludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool {
-	// If we're using full snapshot, not directed snapshot, capture every module
-	if !cfg.DirectedVendorSnapshot() {
-		return false
-	}
-	// Else, checks if name is in VENDOR_SNAPSHOT_MODULES.
-	return !cfg.VendorSnapshotModules()[name]
-}
-
-func (VendorSnapshotImage) ImageName() string {
-	return VendorSnapshotImageName
-}
-
-var VendorSnapshotImageSingleton VendorSnapshotImage
-
-func init() {
-	VendorSnapshotImageSingleton.Init(android.InitRegistrationContext)
-}
diff --git a/soong_ui.bash b/soong_ui.bash
index 8e7cd19..7737880 100755
--- a/soong_ui.bash
+++ b/soong_ui.bash
@@ -35,6 +35,7 @@
 soong_build_go soong_ui android/soong/cmd/soong_ui
 soong_build_go mk2rbc android/soong/mk2rbc/mk2rbc
 soong_build_go rbcrun rbcrun/rbcrun
+soong_build_go release-config android/soong/cmd/release_config/release_config
 
 cd ${TOP}
 exec "$(getoutdir)/soong_ui" "$@"
diff --git a/starlark_import/README.md b/starlark_import/README.md
deleted file mode 100644
index e444759..0000000
--- a/starlark_import/README.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# starlark_import package
-
-This allows soong to read constant information from starlark files. At package initialization
-time, soong will read `build/bazel/constants_exported_to_soong.bzl`, and then make the
-variables from that file available via `starlark_import.GetStarlarkValue()`. So to import
-a new variable, it must be added to `constants_exported_to_soong.bzl` and then it can
-be accessed by name.
-
-Only constant information can be read, since this is not a full bazel execution but a
-standalone starlark interpreter. This means you can't use bazel contructs like `rule`,
-`provider`, `select`, `glob`, etc.
-
-All starlark files that were loaded must be added as ninja deps that cause soong to rerun.
-The loaded files can be retrieved via `starlark_import.GetNinjaDeps()`.
diff --git a/starlark_import/starlark_import.go b/starlark_import/starlark_import.go
deleted file mode 100644
index ebe4247..0000000
--- a/starlark_import/starlark_import.go
+++ /dev/null
@@ -1,306 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package starlark_import
-
-import (
-	"fmt"
-	"os"
-	"path/filepath"
-	"sort"
-	"strings"
-	"sync"
-	"time"
-
-	"go.starlark.net/starlark"
-	"go.starlark.net/starlarkjson"
-	"go.starlark.net/starlarkstruct"
-)
-
-func init() {
-	go func() {
-		startTime := time.Now()
-		v, d, err := runStarlarkFile("//build/bazel/constants_exported_to_soong.bzl")
-		endTime := time.Now()
-		//fmt.Fprintf(os.Stderr, "starlark run time: %s\n", endTime.Sub(startTime).String())
-		globalResult.Set(starlarkResult{
-			values:    v,
-			ninjaDeps: d,
-			err:       err,
-			startTime: startTime,
-			endTime:   endTime,
-		})
-	}()
-}
-
-type starlarkResult struct {
-	values    starlark.StringDict
-	ninjaDeps []string
-	err       error
-	startTime time.Time
-	endTime   time.Time
-}
-
-// setOnce wraps a value and exposes Set() and Get() accessors for it.
-// The Get() calls will block until a Set() has been called.
-// A second call to Set() will panic.
-// setOnce must be created using newSetOnce()
-type setOnce[T any] struct {
-	value T
-	lock  sync.Mutex
-	wg    sync.WaitGroup
-	isSet bool
-}
-
-func (o *setOnce[T]) Set(value T) {
-	o.lock.Lock()
-	defer o.lock.Unlock()
-	if o.isSet {
-		panic("Value already set")
-	}
-
-	o.value = value
-	o.isSet = true
-	o.wg.Done()
-}
-
-func (o *setOnce[T]) Get() T {
-	if !o.isSet {
-		o.wg.Wait()
-	}
-	return o.value
-}
-
-func newSetOnce[T any]() *setOnce[T] {
-	result := &setOnce[T]{}
-	result.wg.Add(1)
-	return result
-}
-
-var globalResult = newSetOnce[starlarkResult]()
-
-func GetStarlarkValue[T any](key string) (T, error) {
-	result := globalResult.Get()
-	if result.err != nil {
-		var zero T
-		return zero, result.err
-	}
-	if !result.values.Has(key) {
-		var zero T
-		return zero, fmt.Errorf("a starlark variable by that name wasn't found, did you update //build/bazel/constants_exported_to_soong.bzl?")
-	}
-	return Unmarshal[T](result.values[key])
-}
-
-func GetNinjaDeps() ([]string, error) {
-	result := globalResult.Get()
-	if result.err != nil {
-		return nil, result.err
-	}
-	return result.ninjaDeps, nil
-}
-
-func getTopDir() (string, error) {
-	// It's hard to communicate the top dir to this package in any other way than reading the
-	// arguments directly, because we need to know this at package initialization time. Many
-	// soong constants that we'd like to read from starlark are initialized during package
-	// initialization.
-	for i, arg := range os.Args {
-		if arg == "--top" {
-			if i < len(os.Args)-1 && os.Args[i+1] != "" {
-				return os.Args[i+1], nil
-			}
-		}
-	}
-
-	// When running tests, --top is not passed. Instead, search for the top dir manually
-	cwd, err := os.Getwd()
-	if err != nil {
-		return "", err
-	}
-	for cwd != "/" {
-		if _, err := os.Stat(filepath.Join(cwd, "build/soong/soong_ui.bash")); err == nil {
-			return cwd, nil
-		}
-		cwd = filepath.Dir(cwd)
-	}
-	return "", fmt.Errorf("could not find top dir")
-}
-
-const callerDirKey = "callerDir"
-
-type modentry struct {
-	globals starlark.StringDict
-	err     error
-}
-
-func unsupportedMethod(t *starlark.Thread, fn *starlark.Builtin, _ starlark.Tuple, _ []starlark.Tuple) (starlark.Value, error) {
-	return nil, fmt.Errorf("%sthis file is read by soong, and must therefore be pure starlark and include only constant information. %q is not allowed", t.CallStack().String(), fn.Name())
-}
-
-var builtins = starlark.StringDict{
-	"aspect":     starlark.NewBuiltin("aspect", unsupportedMethod),
-	"glob":       starlark.NewBuiltin("glob", unsupportedMethod),
-	"json":       starlarkjson.Module,
-	"provider":   starlark.NewBuiltin("provider", unsupportedMethod),
-	"rule":       starlark.NewBuiltin("rule", unsupportedMethod),
-	"struct":     starlark.NewBuiltin("struct", starlarkstruct.Make),
-	"select":     starlark.NewBuiltin("select", unsupportedMethod),
-	"transition": starlark.NewBuiltin("transition", unsupportedMethod),
-}
-
-// Takes a module name (the first argument to the load() function) and returns the path
-// it's trying to load, stripping out leading //, and handling leading :s.
-func cleanModuleName(moduleName string, callerDir string) (string, error) {
-	if strings.Count(moduleName, ":") > 1 {
-		return "", fmt.Errorf("at most 1 colon must be present in starlark path: %s", moduleName)
-	}
-
-	// We don't have full support for external repositories, but at least support skylib's dicts.
-	if moduleName == "@bazel_skylib//lib:dicts.bzl" {
-		return "external/bazel-skylib/lib/dicts.bzl", nil
-	}
-
-	localLoad := false
-	if strings.HasPrefix(moduleName, "@//") {
-		moduleName = moduleName[3:]
-	} else if strings.HasPrefix(moduleName, "//") {
-		moduleName = moduleName[2:]
-	} else if strings.HasPrefix(moduleName, ":") {
-		moduleName = moduleName[1:]
-		localLoad = true
-	} else {
-		return "", fmt.Errorf("load path must start with // or :")
-	}
-
-	if ix := strings.LastIndex(moduleName, ":"); ix >= 0 {
-		moduleName = moduleName[:ix] + string(os.PathSeparator) + moduleName[ix+1:]
-	}
-
-	if filepath.Clean(moduleName) != moduleName {
-		return "", fmt.Errorf("load path must be clean, found: %s, expected: %s", moduleName, filepath.Clean(moduleName))
-	}
-	if strings.HasPrefix(moduleName, "../") {
-		return "", fmt.Errorf("load path must not start with ../: %s", moduleName)
-	}
-	if strings.HasPrefix(moduleName, "/") {
-		return "", fmt.Errorf("load path starts with /, use // for a absolute path: %s", moduleName)
-	}
-
-	if localLoad {
-		return filepath.Join(callerDir, moduleName), nil
-	}
-
-	return moduleName, nil
-}
-
-// loader implements load statement. The format of the loaded module URI is
-//
-//	[//path]:base
-//
-// The file path is $ROOT/path/base if path is present, <caller_dir>/base otherwise.
-func loader(thread *starlark.Thread, module string, topDir string, moduleCache map[string]*modentry, moduleCacheLock *sync.Mutex, filesystem map[string]string) (starlark.StringDict, error) {
-	modulePath, err := cleanModuleName(module, thread.Local(callerDirKey).(string))
-	if err != nil {
-		return nil, err
-	}
-	moduleCacheLock.Lock()
-	e, ok := moduleCache[modulePath]
-	if e == nil {
-		if ok {
-			moduleCacheLock.Unlock()
-			return nil, fmt.Errorf("cycle in load graph")
-		}
-
-		// Add a placeholder to indicate "load in progress".
-		moduleCache[modulePath] = nil
-		moduleCacheLock.Unlock()
-
-		childThread := &starlark.Thread{Name: "exec " + module, Load: thread.Load}
-
-		// Cheating for the sake of testing:
-		// propagate starlarktest's Reporter key, otherwise testing
-		// the load function may cause panic in starlarktest code.
-		const testReporterKey = "Reporter"
-		if v := thread.Local(testReporterKey); v != nil {
-			childThread.SetLocal(testReporterKey, v)
-		}
-
-		childThread.SetLocal(callerDirKey, filepath.Dir(modulePath))
-
-		if filesystem != nil {
-			globals, err := starlark.ExecFile(childThread, filepath.Join(topDir, modulePath), filesystem[modulePath], builtins)
-			e = &modentry{globals, err}
-		} else {
-			globals, err := starlark.ExecFile(childThread, filepath.Join(topDir, modulePath), nil, builtins)
-			e = &modentry{globals, err}
-		}
-
-		// Update the cache.
-		moduleCacheLock.Lock()
-		moduleCache[modulePath] = e
-	}
-	moduleCacheLock.Unlock()
-	return e.globals, e.err
-}
-
-// Run runs the given starlark file and returns its global variables and a list of all starlark
-// files that were loaded. The top dir for starlark's // is found via getTopDir().
-func runStarlarkFile(filename string) (starlark.StringDict, []string, error) {
-	topDir, err := getTopDir()
-	if err != nil {
-		return nil, nil, err
-	}
-	return runStarlarkFileWithFilesystem(filename, topDir, nil)
-}
-
-func runStarlarkFileWithFilesystem(filename string, topDir string, filesystem map[string]string) (starlark.StringDict, []string, error) {
-	if !strings.HasPrefix(filename, "//") && !strings.HasPrefix(filename, ":") {
-		filename = "//" + filename
-	}
-	filename, err := cleanModuleName(filename, "")
-	if err != nil {
-		return nil, nil, err
-	}
-	moduleCache := make(map[string]*modentry)
-	moduleCache[filename] = nil
-	moduleCacheLock := &sync.Mutex{}
-	mainThread := &starlark.Thread{
-		Name: "main",
-		Print: func(_ *starlark.Thread, msg string) {
-			// Ignore prints
-		},
-		Load: func(thread *starlark.Thread, module string) (starlark.StringDict, error) {
-			return loader(thread, module, topDir, moduleCache, moduleCacheLock, filesystem)
-		},
-	}
-	mainThread.SetLocal(callerDirKey, filepath.Dir(filename))
-
-	var result starlark.StringDict
-	if filesystem != nil {
-		result, err = starlark.ExecFile(mainThread, filepath.Join(topDir, filename), filesystem[filename], builtins)
-	} else {
-		result, err = starlark.ExecFile(mainThread, filepath.Join(topDir, filename), nil, builtins)
-	}
-	return result, sortedStringKeys(moduleCache), err
-}
-
-func sortedStringKeys(m map[string]*modentry) []string {
-	s := make([]string, 0, len(m))
-	for k := range m {
-		s = append(s, k)
-	}
-	sort.Strings(s)
-	return s
-}
diff --git a/starlark_import/starlark_import_test.go b/starlark_import/starlark_import_test.go
deleted file mode 100644
index 8a58e3b..0000000
--- a/starlark_import/starlark_import_test.go
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package starlark_import
-
-import (
-	"strings"
-	"testing"
-
-	"go.starlark.net/starlark"
-)
-
-func TestBasic(t *testing.T) {
-	globals, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
-		"a.bzl": `
-my_string = "hello, world!"
-`})
-	if err != nil {
-		t.Error(err)
-		return
-	}
-
-	if globals["my_string"].(starlark.String) != "hello, world!" {
-		t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
-	}
-}
-
-func TestLoad(t *testing.T) {
-	globals, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
-		"a.bzl": `
-load("//b.bzl", _b_string = "my_string")
-my_string = "hello, " + _b_string
-`,
-		"b.bzl": `
-my_string = "world!"
-`})
-	if err != nil {
-		t.Error(err)
-		return
-	}
-
-	if globals["my_string"].(starlark.String) != "hello, world!" {
-		t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
-	}
-}
-
-func TestLoadRelative(t *testing.T) {
-	globals, ninjaDeps, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
-		"a.bzl": `
-load(":b.bzl", _b_string = "my_string")
-load("//foo/c.bzl", _c_string = "my_string")
-my_string = "hello, " + _b_string
-c_string = _c_string
-`,
-		"b.bzl": `
-my_string = "world!"
-`,
-		"foo/c.bzl": `
-load(":d.bzl", _d_string = "my_string")
-my_string = "hello, " + _d_string
-`,
-		"foo/d.bzl": `
-my_string = "world!"
-`})
-	if err != nil {
-		t.Error(err)
-		return
-	}
-
-	if globals["my_string"].(starlark.String) != "hello, world!" {
-		t.Errorf("Expected %q, got %q", "hello, world!", globals["my_string"].String())
-	}
-
-	expectedNinjaDeps := []string{
-		"a.bzl",
-		"b.bzl",
-		"foo/c.bzl",
-		"foo/d.bzl",
-	}
-	if !slicesEqual(ninjaDeps, expectedNinjaDeps) {
-		t.Errorf("Expected %v ninja deps, got %v", expectedNinjaDeps, ninjaDeps)
-	}
-}
-
-func TestLoadCycle(t *testing.T) {
-	_, _, err := runStarlarkFileWithFilesystem("a.bzl", "", map[string]string{
-		"a.bzl": `
-load(":b.bzl", _b_string = "my_string")
-my_string = "hello, " + _b_string
-`,
-		"b.bzl": `
-load(":a.bzl", _a_string = "my_string")
-my_string = "hello, " + _a_string
-`})
-	if err == nil || !strings.Contains(err.Error(), "cycle in load graph") {
-		t.Errorf("Expected cycle in load graph, got: %v", err)
-		return
-	}
-}
-
-func slicesEqual[T comparable](a []T, b []T) bool {
-	if len(a) != len(b) {
-		return false
-	}
-	for i := range a {
-		if a[i] != b[i] {
-			return false
-		}
-	}
-	return true
-}
diff --git a/starlark_import/unmarshal.go b/starlark_import/unmarshal.go
deleted file mode 100644
index b243471..0000000
--- a/starlark_import/unmarshal.go
+++ /dev/null
@@ -1,304 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package starlark_import
-
-import (
-	"fmt"
-	"math"
-	"reflect"
-	"unsafe"
-
-	"go.starlark.net/starlark"
-	"go.starlark.net/starlarkstruct"
-)
-
-func Unmarshal[T any](value starlark.Value) (T, error) {
-	x, err := UnmarshalReflect(value, reflect.TypeOf((*T)(nil)).Elem())
-	return x.Interface().(T), err
-}
-
-func UnmarshalReflect(value starlark.Value, ty reflect.Type) (reflect.Value, error) {
-	if ty == reflect.TypeOf((*starlark.Value)(nil)).Elem() {
-		return reflect.ValueOf(value), nil
-	}
-	zero := reflect.Zero(ty)
-	if value == nil {
-		panic("nil value")
-	}
-	var result reflect.Value
-	if ty.Kind() == reflect.Interface {
-		var err error
-		ty, err = typeOfStarlarkValue(value)
-		if err != nil {
-			return zero, err
-		}
-	}
-	if ty.Kind() == reflect.Map {
-		result = reflect.MakeMap(ty)
-	} else {
-		result = reflect.Indirect(reflect.New(ty))
-	}
-
-	switch v := value.(type) {
-	case starlark.String:
-		if result.Type().Kind() != reflect.String {
-			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
-		}
-		result.SetString(v.GoString())
-	case starlark.Int:
-		signedValue, signedOk := v.Int64()
-		unsignedValue, unsignedOk := v.Uint64()
-		switch result.Type().Kind() {
-		case reflect.Int64:
-			if !signedOk {
-				return zero, fmt.Errorf("starlark int didn't fit in go int64")
-			}
-			result.SetInt(signedValue)
-		case reflect.Int32:
-			if !signedOk || signedValue > math.MaxInt32 || signedValue < math.MinInt32 {
-				return zero, fmt.Errorf("starlark int didn't fit in go int32")
-			}
-			result.SetInt(signedValue)
-		case reflect.Int16:
-			if !signedOk || signedValue > math.MaxInt16 || signedValue < math.MinInt16 {
-				return zero, fmt.Errorf("starlark int didn't fit in go int16")
-			}
-			result.SetInt(signedValue)
-		case reflect.Int8:
-			if !signedOk || signedValue > math.MaxInt8 || signedValue < math.MinInt8 {
-				return zero, fmt.Errorf("starlark int didn't fit in go int8")
-			}
-			result.SetInt(signedValue)
-		case reflect.Int:
-			if !signedOk || signedValue > math.MaxInt || signedValue < math.MinInt {
-				return zero, fmt.Errorf("starlark int didn't fit in go int")
-			}
-			result.SetInt(signedValue)
-		case reflect.Uint64:
-			if !unsignedOk {
-				return zero, fmt.Errorf("starlark int didn't fit in go uint64")
-			}
-			result.SetUint(unsignedValue)
-		case reflect.Uint32:
-			if !unsignedOk || unsignedValue > math.MaxUint32 {
-				return zero, fmt.Errorf("starlark int didn't fit in go uint32")
-			}
-			result.SetUint(unsignedValue)
-		case reflect.Uint16:
-			if !unsignedOk || unsignedValue > math.MaxUint16 {
-				return zero, fmt.Errorf("starlark int didn't fit in go uint16")
-			}
-			result.SetUint(unsignedValue)
-		case reflect.Uint8:
-			if !unsignedOk || unsignedValue > math.MaxUint8 {
-				return zero, fmt.Errorf("starlark int didn't fit in go uint8")
-			}
-			result.SetUint(unsignedValue)
-		case reflect.Uint:
-			if !unsignedOk || unsignedValue > math.MaxUint {
-				return zero, fmt.Errorf("starlark int didn't fit in go uint")
-			}
-			result.SetUint(unsignedValue)
-		default:
-			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
-		}
-	case starlark.Float:
-		f := float64(v)
-		switch result.Type().Kind() {
-		case reflect.Float64:
-			result.SetFloat(f)
-		case reflect.Float32:
-			if f > math.MaxFloat32 || f < -math.MaxFloat32 {
-				return zero, fmt.Errorf("starlark float didn't fit in go float32")
-			}
-			result.SetFloat(f)
-		default:
-			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
-		}
-	case starlark.Bool:
-		if result.Type().Kind() != reflect.Bool {
-			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
-		}
-		result.SetBool(bool(v))
-	case starlark.Tuple:
-		if result.Type().Kind() != reflect.Slice {
-			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
-		}
-		elemType := result.Type().Elem()
-		// TODO: Add this grow call when we're on go 1.20
-		//result.Grow(v.Len())
-		for i := 0; i < v.Len(); i++ {
-			elem, err := UnmarshalReflect(v.Index(i), elemType)
-			if err != nil {
-				return zero, err
-			}
-			result = reflect.Append(result, elem)
-		}
-	case *starlark.List:
-		if result.Type().Kind() != reflect.Slice {
-			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
-		}
-		elemType := result.Type().Elem()
-		// TODO: Add this grow call when we're on go 1.20
-		//result.Grow(v.Len())
-		for i := 0; i < v.Len(); i++ {
-			elem, err := UnmarshalReflect(v.Index(i), elemType)
-			if err != nil {
-				return zero, err
-			}
-			result = reflect.Append(result, elem)
-		}
-	case *starlark.Dict:
-		if result.Type().Kind() != reflect.Map {
-			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
-		}
-		keyType := result.Type().Key()
-		valueType := result.Type().Elem()
-		for _, pair := range v.Items() {
-			key := pair.Index(0)
-			value := pair.Index(1)
-
-			unmarshalledKey, err := UnmarshalReflect(key, keyType)
-			if err != nil {
-				return zero, err
-			}
-			unmarshalledValue, err := UnmarshalReflect(value, valueType)
-			if err != nil {
-				return zero, err
-			}
-
-			result.SetMapIndex(unmarshalledKey, unmarshalledValue)
-		}
-	case *starlarkstruct.Struct:
-		if result.Type().Kind() != reflect.Struct {
-			return zero, fmt.Errorf("starlark type was %s, but %s requested", v.Type(), result.Type().Kind().String())
-		}
-		if result.NumField() != len(v.AttrNames()) {
-			return zero, fmt.Errorf("starlark struct and go struct have different number of fields (%d and %d)", len(v.AttrNames()), result.NumField())
-		}
-		for _, attrName := range v.AttrNames() {
-			attr, err := v.Attr(attrName)
-			if err != nil {
-				return zero, err
-			}
-
-			// TODO(b/279787235): this should probably support tags to rename the field
-			resultField := result.FieldByName(attrName)
-			if resultField == (reflect.Value{}) {
-				return zero, fmt.Errorf("starlark struct had field %s, but requested struct type did not", attrName)
-			}
-			// This hack allows us to change unexported fields
-			resultField = reflect.NewAt(resultField.Type(), unsafe.Pointer(resultField.UnsafeAddr())).Elem()
-			x, err := UnmarshalReflect(attr, resultField.Type())
-			if err != nil {
-				return zero, err
-			}
-			resultField.Set(x)
-		}
-	default:
-		return zero, fmt.Errorf("unimplemented starlark type: %s", value.Type())
-	}
-
-	return result, nil
-}
-
-func typeOfStarlarkValue(value starlark.Value) (reflect.Type, error) {
-	var err error
-	switch v := value.(type) {
-	case starlark.String:
-		return reflect.TypeOf(""), nil
-	case *starlark.List:
-		innerType := reflect.TypeOf("")
-		if v.Len() > 0 {
-			innerType, err = typeOfStarlarkValue(v.Index(0))
-			if err != nil {
-				return nil, err
-			}
-		}
-		for i := 1; i < v.Len(); i++ {
-			innerTypeI, err := typeOfStarlarkValue(v.Index(i))
-			if err != nil {
-				return nil, err
-			}
-			if innerType != innerTypeI {
-				return nil, fmt.Errorf("List must contain elements of entirely the same type, found %v and %v", innerType, innerTypeI)
-			}
-		}
-		return reflect.SliceOf(innerType), nil
-	case *starlark.Dict:
-		keyType := reflect.TypeOf("")
-		valueType := reflect.TypeOf("")
-		keys := v.Keys()
-		if v.Len() > 0 {
-			firstKey := keys[0]
-			keyType, err = typeOfStarlarkValue(firstKey)
-			if err != nil {
-				return nil, err
-			}
-			firstValue, found, err := v.Get(firstKey)
-			if !found {
-				err = fmt.Errorf("value not found")
-			}
-			if err != nil {
-				return nil, err
-			}
-			valueType, err = typeOfStarlarkValue(firstValue)
-			if err != nil {
-				return nil, err
-			}
-		}
-		for _, key := range keys {
-			keyTypeI, err := typeOfStarlarkValue(key)
-			if err != nil {
-				return nil, err
-			}
-			if keyType != keyTypeI {
-				return nil, fmt.Errorf("dict must contain elements of entirely the same type, found %v and %v", keyType, keyTypeI)
-			}
-			value, found, err := v.Get(key)
-			if !found {
-				err = fmt.Errorf("value not found")
-			}
-			if err != nil {
-				return nil, err
-			}
-			valueTypeI, err := typeOfStarlarkValue(value)
-			if valueType.Kind() != reflect.Interface && valueTypeI != valueType {
-				// If we see conflicting value types, change the result value type to an empty interface
-				valueType = reflect.TypeOf([]interface{}{}).Elem()
-			}
-		}
-		return reflect.MapOf(keyType, valueType), nil
-	case starlark.Int:
-		return reflect.TypeOf(0), nil
-	case starlark.Float:
-		return reflect.TypeOf(0.0), nil
-	case starlark.Bool:
-		return reflect.TypeOf(true), nil
-	default:
-		return nil, fmt.Errorf("unimplemented starlark type: %s", value.Type())
-	}
-}
-
-// UnmarshalNoneable is like Unmarshal, but it will accept None as the top level (but not nested)
-// starlark value. If the value is None, a nil pointer will be returned, otherwise a pointer
-// to the result of Unmarshal will be returned.
-func UnmarshalNoneable[T any](value starlark.Value) (*T, error) {
-	if _, ok := value.(starlark.NoneType); ok {
-		return nil, nil
-	}
-	ret, err := Unmarshal[T](value)
-	return &ret, err
-}
diff --git a/starlark_import/unmarshal_test.go b/starlark_import/unmarshal_test.go
deleted file mode 100644
index bc0ea4c..0000000
--- a/starlark_import/unmarshal_test.go
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package starlark_import
-
-import (
-	"reflect"
-	"testing"
-
-	"go.starlark.net/starlark"
-)
-
-func createStarlarkValue(t *testing.T, code string) starlark.Value {
-	t.Helper()
-	result, err := starlark.ExecFile(&starlark.Thread{}, "main.bzl", "x = "+code, builtins)
-	if err != nil {
-		panic(err)
-	}
-	return result["x"]
-}
-
-func TestUnmarshalConcreteType(t *testing.T) {
-	x, err := Unmarshal[string](createStarlarkValue(t, `"foo"`))
-	if err != nil {
-		t.Error(err)
-		return
-	}
-	if x != "foo" {
-		t.Errorf(`Expected "foo", got %q`, x)
-	}
-}
-
-func TestUnmarshalConcreteTypeWithInterfaces(t *testing.T) {
-	x, err := Unmarshal[map[string]map[string]interface{}](createStarlarkValue(t,
-		`{"foo": {"foo2": "foo3"}, "bar": {"bar2": ["bar3"]}}`))
-	if err != nil {
-		t.Error(err)
-		return
-	}
-	expected := map[string]map[string]interface{}{
-		"foo": {"foo2": "foo3"},
-		"bar": {"bar2": []string{"bar3"}},
-	}
-	if !reflect.DeepEqual(x, expected) {
-		t.Errorf(`Expected %v, got %v`, expected, x)
-	}
-}
-
-func TestUnmarshalToStarlarkValue(t *testing.T) {
-	x, err := Unmarshal[map[string]starlark.Value](createStarlarkValue(t,
-		`{"foo": "Hi", "bar": None}`))
-	if err != nil {
-		t.Error(err)
-		return
-	}
-	if x["foo"].(starlark.String).GoString() != "Hi" {
-		t.Errorf("Expected \"Hi\", got: %q", x["foo"].(starlark.String).GoString())
-	}
-	if x["bar"].Type() != "NoneType" {
-		t.Errorf("Expected \"NoneType\", got: %q", x["bar"].Type())
-	}
-}
-
-func TestUnmarshal(t *testing.T) {
-	testCases := []struct {
-		input    string
-		expected interface{}
-	}{
-		{
-			input:    `"foo"`,
-			expected: "foo",
-		},
-		{
-			input:    `5`,
-			expected: 5,
-		},
-		{
-			input:    `["foo", "bar"]`,
-			expected: []string{"foo", "bar"},
-		},
-		{
-			input:    `("foo", "bar")`,
-			expected: []string{"foo", "bar"},
-		},
-		{
-			input:    `("foo",5)`,
-			expected: []interface{}{"foo", 5},
-		},
-		{
-			input:    `{"foo": 5, "bar": 10}`,
-			expected: map[string]int{"foo": 5, "bar": 10},
-		},
-		{
-			input:    `{"foo": ["qux"], "bar": []}`,
-			expected: map[string][]string{"foo": {"qux"}, "bar": nil},
-		},
-		{
-			input: `struct(Foo="foo", Bar=5)`,
-			expected: struct {
-				Foo string
-				Bar int
-			}{Foo: "foo", Bar: 5},
-		},
-		{
-			// Unexported fields version of the above
-			input: `struct(foo="foo", bar=5)`,
-			expected: struct {
-				foo string
-				bar int
-			}{foo: "foo", bar: 5},
-		},
-		{
-			input: `{"foo": "foo2", "bar": ["bar2"], "baz": 5, "qux": {"qux2": "qux3"}, "quux": {"quux2": "quux3", "quux4": 5}}`,
-			expected: map[string]interface{}{
-				"foo": "foo2",
-				"bar": []string{"bar2"},
-				"baz": 5,
-				"qux": map[string]string{"qux2": "qux3"},
-				"quux": map[string]interface{}{
-					"quux2": "quux3",
-					"quux4": 5,
-				},
-			},
-		},
-	}
-
-	for _, tc := range testCases {
-		x, err := UnmarshalReflect(createStarlarkValue(t, tc.input), reflect.TypeOf(tc.expected))
-		if err != nil {
-			t.Error(err)
-			continue
-		}
-		if !reflect.DeepEqual(x.Interface(), tc.expected) {
-			t.Errorf(`Expected %#v, got %#v`, tc.expected, x.Interface())
-		}
-	}
-}
diff --git a/sysprop/Android.bp b/sysprop/Android.bp
index e5263fe..a00a5e4 100644
--- a/sysprop/Android.bp
+++ b/sysprop/Android.bp
@@ -9,9 +9,9 @@
         "blueprint",
         "soong",
         "soong-android",
-        "soong-bp2build",
         "soong-cc",
         "soong-java",
+        "soong-rust",
     ],
     srcs: [
         "sysprop_library.go",
@@ -19,7 +19,6 @@
     ],
     testSrcs: [
         "sysprop_test.go",
-        "sysprop_library_conversion_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 0edbb7c..b9b68be 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -21,15 +21,16 @@
 	"io"
 	"os"
 	"path"
+	"strings"
 	"sync"
 
-	"android/soong/bazel"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 	"android/soong/cc"
 	"android/soong/java"
+	"android/soong/rust"
 )
 
 type dependencyTag struct {
@@ -52,7 +53,14 @@
 	genSrcjars android.Paths
 }
 
+type syspropRustGenRule struct {
+	*rust.BaseSourceProvider
+
+	properties rustLibraryProperties
+}
+
 var _ android.OutputFileProducer = (*syspropJavaGenRule)(nil)
+var _ rust.SourceProvider = (*syspropRustGenRule)(nil)
 
 var (
 	syspropJava = pctx.AndroidStaticRule("syspropJava",
@@ -65,11 +73,20 @@
 				"$soongZipCmd",
 			},
 		}, "scope")
+	syspropRust = pctx.AndroidStaticRule("syspropRust",
+		blueprint.RuleParams{
+			Command: `rm -rf $out_dir && mkdir -p $out_dir && ` +
+				`$syspropRustCmd --scope $scope --rust-output-dir $out_dir $in`,
+			CommandDeps: []string{
+				"$syspropRustCmd",
+			},
+		}, "scope", "out_dir")
 )
 
 func init() {
 	pctx.HostBinToolVariable("soongZipCmd", "soong_zip")
 	pctx.HostBinToolVariable("syspropJavaCmd", "sysprop_java")
+	pctx.HostBinToolVariable("syspropRustCmd", "sysprop_rust")
 }
 
 // syspropJavaGenRule module generates srcjar containing generated java APIs.
@@ -123,10 +140,78 @@
 	return g
 }
 
+// syspropRustGenRule module generates rust source files containing generated rust APIs.
+// It also depends on check api rule, so api check has to pass to use sysprop_library.
+func (g *syspropRustGenRule) GenerateSource(ctx rust.ModuleContext, deps rust.PathDeps) android.Path {
+	var checkApiFileTimeStamp android.WritablePath
+
+	ctx.VisitDirectDeps(func(dep android.Module) {
+		if m, ok := dep.(*syspropLibrary); ok {
+			checkApiFileTimeStamp = m.checkApiFileTimeStamp
+		}
+	})
+
+	outputDir := android.PathForModuleOut(ctx, "src")
+	libFile := outputDir.Join(ctx, "lib.rs")
+	g.BaseSourceProvider.OutputFiles = append(g.BaseSourceProvider.OutputFiles, libFile)
+	libFileLines := []string{"//! Autogenerated system property accessors."}
+
+	for _, syspropFile := range android.PathsForModuleSrc(ctx, g.properties.Sysprop_srcs) {
+		moduleName := syspropPathToRustModule(syspropFile)
+		moduleDir := outputDir.Join(ctx, moduleName)
+		modulePath := moduleDir.Join(ctx, "mod.rs")
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        syspropRust,
+			Description: "sysprop_rust " + syspropFile.Rel(),
+			Output:      modulePath,
+			Input:       syspropFile,
+			Implicit:    checkApiFileTimeStamp,
+			Args: map[string]string{
+				"scope":   g.properties.Scope,
+				"out_dir": moduleDir.String(),
+			},
+		})
+
+		g.BaseSourceProvider.OutputFiles = append(g.BaseSourceProvider.OutputFiles, modulePath)
+		libFileLines = append(libFileLines, fmt.Sprintf("pub mod %s;", moduleName))
+	}
+
+	libFileSource := strings.Join(libFileLines, "\n")
+	android.WriteFileRule(ctx, libFile, libFileSource)
+
+	return libFile
+}
+
+func (g *syspropRustGenRule) SourceProviderProps() []interface{} {
+	return append(g.BaseSourceProvider.SourceProviderProps(), &g.Properties)
+}
+
+// syspropPathToRustModule takes a path to a .sysprop file and returns the name to use for the
+// corresponding Rust module.
+func syspropPathToRustModule(syspropFilename android.Path) string {
+	filenameBase := strings.TrimSuffix(syspropFilename.Base(), ".sysprop")
+	return strings.ToLower(filenameBase)
+}
+
+func (g *syspropRustGenRule) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// Add a dependency from the stubs to sysprop library so that the generator rule can depend on
+	// the check API rule of the sysprop library.
+	ctx.AddFarVariationDependencies(nil, nil, proptools.String(g.properties.Check_api))
+}
+
+func syspropRustGenFactory() android.Module {
+	g := &syspropRustGenRule{
+		BaseSourceProvider: rust.NewSourceProvider(),
+	}
+	sourceProvider := rust.NewSourceProviderModule(android.DeviceSupported, g, false, false)
+	sourceProvider.AddProperties(&g.properties)
+	return sourceProvider.Init()
+}
+
 type syspropLibrary struct {
 	android.ModuleBase
 	android.ApexModuleBase
-	android.BazelModuleBase
 
 	properties syspropLibraryProperties
 
@@ -169,6 +254,12 @@
 		// Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
 		// Forwarded to cc_library.min_sdk_version
 		Min_sdk_version *string
+
+		// C compiler flags used to build library
+		Cflags []string
+
+		// Linker flags used to build binary
+		Ldflags []string
 	}
 
 	Java struct {
@@ -176,6 +267,12 @@
 		// Forwarded to java_library.min_sdk_version
 		Min_sdk_version *string
 	}
+
+	Rust struct {
+		// Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
+		// Forwarded to rust_library.min_sdk_version
+		Min_sdk_version *string
+	}
 }
 
 var (
@@ -229,6 +326,17 @@
 	return m.BaseModuleName() + "_java_gen_public"
 }
 
+func (m *syspropLibrary) rustGenStubName() string {
+	return "lib" + m.rustCrateName() + "_rust"
+}
+
+func (m *syspropLibrary) rustCrateName() string {
+	moduleName := strings.ToLower(m.BaseModuleName())
+	moduleName = strings.ReplaceAll(moduleName, "-", "_")
+	moduleName = strings.ReplaceAll(moduleName, ".", "_")
+	return moduleName
+}
+
 func (m *syspropLibrary) BaseModuleName() string {
 	return m.ModuleBase.Name()
 }
@@ -241,12 +349,13 @@
 // generated java_library will depend on these API files.
 func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	baseModuleName := m.BaseModuleName()
-
-	for _, syspropFile := range android.PathsForModuleSrc(ctx, m.properties.Srcs) {
+	srcs := android.PathsForModuleSrc(ctx, m.properties.Srcs)
+	for _, syspropFile := range srcs {
 		if syspropFile.Ext() != ".sysprop" {
 			ctx.PropertyErrorf("srcs", "srcs contains non-sysprop file %q", syspropFile.String())
 		}
 	}
+	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
 
 	if ctx.Failed() {
 		return
@@ -264,7 +373,7 @@
 	rule.Command().
 		BuiltTool("sysprop_api_dump").
 		Output(m.dumpedApiFile).
-		Inputs(android.PathsForModuleSrc(ctx, m.properties.Srcs))
+		Inputs(srcs)
 	rule.Build(baseModuleName+"_api_dump", baseModuleName+" api dump")
 
 	// check API rule
@@ -338,9 +447,12 @@
 			// Actual implementation libraries are created on LoadHookMutator
 			fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)", " # sysprop.syspropLibrary")
 			fmt.Fprintln(w, "LOCAL_MODULE :=", m.Name())
-			data.Entries.WriteLicenseVariables(w)
 			fmt.Fprintf(w, "LOCAL_MODULE_CLASS := FAKE\n")
 			fmt.Fprintf(w, "LOCAL_MODULE_TAGS := optional\n")
+			// AconfigUpdateAndroidMkData may have added elements to Extra.  Process them here.
+			for _, extra := range data.Extra {
+				extra(w, nil)
+			}
 			fmt.Fprintf(w, "include $(BUILD_SYSTEM)/base_rules.mk\n\n")
 			fmt.Fprintf(w, "$(LOCAL_BUILT_MODULE): %s\n", m.checkApiFileTimeStamp.String())
 			fmt.Fprintf(w, "\ttouch $@\n\n")
@@ -377,7 +489,6 @@
 	)
 	android.InitAndroidModule(m)
 	android.InitApexModule(m)
-	android.InitBazelModule(m)
 	android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
 	return m
 }
@@ -409,9 +520,8 @@
 	Host_supported     *bool
 	Apex_available     []string
 	Min_sdk_version    *string
-	Bazel_module       struct {
-		Bp2build_available *bool
-	}
+	Cflags             []string
+	Ldflags            []string
 }
 
 type javaLibraryProperties struct {
@@ -430,6 +540,21 @@
 	Min_sdk_version   *string
 }
 
+type rustLibraryProperties struct {
+	Name              *string
+	Sysprop_srcs      []string `android:"path"`
+	Scope             string
+	Check_api         *string
+	Srcs              []string
+	Installable       *bool
+	Crate_name        string
+	Rustlibs          []string
+	Vendor_available  *bool
+	Product_available *bool
+	Apex_available    []string
+	Min_sdk_version   *string
+}
+
 func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) {
 	if len(m.properties.Srcs) == 0 {
 		ctx.PropertyErrorf("srcs", "sysprop_library must specify srcs")
@@ -492,11 +617,8 @@
 	ccProps.Host_supported = m.properties.Host_supported
 	ccProps.Apex_available = m.ApexProperties.Apex_available
 	ccProps.Min_sdk_version = m.properties.Cpp.Min_sdk_version
-	// A Bazel macro handles this, so this module does not need to be handled
-	// in bp2build
-	// TODO(b/237810289) perhaps do something different here so that we aren't
-	//                   also disabling these modules in mixed builds
-	ccProps.Bazel_module.Bp2build_available = proptools.BoolPtr(false)
+	ccProps.Cflags = m.properties.Cpp.Cflags
+	ccProps.Ldflags = m.properties.Cpp.Ldflags
 	ctx.CreateModule(cc.LibraryFactory, &ccProps)
 
 	scope := "internal"
@@ -561,6 +683,25 @@
 		})
 	}
 
+	// Generate a Rust implementation library.
+	rustProps := rustLibraryProperties{
+		Name:         proptools.StringPtr(m.rustGenStubName()),
+		Sysprop_srcs: m.properties.Srcs,
+		Scope:        scope,
+		Check_api:    proptools.StringPtr(ctx.ModuleName()),
+		Installable:  proptools.BoolPtr(false),
+		Crate_name:   m.rustCrateName(),
+		Rustlibs: []string{
+			"liblog_rust",
+			"librustutils",
+		},
+		Vendor_available:  m.properties.Vendor_available,
+		Product_available: m.properties.Product_available,
+		Apex_available:    m.ApexProperties.Apex_available,
+		Min_sdk_version:   proptools.StringPtr("29"),
+	}
+	ctx.CreateModule(syspropRustGenFactory, &rustProps)
+
 	// syspropLibraries will be used by property_contexts to check types.
 	// Record absolute paths of sysprop_library to prevent soong_namespace problem.
 	if m.ExportedToMake() {
@@ -571,16 +712,3 @@
 		*libraries = append(*libraries, "//"+ctx.ModuleDir()+":"+ctx.ModuleName())
 	}
 }
-
-// TODO(b/240463568): Additional properties will be added for API validation
-func (m *syspropLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	labels := cc.SyspropLibraryLabels{
-		SyspropLibraryLabel: m.BaseModuleName(),
-		SharedLibraryLabel:  m.CcImplementationModuleName(),
-		StaticLibraryLabel:  cc.BazelLabelNameForStaticModule(m.CcImplementationModuleName()),
-	}
-	cc.Bp2buildSysprop(ctx,
-		labels,
-		bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Srcs)),
-		m.properties.Cpp.Min_sdk_version)
-}
diff --git a/sysprop/sysprop_library_conversion_test.go b/sysprop/sysprop_library_conversion_test.go
deleted file mode 100644
index 89adf7d..0000000
--- a/sysprop/sysprop_library_conversion_test.go
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package sysprop
-
-import (
-	"testing"
-
-	"android/soong/bp2build"
-)
-
-func TestSyspropLibrarySimple(t *testing.T) {
-	bp2build.RunBp2BuildTestCaseSimple(t, bp2build.Bp2buildTestCase{
-		Description:                "sysprop_library simple",
-		ModuleTypeUnderTest:        "sysprop_library",
-		ModuleTypeUnderTestFactory: syspropLibraryFactory,
-		Filesystem: map[string]string{
-			"foo.sysprop": "",
-			"bar.sysprop": "",
-		},
-		Blueprint: `
-sysprop_library {
-	name: "sysprop_foo",
-	srcs: [
-		"foo.sysprop",
-		"bar.sysprop",
-	],
-	property_owner: "Platform",
-}
-`,
-		ExpectedBazelTargets: []string{
-			bp2build.MakeBazelTargetNoRestrictions("sysprop_library",
-				"sysprop_foo",
-				bp2build.AttrNameToString{
-					"srcs": `[
-        "foo.sysprop",
-        "bar.sysprop",
-    ]`,
-				}),
-			bp2build.MakeBazelTargetNoRestrictions("cc_sysprop_library_shared",
-				"libsysprop_foo",
-				bp2build.AttrNameToString{
-					"dep": `":sysprop_foo"`,
-				}),
-			bp2build.MakeBazelTargetNoRestrictions("cc_sysprop_library_static",
-				"libsysprop_foo_bp2build_cc_library_static",
-				bp2build.AttrNameToString{
-					"dep": `":sysprop_foo"`,
-				}),
-		},
-	})
-}
-
-func TestSyspropLibraryCppMinSdkVersion(t *testing.T) {
-	bp2build.RunBp2BuildTestCaseSimple(t, bp2build.Bp2buildTestCase{
-		Description:                "sysprop_library with min_sdk_version",
-		ModuleTypeUnderTest:        "sysprop_library",
-		ModuleTypeUnderTestFactory: syspropLibraryFactory,
-		Filesystem: map[string]string{
-			"foo.sysprop": "",
-			"bar.sysprop": "",
-		},
-		Blueprint: `
-sysprop_library {
-	name: "sysprop_foo",
-	srcs: [
-		"foo.sysprop",
-		"bar.sysprop",
-	],
-	cpp: {
-		min_sdk_version: "5",
-	},
-	property_owner: "Platform",
-}
-`,
-		ExpectedBazelTargets: []string{
-			bp2build.MakeBazelTargetNoRestrictions("sysprop_library",
-				"sysprop_foo",
-				bp2build.AttrNameToString{
-					"srcs": `[
-        "foo.sysprop",
-        "bar.sysprop",
-    ]`,
-				}),
-			bp2build.MakeBazelTargetNoRestrictions("cc_sysprop_library_shared",
-				"libsysprop_foo",
-				bp2build.AttrNameToString{
-					"dep":             `":sysprop_foo"`,
-					"min_sdk_version": `"5"`,
-				}),
-			bp2build.MakeBazelTargetNoRestrictions("cc_sysprop_library_static",
-				"libsysprop_foo_bp2build_cc_library_static",
-				bp2build.AttrNameToString{
-					"dep":             `":sysprop_foo"`,
-					"min_sdk_version": `"5"`,
-				}),
-		},
-	})
-}
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 80b86e0..7d4e69d 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -22,6 +22,7 @@
 	"android/soong/android"
 	"android/soong/cc"
 	"android/soong/java"
+	"android/soong/rust"
 
 	"github.com/google/blueprint/proptools"
 )
@@ -42,21 +43,10 @@
 		cc_library_headers {
 			name: "libbase_headers",
 			vendor_available: true,
+			product_available: true,
 			recovery_available: true,
 		}
 
-		cc_library {
-			name: "liblog",
-			no_libcrt: true,
-			nocrt: true,
-			system_shared_libs: [],
-			recovery_available: true,
-			host_supported: true,
-			llndk: {
-				symbol_file: "liblog.map.txt",
-			}
-		}
-
 		java_library {
 			name: "sysprop-library-stub-platform",
 			sdk_version: "core_current",
@@ -73,6 +63,24 @@
 			product_specific: true,
 			sdk_version: "core_current",
 		}
+
+		rust_library {
+			name: "librustutils",
+			crate_name: "rustutils",
+			srcs: ["librustutils/lib.rs"],
+			product_available: true,
+			vendor_available: true,
+			min_sdk_version: "29",
+		}
+
+		rust_library {
+			name: "liblog_rust",
+			crate_name: "log",
+			srcs: ["log/src/lib.rs"],
+			product_available: true,
+			vendor_available: true,
+			min_sdk_version: "29",
+		}
 	`
 
 	mockFS := android.MockFS{
@@ -114,16 +122,24 @@
 		"android/sysprop/PlatformProperties.sysprop": nil,
 		"com/android/VendorProperties.sysprop":       nil,
 		"com/android2/OdmProperties.sysprop":         nil,
+
+		"librustutils/lib.rs": nil,
+		"log/src/lib.rs":      nil,
 	}
 
 	result := android.GroupFixturePreparers(
 		cc.PrepareForTestWithCcDefaultModules,
 		java.PrepareForTestWithJavaDefaultModules,
+		rust.PrepareForTestWithRustDefaultModules,
 		PrepareForTestWithSyspropBuildComponents,
 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 			variables.DeviceSystemSdkVersions = []string{"28"}
-			variables.DeviceVndkVersion = proptools.StringPtr("current")
-			variables.Platform_vndk_version = proptools.StringPtr("29")
+			variables.DeviceCurrentApiLevelForVendorModules = proptools.StringPtr("28")
+		}),
+		java.FixtureWithPrebuiltApis(map[string][]string{
+			"28": {},
+			"29": {},
+			"30": {},
 		}),
 		mockFS.AddToFixture(),
 		android.FixtureWithRootAndroidBp(bp),
@@ -240,16 +256,26 @@
 
 	// Check for generated cc_library
 	for _, variant := range []string{
-		"android_vendor.29_arm_armv7-a-neon_shared",
-		"android_vendor.29_arm_armv7-a-neon_static",
-		"android_vendor.29_arm64_armv8-a_shared",
-		"android_vendor.29_arm64_armv8-a_static",
+		"android_vendor_arm_armv7-a-neon_shared",
+		"android_vendor_arm_armv7-a-neon_static",
+		"android_vendor_arm64_armv8-a_shared",
+		"android_vendor_arm64_armv8-a_static",
 	} {
 		result.ModuleForTests("libsysprop-platform", variant)
 		result.ModuleForTests("libsysprop-vendor", variant)
 		result.ModuleForTests("libsysprop-odm", variant)
 	}
 
+	// product variant of vendor-owned sysprop_library
+	for _, variant := range []string{
+		"android_product_arm_armv7-a-neon_shared",
+		"android_product_arm_armv7-a-neon_static",
+		"android_product_arm64_armv8-a_shared",
+		"android_product_arm64_armv8-a_static",
+	} {
+		result.ModuleForTests("libsysprop-vendor-on-product", variant)
+	}
+
 	for _, variant := range []string{
 		"android_arm_armv7-a-neon_shared",
 		"android_arm_armv7-a-neon_static",
@@ -259,9 +285,6 @@
 		library := result.ModuleForTests("libsysprop-platform", variant).Module().(*cc.Module)
 		expectedApexAvailableOnLibrary := []string{"//apex_available:platform"}
 		android.AssertDeepEquals(t, "apex available property on libsysprop-platform", expectedApexAvailableOnLibrary, library.ApexProperties.Apex_available)
-
-		// product variant of vendor-owned sysprop_library
-		result.ModuleForTests("libsysprop-vendor-on-product", variant)
 	}
 
 	result.ModuleForTests("sysprop-platform", "android_common")
@@ -271,16 +294,16 @@
 
 	// Check for exported includes
 	coreVariant := "android_arm64_armv8-a_static"
-	vendorVariant := "android_vendor.29_arm64_armv8-a_static"
+	vendorVariant := "android_vendor_arm64_armv8-a_static"
+	productVariant := "android_product_arm64_armv8-a_static"
 
 	platformInternalPath := "libsysprop-platform/android_arm64_armv8-a_static/gen/sysprop/include"
-	platformPublicCorePath := "libsysprop-platform/android_arm64_armv8-a_static/gen/sysprop/public/include"
-	platformPublicVendorPath := "libsysprop-platform/android_vendor.29_arm64_armv8-a_static/gen/sysprop/public/include"
+	platformPublicVendorPath := "libsysprop-platform/android_vendor_arm64_armv8-a_static/gen/sysprop/public/include"
 
-	platformOnProductPath := "libsysprop-platform-on-product/android_arm64_armv8-a_static/gen/sysprop/public/include"
+	platformOnProductPath := "libsysprop-platform-on-product/android_product_arm64_armv8-a_static/gen/sysprop/public/include"
 
-	vendorInternalPath := "libsysprop-vendor/android_vendor.29_arm64_armv8-a_static/gen/sysprop/include"
-	vendorPublicPath := "libsysprop-vendor-on-product/android_arm64_armv8-a_static/gen/sysprop/public/include"
+	vendorInternalPath := "libsysprop-vendor/android_vendor_arm64_armv8-a_static/gen/sysprop/include"
+	vendorOnProductPath := "libsysprop-vendor-on-product/android_product_arm64_armv8-a_static/gen/sysprop/public/include"
 
 	platformClient := result.ModuleForTests("cc-client-platform", coreVariant)
 	platformFlags := platformClient.Rule("cc").Args["cFlags"]
@@ -294,14 +317,14 @@
 	// platform-static should use platform's internal header
 	android.AssertStringDoesContain(t, "flags for platform-static", platformStaticFlags, platformInternalPath)
 
-	productClient := result.ModuleForTests("cc-client-product", coreVariant)
+	productClient := result.ModuleForTests("cc-client-product", productVariant)
 	productFlags := productClient.Rule("cc").Args["cFlags"]
 
 	// Product should use platform's and vendor's public headers
 	if !strings.Contains(productFlags, platformOnProductPath) ||
-		!strings.Contains(productFlags, vendorPublicPath) {
+		!strings.Contains(productFlags, vendorOnProductPath) {
 		t.Errorf("flags for product must contain %#v and %#v, but was %#v.",
-			platformPublicCorePath, vendorPublicPath, productFlags)
+			platformOnProductPath, vendorOnProductPath, productFlags)
 	}
 
 	vendorClient := result.ModuleForTests("cc-client-vendor", vendorVariant)
@@ -342,6 +365,10 @@
 	javaModule := result.ModuleForTests("sysprop-platform", "android_common").Module().(*java.Library)
 	propFromJava := javaModule.ApexProperties.Apex_available
 	android.AssertDeepEquals(t, "apex_available forwarding to java module", expected, propFromJava)
+
+	rustModule := result.ModuleForTests("libsysprop_platform_rust", "android_arm64_armv8-a_rlib_rlib-std").Module().(*rust.Module)
+	propFromRust := rustModule.ApexProperties.Apex_available
+	android.AssertDeepEquals(t, "apex_available forwarding to rust module", expected, propFromRust)
 }
 
 func TestMinSdkVersionIsForwarded(t *testing.T) {
@@ -357,6 +384,9 @@
 			java: {
 				min_sdk_version: "30",
 			},
+			rust: {
+				min_sdk_version: "29",
+			}
 		}
 	`)
 
@@ -367,4 +397,8 @@
 	javaModule := result.ModuleForTests("sysprop-platform", "android_common").Module().(*java.Library)
 	propFromJava := javaModule.MinSdkVersionString()
 	android.AssertStringEquals(t, "min_sdk_version forwarding to java module", "30", propFromJava)
+
+	rustModule := result.ModuleForTests("libsysprop_platform_rust", "android_arm64_armv8-a_rlib_rlib-std").Module().(*rust.Module)
+	propFromRust := proptools.String(rustModule.Properties.Min_sdk_version)
+	android.AssertStringEquals(t, "min_sdk_version forwarding to rust module", "29", propFromRust)
 }
diff --git a/testing/Android.bp b/testing/Android.bp
new file mode 100644
index 0000000..43040b0
--- /dev/null
+++ b/testing/Android.bp
@@ -0,0 +1,24 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-testing",
+    pkgPath: "android/soong/testing",
+    deps: [
+        "blueprint",
+        "soong-android",
+        "soong-testing-code_metadata_internal_proto",
+        "soong-testing-test_spec_proto",
+
+    ],
+    srcs: [
+        "all_code_metadata.go",
+        "all_test_specs.go",
+        "code_metadata.go",
+        "test_spec.go",
+        "init.go",
+        "test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/testing/OWNERS b/testing/OWNERS
new file mode 100644
index 0000000..03bcdf1
--- /dev/null
+++ b/testing/OWNERS
@@ -0,0 +1,4 @@
+dariofreni@google.com
+joeo@google.com
+ronish@google.com
+caditya@google.com
diff --git a/testing/all_code_metadata.go b/testing/all_code_metadata.go
new file mode 100644
index 0000000..12aa7b5
--- /dev/null
+++ b/testing/all_code_metadata.go
@@ -0,0 +1,46 @@
+package testing
+
+import (
+	"android/soong/android"
+)
+
+const fileContainingCodeMetadataFilePaths = "all_code_metadata_paths.rsp"
+const allCodeMetadataFile = "all_code_metadata.pb"
+
+func AllCodeMetadataFactory() android.Singleton {
+	return &allCodeMetadataSingleton{}
+}
+
+type allCodeMetadataSingleton struct {
+	// Path where the collected metadata is stored after successful validation.
+	outputPath android.OutputPath
+}
+
+func (this *allCodeMetadataSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	var intermediateMetadataPaths android.Paths
+
+	ctx.VisitAllModules(
+		func(module android.Module) {
+			if metadata, ok := android.SingletonModuleProvider(ctx, module, CodeMetadataProviderKey); ok {
+				intermediateMetadataPaths = append(intermediateMetadataPaths, metadata.IntermediatePath)
+			}
+		},
+	)
+
+	rspFile := android.PathForOutput(ctx, fileContainingCodeMetadataFilePaths)
+	this.outputPath = android.PathForOutput(ctx, ownershipDirectory, allCodeMetadataFile)
+
+	rule := android.NewRuleBuilder(pctx, ctx)
+	cmd := rule.Command().
+		BuiltTool("metadata").
+		FlagWithArg("-rule ", "code_metadata").
+		FlagWithRspFileInputList("-inputFile ", rspFile, intermediateMetadataPaths)
+	cmd.FlagWithOutput("-outputFile ", this.outputPath)
+	rule.Build("all_code_metadata_rule", "Generate all code metadata")
+
+	ctx.Phony("all_code_metadata", this.outputPath)
+}
+
+func (this *allCodeMetadataSingleton) MakeVars(ctx android.MakeVarsContext) {
+	ctx.DistForGoal("code_metadata", this.outputPath)
+}
diff --git a/testing/all_test_specs.go b/testing/all_test_specs.go
new file mode 100644
index 0000000..b035435
--- /dev/null
+++ b/testing/all_test_specs.go
@@ -0,0 +1,44 @@
+package testing
+
+import (
+	"android/soong/android"
+)
+
+const ownershipDirectory = "ownership"
+const fileContainingFilePaths = "all_test_spec_paths.rsp"
+const allTestSpecsFile = "all_test_specs.pb"
+
+func AllTestSpecsFactory() android.Singleton {
+	return &allTestSpecsSingleton{}
+}
+
+type allTestSpecsSingleton struct {
+	// Path where the collected metadata is stored after successful validation.
+	outputPath android.OutputPath
+}
+
+func (this *allTestSpecsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	var intermediateMetadataPaths android.Paths
+
+	ctx.VisitAllModules(func(module android.Module) {
+		if metadata, ok := android.SingletonModuleProvider(ctx, module, TestSpecProviderKey); ok {
+			intermediateMetadataPaths = append(intermediateMetadataPaths, metadata.IntermediatePath)
+		}
+	})
+
+	rspFile := android.PathForOutput(ctx, fileContainingFilePaths)
+	this.outputPath = android.PathForOutput(ctx, ownershipDirectory, allTestSpecsFile)
+
+	rule := android.NewRuleBuilder(pctx, ctx)
+	cmd := rule.Command().
+		BuiltTool("metadata").
+		FlagWithArg("-rule ", "test_spec").
+		FlagWithRspFileInputList("-inputFile ", rspFile, intermediateMetadataPaths)
+	cmd.FlagWithOutput("-outputFile ", this.outputPath)
+	rule.Build("all_test_specs_rule", "Generate all test specifications")
+	ctx.Phony("all_test_specs", this.outputPath)
+}
+
+func (this *allTestSpecsSingleton) MakeVars(ctx android.MakeVarsContext) {
+	ctx.DistForGoal("test_specs", this.outputPath)
+}
diff --git a/testing/code_metadata.go b/testing/code_metadata.go
new file mode 100644
index 0000000..11ba430
--- /dev/null
+++ b/testing/code_metadata.go
@@ -0,0 +1,137 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package testing
+
+import (
+	"path/filepath"
+
+	"android/soong/android"
+	"android/soong/testing/code_metadata_internal_proto"
+	"github.com/google/blueprint"
+
+	"google.golang.org/protobuf/proto"
+)
+
+func CodeMetadataFactory() android.Module {
+	module := &CodeMetadataModule{}
+
+	android.InitAndroidModule(module)
+	android.InitDefaultableModule(module)
+	module.AddProperties(&module.properties)
+
+	return module
+}
+
+type CodeMetadataModule struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+
+	// Properties for "code_metadata"
+	properties struct {
+		// Specifies the name of the code_config.
+		Name string
+		// Specifies the team ID.
+		TeamId string
+		// Specifies the list of modules that this code_metadata covers.
+		Code []string
+		// An optional field to specify if multiple ownerships for source files is allowed.
+		MultiOwnership bool
+	}
+}
+
+type codeDepTagType struct {
+	blueprint.BaseDependencyTag
+}
+
+var codeDepTag = codeDepTagType{}
+
+func (module *CodeMetadataModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// Validate Properties
+	if len(module.properties.TeamId) == 0 {
+		ctx.PropertyErrorf(
+			"TeamId",
+			"Team Id not found in the code_metadata module. Hint: Maybe the teamId property hasn't been properly specified.",
+		)
+	}
+	if !isInt(module.properties.TeamId) {
+		ctx.PropertyErrorf(
+			"TeamId", "Invalid value for Team ID. The Team ID must be an integer.",
+		)
+	}
+	if len(module.properties.Code) == 0 {
+		ctx.PropertyErrorf(
+			"Code",
+			"Targets to be attributed cannot be empty. Hint: Maybe the code property hasn't been properly specified.",
+		)
+	}
+	ctx.AddDependency(ctx.Module(), codeDepTag, module.properties.Code...)
+}
+
+// Provider published by CodeMetadata
+type CodeMetadataProviderData struct {
+	IntermediatePath android.WritablePath
+}
+
+var CodeMetadataProviderKey = blueprint.NewProvider[CodeMetadataProviderData]()
+
+func (module *CodeMetadataModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	metadataList := make(
+		[]*code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership, 0,
+		len(module.properties.Code),
+	)
+	bpFilePath := filepath.Join(ctx.ModuleDir(), ctx.BlueprintsFile())
+
+	for _, m := range ctx.GetDirectDepsWithTag(codeDepTag) {
+		targetName := m.Name()
+		var moduleSrcs []string
+		if srcsFileInfo, ok := android.OtherModuleProvider(ctx, m, blueprint.SrcsFileProviderKey); ok {
+			moduleSrcs = srcsFileInfo.SrcPaths
+		}
+		if module.properties.MultiOwnership {
+			metadata := &code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership{
+				TargetName:     &targetName,
+				TrendyTeamId:   &module.properties.TeamId,
+				Path:           &bpFilePath,
+				MultiOwnership: &module.properties.MultiOwnership,
+				SourceFiles:    moduleSrcs,
+			}
+			metadataList = append(metadataList, metadata)
+		} else {
+			metadata := &code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership{
+				TargetName:   &targetName,
+				TrendyTeamId: &module.properties.TeamId,
+				Path:         &bpFilePath,
+				SourceFiles:  moduleSrcs,
+			}
+			metadataList = append(metadataList, metadata)
+		}
+
+	}
+	codeMetadata := &code_metadata_internal_proto.CodeMetadataInternal{TargetOwnershipList: metadataList}
+	protoData, err := proto.Marshal(codeMetadata)
+	if err != nil {
+		ctx.ModuleErrorf("Error marshaling code metadata: %s", err.Error())
+		return
+	}
+	intermediatePath := android.PathForModuleOut(
+		ctx, "intermediateCodeMetadata.pb",
+	)
+	android.WriteFileRuleVerbatim(ctx, intermediatePath, string(protoData))
+
+	android.SetProvider(ctx,
+		CodeMetadataProviderKey,
+		CodeMetadataProviderData{IntermediatePath: intermediatePath},
+	)
+}
diff --git a/starlark_import/Android.bp b/testing/code_metadata_internal_proto/Android.bp
similarity index 62%
copy from starlark_import/Android.bp
copy to testing/code_metadata_internal_proto/Android.bp
index b43217b..a534cc2 100644
--- a/starlark_import/Android.bp
+++ b/testing/code_metadata_internal_proto/Android.bp
@@ -1,4 +1,4 @@
-// Copyright 2023 Google Inc. All rights reserved.
+// Copyright 2022 Google Inc. All rights reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -17,20 +17,13 @@
 }
 
 bootstrap_go_package {
-    name: "soong-starlark",
-    pkgPath: "android/soong/starlark_import",
-    srcs: [
-        "starlark_import.go",
-        "unmarshal.go",
-    ],
-    testSrcs: [
-        "starlark_import_test.go",
-        "unmarshal_test.go",
-    ],
+    name: "soong-testing-code_metadata_internal_proto",
+    pkgPath: "android/soong/testing/code_metadata_internal_proto",
     deps: [
-        "go-starlark-starlark",
-        "go-starlark-starlarkstruct",
-        "go-starlark-starlarkjson",
-        "go-starlark-starlarktest",
+            "golang-protobuf-reflect-protoreflect",
+            "golang-protobuf-runtime-protoimpl",
+        ],
+    srcs: [
+        "code_metadata_internal.pb.go",
     ],
 }
diff --git a/testing/code_metadata_internal_proto/OWNERS b/testing/code_metadata_internal_proto/OWNERS
new file mode 100644
index 0000000..03bcdf1
--- /dev/null
+++ b/testing/code_metadata_internal_proto/OWNERS
@@ -0,0 +1,4 @@
+dariofreni@google.com
+joeo@google.com
+ronish@google.com
+caditya@google.com
diff --git a/testing/code_metadata_internal_proto/code_metadata_internal.pb.go b/testing/code_metadata_internal_proto/code_metadata_internal.pb.go
new file mode 100644
index 0000000..ecb8b86
--- /dev/null
+++ b/testing/code_metadata_internal_proto/code_metadata_internal.pb.go
@@ -0,0 +1,277 @@
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.30.0
+// 	protoc        v3.21.12
+// source: code_metadata_internal.proto
+
+package code_metadata_internal_proto
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type CodeMetadataInternal struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// List of all code targets and their metadata.
+	TargetOwnershipList []*CodeMetadataInternal_TargetOwnership `protobuf:"bytes,1,rep,name=target_ownership_list,json=targetOwnershipList" json:"target_ownership_list,omitempty"`
+}
+
+func (x *CodeMetadataInternal) Reset() {
+	*x = CodeMetadataInternal{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_code_metadata_internal_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CodeMetadataInternal) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CodeMetadataInternal) ProtoMessage() {}
+
+func (x *CodeMetadataInternal) ProtoReflect() protoreflect.Message {
+	mi := &file_code_metadata_internal_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CodeMetadataInternal.ProtoReflect.Descriptor instead.
+func (*CodeMetadataInternal) Descriptor() ([]byte, []int) {
+	return file_code_metadata_internal_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *CodeMetadataInternal) GetTargetOwnershipList() []*CodeMetadataInternal_TargetOwnership {
+	if x != nil {
+		return x.TargetOwnershipList
+	}
+	return nil
+}
+
+type CodeMetadataInternal_TargetOwnership struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// REQUIRED: Name of the build target
+	TargetName *string `protobuf:"bytes,1,opt,name=target_name,json=targetName" json:"target_name,omitempty"`
+	// REQUIRED: Code location of the target.
+	// To be used to support legacy/backup systems that use OWNERS file and is
+	// also required for our dashboard to support per code location basis UI
+	Path *string `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"`
+	// REQUIRED: Team ID of the team that owns this target.
+	TrendyTeamId *string `protobuf:"bytes,3,opt,name=trendy_team_id,json=trendyTeamId" json:"trendy_team_id,omitempty"`
+	// OPTIONAL: The src files of the target.
+	// To be used to determine ownership of a file for ownership
+	SourceFiles []string `protobuf:"bytes,4,rep,name=source_files,json=sourceFiles" json:"source_files,omitempty"`
+	// OPTIONAL: Specify if multiple ownerships of the source files are allowed.
+	MultiOwnership *bool `protobuf:"varint,5,opt,name=multi_ownership,json=multiOwnership" json:"multi_ownership,omitempty"`
+}
+
+func (x *CodeMetadataInternal_TargetOwnership) Reset() {
+	*x = CodeMetadataInternal_TargetOwnership{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_code_metadata_internal_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CodeMetadataInternal_TargetOwnership) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CodeMetadataInternal_TargetOwnership) ProtoMessage() {}
+
+func (x *CodeMetadataInternal_TargetOwnership) ProtoReflect() protoreflect.Message {
+	mi := &file_code_metadata_internal_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CodeMetadataInternal_TargetOwnership.ProtoReflect.Descriptor instead.
+func (*CodeMetadataInternal_TargetOwnership) Descriptor() ([]byte, []int) {
+	return file_code_metadata_internal_proto_rawDescGZIP(), []int{0, 0}
+}
+
+func (x *CodeMetadataInternal_TargetOwnership) GetTargetName() string {
+	if x != nil && x.TargetName != nil {
+		return *x.TargetName
+	}
+	return ""
+}
+
+func (x *CodeMetadataInternal_TargetOwnership) GetPath() string {
+	if x != nil && x.Path != nil {
+		return *x.Path
+	}
+	return ""
+}
+
+func (x *CodeMetadataInternal_TargetOwnership) GetTrendyTeamId() string {
+	if x != nil && x.TrendyTeamId != nil {
+		return *x.TrendyTeamId
+	}
+	return ""
+}
+
+func (x *CodeMetadataInternal_TargetOwnership) GetSourceFiles() []string {
+	if x != nil {
+		return x.SourceFiles
+	}
+	return nil
+}
+
+func (x *CodeMetadataInternal_TargetOwnership) GetMultiOwnership() bool {
+	if x != nil && x.MultiOwnership != nil {
+		return *x.MultiOwnership
+	}
+	return false
+}
+
+var File_code_metadata_internal_proto protoreflect.FileDescriptor
+
+var file_code_metadata_internal_proto_rawDesc = []byte{
+	0x0a, 0x1c, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f,
+	0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c,
+	0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x69, 0x6e,
+	0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc9, 0x02, 0x0a,
+	0x14, 0x43, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x49, 0x6e, 0x74,
+	0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x76, 0x0a, 0x15, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f,
+	0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61,
+	0x64, 0x61, 0x74, 0x61, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+	0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f,
+	0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
+	0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0xb8, 0x01,
+	0x0a, 0x0f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69,
+	0x70, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61,
+	0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79,
+	0x5f, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
+	0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x54, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c,
+	0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03,
+	0x28, 0x09, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12,
+	0x27, 0x0a, 0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68,
+	0x69, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x4f,
+	0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x42, 0x34, 0x5a, 0x32, 0x61, 0x6e, 0x64, 0x72,
+	0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e,
+	0x67, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f,
+	0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+}
+
+var (
+	file_code_metadata_internal_proto_rawDescOnce sync.Once
+	file_code_metadata_internal_proto_rawDescData = file_code_metadata_internal_proto_rawDesc
+)
+
+func file_code_metadata_internal_proto_rawDescGZIP() []byte {
+	file_code_metadata_internal_proto_rawDescOnce.Do(func() {
+		file_code_metadata_internal_proto_rawDescData = protoimpl.X.CompressGZIP(file_code_metadata_internal_proto_rawDescData)
+	})
+	return file_code_metadata_internal_proto_rawDescData
+}
+
+var file_code_metadata_internal_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_code_metadata_internal_proto_goTypes = []interface{}{
+	(*CodeMetadataInternal)(nil),                 // 0: code_metadata_internal_proto.CodeMetadataInternal
+	(*CodeMetadataInternal_TargetOwnership)(nil), // 1: code_metadata_internal_proto.CodeMetadataInternal.TargetOwnership
+}
+var file_code_metadata_internal_proto_depIdxs = []int32{
+	1, // 0: code_metadata_internal_proto.CodeMetadataInternal.target_ownership_list:type_name -> code_metadata_internal_proto.CodeMetadataInternal.TargetOwnership
+	1, // [1:1] is the sub-list for method output_type
+	1, // [1:1] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_code_metadata_internal_proto_init() }
+func file_code_metadata_internal_proto_init() {
+	if File_code_metadata_internal_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_code_metadata_internal_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CodeMetadataInternal); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_code_metadata_internal_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CodeMetadataInternal_TargetOwnership); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_code_metadata_internal_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_code_metadata_internal_proto_goTypes,
+		DependencyIndexes: file_code_metadata_internal_proto_depIdxs,
+		MessageInfos:      file_code_metadata_internal_proto_msgTypes,
+	}.Build()
+	File_code_metadata_internal_proto = out.File
+	file_code_metadata_internal_proto_rawDesc = nil
+	file_code_metadata_internal_proto_goTypes = nil
+	file_code_metadata_internal_proto_depIdxs = nil
+}
diff --git a/testing/code_metadata_internal_proto/code_metadata_internal.proto b/testing/code_metadata_internal_proto/code_metadata_internal.proto
new file mode 100644
index 0000000..14edc0f
--- /dev/null
+++ b/testing/code_metadata_internal_proto/code_metadata_internal.proto
@@ -0,0 +1,40 @@
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+package code_metadata_internal_proto;
+option go_package = "android/soong/testing/code_metadata_internal_proto";
+
+message CodeMetadataInternal {
+
+  message TargetOwnership {
+    // REQUIRED: Name of the build target
+    optional string target_name = 1;
+
+    // REQUIRED: Code location of the target.
+    // To be used to support legacy/backup systems that use OWNERS file and is
+    // also required for our dashboard to support per code location basis UI
+    optional string path = 2;
+
+    // REQUIRED: Team ID of the team that owns this target.
+    optional string trendy_team_id = 3;
+
+    // OPTIONAL: The src files of the target.
+    // To be used to determine ownership of a file for ownership
+    repeated string source_files = 4;
+
+    // OPTIONAL: Specify if multiple ownerships of the source files are allowed.
+    optional bool multi_ownership = 5;
+  }
+
+  // List of all code targets and their metadata.
+  repeated TargetOwnership target_ownership_list = 1;
+}
diff --git a/testing/code_metadata_internal_proto/regen.sh b/testing/code_metadata_internal_proto/regen.sh
new file mode 100644
index 0000000..f101a02
--- /dev/null
+++ b/testing/code_metadata_internal_proto/regen.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+aprotoc --go_out=paths=source_relative:. code_metadata_internal.proto
diff --git a/testing/code_metadata_proto/Android.bp b/testing/code_metadata_proto/Android.bp
new file mode 100644
index 0000000..f07efff
--- /dev/null
+++ b/testing/code_metadata_proto/Android.bp
@@ -0,0 +1,43 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-testing-code_metadata_proto",
+    pkgPath: "android/soong/testing/code_metadata_proto",
+    deps: [
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+    ],
+    srcs: [
+        "code_metadata.pb.go",
+    ],
+}
+
+python_library_host {
+    name: "code-metadata-proto-py",
+    pkg_path: "code_metadata",
+    srcs: [
+        "code_metadata.proto",
+    ],
+    libs: [
+        "libprotobuf-python",
+    ],
+    proto: {
+        canonical_path_from_root: false,
+    },
+}
diff --git a/testing/code_metadata_proto/OWNERS b/testing/code_metadata_proto/OWNERS
new file mode 100644
index 0000000..03bcdf1
--- /dev/null
+++ b/testing/code_metadata_proto/OWNERS
@@ -0,0 +1,4 @@
+dariofreni@google.com
+joeo@google.com
+ronish@google.com
+caditya@google.com
diff --git a/testing/code_metadata_proto/code_metadata.pb.go b/testing/code_metadata_proto/code_metadata.pb.go
new file mode 100644
index 0000000..711bf7a
--- /dev/null
+++ b/testing/code_metadata_proto/code_metadata.pb.go
@@ -0,0 +1,263 @@
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.30.0
+// 	protoc        v3.21.12
+// source: code_metadata.proto
+
+package code_metadata_proto
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type CodeMetadata struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// List of all code targets and their metadata.
+	TargetOwnershipList []*CodeMetadata_TargetOwnership `protobuf:"bytes,1,rep,name=target_ownership_list,json=targetOwnershipList" json:"target_ownership_list,omitempty"`
+}
+
+func (x *CodeMetadata) Reset() {
+	*x = CodeMetadata{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_code_metadata_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CodeMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CodeMetadata) ProtoMessage() {}
+
+func (x *CodeMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_code_metadata_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CodeMetadata.ProtoReflect.Descriptor instead.
+func (*CodeMetadata) Descriptor() ([]byte, []int) {
+	return file_code_metadata_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *CodeMetadata) GetTargetOwnershipList() []*CodeMetadata_TargetOwnership {
+	if x != nil {
+		return x.TargetOwnershipList
+	}
+	return nil
+}
+
+type CodeMetadata_TargetOwnership struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// REQUIRED: Name of the build target
+	TargetName *string `protobuf:"bytes,1,opt,name=target_name,json=targetName" json:"target_name,omitempty"`
+	// REQUIRED: Code location of the target.
+	// To be used to support legacy/backup systems that use OWNERS file and is
+	// also required for our dashboard to support per code location basis UI
+	Path *string `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"`
+	// REQUIRED: Team ID of the team that owns this target.
+	TrendyTeamId *string `protobuf:"bytes,3,opt,name=trendy_team_id,json=trendyTeamId" json:"trendy_team_id,omitempty"`
+	// OPTIONAL: The src files of the target.
+	// To be used to determine ownership of a file for ownership
+	SourceFiles []string `protobuf:"bytes,4,rep,name=source_files,json=sourceFiles" json:"source_files,omitempty"`
+}
+
+func (x *CodeMetadata_TargetOwnership) Reset() {
+	*x = CodeMetadata_TargetOwnership{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_code_metadata_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *CodeMetadata_TargetOwnership) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*CodeMetadata_TargetOwnership) ProtoMessage() {}
+
+func (x *CodeMetadata_TargetOwnership) ProtoReflect() protoreflect.Message {
+	mi := &file_code_metadata_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use CodeMetadata_TargetOwnership.ProtoReflect.Descriptor instead.
+func (*CodeMetadata_TargetOwnership) Descriptor() ([]byte, []int) {
+	return file_code_metadata_proto_rawDescGZIP(), []int{0, 0}
+}
+
+func (x *CodeMetadata_TargetOwnership) GetTargetName() string {
+	if x != nil && x.TargetName != nil {
+		return *x.TargetName
+	}
+	return ""
+}
+
+func (x *CodeMetadata_TargetOwnership) GetPath() string {
+	if x != nil && x.Path != nil {
+		return *x.Path
+	}
+	return ""
+}
+
+func (x *CodeMetadata_TargetOwnership) GetTrendyTeamId() string {
+	if x != nil && x.TrendyTeamId != nil {
+		return *x.TrendyTeamId
+	}
+	return ""
+}
+
+func (x *CodeMetadata_TargetOwnership) GetSourceFiles() []string {
+	if x != nil {
+		return x.SourceFiles
+	}
+	return nil
+}
+
+var File_code_metadata_proto protoreflect.FileDescriptor
+
+var file_code_metadata_proto_rawDesc = []byte{
+	0x0a, 0x13, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61,
+	0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x87, 0x02, 0x0a, 0x0c, 0x43,
+	0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x65, 0x0a, 0x15, 0x74,
+	0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f,
+	0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x63, 0x6f, 0x64,
+	0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x2e, 0x43, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61,
+	0x72, 0x67, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x13, 0x74,
+	0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x4c, 0x69,
+	0x73, 0x74, 0x1a, 0x8f, 0x01, 0x0a, 0x0f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x77, 0x6e,
+	0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
+	0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72,
+	0x67, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x74,
+	0x72, 0x65, 0x6e, 0x64, 0x79, 0x5f, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x54, 0x65, 0x61, 0x6d, 0x49,
+	0x64, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65,
+	0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46,
+	0x69, 0x6c, 0x65, 0x73, 0x42, 0x2b, 0x5a, 0x29, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
+	0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x63, 0x6f,
+	0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74,
+	0x6f,
+}
+
+var (
+	file_code_metadata_proto_rawDescOnce sync.Once
+	file_code_metadata_proto_rawDescData = file_code_metadata_proto_rawDesc
+)
+
+func file_code_metadata_proto_rawDescGZIP() []byte {
+	file_code_metadata_proto_rawDescOnce.Do(func() {
+		file_code_metadata_proto_rawDescData = protoimpl.X.CompressGZIP(file_code_metadata_proto_rawDescData)
+	})
+	return file_code_metadata_proto_rawDescData
+}
+
+var file_code_metadata_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_code_metadata_proto_goTypes = []interface{}{
+	(*CodeMetadata)(nil),                 // 0: code_metadata_proto.CodeMetadata
+	(*CodeMetadata_TargetOwnership)(nil), // 1: code_metadata_proto.CodeMetadata.TargetOwnership
+}
+var file_code_metadata_proto_depIdxs = []int32{
+	1, // 0: code_metadata_proto.CodeMetadata.target_ownership_list:type_name -> code_metadata_proto.CodeMetadata.TargetOwnership
+	1, // [1:1] is the sub-list for method output_type
+	1, // [1:1] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_code_metadata_proto_init() }
+func file_code_metadata_proto_init() {
+	if File_code_metadata_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_code_metadata_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CodeMetadata); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_code_metadata_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CodeMetadata_TargetOwnership); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_code_metadata_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_code_metadata_proto_goTypes,
+		DependencyIndexes: file_code_metadata_proto_depIdxs,
+		MessageInfos:      file_code_metadata_proto_msgTypes,
+	}.Build()
+	File_code_metadata_proto = out.File
+	file_code_metadata_proto_rawDesc = nil
+	file_code_metadata_proto_goTypes = nil
+	file_code_metadata_proto_depIdxs = nil
+}
diff --git a/testing/code_metadata_proto/code_metadata.proto b/testing/code_metadata_proto/code_metadata.proto
new file mode 100644
index 0000000..2548363
--- /dev/null
+++ b/testing/code_metadata_proto/code_metadata.proto
@@ -0,0 +1,37 @@
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+package code_metadata_proto;
+option go_package = "android/soong/testing/code_metadata_proto";
+
+message CodeMetadata {
+
+  message TargetOwnership {
+    // REQUIRED: Name of the build target
+    optional string target_name = 1;
+
+    // REQUIRED: Code location of the target.
+    // To be used to support legacy/backup systems that use OWNERS file and is
+    // also required for our dashboard to support per code location basis UI
+    optional string path = 2;
+
+    // REQUIRED: Team ID of the team that owns this target.
+    optional string trendy_team_id = 3;
+
+    // OPTIONAL: The src files of the target.
+    // To be used to determine ownership of a file for ownership
+    repeated string source_files = 4;
+  }
+
+  // List of all code targets and their metadata.
+  repeated TargetOwnership target_ownership_list = 1;
+}
diff --git a/testing/code_metadata_proto/regen.sh b/testing/code_metadata_proto/regen.sh
new file mode 100644
index 0000000..ffe06f7
--- /dev/null
+++ b/testing/code_metadata_proto/regen.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+aprotoc --go_out=paths=source_relative:. code_metadata.proto
diff --git a/testing/init.go b/testing/init.go
new file mode 100644
index 0000000..edcbf59
--- /dev/null
+++ b/testing/init.go
@@ -0,0 +1,35 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package testing
+
+import (
+	"android/soong/android"
+)
+
+var (
+	pctx = android.NewPackageContext("android/soong/testing")
+)
+
+func init() {
+	RegisterBuildComponents(android.InitRegistrationContext)
+	pctx.HostBinToolVariable("metadata", "metadata")
+}
+
+func RegisterBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("code_metadata", CodeMetadataFactory)
+	ctx.RegisterModuleType("test_spec", TestSpecFactory)
+	ctx.RegisterParallelSingletonType("all_code_metadata", AllCodeMetadataFactory)
+	ctx.RegisterParallelSingletonType("all_test_specs", AllTestSpecsFactory)
+}
diff --git a/snapshot/test.go b/testing/test.go
similarity index 67%
rename from snapshot/test.go
rename to testing/test.go
index 346af2b..cd97a8f 100644
--- a/snapshot/test.go
+++ b/testing/test.go
@@ -1,10 +1,10 @@
-// Copyright 2021 The Android Open Source Project
+// Copyright 2023 Google Inc. All rights reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//      http://www.apache.org/licenses/LICENSE-2.0
+//     http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -12,13 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package snapshot
+package testing
 
 import (
-	"os"
-	"testing"
+	"android/soong/android"
 )
 
-func TestMain(m *testing.M) {
-	os.Exit(m.Run())
-}
+var PrepareForTestWithTestingBuildComponents = android.FixtureRegisterWithContext(RegisterBuildComponents)
diff --git a/testing/test_spec.go b/testing/test_spec.go
new file mode 100644
index 0000000..4d885c6
--- /dev/null
+++ b/testing/test_spec.go
@@ -0,0 +1,127 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package testing
+
+import (
+	"path/filepath"
+	"strconv"
+
+	"android/soong/android"
+	"android/soong/testing/test_spec_proto"
+	"google.golang.org/protobuf/proto"
+
+	"github.com/google/blueprint"
+)
+
+// ErrTestModuleDataNotFound is the error message for missing test module provider data.
+const ErrTestModuleDataNotFound = "The module '%s' does not provide test specification data. Hint: This issue could arise if either the module is not a valid testing module or if it lacks the required 'TestModuleProviderKey' provider.\n"
+
+func TestSpecFactory() android.Module {
+	module := &TestSpecModule{}
+
+	android.InitAndroidModule(module)
+	android.InitDefaultableModule(module)
+	module.AddProperties(&module.properties)
+
+	return module
+}
+
+type TestSpecModule struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+
+	// Properties for "test_spec"
+	properties struct {
+		// Specifies the name of the test config.
+		Name string
+		// Specifies the team ID.
+		TeamId string
+		// Specifies the list of tests covered under this module.
+		Tests []string
+	}
+}
+
+type testsDepTagType struct {
+	blueprint.BaseDependencyTag
+}
+
+var testsDepTag = testsDepTagType{}
+
+func (module *TestSpecModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// Validate Properties
+	if len(module.properties.TeamId) == 0 {
+		ctx.PropertyErrorf("TeamId", "Team Id not found in the test_spec module. Hint: Maybe the TeamId property hasn't been properly specified.")
+	}
+	if !isInt(module.properties.TeamId) {
+		ctx.PropertyErrorf("TeamId", "Invalid value for Team ID. The Team ID must be an integer.")
+	}
+	if len(module.properties.Tests) == 0 {
+		ctx.PropertyErrorf("Tests", "Expected to attribute some test but none found. Hint: Maybe the test property hasn't been properly specified.")
+	}
+	ctx.AddDependency(ctx.Module(), testsDepTag, module.properties.Tests...)
+}
+func isInt(s string) bool {
+	_, err := strconv.Atoi(s)
+	return err == nil
+}
+
+// Provider published by TestSpec
+type TestSpecProviderData struct {
+	IntermediatePath android.WritablePath
+}
+
+var TestSpecProviderKey = blueprint.NewProvider[TestSpecProviderData]()
+
+type TestModuleProviderData struct {
+}
+
+var TestModuleProviderKey = blueprint.NewProvider[TestModuleProviderData]()
+
+func (module *TestSpecModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	for _, m := range ctx.GetDirectDepsWithTag(testsDepTag) {
+		if _, ok := android.OtherModuleProvider(ctx, m, TestModuleProviderKey); !ok {
+			ctx.ModuleErrorf(ErrTestModuleDataNotFound, m.Name())
+		}
+	}
+	bpFilePath := filepath.Join(ctx.ModuleDir(), ctx.BlueprintsFile())
+	metadataList := make(
+		[]*test_spec_proto.TestSpec_OwnershipMetadata, 0,
+		len(module.properties.Tests),
+	)
+	for _, test := range module.properties.Tests {
+		targetName := test
+		metadata := test_spec_proto.TestSpec_OwnershipMetadata{
+			TrendyTeamId: &module.properties.TeamId,
+			TargetName:   &targetName,
+			Path:         &bpFilePath,
+		}
+		metadataList = append(metadataList, &metadata)
+	}
+	intermediatePath := android.PathForModuleOut(
+		ctx, "intermediateTestSpecMetadata.pb",
+	)
+	testSpecMetadata := test_spec_proto.TestSpec{OwnershipMetadataList: metadataList}
+	protoData, err := proto.Marshal(&testSpecMetadata)
+	if err != nil {
+		ctx.ModuleErrorf("Error: %s", err.Error())
+	}
+	android.WriteFileRuleVerbatim(ctx, intermediatePath, string(protoData))
+
+	android.SetProvider(ctx,
+		TestSpecProviderKey, TestSpecProviderData{
+			IntermediatePath: intermediatePath,
+		},
+	)
+}
diff --git a/testing/test_spec_proto/Android.bp b/testing/test_spec_proto/Android.bp
new file mode 100644
index 0000000..d5ad70b
--- /dev/null
+++ b/testing/test_spec_proto/Android.bp
@@ -0,0 +1,43 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-testing-test_spec_proto",
+    pkgPath: "android/soong/testing/test_spec_proto",
+    deps: [
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+    ],
+    srcs: [
+        "test_spec.pb.go",
+    ],
+}
+
+python_library_host {
+    name: "test-spec-proto-py",
+    pkg_path: "test_spec",
+    srcs: [
+        "test_spec.proto",
+    ],
+    libs: [
+        "libprotobuf-python",
+    ],
+    proto: {
+        canonical_path_from_root: false,
+    },
+}
diff --git a/testing/test_spec_proto/OWNERS b/testing/test_spec_proto/OWNERS
new file mode 100644
index 0000000..03bcdf1
--- /dev/null
+++ b/testing/test_spec_proto/OWNERS
@@ -0,0 +1,4 @@
+dariofreni@google.com
+joeo@google.com
+ronish@google.com
+caditya@google.com
diff --git a/testing/test_spec_proto/regen.sh b/testing/test_spec_proto/regen.sh
new file mode 100644
index 0000000..2cf8203
--- /dev/null
+++ b/testing/test_spec_proto/regen.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+aprotoc --go_out=paths=source_relative:. test_spec.proto
diff --git a/testing/test_spec_proto/test_spec.pb.go b/testing/test_spec_proto/test_spec.pb.go
new file mode 100644
index 0000000..5cce600
--- /dev/null
+++ b/testing/test_spec_proto/test_spec.pb.go
@@ -0,0 +1,244 @@
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.30.0
+// 	protoc        v3.21.12
+// source: test_spec.proto
+
+package test_spec_proto
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type TestSpec struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// List of all test targets and their metadata.
+	OwnershipMetadataList []*TestSpec_OwnershipMetadata `protobuf:"bytes,1,rep,name=ownership_metadata_list,json=ownershipMetadataList" json:"ownership_metadata_list,omitempty"`
+}
+
+func (x *TestSpec) Reset() {
+	*x = TestSpec{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_test_spec_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TestSpec) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TestSpec) ProtoMessage() {}
+
+func (x *TestSpec) ProtoReflect() protoreflect.Message {
+	mi := &file_test_spec_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use TestSpec.ProtoReflect.Descriptor instead.
+func (*TestSpec) Descriptor() ([]byte, []int) {
+	return file_test_spec_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *TestSpec) GetOwnershipMetadataList() []*TestSpec_OwnershipMetadata {
+	if x != nil {
+		return x.OwnershipMetadataList
+	}
+	return nil
+}
+
+type TestSpec_OwnershipMetadata struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TargetName   *string `protobuf:"bytes,1,opt,name=target_name,json=targetName" json:"target_name,omitempty"`
+	Path         *string `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"`
+	TrendyTeamId *string `protobuf:"bytes,3,opt,name=trendy_team_id,json=trendyTeamId" json:"trendy_team_id,omitempty"`
+}
+
+func (x *TestSpec_OwnershipMetadata) Reset() {
+	*x = TestSpec_OwnershipMetadata{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_test_spec_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TestSpec_OwnershipMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TestSpec_OwnershipMetadata) ProtoMessage() {}
+
+func (x *TestSpec_OwnershipMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_test_spec_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use TestSpec_OwnershipMetadata.ProtoReflect.Descriptor instead.
+func (*TestSpec_OwnershipMetadata) Descriptor() ([]byte, []int) {
+	return file_test_spec_proto_rawDescGZIP(), []int{0, 0}
+}
+
+func (x *TestSpec_OwnershipMetadata) GetTargetName() string {
+	if x != nil && x.TargetName != nil {
+		return *x.TargetName
+	}
+	return ""
+}
+
+func (x *TestSpec_OwnershipMetadata) GetPath() string {
+	if x != nil && x.Path != nil {
+		return *x.Path
+	}
+	return ""
+}
+
+func (x *TestSpec_OwnershipMetadata) GetTrendyTeamId() string {
+	if x != nil && x.TrendyTeamId != nil {
+		return *x.TrendyTeamId
+	}
+	return ""
+}
+
+var File_test_spec_proto protoreflect.FileDescriptor
+
+var file_test_spec_proto_rawDesc = []byte{
+	0x0a, 0x0f, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x12, 0x0f, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x22, 0xdf, 0x01, 0x0a, 0x08, 0x54, 0x65, 0x73, 0x74, 0x53, 0x70, 0x65, 0x63, 0x12,
+	0x63, 0x0a, 0x17, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f, 0x6d, 0x65, 0x74,
+	0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x2b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x4f, 0x77, 0x6e, 0x65,
+	0x72, 0x73, 0x68, 0x69, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x15, 0x6f,
+	0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+	0x4c, 0x69, 0x73, 0x74, 0x1a, 0x6e, 0x0a, 0x11, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69,
+	0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72,
+	0x67, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
+	0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61,
+	0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24,
+	0x0a, 0x0e, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x5f, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x54, 0x65,
+	0x61, 0x6d, 0x49, 0x64, 0x42, 0x27, 0x5a, 0x25, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
+	0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x74, 0x65,
+	0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+}
+
+var (
+	file_test_spec_proto_rawDescOnce sync.Once
+	file_test_spec_proto_rawDescData = file_test_spec_proto_rawDesc
+)
+
+func file_test_spec_proto_rawDescGZIP() []byte {
+	file_test_spec_proto_rawDescOnce.Do(func() {
+		file_test_spec_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_spec_proto_rawDescData)
+	})
+	return file_test_spec_proto_rawDescData
+}
+
+var file_test_spec_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_test_spec_proto_goTypes = []interface{}{
+	(*TestSpec)(nil),                   // 0: test_spec_proto.TestSpec
+	(*TestSpec_OwnershipMetadata)(nil), // 1: test_spec_proto.TestSpec.OwnershipMetadata
+}
+var file_test_spec_proto_depIdxs = []int32{
+	1, // 0: test_spec_proto.TestSpec.ownership_metadata_list:type_name -> test_spec_proto.TestSpec.OwnershipMetadata
+	1, // [1:1] is the sub-list for method output_type
+	1, // [1:1] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_test_spec_proto_init() }
+func file_test_spec_proto_init() {
+	if File_test_spec_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_test_spec_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TestSpec); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_test_spec_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TestSpec_OwnershipMetadata); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_test_spec_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_test_spec_proto_goTypes,
+		DependencyIndexes: file_test_spec_proto_depIdxs,
+		MessageInfos:      file_test_spec_proto_msgTypes,
+	}.Build()
+	File_test_spec_proto = out.File
+	file_test_spec_proto_rawDesc = nil
+	file_test_spec_proto_goTypes = nil
+	file_test_spec_proto_depIdxs = nil
+}
diff --git a/testing/test_spec_proto/test_spec.proto b/testing/test_spec_proto/test_spec.proto
new file mode 100644
index 0000000..86bc789
--- /dev/null
+++ b/testing/test_spec_proto/test_spec.proto
@@ -0,0 +1,33 @@
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+package test_spec_proto;
+option go_package = "android/soong/testing/test_spec_proto";
+
+message TestSpec {
+
+  message OwnershipMetadata {
+    // REQUIRED: Name of the build target
+    optional string target_name = 1;
+
+    // REQUIRED: Code location of the target.
+    // To be used to support legacy/backup systems that use OWNERS file and is
+    // also required for our dashboard to support per code location basis UI
+    optional string path = 2;
+
+    // REQUIRED: Team ID of the team that owns this target.
+    optional string trendy_team_id = 3;
+  }
+
+  // List of all test targets and their metadata.
+  repeated OwnershipMetadata ownership_metadata_list = 1;
+}
diff --git a/tests/androidmk_test.sh b/tests/androidmk_test.sh
index b81828b..aecc4e8 100755
--- a/tests/androidmk_test.sh
+++ b/tests/androidmk_test.sh
@@ -5,7 +5,7 @@
 # How to run: bash path-to-script/androidmk_test.sh
 # Tests of converting license functionality of the androidmk tool
 REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
-"$REAL_TOP/build/soong/soong_ui.bash" --make-mode androidmk
+"$REAL_TOP/build/soong/soong_ui.bash" --make-mode TARGET_RELEASE=trunk_staging androidmk
 
 source "$(dirname "$0")/lib.sh"
 
diff --git a/tests/apex_cc_module_arch_variant_tests.sh b/tests/apex_cc_module_arch_variant_tests.sh
deleted file mode 100755
index 1f5e003..0000000
--- a/tests/apex_cc_module_arch_variant_tests.sh
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/bin/bash
-
-# Copyright (C) 2022 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-set -uo pipefail
-
-# Integration test for verifying arch variant cflags set on cc modules included
-# in Bazel-built apexes in the real source tree.
-
-if [ ! -e "build/make/core/Makefile" ]; then
-  echo "$0 must be run from the top of the Android source tree."
-  exit 1
-fi
-
-############
-# Test Setup
-############
-
-OUTPUT_DIR="$(mktemp -d tmp.XXXXXX)"
-BAZEL_OUTPUT_DIR="$OUTPUT_DIR/bazel"
-
-export TARGET_PRODUCT="aosp_arm64"
-[ "$#" -ge 1 ] && export TARGET_PRODUCT="$1"
-ARCH_VARIANT_CFLAG="armv8-a"
-[ "$#" -ge 2 ] && ARCH_VARIANT_CFLAG="$2"
-CPU_VARIANT_CFLAG=""
-[ "$#" -ge 3 ] && CPU_VARIANT_CFLAG="$3"
-
-function call_bazel() {
-  build/bazel/bin/bazel --output_base="$BAZEL_OUTPUT_DIR" $@
-}
-
-function cleanup {
-  # call bazel clean because some bazel outputs don't have w bits.
-  call_bazel clean
-  rm -rf "${OUTPUT_DIR}"
-}
-trap cleanup EXIT
-
-######################
-# Run bp2build / Bazel
-######################
-build/soong/soong_ui.bash --make-mode BP2BUILD_VERBOSE=1 --skip-soong-tests bp2build
-
-# Number of CppCompile actions with arch variant flag
-actions_with_arch_variant_num=$(call_bazel aquery --config=bp2build --config=ci --config=android \
-  'mnemonic("CppCompile", deps(//build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal))' | grep -c \'-march=$ARCH_VARIANT_CFLAG\')
-
-# Number of all CppCompile actions
-all_cppcompile_actions_num=0
-aquery_summary=$(call_bazel aquery --config=bp2build --config=ci --config=android --output=summary \
-  'mnemonic("CppCompile", deps(//build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal))' \
-  | egrep -o '.*opt-ST.*: ([0-9]+)$' \
-  | cut -d: -f2 -)
-
-while read -r num;
-do
-  all_cppcompile_actions_num=$(($all_cppcompile_actions_num + $num))
-done <<< "$aquery_summary"
-
-if [ $actions_with_arch_variant_num -eq $all_cppcompile_actions_num ]
-then
-  echo "Pass: arch variant is set."
-else
-  echo "Error: number of CppCompile actions with arch variant set: actual=$actions_with_arch_variant_num, expected=$all_cppcompile_actions_num"
-  exit 1
-fi
-
-if [ $CPU_VARIANT_CFLAG ]
-then
-  # Number of CppCompiler actions with cpu variant flag
-  actions_with_cpu_variant_num=$(call_bazel aquery --config=bp2build --config=ci --config=android \
-    'mnemonic("CppCompile", deps(//build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal))' | grep -c "\-mcpu=$CPU_VARIANT_CFLAG")
-
-  if [ $actions_with_cpu_variant_num -eq $all_cppcompile_actions_num ]
-  then
-    echo "Pass: cpu variant is set."
-  else
-    echo "Error: number of CppCompile actions with cpu variant set: actual=$actions_with_cpu_variant_num, expected=$all_cppcompile_actions_num"
-    exit 1
-  fi
-fi
diff --git a/tests/apex_comparison_tests.sh b/tests/apex_comparison_tests.sh
deleted file mode 100755
index 8893060..0000000
--- a/tests/apex_comparison_tests.sh
+++ /dev/null
@@ -1,119 +0,0 @@
-#!/bin/bash
-
-# Copyright (C) 2022 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-set -euo pipefail
-
-# Soong/Bazel integration test for building unbundled apexes in the real source tree.
-#
-# These tests build artifacts from head and compares their contents.
-
-if [ ! -e "build/make/core/Makefile" ]; then
-  echo "$0 must be run from the top of the Android source tree."
-  exit 1
-fi
-
-############
-# Test Setup
-############
-
-OUTPUT_DIR="$(mktemp -d $(pwd)/tmp.XXXXXX)"
-SOONG_OUTPUT_DIR="$OUTPUT_DIR/soong"
-BAZEL_OUTPUT_DIR="$OUTPUT_DIR/bazel"
-
-export TARGET_PRODUCT="module_arm"
-[ "$#" -eq 1 ] && export TARGET_PRODUCT="$1"
-
-function call_bazel() {
-  build/bazel/bin/bazel --output_base="$BAZEL_OUTPUT_DIR" $@
-}
-
-function cleanup {
-  # call bazel clean because some bazel outputs don't have w bits.
-  call_bazel clean
-  rm -rf "${OUTPUT_DIR}"
-}
-
-function deapexer() {
-  DEBUGFS_PATH="$(realpath $(call_bazel cquery --config=bp2build --config=linux_x86_64 --config=ci --output=files //external/e2fsprogs/debugfs))"
-  call_bazel run --config=bp2build //system/apex/tools:deapexer -- --debugfs_path=$DEBUGFS_PATH $@
-}
-
-trap cleanup EXIT
-
-###########
-# Run Soong
-###########
-export UNBUNDLED_BUILD_SDKS_FROM_SOURCE=true # don't rely on prebuilts
-export TARGET_BUILD_APPS="com.android.adbd com.android.tzdata build.bazel.examples.apex.minimal"
-packages/modules/common/build/build_unbundled_mainline_module.sh \
-  --product "$TARGET_PRODUCT" \
-  --dist_dir "$SOONG_OUTPUT_DIR"
-
-######################
-# Run bp2build / Bazel
-######################
-build/soong/soong_ui.bash --make-mode BP2BUILD_VERBOSE=1 --skip-soong-tests bp2build
-
-BAZEL_OUT="$(call_bazel info --config=bp2build output_path)"
-
-call_bazel build --config=bp2build --config=ci --config=android \
-  //packages/modules/adb/apex:com.android.adbd \
-  //system/timezone/apex:com.android.tzdata \
-  //build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal
-BAZEL_ADBD="$(realpath $(call_bazel cquery --config=bp2build --config=android --config=ci --output=files //packages/modules/adb/apex:com.android.adbd))"
-BAZEL_TZDATA="$(realpath $(call_bazel cquery --config=bp2build --config=android --config=ci --output=files //system/timezone/apex:com.android.tzdata))"
-BAZEL_MINIMAL="$(realpath $(call_bazel cquery --config=bp2build --config=android --config=ci --output=files //build/bazel/examples/apex/minimal:build.bazel.examples.apex.minimal))"
-
-# # Build debugfs separately, as it's not a dep of apexer, but needs to be an explicit arg.
-call_bazel build --config=bp2build --config=linux_x86_64 //external/e2fsprogs/debugfs
-
-#######
-# Tests
-#######
-
-function compare_deapexer_list() {
-  local BAZEL_APEX=$1; shift
-  local APEX=$1; shift
-
-  # Compare the outputs of `deapexer list`, which lists the contents of the apex filesystem image.
-  local SOONG_APEX="$SOONG_OUTPUT_DIR/$APEX"
-
-  local SOONG_LIST="$OUTPUT_DIR/soong.list"
-  local BAZEL_LIST="$OUTPUT_DIR/bazel.list"
-
-  deapexer list "$SOONG_APEX" > "$SOONG_LIST"
-  deapexer list "$BAZEL_APEX" > "$BAZEL_LIST"
-
-  if cmp -s "$SOONG_LIST" "$BAZEL_LIST"
-  then
-    echo "ok: $APEX"
-  else
-    echo "contents of $APEX are different between Soong and Bazel:"
-    echo
-    echo expected
-    echo
-    cat "$SOONG_LIST"
-    echo
-    echo got
-    echo
-    cat "$BAZEL_LIST"
-    exit 1
-  fi
-}
-
-compare_deapexer_list "${BAZEL_ADBD}" com.android.adbd.apex
-compare_deapexer_list "${BAZEL_TZDATA}" com.android.tzdata.apex
-compare_deapexer_list "${BAZEL_MINIMAL}" build.bazel.examples.apex.minimal.apex
diff --git a/tests/b_args_test.sh b/tests/b_args_test.sh
new file mode 100755
index 0000000..0dfbabf
--- /dev/null
+++ b/tests/b_args_test.sh
@@ -0,0 +1,43 @@
+#!/bin/bash -eu
+
+# This file tests the creation of bazel commands for b usage
+set -o pipefail
+source "$(dirname "$0")/../../bazel/lib.sh"
+
+BES_UUID="blank"
+OUT_DIR="arbitrary_out"
+b_args=$(formulate_b_args "build --config=nonsense foo:bar")
+
+if [[ $b_args != "build --profile=$OUT_DIR/bazel_metrics-profile --config=bp2build --invocation_id=$BES_UUID --config=metrics_data --config=nonsense foo:bar" ]]; then
+   echo "b args are malformed"
+   echo "Expected : build --profile=$OUT_DIR/bazel_metrics-profile --config=bp2build  --invocation_id=$BES_UUID --config=metrics_data --config=nonsense foo:bar"
+   echo "Actual: $b_args"
+   exit 1
+fi
+
+b_args=$(formulate_b_args "build --config=nonsense --disable_bes --package_path \"my package\" foo:bar")
+
+if [[ $b_args != "build --profile=$OUT_DIR/bazel_metrics-profile --config=bp2build --invocation_id=$BES_UUID --config=nonsense --package_path \"my package\" foo:bar" ]]; then
+   echo "b args are malformed"
+   echo "Expected : build --profile=$OUT_DIR/bazel_metrics-profile --config=bp2build  --invocation_id=$BES_UUID --config=nonsense --package_path \"my package\" foo:bar"
+   echo "Actual: $b_args"
+   exit 1
+fi
+
+# Test with startup option
+b_args=$(formulate_b_args "--batch build --config=nonsense --disable_bes --package_path \"my package\" foo:bar")
+if [[ $b_args != "--batch build --profile=$OUT_DIR/bazel_metrics-profile --config=bp2build --invocation_id=$BES_UUID --config=nonsense --package_path \"my package\" foo:bar" ]]; then
+   echo "b args are malformed"
+   echo "Expected : --batch build --profile=$OUT_DIR/bazel_metrics-profile --config=bp2build  --invocation_id=$BES_UUID --config=nonsense --package_path \"my package\" foo:bar"
+   echo "Actual: $b_args"
+   exit 1
+fi
+
+OUT_DIR="mock_out"
+TEST_PROFILE_OUT=$(get_profile_out_dir)
+if [[ $TEST_PROFILE_OUT != "mock_out" ]]; then
+   echo "Profile Out is malformed."
+   echo "Expected: mock_out"
+   echo "Actual: $TEST_PROFILE_OUT"
+   exit 1
+fi
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index 5fc05f8..2e40950 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -9,6 +9,8 @@
 
 readonly GENERATED_BUILD_FILE_NAME="BUILD.bazel"
 
+readonly target_product="${TARGET_PRODUCT:-aosp_arm}"
+
 function test_smoke {
   setup
   run_soong
@@ -18,10 +20,10 @@
   setup
   run_soong
   local -r bootstrap_mtime1=$(stat -c "%y" out/soong/bootstrap.ninja)
-  local -r output_mtime1=$(stat -c "%y" out/soong/build.ninja)
+  local -r output_mtime1=$(stat -c "%y" out/soong/build."${target_product}".ninja)
   run_soong
   local -r bootstrap_mtime2=$(stat -c "%y" out/soong/bootstrap.ninja)
-  local -r output_mtime2=$(stat -c "%y" out/soong/build.ninja)
+  local -r output_mtime2=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
   if [[ "$bootstrap_mtime1" == "$bootstrap_mtime2" ]]; then
     # Bootstrapping is always done. It doesn't take a measurable amount of time.
@@ -60,7 +62,7 @@
   touch a/my_little_binary_host.py
   run_soong
 
-  grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja || fail "module not found"
+  grep -q "^# Module:.*my_little_binary_host" out/soong/build."${target_product}".ninja || fail "module not found"
 
   cat > a/Android.bp <<'EOF'
 python_binary_host {
@@ -71,14 +73,14 @@
   touch a/my_great_binary_host.py
   run_soong
 
-  grep -q "^# Module:.*my_little_binary_host" out/soong/build.ninja && fail "old module found"
-  grep -q "^# Module:.*my_great_binary_host" out/soong/build.ninja || fail "new module not found"
+  grep -q "^# Module:.*my_little_binary_host" out/soong/build."${target_product}".ninja && fail "old module found"
+  grep -q "^# Module:.*my_great_binary_host" out/soong/build."${target_product}".ninja || fail "new module not found"
 }
 
 function test_add_android_bp() {
   setup
   run_soong
-  local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime1=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
   mkdir -p a
   cat > a/Android.bp <<'EOF'
@@ -90,12 +92,12 @@
   touch a/my_little_binary_host.py
   run_soong
 
-  local -r mtime2=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime2=$(stat -c "%y" out/soong/build."${target_product}".ninja)
   if [[ "$mtime1" == "$mtime2" ]]; then
     fail "Output Ninja file did not change"
   fi
 
-  grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "New module not in output"
+  grep -q "^# Module:.*my_little_binary_host$" out/soong/build."${target_product}".ninja || fail "New module not in output"
 
   run_soong
 }
@@ -112,12 +114,12 @@
   touch a/my_little_binary_host.py
   run_soong
 
-  grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja || fail "Module not in output"
+  grep -q "^# Module:.*my_little_binary_host$" out/soong/build."${target_product}".ninja || fail "Module not in output"
 
   rm a/Android.bp
   run_soong
 
-  if grep -q "^# Module:.*my_little_binary_host$" out/soong/build.ninja; then
+  if grep -q "^# Module:.*my_little_binary_host$" out/soong/build."${target_product}".ninja; then
     fail "Old module in output"
   fi
 }
@@ -141,16 +143,12 @@
 EOF
   touch a/my_little_binary_host.py
   run_soong
-  local -r ninja_mtime1=$(stat -c "%y" out/soong/build.ninja)
+  local -r ninja_mtime1=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
-  local glob_deps_file=out/soong/globs/build/0.d
-
-  if [ -e "$glob_deps_file" ]; then
-    fail "Glob deps file unexpectedly written on first build"
-  fi
+  local glob_deps_file=out/soong/globs/"${target_product}"/0.d
 
   run_soong
-  local -r ninja_mtime2=$(stat -c "%y" out/soong/build.ninja)
+  local -r ninja_mtime2=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
   # There is an ineffiencency in glob that requires bpglob to rerun once for each glob to update
   # the entry in the .ninja_log.  It doesn't update the output file, but we can detect the rerun
@@ -166,7 +164,7 @@
   fi
 
   run_soong
-  local -r ninja_mtime3=$(stat -c "%y" out/soong/build.ninja)
+  local -r ninja_mtime3=$(stat -c "%y" out/soong/build."${target_product}".ninja)
   local -r glob_deps_mtime3=$(stat -c "%y" "$glob_deps_file")
 
   if [[ "$ninja_mtime2" != "$ninja_mtime3" ]]; then
@@ -191,17 +189,17 @@
 EOF
   touch a/my_little_binary_host.py
   run_soong
-  local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime1=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
   touch a/my_little_library.py
   run_soong
 
-  local -r mtime2=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime2=$(stat -c "%y" out/soong/build."${target_product}".ninja)
   if [[ "$mtime1" == "$mtime2" ]]; then
     fail "Output Ninja file did not change"
   fi
 
-  grep -q my_little_library.py out/soong/build.ninja || fail "new file is not in output"
+  grep -q my_little_library.py out/soong/build."${target_product}".ninja || fail "new file is not in output"
 }
 
 function test_soong_build_rerun_iff_environment_changes() {
@@ -267,17 +265,17 @@
 
   export CHERRY=TASTY
   run_soong
-  grep -q "CHERRY IS TASTY" out/soong/build.ninja \
+  grep -q "CHERRY IS TASTY" out/soong/build."${target_product}".ninja \
     || fail "first value of environment variable is not used"
 
   export CHERRY=RED
   run_soong
-  grep -q "CHERRY IS RED" out/soong/build.ninja \
+  grep -q "CHERRY IS RED" out/soong/build."${target_product}".ninja \
     || fail "second value of environment variable not used"
-  local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime1=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
   run_soong
-  local -r mtime2=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime2=$(stat -c "%y" out/soong/build."${target_product}".ninja)
   if [[ "$mtime1" != "$mtime2" ]]; then
     fail "Output Ninja file changed when environment variable did not"
   fi
@@ -287,7 +285,7 @@
 function test_create_global_include_directory() {
   setup
   run_soong
-  local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime1=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
   # Soong needs to know if top level directories like hardware/ exist for use
   # as global include directories.  Make sure that doesn't cause regens for
@@ -295,7 +293,7 @@
   mkdir -p system/core
 
   run_soong
-  local -r mtime2=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime2=$(stat -c "%y" out/soong/build."${target_product}".ninja)
   if [[ "$mtime1" != "$mtime2" ]]; then
     fail "Output Ninja file changed when top level directory changed"
   fi
@@ -305,7 +303,7 @@
   mkdir -p system/core/include
 
   run_soong
-  local -r mtime3=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime3=$(stat -c "%y" out/soong/build."${target_product}".ninja)
   if [[ "$mtime2" = "$mtime3" ]]; then
     fail "Output Ninja file did not change when global include directory created"
   fi
@@ -315,7 +313,7 @@
 function test_add_file_to_soong_build() {
   setup
   run_soong
-  local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime1=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
   mkdir -p vendor/foo/picard
   cat > vendor/foo/picard/Android.bp <<'EOF'
@@ -377,12 +375,12 @@
 EOF
 
   run_soong
-  local -r mtime2=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime2=$(stat -c "%y" out/soong/build."${target_product}".ninja)
   if [[ "$mtime1" == "$mtime2" ]]; then
     fail "Output Ninja file did not change"
   fi
 
-  grep -q "Make it so" out/soong/build.ninja || fail "New action not present"
+  grep -q "Make it so" out/soong/build."${target_product}".ninja || fail "New action not present"
 }
 
 # Tests a glob in a build= statement in an Android.bp file, which is interpreted
@@ -455,9 +453,9 @@
 EOF
 
   run_soong
-  local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime1=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
-  grep -q "Make it so" out/soong/build.ninja || fail "Original action not present"
+  grep -q "Make it so" out/soong/build."${target_product}".ninja || fail "Original action not present"
 
   cat > build/soong/picard/foob.bp <<'EOF'
 bootstrap_go_package {
@@ -487,14 +485,14 @@
 EOF
 
   run_soong
-  local -r mtime2=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime2=$(stat -c "%y" out/soong/build."${target_product}".ninja)
   if [[ "$mtime1" == "$mtime2" ]]; then
     fail "Output Ninja file did not change"
   fi
 
-  grep -q "Engage" out/soong/build.ninja || fail "New action not present"
+  grep -q "Engage" out/soong/build."${target_product}".ninja || fail "New action not present"
 
-  if grep -q "Make it so" out/soong/build.ninja; then
+  if grep -q "Make it so" out/soong/build."${target_product}".ninja; then
     fail "Original action still present"
   fi
 }
@@ -512,7 +510,7 @@
   setup
 
   run_soong
-  local -r ninja_mtime1=$(stat -c "%y" out/soong/build.ninja)
+  local -r ninja_mtime1=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
   run_soong soong_docs
   local -r docs_mtime1=$(stat -c "%y" out/soong/docs/soong_build.html)
@@ -525,7 +523,7 @@
   fi
 
   run_soong
-  local -r ninja_mtime2=$(stat -c "%y" out/soong/build.ninja)
+  local -r ninja_mtime2=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
   if [[ "$ninja_mtime1" != "$ninja_mtime2" ]]; then
     fail "Output Ninja file changed on null build"
@@ -565,144 +563,6 @@
   fi
 }
 
-function test_bp2build_smoke {
-  setup
-  run_soong bp2build
-  [[ -e out/soong/bp2build_workspace_marker ]] || fail "bp2build marker file not created"
-  [[ -e out/soong/workspace ]] || fail "Bazel workspace not created"
-}
-
-function test_bp2build_generates_marker_file {
-  setup
-
-  run_soong bp2build
-
-  if [[ ! -f "./out/soong/bp2build_files_marker" ]]; then
-    fail "bp2build marker file was not generated"
-  fi
-
-  if [[ ! -f "./out/soong/bp2build_workspace_marker" ]]; then
-    fail "symlink forest marker file was not generated"
-  fi
-}
-
-function test_bp2build_add_irrelevant_file {
-  setup
-
-  mkdir -p a/b
-  touch a/b/c.txt
-  cat > a/b/Android.bp <<'EOF'
-filegroup {
-  name: "c",
-  srcs: ["c.txt"],
-  bazel_module: { bp2build_available: true },
-}
-EOF
-
-  run_soong bp2build
-  if [[ ! -e out/soong/bp2build/a/b/BUILD.bazel ]]; then
-    fail "BUILD file in symlink forest was not created";
-  fi
-
-  local -r mtime1=$(stat -c "%y" out/soong/bp2build/a/b/BUILD.bazel)
-
-  touch a/irrelevant.txt
-  run_soong bp2build
-  local -r mtime2=$(stat -c "%y" out/soong/bp2build/a/b/BUILD.bazel)
-
-  if [[ "$mtime1" != "$mtime2" ]]; then
-    fail "BUILD.bazel file was regenerated"
-  fi
-
-  if [[ ! -e "out/soong/workspace/a/irrelevant.txt" ]]; then
-    fail "New file was not symlinked into symlink forest"
-  fi
-}
-
-function test_bp2build_add_android_bp {
-  setup
-
-  mkdir -p a
-  touch a/a.txt
-  cat > a/Android.bp <<'EOF'
-filegroup {
-  name: "a",
-  srcs: ["a.txt"],
-  bazel_module: { bp2build_available: true },
-}
-EOF
-
-  run_soong bp2build
-  [[ -e out/soong/bp2build/a/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not created"
-  [[ -L out/soong/workspace/a/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not symlinked"
-
-  mkdir -p b
-  touch b/b.txt
-  cat > b/Android.bp <<'EOF'
-filegroup {
-  name: "b",
-  srcs: ["b.txt"],
-  bazel_module: { bp2build_available: true },
-}
-EOF
-
-  run_soong bp2build
-  [[ -e out/soong/bp2build/b/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not created"
-  [[ -L out/soong/workspace/b/${GENERATED_BUILD_FILE_NAME} ]] || fail "a/${GENERATED_BUILD_FILE_NAME} not symlinked"
-}
-
-function test_bp2build_null_build {
-  setup
-
-  run_soong bp2build
-  local -r mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
-
-  run_soong bp2build
-  local -r mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
-
-  if [[ "$mtime1" != "$mtime2" ]]; then
-    fail "Output Ninja file changed on null build"
-  fi
-}
-
-function test_bp2build_add_to_glob {
-  setup
-
-  mkdir -p a
-  touch a/a1.txt
-  cat > a/Android.bp <<'EOF'
-filegroup {
-  name: "a",
-  srcs: ["*.txt"],
-  bazel_module: { bp2build_available: true },
-}
-EOF
-
-  run_soong bp2build
-  grep -q a1.txt "out/soong/bp2build/a/${GENERATED_BUILD_FILE_NAME}" || fail "a1.txt not in ${GENERATED_BUILD_FILE_NAME} file"
-
-  touch a/a2.txt
-  run_soong bp2build
-  grep -q a2.txt "out/soong/bp2build/a/${GENERATED_BUILD_FILE_NAME}" || fail "a2.txt not in ${GENERATED_BUILD_FILE_NAME} file"
-}
-
-function test_multiple_soong_build_modes() {
-  setup
-  run_soong json-module-graph bp2build nothing
-  if [[ ! -f "out/soong/bp2build_workspace_marker" ]]; then
-    fail "bp2build marker file was not generated"
-  fi
-
-
-  if [[ ! -f "out/soong/module-graph.json" ]]; then
-    fail "JSON file was not created"
-  fi
-
-  if [[ ! -f "out/soong/build.ninja" ]]; then
-    fail "Main build.ninja file was not created"
-  fi
-}
-
 function test_dump_json_module_graph() {
   setup
   run_soong json-module-graph
@@ -715,13 +575,13 @@
   setup
 
   run_soong
-  local -r ninja_mtime1=$(stat -c "%y" out/soong/build.ninja)
+  local -r ninja_mtime1=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
   run_soong json-module-graph
   local -r json_mtime1=$(stat -c "%y" out/soong/module-graph.json)
 
   run_soong
-  local -r ninja_mtime2=$(stat -c "%y" out/soong/build.ninja)
+  local -r ninja_mtime2=$(stat -c "%y" out/soong/build."${target_product}".ninja)
   if [[ "$ninja_mtime1" != "$ninja_mtime2" ]]; then
     fail "Output Ninja file changed after writing JSON module graph"
   fi
@@ -734,143 +594,6 @@
 
 }
 
-function test_bp2build_bazel_workspace_structure {
-  setup
-
-  mkdir -p a/b
-  touch a/a.txt
-  touch a/b/b.txt
-  cat > a/b/Android.bp <<'EOF'
-filegroup {
-  name: "b",
-  srcs: ["b.txt"],
-  bazel_module: { bp2build_available: true },
-}
-EOF
-
-  run_soong bp2build
-  [[ -e out/soong/workspace ]] || fail "Bazel workspace not created"
-  [[ -d out/soong/workspace/a/b ]] || fail "module directory not a directory"
-  [[ -L "out/soong/workspace/a/b/${GENERATED_BUILD_FILE_NAME}" ]] || fail "${GENERATED_BUILD_FILE_NAME} file not symlinked"
-  [[ "$(readlink -f out/soong/workspace/a/b/${GENERATED_BUILD_FILE_NAME})" =~ "bp2build/a/b/${GENERATED_BUILD_FILE_NAME}"$ ]] \
-    || fail "BUILD files symlinked at the wrong place"
-  [[ -L out/soong/workspace/a/b/b.txt ]] || fail "a/b/b.txt not symlinked"
-  [[ -L out/soong/workspace/a/a.txt ]] || fail "a/b/a.txt not symlinked"
-  [[ ! -e out/soong/workspace/out ]] || fail "out directory symlinked"
-}
-
-function test_bp2build_bazel_workspace_add_file {
-  setup
-
-  mkdir -p a
-  touch a/a.txt
-  cat > a/Android.bp <<EOF
-filegroup {
-  name: "a",
-  srcs: ["a.txt"],
-  bazel_module: { bp2build_available: true },
-}
-EOF
-
-  run_soong bp2build
-
-  touch a/a2.txt  # No reference in the .bp file needed
-  run_soong bp2build
-  [[ -L out/soong/workspace/a/a2.txt ]] || fail "a/a2.txt not symlinked"
-}
-
-function test_bp2build_build_file_precedence {
-  setup
-
-  mkdir -p a
-  touch a/a.txt
-  touch a/${GENERATED_BUILD_FILE_NAME}
-  cat > a/Android.bp <<EOF
-filegroup {
-  name: "a",
-  srcs: ["a.txt"],
-  bazel_module: { bp2build_available: true },
-}
-EOF
-
-  run_soong bp2build
-  [[ -L "out/soong/workspace/a/${GENERATED_BUILD_FILE_NAME}" ]] || fail "${GENERATED_BUILD_FILE_NAME} file not symlinked"
-  [[ "$(readlink -f out/soong/workspace/a/${GENERATED_BUILD_FILE_NAME})" =~ "bp2build/a/${GENERATED_BUILD_FILE_NAME}"$ ]] \
-    || fail "${GENERATED_BUILD_FILE_NAME} files symlinked to the wrong place"
-}
-
-function test_bp2build_fails_fast {
-  setup
-
-  mkdir -p "a/${GENERATED_BUILD_FILE_NAME}"
-  cat > a/Android.bp <<EOF
-filegroup {
-  name: "a",
-  srcs: ["a.txt"],
-  bazel_module: { bp2build_available: true },
-}
-EOF
-
-  mkdir -p "b/${GENERATED_BUILD_FILE_NAME}"
-  cat > b/Android.bp <<EOF
-filegroup {
-  name: "b",
-  srcs: ["b.txt"],
-  bazel_module: { bp2build_available: true },
-}
-EOF
-
-  if run_soong bp2build >& "$MOCK_TOP/errors"; then
-    fail "Build should have failed"
-  fi
-
-  # we should expect at least one error
-  grep -q -E "(a|b)/${GENERATED_BUILD_FILE_NAME}' exist" "$MOCK_TOP/errors" || fail "Error for ${GENERATED_BUILD_FILE_NAME} not found"
-}
-
-function test_bp2build_back_and_forth_null_build {
-  setup
-
-  run_soong
-  local -r output_mtime1=$(stat -c "%y" out/soong/build.ninja)
-
-  run_soong bp2build
-  local -r output_mtime2=$(stat -c "%y" out/soong/build.ninja)
-  if [[ "$output_mtime1" != "$output_mtime2" ]]; then
-    fail "Output Ninja file changed when switching to bp2build"
-  fi
-
-  local -r marker_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
-
-  run_soong
-  local -r output_mtime3=$(stat -c "%y" out/soong/build.ninja)
-  local -r marker_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
-  if [[ "$output_mtime1" != "$output_mtime3" ]]; then
-    fail "Output Ninja file changed when switching to regular build from bp2build"
-  fi
-  if [[ "$marker_mtime1" != "$marker_mtime2" ]]; then
-    fail "bp2build marker file changed when switching to regular build from bp2build"
-  fi
-
-  run_soong bp2build
-  local -r output_mtime4=$(stat -c "%y" out/soong/build.ninja)
-  local -r marker_mtime3=$(stat -c "%y" out/soong/bp2build_workspace_marker)
-  if [[ "$output_mtime1" != "$output_mtime4" ]]; then
-    fail "Output Ninja file changed when switching back to bp2build"
-  fi
-  if [[ "$marker_mtime1" != "$marker_mtime3" ]]; then
-    fail "bp2build marker file changed when switching back to bp2build"
-  fi
-}
-
-function test_queryview_smoke() {
-  setup
-
-  run_soong queryview
-  [[ -e out/soong/queryview/WORKSPACE ]] || fail "queryview WORKSPACE file not created"
-
-}
-
 function test_queryview_null_build() {
   setup
 
@@ -886,14 +609,14 @@
 }
 
 # This test verifies that adding a new glob to a blueprint file only
-# causes build.ninja to be regenerated on the *next* build, and *not*
+# causes build."${target_product}".ninja to be regenerated on the *next* build, and *not*
 # the build after. (This is a regression test for a bug where globs
 # resulted in two successive regenerations.)
 function test_new_glob_incrementality {
   setup
 
   run_soong nothing
-  local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime1=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
   mkdir -p globdefpkg/
   cat > globdefpkg/Android.bp <<'EOF'
@@ -904,14 +627,14 @@
 EOF
 
   run_soong nothing
-  local -r mtime2=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime2=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
   if [[ "$mtime1" == "$mtime2" ]]; then
     fail "Ninja file was not regenerated, despite a new bp file"
   fi
 
   run_soong nothing
-  local -r mtime3=$(stat -c "%y" out/soong/build.ninja)
+  local -r mtime3=$(stat -c "%y" out/soong/build."${target_product}".ninja)
 
   if [[ "$mtime2" != "$mtime3" ]]; then
     fail "Ninja file was regenerated despite no previous bp changes"
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
deleted file mode 100755
index 090114b..0000000
--- a/tests/bp2build_bazel_test.sh
+++ /dev/null
@@ -1,477 +0,0 @@
-#!/bin/bash -eu
-
-set -o pipefail
-
-# Test that bp2build and Bazel can play nicely together
-
-source "$(dirname "$0")/lib.sh"
-
-readonly GENERATED_BUILD_FILE_NAME="BUILD.bazel"
-
-function test_bp2build_null_build {
-  setup
-  run_soong bp2build
-  local -r output_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
-
-  run_soong bp2build
-  local -r output_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
-
-  if [[ "$output_mtime1" != "$output_mtime2" ]]; then
-    fail "Output bp2build marker file changed on null build"
-  fi
-}
-
-# Tests that, if bp2build reruns due to a blueprint file changing, that
-# BUILD files whose contents are unchanged are not regenerated.
-function test_bp2build_unchanged {
-  setup
-
-  mkdir -p pkg
-  touch pkg/x.txt
-  cat > pkg/Android.bp <<'EOF'
-filegroup {
-    name: "x",
-    srcs: ["x.txt"],
-    bazel_module: {bp2build_available: true},
-  }
-EOF
-
-  run_soong bp2build
-  local -r buildfile_mtime1=$(stat -c "%y" out/soong/bp2build/pkg/BUILD.bazel)
-  local -r marker_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
-
-  # Force bp2build to rerun by updating the timestamp of a blueprint file.
-  touch pkg/Android.bp
-
-  run_soong bp2build
-  local -r buildfile_mtime2=$(stat -c "%y" out/soong/bp2build/pkg/BUILD.bazel)
-  local -r marker_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
-
-  if [[ "$marker_mtime1" == "$marker_mtime2" ]]; then
-    fail "Expected bp2build marker file to change"
-  fi
-  if [[ "$buildfile_mtime1" != "$buildfile_mtime2" ]]; then
-    fail "BUILD.bazel was updated even though contents are same"
-  fi
-
-  # Force bp2build to rerun by updating the timestamp of the constants_exported_to_soong.bzl file.
-  touch build/bazel/constants_exported_to_soong.bzl
-
-  run_soong bp2build
-  local -r buildfile_mtime3=$(stat -c "%y" out/soong/bp2build/pkg/BUILD.bazel)
-  local -r marker_mtime3=$(stat -c "%y" out/soong/bp2build_workspace_marker)
-
-  if [[ "$marker_mtime2" == "$marker_mtime3" ]]; then
-    fail "Expected bp2build marker file to change"
-  fi
-  if [[ "$buildfile_mtime2" != "$buildfile_mtime3" ]]; then
-    fail "BUILD.bazel was updated even though contents are same"
-  fi
-}
-
-# Tests that blueprint files that are deleted are not present when the
-# bp2build tree is regenerated.
-function test_bp2build_deleted_blueprint {
-  setup
-
-  mkdir -p pkg
-  touch pkg/x.txt
-  cat > pkg/Android.bp <<'EOF'
-filegroup {
-    name: "x",
-    srcs: ["x.txt"],
-    bazel_module: {bp2build_available: true},
-  }
-EOF
-
-  run_soong bp2build
-  if [[ ! -e "./out/soong/bp2build/pkg/BUILD.bazel" ]]; then
-    fail "Expected pkg/BUILD.bazel to be generated"
-  fi
-
-  rm pkg/Android.bp
-
-  run_soong bp2build
-  if [[ -e "./out/soong/bp2build/pkg/BUILD.bazel" ]]; then
-    fail "Expected pkg/BUILD.bazel to be deleted"
-  fi
-}
-
-function test_bp2build_null_build_with_globs {
-  setup
-
-  mkdir -p foo/bar
-  cat > foo/bar/Android.bp <<'EOF'
-filegroup {
-    name: "globs",
-    srcs: ["*.txt"],
-  }
-EOF
-  touch foo/bar/a.txt foo/bar/b.txt
-
-  run_soong bp2build
-  local -r output_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
-
-  run_soong bp2build
-  local -r output_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
-
-  if [[ "$output_mtime1" != "$output_mtime2" ]]; then
-    fail "Output bp2build marker file changed on null build"
-  fi
-}
-
-function test_different_relative_outdir {
-  setup
-
-  mkdir -p a
-  touch a/g.txt
-  cat > a/Android.bp <<'EOF'
-filegroup {
-    name: "g",
-    srcs: ["g.txt"],
-    bazel_module: {bp2build_available: true},
-  }
-EOF
-
-  # A directory under $MOCK_TOP
-  outdir=out2
-  trap "rm -rf $outdir" EXIT
-  # Modify OUT_DIR in a subshell so it doesn't affect the top level one.
-  (export OUT_DIR=$outdir; run_soong bp2build && run_bazel build --config=bp2build --config=ci //a:g)
-}
-
-function test_different_absolute_outdir {
-  setup
-
-  mkdir -p a
-  touch a/g.txt
-  cat > a/Android.bp <<'EOF'
-filegroup {
-    name: "g",
-    srcs: ["g.txt"],
-    bazel_module: {bp2build_available: true},
-  }
-EOF
-
-  # A directory under /tmp/...
-  outdir=$(mktemp -t -d st.XXXXX)
-  trap 'rm -rf $outdir' EXIT
-  # Modify OUT_DIR in a subshell so it doesn't affect the top level one.
-  (export OUT_DIR=$outdir; run_soong bp2build && run_bazel build --config=bp2build --config=ci //a:g)
-}
-
-function _bp2build_generates_all_buildfiles {
-  setup
-
-  mkdir -p foo/convertible_soong_module
-  cat > foo/convertible_soong_module/Android.bp <<'EOF'
-genrule {
-    name: "the_answer",
-    cmd: "echo '42' > $(out)",
-    out: [
-        "the_answer.txt",
-    ],
-    bazel_module: {
-        bp2build_available: true,
-    },
-  }
-EOF
-
-  mkdir -p foo/unconvertible_soong_module
-  cat > foo/unconvertible_soong_module/Android.bp <<'EOF'
-genrule {
-    name: "not_the_answer",
-    cmd: "echo '43' > $(out)",
-    out: [
-        "not_the_answer.txt",
-    ],
-    bazel_module: {
-        bp2build_available: false,
-    },
-  }
-EOF
-
-  run_soong bp2build
-
-  if [[ ! -f "./out/soong/workspace/foo/convertible_soong_module/${GENERATED_BUILD_FILE_NAME}" ]]; then
-    fail "./out/soong/workspace/foo/convertible_soong_module/${GENERATED_BUILD_FILE_NAME} was not generated"
-  fi
-
-  if [[ ! -f "./out/soong/workspace/foo/unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}" ]]; then
-    fail "./out/soong/workspace/foo/unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME} was not generated"
-  fi
-
-  if ! grep "the_answer" "./out/soong/workspace/foo/convertible_soong_module/${GENERATED_BUILD_FILE_NAME}"; then
-    fail "missing BUILD target the_answer in convertible_soong_module/${GENERATED_BUILD_FILE_NAME}"
-  fi
-
-  if grep "not_the_answer" "./out/soong/workspace/foo/unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}"; then
-    fail "found unexpected BUILD target not_the_answer in unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}"
-  fi
-
-  if ! grep "filegroup" "./out/soong/workspace/foo/unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}"; then
-    fail "missing filegroup in unconvertible_soong_module/${GENERATED_BUILD_FILE_NAME}"
-  fi
-
-  # NOTE: We don't actually use the extra BUILD file for anything here
-  run_bazel build --config=android --config=bp2build --config=ci //foo/...
-
-  local -r the_answer_file="$(find -L bazel-out -name the_answer.txt)"
-  if [[ ! -f "${the_answer_file}" ]]; then
-    fail "Expected the_answer.txt to be generated, but was missing"
-  fi
-  if ! grep 42 "${the_answer_file}"; then
-    fail "Expected to find 42 in '${the_answer_file}'"
-  fi
-}
-
-function test_bp2build_generates_all_buildfiles {
-  _save_trap=$(trap -p EXIT)
-  trap '[[ $? -ne 0 ]] && echo Are you running this locally? Try changing --sandbox_tmpfs_path to something other than /tmp/ in build/bazel/linux.bazelrc.' EXIT
-  _bp2build_generates_all_buildfiles
-  eval "${_save_trap}"
-}
-
-function test_build_files_take_precedence {
-  _save_trap=$(trap -p EXIT)
-  trap '[[ $? -ne 0 ]] && echo Are you running this locally? Try changing --sandbox_tmpfs_path to something other than /tmp/ in build/bazel/linux.bazelrc.' EXIT
-  _build_files_take_precedence
-  eval "${_save_trap}"
-}
-
-function _build_files_take_precedence {
-  setup
-
-  # This specific directory is hardcoded in bp2build as being one
-  # where the BUILD file should be intentionally kept.
-  mkdir -p testpkg/keep_build_file
-  cat > testpkg/keep_build_file/Android.bp <<'EOF'
-genrule {
-    name: "print_origin",
-    cmd: "echo 'from_soong' > $(out)",
-    out: [
-        "origin.txt",
-    ],
-    bazel_module: {
-        bp2build_available: true,
-    },
-  }
-EOF
-
-  run_soong bp2build
-  run_bazel build --config=android --config=bp2build --config=ci //testpkg/keep_build_file:print_origin
-
-  local -r output_file="$(find -L bazel-out -name origin.txt)"
-  if [[ ! -f "${output_file}" ]]; then
-    fail "Expected origin.txt to be generated, but was missing"
-  fi
-  if ! grep from_soong "${output_file}"; then
-    fail "Expected to find 'from_soong' in '${output_file}'"
-  fi
-
-  cat > testpkg/keep_build_file/BUILD.bazel <<'EOF'
-genrule(
-    name = "print_origin",
-    outs = ["origin.txt"],
-    cmd = "echo 'from_bazel' > $@",
-)
-EOF
-
-  # Clean the workspace. There is a test infrastructure bug where run_bazel
-  # will symlink Android.bp files in the source directory again and thus
-  # pollute the workspace.
-  # TODO: b/286059878 - Remove this clean after the underlying bug is fixed.
-  run_soong clean
-  run_soong bp2build
-  run_bazel build --config=android --config=bp2build --config=ci //testpkg/keep_build_file:print_origin
-  if ! grep from_bazel "${output_file}"; then
-    fail "Expected to find 'from_bazel' in '${output_file}'"
-  fi
-}
-
-function test_bp2build_symlinks_files {
-  setup
-  mkdir -p foo
-  touch foo/BLANK1
-  touch foo/BLANK2
-  touch foo/F2D
-  touch foo/BUILD
-
-  run_soong bp2build
-
-  if [[ -e "./out/soong/workspace/foo/BUILD" ]]; then
-    fail "./out/soong/workspace/foo/BUILD should be omitted"
-  fi
-  for file in BLANK1 BLANK2 F2D
-  do
-    if [[ ! -L "./out/soong/workspace/foo/$file" ]]; then
-      fail "./out/soong/workspace/foo/$file should exist"
-    fi
-  done
-  local -r BLANK1_BEFORE=$(stat -c %y "./out/soong/workspace/foo/BLANK1")
-
-  rm foo/BLANK2
-  rm foo/F2D
-  mkdir foo/F2D
-  touch foo/F2D/BUILD
-
-  run_soong bp2build
-
-  if [[ -e "./out/soong/workspace/foo/BUILD" ]]; then
-    fail "./out/soong/workspace/foo/BUILD should be omitted"
-  fi
-  local -r BLANK1_AFTER=$(stat -c %y "./out/soong/workspace/foo/BLANK1")
-  if [[ "$BLANK1_AFTER" != "$BLANK1_BEFORE" ]]; then
-    fail "./out/soong/workspace/foo/BLANK1 should be untouched"
-  fi
-  if [[  -e "./out/soong/workspace/foo/BLANK2" ]]; then
-    fail "./out/soong/workspace/foo/BLANK2 should be removed"
-  fi
-  if [[ -L "./out/soong/workspace/foo/F2D" ]] || [[ ! -d "./out/soong/workspace/foo/F2D" ]]; then
-    fail "./out/soong/workspace/foo/F2D should be a dir"
-  fi
-}
-
-function test_cc_correctness {
-  setup
-
-  mkdir -p a
-  cat > a/Android.bp <<EOF
-cc_object {
-  name: "qq",
-  srcs: ["qq.cc"],
-  bazel_module: {
-    bp2build_available: true,
-  },
-  stl: "none",
-  system_shared_libs: [],
-}
-EOF
-
-  cat > a/qq.cc <<EOF
-#include "qq.h"
-int qq() {
-  return QQ;
-}
-EOF
-
-  cat > a/qq.h <<EOF
-#define QQ 1
-EOF
-
-  run_soong bp2build
-
-  run_bazel build --config=android --config=bp2build --config=ci //a:qq
-  local -r output_mtime1=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
-
-  run_bazel build --config=android --config=bp2build --config=ci //a:qq
-  local -r output_mtime2=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
-
-  if [[ "$output_mtime1" != "$output_mtime2" ]]; then
-    fail "output changed on null build"
-  fi
-
-  cat > a/qq.h <<EOF
-#define QQ 2
-EOF
-
-  run_bazel build --config=android --config=bp2build --config=ci //a:qq
-  local -r output_mtime3=$(stat -c "%y" bazel-bin/a/_objs/qq/qq.o)
-
-  if [[ "$output_mtime1" == "$output_mtime3" ]]; then
-    fail "output not changed when included header changed"
-  fi
-}
-
-# Regression test for the following failure during symlink forest creation:
-#
-#   Cannot stat '/tmp/st.rr054/foo/bar/unresolved_symlink': stat /tmp/st.rr054/foo/bar/unresolved_symlink: no such file or directory
-#
-function test_bp2build_null_build_with_unresolved_symlink_in_source() {
-  setup
-
-  mkdir -p foo/bar
-  ln -s /tmp/non-existent foo/bar/unresolved_symlink
-  cat > foo/bar/Android.bp <<'EOF'
-filegroup {
-    name: "fg",
-    srcs: ["unresolved_symlink/non-existent-file.txt"],
-  }
-EOF
-
-  run_soong bp2build
-
-  dest=$(readlink -f out/soong/workspace/foo/bar/unresolved_symlink)
-  if [[ "$dest" != "/tmp/non-existent" ]]; then
-    fail "expected to plant an unresolved symlink out/soong/workspace/foo/bar/unresolved_symlink that resolves to /tmp/non-existent"
-  fi
-}
-
-# Smoke test to verify api_bp2build worksapce does not contain any errors
-function test_api_bp2build_empty_build() {
-  setup
-  run_soong api_bp2build
-  run_bazel build --config=android --config=api_bp2build //:empty
-}
-
-# Verify that an *_api_contribution target can refer to an api file from
-# another Bazel package.
-function test_api_export_from_another_bazel_package() {
-  setup
-  # Parent dir Android.bp
-  mkdir -p foo
-  cat > foo/Android.bp << 'EOF'
-cc_library {
-  name: "libfoo",
-  stubs: {
-    symbol_file: "api/libfoo.map.txt",
-  },
-}
-EOF
-  # Child dir Android.bp
-  mkdir -p foo/api
-  cat > foo/api/Android.bp << 'EOF'
-package{}
-EOF
-  touch foo/api/libfoo.map.txt
-  # Run test
-  run_soong api_bp2build
-  run_bazel build --config=android --config=api_bp2build //foo:libfoo.contribution
-}
-
-function test_bazel_standalone_output_paths_contain_product_name {
-  setup
-  mkdir -p a
-  cat > a/Android.bp <<EOF
-cc_object {
-  name: "qq",
-  srcs: ["qq.cc"],
-  bazel_module: {
-    bp2build_available: true,
-  },
-  stl: "none",
-  system_shared_libs: [],
-}
-EOF
-
-  cat > a/qq.cc <<EOF
-#include "qq.h"
-int qq() {
-  return QQ;
-}
-EOF
-
-  cat > a/qq.h <<EOF
-#define QQ 1
-EOF
-
-  export TARGET_PRODUCT=aosp_arm; run_soong bp2build
-  local -r output=$(run_bazel cquery //a:qq --output=files --config=android --config=bp2build --config=ci)
-  if [[ ! $(echo ${output} | grep "bazel-out/aosp_arm") ]]; then
-    fail "Did not find the product name '${TARGET_PRODUCT}' in the output path. This can cause " \
-      "unnecessary rebuilds when toggling between products as bazel outputs for different products will " \
-      "clobber each other. Output paths are: \n${output}"
-  fi
-}
-
-scan_and_run_tests
diff --git a/tests/dcla_apex_comparison_test.sh b/tests/dcla_apex_comparison_test.sh
deleted file mode 100755
index e3c189f..0000000
--- a/tests/dcla_apex_comparison_test.sh
+++ /dev/null
@@ -1,166 +0,0 @@
-#!/bin/bash
-
-# Copyright (C) 2023 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-set -euo pipefail
-
-# Soong/Bazel integration test to build the mainline modules in mixed build and
-# compare the DCLA libs extracted from those modules to ensure they are identical.
-
-if [ ! -e "build/make/core/Makefile" ]; then
-  echo "$0 must be run from the top of the Android source tree."
-  exit 1
-fi
-
-TARGET_PRODUCTS=(
-  module_arm64
-  module_x86_64
-)
-
-MODULES=(
-  # These modules depend on the DCLA libs
-  com.android.adbd
-  com.android.art
-  com.android.art.debug
-  com.android.art.testing
-  com.android.btservices
-  com.android.conscrypt
-  com.android.i18n
-  com.android.media
-  com.android.media.swcodec
-  com.android.resolv
-  com.android.runtime
-  com.android.tethering
-)
-
-BAZEL_TARGETS=(
-  //packages/modules/adb/apex:com.android.adbd
-  //frameworks/av/apex:com.android.media.swcodec
-)
-
-DCLA_LIBS=(
-  libbase.so
-  libc++.so
-  libcrypto.so
-  libcutils.so
-  libstagefright_flacdec.so
-  libutils.so
-)
-
-if [[ -z ${OUT_DIR+x} ]]; then
-  OUT_DIR="out"
-fi
-
-if [[ -z ${ANDROID_HOST_OUT+x} ]]; then
-  export ANDROID_HOST_OUT="out/host/linux-x86"
-fi
-
-######################
-# Build deapexer and debugfs
-######################
-DEAPEXER="${ANDROID_HOST_OUT}/bin/deapexer"
-DEBUGFS="${ANDROID_HOST_OUT}/bin/debugfs"
-if [[ ! -f "${DEAPEXER}" ]] || [[ ! -f "${DEBUGFS}" ]]; then
-  build/soong/soong_ui.bash --make-mode --skip-soong-tests deapexer debugfs
-fi
-
-DEAPEXER="${DEAPEXER} --debugfs_path=${DEBUGFS}"
-
-############
-# Test Setup
-############
-OUTPUT_DIR="$(mktemp -d tmp.XXXXXX)"
-
-function call_bazel() {
-  build/bazel/bin/bazel $@
-}
-
-function cleanup {
-  rm -rf "${OUTPUT_DIR}"
-}
-trap cleanup EXIT
-
-#######
-# Tests
-#######
-
-function extract_dcla_libs() {
-  local product=$1; shift
-  local modules=("$@"); shift
-
-  for module in "${modules[@]}"; do
-    local apex="${OUTPUT_DIR}/${product}/${module}.apex"
-    local extract_dir="${OUTPUT_DIR}/${product}/${module}/extract"
-
-    $DEAPEXER extract "${apex}" "${extract_dir}"
-  done
-}
-
-function compare_dcla_libs() {
-  local product=$1; shift
-  local modules=("$@"); shift
-
-  for lib in "${DCLA_LIBS[@]}"; do
-    for arch in lib lib64; do
-      local prev_sha=""
-      for module in "${modules[@]}"; do
-        local file="${OUTPUT_DIR}/${product}/${module}/extract/${arch}/${lib}"
-        if [[ ! -f "${file}" ]]; then
-          # not all libs are present in a module
-          echo "file doesn't exist: ${file}"
-          continue
-        fi
-        sha=$(sha1sum ${file})
-        sha="${sha% *}"
-        if [ "${prev_sha}" == "" ]; then
-          prev_sha="${sha}"
-        elif [ "${sha}" != "${prev_sha}" ] && { [ "${lib}" != "libcrypto.so" ] || [[ "${module}" != *"com.android.tethering" ]]; }; then
-          echo "Test failed, ${lib} has different hash value"
-          exit 1
-        fi
-      done
-    done
-  done
-}
-
-export UNBUNDLED_BUILD_SDKS_FROM_SOURCE=true # don't rely on prebuilts
-export TARGET_BUILD_APPS="${MODULES[@]}"
-for product in "${TARGET_PRODUCTS[@]}"; do
-  ###########
-  # Build the mainline modules
-  ###########
-  packages/modules/common/build/build_unbundled_mainline_module.sh \
-    --product "${product}" \
-    --dist_dir "${OUTPUT_DIR}/${product}"
-
-  bazel_apexes=()
-  if [[ -n ${TEST_BAZEL+x} ]] && [ "${TEST_BAZEL}" = true ]; then
-    export TARGET_PRODUCT="${product/module/aosp}"
-    call_bazel build --config=bp2build --config=ci --config=android "${BAZEL_TARGETS[@]}"
-    for target in "${BAZEL_TARGETS[@]}"; do
-      apex_path="$(realpath $(call_bazel cquery --config=bp2build --config=android --config=ci --output=files $target))"
-      mkdir -p ${OUTPUT_DIR}/${product}
-      bazel_apex="bazel_$(basename $apex_path)"
-      mv $apex_path ${OUTPUT_DIR}/${product}/${bazel_apex}
-      bazel_apexes+=(${bazel_apex%".apex"})
-    done
-  fi
-
-  all_modeuls=(${MODULES[@]} ${bazel_apexes[@]})
-  extract_dcla_libs "${product}" "${all_modeuls[@]}"
-  compare_dcla_libs "${product}" "${all_modeuls[@]}"
-done
-
-echo "Test passed"
diff --git a/tests/genrule_sandbox_test.py b/tests/genrule_sandbox_test.py
index 0cebc2a..3799e92 100755
--- a/tests/genrule_sandbox_test.py
+++ b/tests/genrule_sandbox_test.py
@@ -15,12 +15,14 @@
 # limitations under the License.
 
 import argparse
+import asyncio
 import collections
 import json
 import os
+import socket
 import subprocess
 import sys
-import tempfile
+import textwrap
 
 def get_top() -> str:
   path = '.'
@@ -30,38 +32,65 @@
     path = os.path.join(path, '..')
   return os.path.abspath(path)
 
-def _build_with_soong(targets, target_product, *, keep_going = False, extra_env={}):
-  env = {
-      **os.environ,
-      "TARGET_PRODUCT": target_product,
-      "TARGET_BUILD_VARIANT": "userdebug",
-  }
-  env.update(extra_env)
+async def _build_with_soong(out_dir, targets, *, extra_env={}):
+  env = os.environ | extra_env
+
+  # Use nsjail to remap the out_dir to out/, because some genrules write the path to the out
+  # dir into their artifacts, so if the out directories were different it would cause a diff
+  # that doesn't really matter.
   args = [
+      'prebuilts/build-tools/linux-x86/bin/nsjail',
+      '-q',
+      '--cwd',
+      os.getcwd(),
+      '-e',
+      '-B',
+      '/',
+      '-B',
+      f'{os.path.abspath(out_dir)}:{os.path.abspath("out")}',
+      '--time_limit',
+      '0',
+      '--skip_setsid',
+      '--keep_caps',
+      '--disable_clone_newcgroup',
+      '--disable_clone_newnet',
+      '--rlimit_as',
+      'soft',
+      '--rlimit_core',
+      'soft',
+      '--rlimit_cpu',
+      'soft',
+      '--rlimit_fsize',
+      'soft',
+      '--rlimit_nofile',
+      'soft',
+      '--proc_rw',
+      '--hostname',
+      socket.gethostname(),
+      '--',
       "build/soong/soong_ui.bash",
       "--make-mode",
       "--skip-soong-tests",
   ]
-  if keep_going:
-    args.append("-k")
   args.extend(targets)
-  try:
-    subprocess.check_output(
-        args,
-        env=env,
-    )
-  except subprocess.CalledProcessError as e:
-    print(e)
-    print(e.stdout)
-    print(e.stderr)
-    exit(1)
+  process = await asyncio.create_subprocess_exec(
+      *args,
+      stdout=asyncio.subprocess.PIPE,
+      stderr=asyncio.subprocess.PIPE,
+      env=env,
+  )
+  stdout, stderr = await process.communicate()
+  if process.returncode != 0:
+    print(stdout)
+    print(stderr)
+    sys.exit(process.returncode)
 
 
-def _find_outputs_for_modules(modules, out_dir, target_product):
-  module_path = os.path.join(out_dir, "soong", "module-actions.json")
+async def _find_outputs_for_modules(modules):
+  module_path = "out/soong/module-actions.json"
 
   if not os.path.exists(module_path):
-    _build_with_soong(["json-module-graph"], target_product)
+    await _build_with_soong('out', ["json-module-graph"])
 
   with open(module_path) as f:
     action_graph = json.load(f)
@@ -70,7 +99,7 @@
   for mod in action_graph:
     name = mod["Name"]
     if name in modules:
-      for act in mod["Module"]["Actions"]:
+      for act in (mod["Module"]["Actions"] or []):
         if "}generate" in act["Desc"]:
           module_to_outs[name].update(act["Outputs"])
   return module_to_outs
@@ -88,20 +117,19 @@
   return different_modules
 
 
-def main():
+async def main():
   parser = argparse.ArgumentParser()
   parser.add_argument(
-      "--target_product",
-      "-t",
-      default="aosp_cf_arm64_phone",
-      help="optional, target product, always runs as eng",
-  )
-  parser.add_argument(
       "modules",
       nargs="+",
       help="modules to compare builds with genrule sandboxing enabled/not",
   )
   parser.add_argument(
+      "--check-determinism",
+      action="store_true",
+      help="Don't check for working sandboxing. Instead, run two default builds, and compare their outputs. This is used to check for nondeterminsim, which would also affect the sandboxed test.",
+  )
+  parser.add_argument(
       "--show-diff",
       "-d",
       action="store_true",
@@ -116,10 +144,13 @@
   args = parser.parse_args()
   os.chdir(get_top())
 
-  out_dir = os.environ.get("OUT_DIR", "out")
+  if "TARGET_PRODUCT" not in os.environ:
+    sys.exit("Please run lunch first")
+  if os.environ.get("OUT_DIR", "out") != "out":
+    sys.exit(f"This script expects OUT_DIR to be 'out', got: '{os.environ.get('OUT_DIR')}'")
 
   print("finding output files for the modules...")
-  module_to_outs = _find_outputs_for_modules(set(args.modules), out_dir, args.target_product)
+  module_to_outs = await _find_outputs_for_modules(set(args.modules))
   if not module_to_outs:
     sys.exit("No outputs found")
 
@@ -129,33 +160,48 @@
     sys.exit(0)
 
   all_outs = list(set.union(*module_to_outs.values()))
+  for i, out in enumerate(all_outs):
+    if not out.startswith("out/"):
+      sys.exit("Expected output file to start with out/, found: " + out)
 
-  print("building without sandboxing...")
-  _build_with_soong(all_outs, args.target_product)
-  with tempfile.TemporaryDirectory() as tempdir:
-    for f in all_outs:
-      subprocess.check_call(["cp", "--parents", f, tempdir])
+  other_out_dir = "out_check_determinism" if args.check_determinism else "out_not_sandboxed"
+  other_env = {"GENRULE_SANDBOXING": "false"}
+  if args.check_determinism:
+    other_env = {}
 
-    print("building with sandboxing...")
-    _build_with_soong(
-        all_outs,
-        args.target_product,
-        # We've verified these build without sandboxing already, so do the sandboxing build
-        # with keep_going = True so that we can find all the genrules that fail to build with
-        # sandboxing.
-        keep_going = True,
-        extra_env={"GENRULE_SANDBOXING": "true"},
-    )
+  # nsjail will complain if the out dir doesn't exist
+  os.makedirs("out", exist_ok=True)
+  os.makedirs(other_out_dir, exist_ok=True)
 
-    diffs = _compare_outputs(module_to_outs, tempdir)
-    if len(diffs) == 0:
-      print("All modules are correct")
-    elif args.show_diff:
-      for m, d in diffs.items():
-        print(f"Module {m} has diffs {d}")
-    else:
-      print(f"Modules {list(diffs.keys())} have diffs")
+  print("building...")
+  await asyncio.gather(
+    _build_with_soong("out", all_outs),
+    _build_with_soong(other_out_dir, all_outs, extra_env=other_env)
+  )
+
+  diffs = collections.defaultdict(dict)
+  for module, outs in module_to_outs.items():
+    for out in outs:
+      try:
+        subprocess.check_output(["diff", os.path.join(other_out_dir, out.removeprefix("out/")), out])
+      except subprocess.CalledProcessError as e:
+        diffs[module][out] = e.stdout
+
+  if len(diffs) == 0:
+    print("All modules are correct")
+  elif args.show_diff:
+    for m, files in diffs.items():
+      print(f"Module {m} has diffs:")
+      for f, d in files.items():
+        print("  "+f+":")
+        print(textwrap.indent(d, "    "))
+  else:
+    print(f"Modules {list(diffs.keys())} have diffs in these files:")
+    all_diff_files = [f for m in diffs.values() for f in m]
+    for f in all_diff_files:
+      print(f)
+
 
 
 if __name__ == "__main__":
-  main()
+  asyncio.run(main())
diff --git a/tests/lib.sh b/tests/lib.sh
index f3db76f..4c320d0 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -8,10 +8,15 @@
 
 REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
 
+function make_mock_top {
+  mock=$(mktemp -t -d st.XXXXX)
+  echo "$mock"
+}
+
 if [[ -n "$HARDWIRED_MOCK_TOP" ]]; then
   MOCK_TOP="$HARDWIRED_MOCK_TOP"
 else
-  MOCK_TOP=$(mktemp -t -d st.XXXXX)
+  MOCK_TOP=$(make_mock_top)
   trap cleanup_mock_top EXIT
 fi
 
@@ -135,7 +140,7 @@
 
 # shellcheck disable=SC2120
 function run_soong {
-  USE_RBE=false build/soong/soong_ui.bash --make-mode --skip-ninja --skip-config --soong-only --skip-soong-tests "$@"
+  USE_RBE=false TARGET_PRODUCT=aosp_arm TARGET_RELEASE=trunk_staging TARGET_BUILD_VARIANT=userdebug build/soong/soong_ui.bash --make-mode --skip-ninja --skip-config --soong-only --skip-soong-tests "$@"
 }
 
 function create_mock_bazel {
@@ -154,8 +159,12 @@
   symlink_directory external/bazelbuild-rules_go
   symlink_directory external/bazelbuild-rules_license
   symlink_directory external/bazelbuild-kotlin-rules
+  symlink_directory external/bazelbuild-rules_cc
   symlink_directory external/bazelbuild-rules_python
   symlink_directory external/bazelbuild-rules_java
+  symlink_directory external/bazelbuild-rules_rust
+  symlink_directory external/bazelbuild-rules_testing
+  symlink_directory external/rust/crates/tinyjson
 
   symlink_file WORKSPACE
   symlink_file BUILD
@@ -194,3 +203,11 @@
     info "Completed test case \e[96;1m$f\e[0m"
   done
 }
+
+function move_mock_top {
+  MOCK_TOP2=$(make_mock_top)
+  rm -rf $MOCK_TOP2
+  mv $MOCK_TOP $MOCK_TOP2
+  MOCK_TOP=$MOCK_TOP2
+  trap cleanup_mock_top EXIT
+}
diff --git a/tests/mixed_mode_test.sh b/tests/mixed_mode_test.sh
deleted file mode 100755
index ca63fdf..0000000
--- a/tests/mixed_mode_test.sh
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/bin/bash
-
-set -o pipefail
-
-# This test exercises mixed builds where Soong and Bazel cooperate in building
-# Android.
-#
-# When the execroot is deleted, the Bazel server process will automatically
-# terminate itself.
-
-source "$(dirname "$0")/lib.sh"
-
-function test_bazel_smoke {
-  setup
-
-  run_soong bp2build
-
-  run_bazel info --config=bp2build
-}
-
-function test_add_irrelevant_file {
-  setup
-
-  mkdir -p soong_tests/a/b
-  touch soong_tests/a/b/c.txt
-  cat > soong_tests/a/b/Android.bp <<'EOF'
-filegroup {
-  name: "c",
-  srcs: ["c.txt"],
-  bazel_module: { bp2build_available: true },
-}
-EOF
-
-  run_soong --bazel-mode-staging nothing
-
-  if [[ ! -e out/soong/bp2build/soong_tests/a/b/BUILD.bazel ]]; then
-    fail "BUILD.bazel not created"
-  fi
-
-  if [[ ! -e out/soong/build.ninja ]]; then
-    fail "build.ninja not created"
-  fi
-
-  local mtime_build1=$(stat -c "%y" out/soong/bp2build/soong_tests/a/b/BUILD.bazel)
-  local mtime_ninja1=$(stat -c "%y" out/soong/build.ninja)
-
-  touch soong_tests/a/irrelevant.txt
-
-  run_soong --bazel-mode-staging nothing
-  local mtime_build2=$(stat -c "%y" out/soong/bp2build/soong_tests/a/b/BUILD.bazel)
-  local mtime_ninja2=$(stat -c "%y" out/soong/build.ninja)
-
-  if [[ "$mtime_build1" != "$mtime_build2" ]]; then
-    fail "BUILD.bazel was generated"
-  fi
-
-  if [[ "$mtime_ninja1" != "$mtime_ninja2" ]]; then
-    fail "build.ninja was regenerated"
-  fi
-
-  if [[ ! -e out/soong/workspace/soong_tests/a/irrelevant.txt ]]; then
-    fail "new file was not symlinked"
-  fi
-}
-
-function test_force_enabled_modules {
-  setup
-  # b/273910287 - test force enable modules
-  mkdir -p soong_tests/a/b
-  cat > soong_tests/a/b/Android.bp <<'EOF'
-genrule {
-    name: "touch-file",
-    out: ["fake-out.txt"],
-    cmd: "touch $(out)",
-    bazel_module: { bp2build_available: true },
-}
-
-genrule {
-    name: "unenabled-touch-file",
-    out: ["fake-out2.txt"],
-    cmd: "touch $(out)",
-    bazel_module: { bp2build_available: false },
-}
-EOF
-  run_soong --bazel-mode-staging --bazel-force-enabled-modules=touch-file nothing
-  local bazel_contained=`grep out/soong/.intermediates/soong_tests/a/b/touch-file/gen/fake-out.txt out/soong/build.ninja`
-  if [[ $bazel_contained == '' ]]; then
-    fail "Bazel actions not found for force-enabled module"
-  fi
-
-  unused=`run_soong --bazel-force-enabled-modules=unenabled-touch-file --ensure-allowlist-integrity nothing >/dev/null`
-
-  if [[ $? -ne 1 ]]; then
-    fail "Expected failure due to force-enabling an unenabled module "
-  fi
-}
-
-
-scan_and_run_tests
diff --git a/tests/persistent_bazel_test.sh b/tests/persistent_bazel_test.sh
deleted file mode 100755
index 9b7b58f..0000000
--- a/tests/persistent_bazel_test.sh
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/bin/bash -eu
-
-# Copyright (C) 2023 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-set -o pipefail
-
-source "$(dirname "$0")/lib.sh"
-
-# This test verifies that adding USE_PERSISTENT_BAZEL creates a Bazel process
-# that outlasts the build process.
-# This test should only be run in sandboxed environments (because this test
-# verifies a Bazel process using global process list, and may spawn lingering
-# Bazel processes).
-function test_persistent_bazel {
-  setup
-
-  # Ensure no existing Bazel process.
-  if [[ -e out/bazel/output/server/server.pid.txt ]]; then
-    kill $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null || true
-    if kill -0 $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null ; then
-      fail "Error killing pre-setup bazel"
-    fi
-  fi
-
-  USE_PERSISTENT_BAZEL=1 run_soong nothing
-
-  if ! kill -0 $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null ; then
-    fail "Persistent bazel process expected, but not found after first build"
-  fi
-  BAZEL_PID=$(cat out/bazel/output/server/server.pid.txt)
-
-  USE_PERSISTENT_BAZEL=1 run_soong nothing
-
-  if ! kill -0 $BAZEL_PID 2>/dev/null ; then
-    fail "Bazel pid $BAZEL_PID was killed after second build"
-  fi
-
-  kill $BAZEL_PID 2>/dev/null
-  if ! kill -0 $BAZEL_PID 2>/dev/null ; then
-    fail "Error killing bazel on shutdown"
-  fi
-}
-
-# Verifies that USE_PERSISTENT_BAZEL mode operates as expected in the event
-# that there are Bazel failures.
-function test_bazel_failure {
-  setup
-
-  # Ensure no existing Bazel process.
-  if [[ -e out/bazel/output/server/server.pid.txt ]]; then
-    kill $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null || true
-    if kill -0 $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null ; then
-      fail "Error killing pre-setup bazel"
-    fi
-  fi
-
-  # Introduce a syntax error in a BUILD file which is used in every build
-  # (Note this is a BUILD file which is copied as part of test setup, so this
-  # has no effect on sources outside of this test.
-  rm -rf  build/bazel/rules
-
-  USE_PERSISTENT_BAZEL=1 run_soong nothing 1>out/failurelog.txt 2>&1 && fail "Expected build failure" || true
-
-  if ! grep -sq "cannot load //build/bazel/rules/common/api_constants.bzl" out/failurelog.txt ; then
-    fail "Expected error to contain 'cannot load //build/bazel/rules/common/api_constants.bzl', instead got:\n$(cat out/failurelog.txt)"
-  fi
-
-  kill $(cat out/bazel/output/server/server.pid.txt) 2>/dev/null || true
-}
-
-scan_and_run_tests
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 6b9ff8b..0235f2b 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -5,22 +5,5 @@
 TOP="$(readlink -f "$(dirname "$0")"/../../..)"
 "$TOP/build/soong/tests/androidmk_test.sh"
 "$TOP/build/soong/tests/bootstrap_test.sh"
-"$TOP/build/soong/tests/mixed_mode_test.sh"
-"$TOP/build/soong/tests/bp2build_bazel_test.sh"
-"$TOP/build/soong/tests/persistent_bazel_test.sh"
 "$TOP/build/soong/tests/soong_test.sh"
-"$TOP/build/soong/tests/stale_metrics_files_test.sh"
 "$TOP/prebuilts/build-tools/linux-x86/bin/py3-cmd" "$TOP/build/bazel/ci/rbc_dashboard.py" aosp_arm64-userdebug
-
-# The following tests build against the full source tree and don't rely on the
-# mock client.
-"$TOP/build/soong/tests/apex_comparison_tests.sh"
-"$TOP/build/soong/tests/apex_comparison_tests.sh" "module_arm64only"
-TEST_BAZEL=true extra_build_params=--bazel-mode-staging "$TOP/build/soong/tests/dcla_apex_comparison_test.sh"
-#BUILD_BROKEN_DISABLE_BAZEL=true "$TOP/build/soong/tests/dcla_apex_comparison_test.sh"
-"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh"
-"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_arm" "armv7-a"
-"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53"
-
-"$TOP/build/bazel/ci/b_test.sh"
-
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index c41f28d..8dc1630 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -35,25 +35,23 @@
 }
 
 function run_soong {
-  target_product="$1";shift
-  out_dir="$1"; shift
-  targets="$1"; shift
+  local out_dir="$1"; shift
+  local targets="$1"; shift
   if [ "$#" -ge 1 ]; then
-    apps=$1; shift
-    TARGET_PRODUCT="${target_product}" TARGET_BUILD_VARIANT=userdebug OUT_DIR="${out_dir}" TARGET_BUILD_UNBUNDLED=true TARGET_BUILD_APPS=$apps build/soong/soong_ui.bash --make-mode ${targets}
+    local apps=$1; shift
+    TARGET_PRODUCT="${target_product}" TARGET_RELEASE="${target_release}" TARGET_BUILD_VARIANT="${target_build_variant}" OUT_DIR="${out_dir}" TARGET_BUILD_UNBUNDLED=true TARGET_BUILD_APPS=$apps \
+        build/soong/soong_ui.bash --make-mode ${targets}
   else
-    TARGET_PRODUCT="${target_product}" TARGET_BUILD_VARIANT=userdebug OUT_DIR="${out_dir}" build/soong/soong_ui.bash --make-mode ${targets}
+    TARGET_PRODUCT="${target_product}" TARGET_RELEASE="${target_release}" TARGET_BUILD_VARIANT="${target_build_variant}" OUT_DIR="${out_dir}" \
+        build/soong/soong_ui.bash --make-mode ${targets}
   fi
 }
 
 function diff_files {
-  file_list_file="$1"; shift
-  files_in_spdx_file="$1"; shift
-  partition_name="$1"; shift
-  exclude=
-  if [ -v 'diff_excludes[$partition_name]' ]; then
-   exclude=${diff_excludes[$partition_name]}
-  fi
+  local file_list_file="$1"; shift
+  local files_in_spdx_file="$1"; shift
+  local partition_name="$1"; shift
+  local exclude="$1"; shift
 
   diff "$file_list_file" "$files_in_spdx_file" $exclude
   if [ $? != "0" ]; then
@@ -70,7 +68,7 @@
 
   # Test
   # m droid, build sbom later in case additional dependencies might be built and included in partition images.
-  run_soong "aosp_cf_x86_64_phone" "${out_dir}" "droid dump.erofs lz4"
+  run_soong "${out_dir}" "droid dump.erofs lz4"
 
   product_out=$out_dir/target/product/vsoc_x86_64
   sbom_test=$product_out/sbom_test
@@ -78,53 +76,12 @@
   cp $product_out/*.img $sbom_test
 
   # m sbom
-  run_soong "aosp_cf_x86_64_phone" "${out_dir}" sbom
+  run_soong "${out_dir}" sbom
 
   # Generate installed file list from .img files in PRODUCT_OUT
   dump_erofs=$out_dir/host/linux-x86/bin/dump.erofs
   lz4=$out_dir/host/linux-x86/bin/lz4
 
-  declare -A diff_excludes
-  diff_excludes[vendor]="\
-    -I /vendor/lib64/libkeystore2_crypto.so"
-  diff_excludes[system]="\
-    -I /system/bin/assemble_cvd
-    -I /system/bin/console_forwarder
-    -I /system/bin/kernel_log_monitor
-    -I /system/bin/logcat_receiver
-    -I /system/bin/mkenvimage_slim
-    -I /system/bin/run_cvd
-    -I /system/bin/simg2img
-    -I /system/bin/log_tee
-    -I /system/lib64/android.hardware.confirmationui@1.0.so \
-    -I /system/lib64/android.hardware.confirmationui-V1-ndk.so \
-    -I /system/lib64/android.hardware.keymaster@4.1.so \
-    -I /system/lib64/android.hardware.security.rkp-V3-ndk.so \
-    -I /system/lib64/android.hardware.security.sharedsecret-V1-ndk.so \
-    -I /system/lib64/android.security.compat-ndk.so \
-    -I /system/lib64/libcuttlefish_allocd_utils.so \
-    -I /system/lib64/libcuttlefish_device_config_proto.so \
-    -I /system/lib64/libcuttlefish_device_config.so \
-    -I /system/lib64/libcuttlefish_fs.so \
-    -I /system/lib64/libcuttlefish_kernel_log_monitor_utils.so \
-    -I /system/lib64/libcuttlefish_utils.so \
-    -I /system/lib64/libfruit.so \
-    -I /system/lib64/libgflags.so \
-    -I /system/lib64/libkeymaster4_1support.so \
-    -I /system/lib64/libkeymaster4support.so \
-    -I /system/lib64/libkeymint.so \
-    -I /system/lib64/libkeystore2_aaid.so \
-    -I /system/lib64/libkeystore2_apc_compat.so \
-    -I /system/lib64/libkeystore2_crypto.so \
-    -I /system/lib64/libkeystore-attestation-application-id.so \
-    -I /system/lib64/libkm_compat_service.so \
-    -I /system/lib64/libkm_compat.so \
-    -I /system/lib64/vndk-29 \
-    -I /system/lib64/vndk-sp-29 \
-    -I /system/lib/vndk-29 \
-    -I /system/lib/vndk-sp-29 \
-    -I /system/usr/icu"
-
   # Example output of dump.erofs is as below, and the data used in the test start
   # at line 11. Column 1 is inode id, column 2 is inode type and column 3 is name.
   # Each line is captured in variable "entry", awk is used to get type and name.
@@ -196,7 +153,7 @@
     sort -n -o "$files_in_spdx_file" "$files_in_spdx_file"
 
     echo ============ Diffing files in $f and SBOM
-    diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name"
+    diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name" ""
   done
 
   RAMDISK_IMAGES="$product_out/ramdisk.img"
@@ -214,7 +171,7 @@
     grep "FileName: /${partition_name}/" $product_out/sbom.spdx | sed 's/^FileName: //' | sort -n > "$files_in_spdx_file"
 
     echo ============ Diffing files in $f and SBOM
-    diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name"
+    diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name" ""
   done
 
   verify_package_verification_code "$product_out/sbom.spdx"
@@ -261,7 +218,7 @@
   out_dir="$(setup)"
 
   # run_soong to build com.android.adbd.apex
-  run_soong "module_arm64" "${out_dir}" "sbom deapexer" "com.android.adbd"
+  run_soong "${out_dir}" "sbom deapexer" "com.android.adbd"
 
   deapexer=${out_dir}/host/linux-x86/bin/deapexer
   debugfs=${out_dir}/host/linux-x86/bin/debugfs_static
@@ -293,7 +250,7 @@
   out_dir="$(setup)"
 
   # run_soong to build Browser2.apk
-  run_soong "module_arm64" "${out_dir}" "sbom" "Browser2"
+  run_soong "${out_dir}" "sbom" "Browser2"
 
   sbom_file=${out_dir}/target/product/module_arm64/system/product/app/Browser2/Browser2.apk.spdx.json
   echo "============ Diffing files in Browser2.apk and SBOM"
@@ -315,6 +272,41 @@
   cleanup "${out_dir}"
 }
 
-test_sbom_aosp_cf_x86_64_phone
-test_sbom_unbundled_apex
-test_sbom_unbundled_apk
\ No newline at end of file
+target_product=aosp_cf_x86_64_phone
+target_release=trunk_staging
+target_build_variant=userdebug
+for i in "$@"; do
+  case $i in
+    TARGET_PRODUCT=*)
+      target_product=${i#*=}
+      shift
+      ;;
+    TARGET_RELEASE=*)
+      target_release=${i#*=}
+      shift
+      ;;
+    TARGET_BUILD_VARIANT=*)
+      target_build_variant=${i#*=}
+      shift
+      ;;
+    *)
+      echo "Unknown command line arguments: $i"
+      exit 1
+      ;;
+  esac
+done
+
+echo "target product: $target_product, target_release: $target_release, target build variant: $target_build_variant"
+case $target_product in
+  aosp_cf_x86_64_phone)
+    test_sbom_aosp_cf_x86_64_phone
+    ;;
+  module_arm64)
+    test_sbom_unbundled_apex
+    test_sbom_unbundled_apk
+    ;;
+  *)
+    echo "Unknown TARGET_PRODUCT: $target_product"
+    exit 1
+    ;;
+esac
\ No newline at end of file
diff --git a/tests/stale_metrics_files_test.sh b/tests/stale_metrics_files_test.sh
deleted file mode 100755
index 0da89c3..0000000
--- a/tests/stale_metrics_files_test.sh
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/bin/bash -e
-
-# This test ensures that stale metrics files are deleted after each run
-
-# Run bazel
-# Note - bp2build metrics are present after clean runs, only
-build/soong/soong_ui.bash --make-mode clean
-build/bazel/bin/b build libcore:all
-soong_build_metrics_files=("out/soong_build_metrics.pb" "out/build_progress.pb" "out/soong_metrics" "out/bp2build_metrics.pb")
-bazel_build_metrics_files=("out/bazel_metrics.pb" "out/build_progress.pb" "out/soong_metrics" "out/bp2build_metrics.pb")
-
-# Ensure bazel metrics files are present
-for i in ${!bazel_build_metrics_files[@]};
-do
-  file=${bazel_build_metrics_files[$i]}
-  if [[ ! -f $file ]]; then
-     echo "Missing metrics file for Bazel build " $file
-     exit 1
-  fi
-done
-
-
-# Run a soong build
-build/soong/soong_ui.bash --make-mode nothing
-
-for i in ${!soong_build_metrics_files[@]};
-do
-  file=${soong_build_metrics_files[$i]}
-  if [[ ! -f $file ]]; then
-     echo "Missing metrics file for Soong build " $file
-     exit 1
-  fi
-done
-
-# Ensure that bazel_metrics.pb is deleted
-if [[ -f out/bazel_metrics.pb ]]; then
-   echo "Stale out/bazel_metrics.pb file detected"
-   exit 1
-fi
-
-# Run bazel again - to make sure that soong_build_metrics.pb gets deleted
-build/bazel/bin/b build libcore:all
-
-if [[ -f out/soong_build_metrics.pb ]]; then
-   echo "Stale out/soong_build_metrics.pb file detected"
-   exit 1
-fi
diff --git a/third_party/zip/android.go b/third_party/zip/android.go
index 0f41f62..b972156 100644
--- a/third_party/zip/android.go
+++ b/third_party/zip/android.go
@@ -56,6 +56,11 @@
 	if err := writeHeader(w.cw, fh); err != nil {
 		return err
 	}
+
+	// Strip the extras again in case writeHeader added the local file header extras that are incorrect for the
+	// central directory.
+	fh.Extra = stripExtras(fh.Extra)
+
 	dataOffset, err := orig.DataOffset()
 	if err != nil {
 		return err
diff --git a/tradefed/Android.bp b/tradefed/Android.bp
index a161108..e852584 100644
--- a/tradefed/Android.bp
+++ b/tradefed/Android.bp
@@ -11,9 +11,9 @@
     ],
     srcs: [
         "autogen.go",
-        "autogen_bazel.go",
         "config.go",
         "makevars.go",
+        "providers.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/tradefed/autogen_bazel.go b/tradefed/autogen_bazel.go
deleted file mode 100644
index d3109d9..0000000
--- a/tradefed/autogen_bazel.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package tradefed
-
-import (
-	"android/soong/android"
-	"android/soong/bazel"
-
-	"github.com/google/blueprint/proptools"
-)
-
-const (
-	InstrumentationTestConfigTemplate  = "build/make/core/instrumentation_test_config_template.xml"
-	JavaTestConfigTemplate             = "build/make/core/java_test_config_template.xml"
-	JavaHostTestConfigTemplate         = "build/make/core/java_host_test_config_template.xml"
-	JavaHostUnitTestConfigTemplate     = "build/make/core/java_host_unit_test_config_template.xml"
-	NativeBenchmarkTestConfigTemplate  = "build/make/core/native_benchmark_test_config_template.xml"
-	NativeHostTestConfigTemplate       = "build/make/core/native_host_test_config_template.xml"
-	NativeTestConfigTemplate           = "build/make/core/native_test_config_template.xml"
-	PythonBinaryHostTestConfigTemplate = "build/make/core/python_binary_host_test_config_template.xml"
-	RustDeviceTestConfigTemplate       = "build/make/core/rust_device_test_config_template.xml"
-	RustHostTestConfigTemplate         = "build/make/core/rust_host_test_config_template.xml"
-	RustDeviceBenchmarkConfigTemplate  = "build/make/core/rust_device_benchmark_config_template.xml"
-	RustHostBenchmarkConfigTemplate    = "build/make/core/rust_host_benchmark_config_template.xml"
-	RobolectricTestConfigTemplate      = "build/make/core/robolectric_test_config_template.xml"
-	ShellTestConfigTemplate            = "build/make/core/shell_test_config_template.xml"
-)
-
-type TestConfigAttributes struct {
-	Test_config *bazel.Label
-
-	Auto_generate_test_config *bool
-	Template_test_config      *bazel.Label
-	Template_configs          []string
-	Template_install_base     *string
-}
-
-func GetTestConfigAttributes(
-	ctx android.TopDownMutatorContext,
-	testConfig *string,
-	extraTestConfigs []string,
-	autoGenConfig *bool,
-	testSuites []string,
-	template *string,
-	templateConfigs []Config,
-	templateInstallBase *string) TestConfigAttributes {
-
-	attrs := TestConfigAttributes{}
-	attrs.Test_config = GetTestConfig(ctx, testConfig)
-	// do not generate a test config if
-	// 1) test config already found
-	// 2) autoGenConfig == false
-	// 3) CTS tests and no template specified.
-	// CTS Modules can be used for test data, so test config files must be explicitly specified.
-	if (attrs.Template_test_config != nil) ||
-		proptools.Bool(autoGenConfig) == false ||
-		(template == nil && !android.InList("cts", testSuites)) {
-
-		return attrs
-	}
-
-	// Add properties for the bazel rule to generate a test config
-	// since a test config was not specified.
-	templateLabel := android.BazelLabelForModuleSrcSingle(ctx, *template)
-	attrs.Template_test_config = &templateLabel
-	attrs.Auto_generate_test_config = autoGenConfig
-	var configStrings []string
-	for _, c := range templateConfigs {
-		configString := proptools.NinjaAndShellEscape(c.Config())
-		configStrings = append(configStrings, configString)
-	}
-	attrs.Template_configs = configStrings
-	attrs.Template_install_base = templateInstallBase
-	return attrs
-}
-
-func GetTestConfig(
-	ctx android.TopDownMutatorContext,
-	testConfig *string,
-) *bazel.Label {
-
-	if testConfig != nil {
-		c, _ := android.BazelStringOrLabelFromProp(ctx, testConfig)
-		if c.Value != nil {
-			return c.Value
-		}
-	}
-
-	// check for default AndroidTest.xml
-	defaultTestConfigPath := ctx.ModuleDir() + "/AndroidTest.xml"
-	c, _ := android.BazelStringOrLabelFromProp(ctx, &defaultTestConfigPath)
-	return c.Value
-}
diff --git a/tradefed/config.go b/tradefed/config.go
index 326a006..b015034 100644
--- a/tradefed/config.go
+++ b/tradefed/config.go
@@ -33,6 +33,7 @@
 	pctx.SourcePathVariable("NativeTestConfigTemplate", "build/make/core/native_test_config_template.xml")
 	pctx.SourcePathVariable("PythonBinaryHostMoblyTestConfigTemplate", "build/make/core/python_binary_host_mobly_test_config_template.xml")
 	pctx.SourcePathVariable("PythonBinaryHostTestConfigTemplate", "build/make/core/python_binary_host_test_config_template.xml")
+	pctx.SourcePathVariable("RavenwoodTestConfigTemplate", "build/make/core/ravenwood_test_config_template.xml")
 	pctx.SourcePathVariable("RustDeviceTestConfigTemplate", "build/make/core/rust_device_test_config_template.xml")
 	pctx.SourcePathVariable("RustHostTestConfigTemplate", "build/make/core/rust_host_test_config_template.xml")
 	pctx.SourcePathVariable("RustDeviceBenchmarkConfigTemplate", "build/make/core/rust_device_benchmark_config_template.xml")
diff --git a/tradefed/providers.go b/tradefed/providers.go
new file mode 100644
index 0000000..66cb625
--- /dev/null
+++ b/tradefed/providers.go
@@ -0,0 +1,26 @@
+package tradefed
+
+import (
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+)
+
+// Output files we need from a base test that we derive from.
+type BaseTestProviderData struct {
+	// data files and apps for android_test
+	InstalledFiles android.Paths
+	// apk for android_test
+	OutputFile android.Path
+	// Either handwritten or generated TF xml.
+	TestConfig android.Path
+	// Other modules we require to be installed to run tests. We expect base to build them.
+	HostRequiredModuleNames []string
+	RequiredModuleNames     []string
+	// List of test suites base uses.
+	TestSuites []string
+	// Used for bases that are Host
+	IsHost bool
+}
+
+var BaseTestProviderKey = blueprint.NewProvider[BaseTestProviderData]()
diff --git a/tradefed/suite_harness/tradefed_binary.go b/tradefed/suite_harness/tradefed_binary.go
index 1ce94bc..96fb354 100644
--- a/tradefed/suite_harness/tradefed_binary.go
+++ b/tradefed/suite_harness/tradefed_binary.go
@@ -35,6 +35,7 @@
 	Short_name                    string
 	Full_name                     string
 	Version                       string
+	Suite_arch                    string
 	Prepend_platform_version_name bool
 }
 
@@ -67,6 +68,7 @@
 				Name:       &genName,
 				Short_name: tfb.Short_name,
 				Full_name:  tfb.Full_name,
+				Suite_arch: tfb.Suite_arch,
 				Version:    version,
 			})
 
@@ -95,6 +97,7 @@
 	Short_name string
 	Full_name  string
 	Version    string
+	Suite_arch string
 }
 
 type tradefedBinaryGen struct {
@@ -127,13 +130,19 @@
 func (tfg *tradefedBinaryGen) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	buildNumberFile := ctx.Config().BuildNumberFile(ctx)
 	outputFile := android.PathForModuleOut(ctx, "test-suite-info.properties")
+
+	arch := strings.ReplaceAll(tfg.properties.Suite_arch, " ", "")
+	if arch == "" {
+		arch = ctx.Config().DevicePrimaryArchType().String()
+	}
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:      tradefedBinaryGenRule,
 		Output:    outputFile,
 		OrderOnly: android.Paths{buildNumberFile},
 		Args: map[string]string{
 			"buildNumberFile": buildNumberFile.String(),
-			"arch":            ctx.Config().DevicePrimaryArchType().String(),
+			"arch":            arch,
 			"name":            tfg.properties.Short_name,
 			"fullname":        tfg.properties.Full_name,
 			"version":         tfg.properties.Version,
diff --git a/tradefed_modules/Android.bp b/tradefed_modules/Android.bp
new file mode 100644
index 0000000..9969ae2
--- /dev/null
+++ b/tradefed_modules/Android.bp
@@ -0,0 +1,21 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-tradefed-modules",
+    pkgPath: "android/soong/tradefed_modules",
+    deps: [
+        "blueprint",
+        "soong-android",
+        "soong-java",
+        "soong-tradefed",
+    ],
+    srcs: [
+        "test_module_config.go",
+    ],
+    testSrcs: [
+        "test_module_config_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/tradefed_modules/test_module_config.go b/tradefed_modules/test_module_config.go
new file mode 100644
index 0000000..b2d5631
--- /dev/null
+++ b/tradefed_modules/test_module_config.go
@@ -0,0 +1,309 @@
+package tradefed_modules
+
+import (
+	"android/soong/android"
+	"android/soong/tradefed"
+	"encoding/json"
+	"fmt"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+func init() {
+	RegisterTestModuleConfigBuildComponents(android.InitRegistrationContext)
+}
+
+// Register the license_kind module type.
+func RegisterTestModuleConfigBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("test_module_config", TestModuleConfigFactory)
+	ctx.RegisterModuleType("test_module_config_host", TestModuleConfigHostFactory)
+}
+
+type testModuleConfigModule struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+	base android.Module
+
+	tradefedProperties
+
+	// Our updated testConfig.
+	testConfig android.OutputPath
+	manifest   android.InstallPath
+	provider   tradefed.BaseTestProviderData
+}
+
+// Host is mostly the same as non-host, just some diffs for AddDependency and
+// AndroidMkEntries, but the properties are the same.
+type testModuleConfigHostModule struct {
+	testModuleConfigModule
+}
+
+// Properties to list in Android.bp for this module.
+type tradefedProperties struct {
+	// Module name of the base test that we will run.
+	Base *string `android:"path,arch_variant"`
+
+	// Tradefed Options to add to tradefed xml when not one of the include or exclude filter or property.
+	// Sample: [{name: "TestRunnerOptionName", value: "OptionValue" }]
+	Options []tradefed.Option
+
+	// List of tradefed include annotations to add to tradefed xml, like "android.platform.test.annotations.Presubmit".
+	// Tests will be restricted to those matching an include_annotation or include_filter.
+	Include_annotations []string
+
+	// List of tradefed include annotations to add to tradefed xml, like "android.support.test.filters.FlakyTest".
+	// Tests matching an exclude annotation or filter will be skipped.
+	Exclude_annotations []string
+
+	// List of tradefed include filters to add to tradefed xml, like "fully.qualified.class#method".
+	// Tests will be restricted to those matching an include_annotation or include_filter.
+	Include_filters []string
+
+	// List of tradefed exclude filters to add to tradefed xml, like "fully.qualified.class#method".
+	// Tests matching an exclude annotation or filter will be skipped.
+	Exclude_filters []string
+
+	// List of compatibility suites (for example "cts", "vts") that the module should be
+	// installed into.
+	Test_suites []string
+}
+
+type dependencyTag struct {
+	blueprint.BaseDependencyTag
+	name string
+}
+
+var (
+	testModuleConfigTag     = dependencyTag{name: "TestModuleConfigBase"}
+	testModuleConfigHostTag = dependencyTag{name: "TestModuleConfigHostBase"}
+	pctx                    = android.NewPackageContext("android/soong/tradefed_modules")
+)
+
+func (m *testModuleConfigModule) InstallInTestcases() bool {
+	return true
+}
+
+func (m *testModuleConfigModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if m.Base == nil {
+		ctx.ModuleErrorf("'base' field must be set to a 'android_test' module.")
+		return
+	}
+	ctx.AddDependency(ctx.Module(), testModuleConfigTag, *m.Base)
+}
+
+// Takes base's Tradefed Config xml file and generates a new one with the test properties
+// appeneded from this module.
+// Rewrite the name of the apk in "test-file-name" to be our module's name, rather than the original one.
+func (m *testModuleConfigModule) fixTestConfig(ctx android.ModuleContext, baseTestConfig android.Path) android.OutputPath {
+	// Test safe to do when no test_runner_options, but check for that earlier?
+	fixedConfig := android.PathForModuleOut(ctx, "test_config_fixer", ctx.ModuleName()+".config")
+	rule := android.NewRuleBuilder(pctx, ctx)
+	command := rule.Command().BuiltTool("test_config_fixer").Input(baseTestConfig).Output(fixedConfig)
+	options := m.composeOptions()
+	if len(options) == 0 {
+		ctx.ModuleErrorf("Test options must be given when using test_module_config. Set include/exclude filter or annotation.")
+	}
+	xmlTestModuleConfigSnippet, _ := json.Marshal(options)
+	escaped := proptools.NinjaAndShellEscape(string(xmlTestModuleConfigSnippet))
+	command.FlagWithArg("--test-file-name=", ctx.ModuleName()+".apk").
+		FlagWithArg("--orig-test-file-name=", *m.tradefedProperties.Base+".apk").
+		FlagWithArg("--test-runner-options=", escaped)
+	rule.Build("fix_test_config", "fix test config")
+	return fixedConfig.OutputPath
+}
+
+// Convert --exclude_filters: ["filter1", "filter2"] ->
+// [ Option{Name: "exclude-filters", Value: "filter1"}, Option{Name: "exclude-filters", Value: "filter2"},
+// ... + include + annotations ]
+func (m *testModuleConfigModule) composeOptions() []tradefed.Option {
+	options := m.Options
+	for _, e := range m.Exclude_filters {
+		options = append(options, tradefed.Option{Name: "exclude-filter", Value: e})
+	}
+	for _, i := range m.Include_filters {
+		options = append(options, tradefed.Option{Name: "include-filter", Value: i})
+	}
+	for _, e := range m.Exclude_annotations {
+		options = append(options, tradefed.Option{Name: "exclude-annotation", Value: e})
+	}
+	for _, i := range m.Include_annotations {
+		options = append(options, tradefed.Option{Name: "include-annotation", Value: i})
+	}
+	return options
+}
+
+// Files to write and where they come from:
+// 1) test_module_config.manifest
+//   - Leave a trail of where we got files from in case other tools need it.
+//
+// 2) $Module.config
+//   - comes from base's module.config (AndroidTest.xml), and then we add our test_options.
+//     provider.TestConfig
+//     [rules via soong_app_prebuilt]
+//
+// 3) $ARCH/$Module.apk
+//   - comes from base
+//     provider.OutputFile
+//     [rules via soong_app_prebuilt]
+//
+// 4) [bases data]
+//   - We copy all of bases data (like helper apks) to our install directory too.
+//     Since we call AndroidMkEntries on base, it will write out LOCAL_COMPATIBILITY_SUPPORT_FILES
+//     with this data and app_prebuilt.mk will generate the rules to copy it from base.
+//     We have no direct rules here to add to ninja.
+//
+// If we change to symlinks, this all needs to change.
+func (m *testModuleConfigModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	m.validateBase(ctx, &testModuleConfigTag, "android_test", false)
+	m.generateManifestAndConfig(ctx)
+
+}
+
+// Ensure at least one test_suite is listed.  Ideally it should be general-tests
+// or device-tests, whichever is listed in base and prefer general-tests if both are listed.
+// However this is not enforced yet.
+//
+// Returns true if okay and reports errors via ModuleErrorf.
+func (m *testModuleConfigModule) validateTestSuites(ctx android.ModuleContext) bool {
+	if len(m.tradefedProperties.Test_suites) == 0 {
+		ctx.ModuleErrorf("At least one test-suite must be set or this won't run. Use \"general-tests\" or \"device-tests\"")
+		return false
+	}
+
+	return true
+}
+
+func TestModuleConfigFactory() android.Module {
+	module := &testModuleConfigModule{}
+
+	module.AddProperties(&module.tradefedProperties)
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+
+	return module
+}
+
+func TestModuleConfigHostFactory() android.Module {
+	module := &testModuleConfigHostModule{}
+
+	module.AddProperties(&module.tradefedProperties)
+	android.InitAndroidMultiTargetsArchModule(module, android.HostSupported, android.MultilibCommon)
+	android.InitDefaultableModule(module)
+
+	return module
+}
+
+// Implements android.AndroidMkEntriesProvider
+var _ android.AndroidMkEntriesProvider = (*testModuleConfigModule)(nil)
+
+func (m *testModuleConfigModule) AndroidMkEntries() []android.AndroidMkEntries {
+	// We rely on base writing LOCAL_COMPATIBILITY_SUPPORT_FILES for its data files
+	entriesList := m.base.(android.AndroidMkEntriesProvider).AndroidMkEntries()
+	entries := &entriesList[0]
+	entries.OutputFile = android.OptionalPathForPath(m.provider.OutputFile)
+	entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+		entries.SetString("LOCAL_MODULE", m.Name()) //  out module name, not base's
+
+		// Out update config file with extra options.
+		entries.SetPath("LOCAL_FULL_TEST_CONFIG", m.testConfig)
+		entries.SetString("LOCAL_MODULE_TAGS", "tests")
+
+		// Don't append to base's test-suites, only use the ones we define, so clear it before
+		// appending to it.
+		entries.SetString("LOCAL_COMPATIBILITY_SUITE", "")
+		entries.AddCompatibilityTestSuites(m.tradefedProperties.Test_suites...)
+
+		if len(m.provider.HostRequiredModuleNames) > 0 {
+			entries.AddStrings("LOCAL_HOST_REQUIRED_MODULES", m.provider.HostRequiredModuleNames...)
+		}
+		if len(m.provider.RequiredModuleNames) > 0 {
+			entries.AddStrings("LOCAL_REQUIRED_MODULES", m.provider.RequiredModuleNames...)
+		}
+
+		if m.provider.IsHost == false {
+			// Not needed for jar_host_test
+			//
+			// Clear the JNI symbols because they belong to base not us. Either transform the names in the string
+			// or clear the variable because we don't need it, we are copying bases libraries not generating
+			// new ones.
+			entries.SetString("LOCAL_SOONG_JNI_LIBS_SYMBOLS", "")
+		}
+	})
+	return entriesList
+}
+
+func (m *testModuleConfigHostModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if m.Base == nil {
+		ctx.ModuleErrorf("'base' field must be set to a 'java_test_host' module")
+		return
+	}
+	ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), testModuleConfigHostTag, *m.Base)
+}
+
+// File to write:
+// 1) out/host/linux-x86/testcases/derived-module/test_module_config.manifest # contains base's name.
+// 2) out/host/linux-x86/testcases/derived-module/derived-module.config  # Update AnroidTest.xml
+// 3) out/host/linux-x86/testcases/derived-module/base.jar
+//   - written via soong_java_prebuilt.mk
+//
+// 4) out/host/linux-x86/testcases/derived-module/* # data dependencies from base.
+//   - written via soong_java_prebuilt.mk
+func (m *testModuleConfigHostModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	m.validateBase(ctx, &testModuleConfigHostTag, "java_test_host", true)
+	m.generateManifestAndConfig(ctx)
+}
+
+// Ensure the base listed is the right type by checking that we get the expected provider data.
+// Returns false on errors and the context is updated with an error indicating the baseType expected.
+func (m *testModuleConfigModule) validateBase(ctx android.ModuleContext, depTag *dependencyTag, baseType string, baseShouldBeHost bool) {
+	ctx.VisitDirectDepsWithTag(*depTag, func(dep android.Module) {
+		if provider, ok := android.OtherModuleProvider(ctx, dep, tradefed.BaseTestProviderKey); ok {
+			if baseShouldBeHost == provider.IsHost {
+				m.base = dep
+				m.provider = provider
+			} else {
+				if baseShouldBeHost {
+					ctx.ModuleErrorf("'android_test' module used as base, but 'java_test_host' expected.")
+				} else {
+					ctx.ModuleErrorf("'java_test_host' module used as base, but 'android_test' expected.")
+				}
+			}
+		} else {
+			ctx.ModuleErrorf("'%s' module used as base but it is not a '%s' module.", *m.Base, baseType)
+		}
+	})
+}
+
+// Actions to write:
+//  1. manifest file to testcases dir
+//  2. New Module.config / AndroidTest.xml file with our options.
+func (m *testModuleConfigModule) generateManifestAndConfig(ctx android.ModuleContext) {
+	// Keep before early returns.
+	android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
+		TestOnly:       true,
+		TopLevelTarget: true,
+	})
+
+	if !m.validateTestSuites(ctx) {
+		return
+	}
+	// Ensure the base provider is accurate
+	if m.provider.TestConfig == nil {
+		return
+	}
+
+	// 1) A manifest file listing the base, write text to a tiny file.
+	installDir := android.PathForModuleInstall(ctx, ctx.ModuleName())
+	manifest := android.PathForModuleOut(ctx, "test_module_config.manifest")
+	android.WriteFileRule(ctx, manifest, fmt.Sprintf("{%q: %q}", "base", *m.tradefedProperties.Base))
+	// build/soong/android/androidmk.go has this comment:
+	//    Assume the primary install file is last
+	// so we need to Install our file last.
+	ctx.InstallFile(installDir, manifest.Base(), manifest)
+
+	// 2) Module.config / AndroidTest.xml
+	m.testConfig = m.fixTestConfig(ctx, m.provider.TestConfig)
+}
+
+var _ android.AndroidMkEntriesProvider = (*testModuleConfigHostModule)(nil)
diff --git a/tradefed_modules/test_module_config_test.go b/tradefed_modules/test_module_config_test.go
new file mode 100644
index 0000000..b2049b1
--- /dev/null
+++ b/tradefed_modules/test_module_config_test.go
@@ -0,0 +1,400 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package tradefed_modules
+
+import (
+	"android/soong/android"
+	"android/soong/java"
+	"strconv"
+	"strings"
+	"testing"
+
+	"github.com/google/blueprint"
+)
+
+const bp = `
+		android_app {
+			name: "foo",
+			srcs: ["a.java"],
+			sdk_version: "current",
+		}
+
+                android_test_helper_app {
+                        name: "HelperApp",
+                        srcs: ["helper.java"],
+                }
+
+		android_test {
+			name: "base",
+			sdk_version: "current",
+                        data: [":HelperApp", "data/testfile"],
+		}
+
+                test_module_config {
+                        name: "derived_test",
+                        base: "base",
+                        exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"],
+                        include_annotations: ["android.platform.test.annotations.LargeTest"],
+                        test_suites: ["general-tests"],
+                }
+
+`
+
+// Ensure we create files needed and set the AndroidMkEntries needed
+func TestModuleConfigAndroidTest(t *testing.T) {
+
+	ctx := android.GroupFixturePreparers(
+		java.PrepareForTestWithJavaDefaultModules,
+		android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+	).RunTestWithBp(t, bp)
+
+	derived := ctx.ModuleForTests("derived_test", "android_common")
+	// Assert there are rules to create these files.
+	derived.Output("test_module_config.manifest")
+	derived.Output("test_config_fixer/derived_test.config")
+
+	// Ensure some basic rules exist.
+	ctx.ModuleForTests("base", "android_common").Output("package-res.apk")
+	entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, derived.Module())[0]
+
+	// Ensure some entries from base are there, specifically support files for data and helper apps.
+	assertEntryPairValues(t, entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"], []string{"HelperApp.apk", "data/testfile"})
+
+	// And some new derived entries are there.
+	android.AssertArrayString(t, "", entries.EntryMap["LOCAL_MODULE_TAGS"], []string{"tests"})
+
+	// And ones we override
+	android.AssertArrayString(t, "", entries.EntryMap["LOCAL_SOONG_JNI_LIBS_SYMBOLS"], []string{""})
+
+	android.AssertStringMatches(t, "", entries.EntryMap["LOCAL_FULL_TEST_CONFIG"][0], "derived_test/android_common/test_config_fixer/derived_test.config")
+}
+
+// Make sure we call test-config-fixer with the right args.
+func TestModuleConfigOptions(t *testing.T) {
+
+	ctx := android.GroupFixturePreparers(
+		java.PrepareForTestWithJavaDefaultModules,
+		android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+	).RunTestWithBp(t, bp)
+
+	// Check that we generate a rule to make a new AndroidTest.xml/Module.config file.
+	derived := ctx.ModuleForTests("derived_test", "android_common")
+	rule_cmd := derived.Rule("fix_test_config").RuleParams.Command
+	android.AssertStringDoesContain(t, "Bad FixConfig rule inputs", rule_cmd,
+		`--test-file-name=derived_test.apk --orig-test-file-name=base.apk --test-runner-options='[{"Name":"exclude-filter","Key":"","Value":"android.test.example.devcodelab.DevCodelabTest#testHelloFail"},{"Name":"include-annotation","Key":"","Value":"android.platform.test.annotations.LargeTest"}]'`)
+}
+
+// Ensure we error for a base we don't support.
+func TestModuleConfigWithHostBaseShouldFailWithExplicitMessage(t *testing.T) {
+	badBp := `
+		java_test_host {
+			name: "base",
+                        srcs: ["a.java"],
+		}
+
+                test_module_config {
+                        name: "derived_test",
+                        base: "base",
+                        exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"],
+                        include_annotations: ["android.platform.test.annotations.LargeTest"],
+                        test_suites: ["general-tests"],
+                }`
+
+	android.GroupFixturePreparers(
+		java.PrepareForTestWithJavaDefaultModules,
+		android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+	).ExtendWithErrorHandler(
+		android.FixtureExpectsAtLeastOneErrorMatchingPattern("'java_test_host' module used as base, but 'android_test' expected")).
+		RunTestWithBp(t, badBp)
+}
+
+func TestModuleConfigBadBaseShouldFailWithGeneralMessage(t *testing.T) {
+	badBp := `
+		java_library {
+			name: "base",
+                        srcs: ["a.java"],
+		}
+
+                test_module_config {
+                        name: "derived_test",
+                        base: "base",
+                        exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"],
+                        include_annotations: ["android.platform.test.annotations.LargeTest"],
+                        test_suites: ["general-tests"],
+                }`
+
+	android.GroupFixturePreparers(
+		java.PrepareForTestWithJavaDefaultModules,
+		android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+	).ExtendWithErrorHandler(
+		android.FixtureExpectsOneErrorPattern("'base' module used as base but it is not a 'android_test' module.")).
+		RunTestWithBp(t, badBp)
+}
+
+func TestModuleConfigNoBaseShouldFail(t *testing.T) {
+	badBp := `
+		java_library {
+			name: "base",
+                        srcs: ["a.java"],
+		}
+
+                test_module_config {
+                        name: "derived_test",
+                        exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"],
+                        include_annotations: ["android.platform.test.annotations.LargeTest"],
+                        test_suites: ["general-tests"],
+                }`
+
+	android.GroupFixturePreparers(
+		java.PrepareForTestWithJavaDefaultModules,
+		android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+	).ExtendWithErrorHandler(
+		android.FixtureExpectsOneErrorPattern("'base' field must be set to a 'android_test' module.")).
+		RunTestWithBp(t, badBp)
+}
+
+// Ensure we error for a base we don't support.
+func TestModuleConfigNoFiltersOrAnnotationsShouldFail(t *testing.T) {
+	badBp := `
+		android_test {
+			name: "base",
+			sdk_version: "current",
+                        srcs: ["a.java"],
+		}
+
+                test_module_config {
+                        name: "derived_test",
+                        base: "base",
+                        test_suites: ["general-tests"],
+                }`
+
+	ctx := android.GroupFixturePreparers(
+		java.PrepareForTestWithJavaDefaultModules,
+		android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+	).ExtendWithErrorHandler(
+		android.FixtureExpectsAtLeastOneErrorMatchingPattern("Test options must be given")).
+		RunTestWithBp(t, badBp)
+
+	ctx.ModuleForTests("derived_test", "android_common")
+}
+
+func TestModuleConfigMultipleDerivedTestsWriteDistinctMakeEntries(t *testing.T) {
+	multiBp := `
+		android_test {
+			name: "base",
+			sdk_version: "current",
+                        srcs: ["a.java"],
+		}
+
+                test_module_config {
+                        name: "derived_test",
+                        base: "base",
+                        include_annotations: ["android.platform.test.annotations.LargeTest"],
+                        test_suites: ["general-tests"],
+                }
+
+                test_module_config {
+                        name: "another_derived_test",
+                        base: "base",
+                        include_annotations: ["android.platform.test.annotations.LargeTest"],
+                        test_suites: ["general-tests"],
+                }`
+
+	ctx := android.GroupFixturePreparers(
+		java.PrepareForTestWithJavaDefaultModules,
+		android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+	).RunTestWithBp(t, multiBp)
+
+	{
+		derived := ctx.ModuleForTests("derived_test", "android_common")
+		entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, derived.Module())[0]
+		// All these should be the same in both derived tests
+		assertEntryPairValues(t, entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"], []string{"HelperApp.apk", "data/testfile"})
+		android.AssertArrayString(t, "", entries.EntryMap["LOCAL_SOONG_JNI_LIBS_SYMBOLS"], []string{""})
+		// Except this one, which points to the updated tradefed xml file.
+		android.AssertStringMatches(t, "", entries.EntryMap["LOCAL_FULL_TEST_CONFIG"][0], "derived_test/android_common/test_config_fixer/derived_test.config")
+		// And this one, the module name.
+		android.AssertArrayString(t, "", entries.EntryMap["LOCAL_MODULE"], []string{"derived_test"})
+	}
+
+	{
+		derived := ctx.ModuleForTests("another_derived_test", "android_common")
+		entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, derived.Module())[0]
+		// All these should be the same in both derived tests
+		assertEntryPairValues(t, entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"], []string{"HelperApp.apk", "data/testfile"})
+		android.AssertArrayString(t, "", entries.EntryMap["LOCAL_SOONG_JNI_LIBS_SYMBOLS"], []string{""})
+		// Except this one, which points to the updated tradefed xml file.
+		android.AssertStringMatches(t, "", entries.EntryMap["LOCAL_FULL_TEST_CONFIG"][0], "another_derived_test/android_common/test_config_fixer/another_derived_test.config")
+		// And this one, the module name.
+		android.AssertArrayString(t, "", entries.EntryMap["LOCAL_MODULE"], []string{"another_derived_test"})
+	}
+}
+
+// Test_module_config_host rule is allowed to depend on java_test_host
+func TestModuleConfigHostBasics(t *testing.T) {
+	bp := `
+               java_test_host {
+                        name: "base",
+                        srcs: ["a.java"],
+                        test_suites: ["suiteA", "general-tests",  "suiteB"],
+               }
+
+                test_module_config_host {
+                        name: "derived_test",
+                        base: "base",
+                        exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"],
+                        include_annotations: ["android.platform.test.annotations.LargeTest"],
+                        test_suites: ["general-tests"],
+                }`
+
+	ctx := android.GroupFixturePreparers(
+		java.PrepareForTestWithJavaDefaultModules,
+		android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+	).RunTestWithBp(t, bp)
+
+	variant := ctx.Config.BuildOS.String() + "_common"
+	derived := ctx.ModuleForTests("derived_test", variant)
+	mod := derived.Module().(*testModuleConfigHostModule)
+	allEntries := android.AndroidMkEntriesForTest(t, ctx.TestContext, mod)
+	entries := allEntries[0]
+	android.AssertArrayString(t, "", entries.EntryMap["LOCAL_MODULE"], []string{"derived_test"})
+
+	if !mod.Host() {
+		t.Errorf("host bit is not set for a java_test_host module.")
+	}
+	actualData, _ := strconv.ParseBool(entries.EntryMap["LOCAL_IS_UNIT_TEST"][0])
+	android.AssertBoolEquals(t, "LOCAL_IS_UNIT_TEST", true, actualData)
+
+}
+
+// When you pass an 'android_test' as base, the warning message is a bit obscure,
+// talking about variants, but it is something.  Ideally we could do better.
+func TestModuleConfigHostBadBaseShouldFailWithVariantWarning(t *testing.T) {
+	badBp := `
+		android_test {
+			name: "base",
+			sdk_version: "current",
+                        srcs: ["a.java"],
+		}
+
+                test_module_config_host {
+                        name: "derived_test",
+                        base: "base",
+                        exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"],
+                        include_annotations: ["android.platform.test.annotations.LargeTest"],
+                }`
+
+	android.GroupFixturePreparers(
+		java.PrepareForTestWithJavaDefaultModules,
+		android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+	).ExtendWithErrorHandler(
+		android.FixtureExpectsAtLeastOneErrorMatchingPattern("missing variant")).
+		RunTestWithBp(t, badBp)
+}
+
+func TestModuleConfigHostNeedsATestSuite(t *testing.T) {
+	badBp := `
+		java_test_host {
+			name: "base",
+                        srcs: ["a.java"],
+		}
+
+                test_module_config_host {
+                        name: "derived_test",
+                        base: "base",
+                        exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"],
+                        include_annotations: ["android.platform.test.annotations.LargeTest"],
+                }`
+
+	android.GroupFixturePreparers(
+		java.PrepareForTestWithJavaDefaultModules,
+		android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+	).ExtendWithErrorHandler(
+		android.FixtureExpectsAtLeastOneErrorMatchingPattern("At least one test-suite must be set")).
+		RunTestWithBp(t, badBp)
+}
+
+func TestTestOnlyProvider(t *testing.T) {
+	t.Parallel()
+	ctx := android.GroupFixturePreparers(
+		java.PrepareForTestWithJavaDefaultModules,
+		android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents),
+	).RunTestWithBp(t, `
+                // These should be test-only
+                test_module_config_host {
+                        name: "host-derived-test",
+                        base: "host-base",
+                        exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"],
+                        include_annotations: ["android.platform.test.annotations.LargeTest"],
+                        test_suites: ["general-tests"],
+                }
+
+                test_module_config {
+                        name: "derived-test",
+                        base: "base",
+                        exclude_filters: ["android.test.example.devcodelab.DevCodelabTest#testHelloFail"],
+                        include_annotations: ["android.platform.test.annotations.LargeTest"],
+                        test_suites: ["general-tests"],
+                }
+
+		android_test {
+			name: "base",
+			sdk_version: "current",
+                        data: ["data/testfile"],
+		}
+
+		java_test_host {
+			name: "host-base",
+                        srcs: ["a.java"],
+                        test_suites: ["general-tests"],
+		}`,
+	)
+
+	// Visit all modules and ensure only the ones that should
+	// marked as test-only are marked as test-only.
+
+	actualTestOnly := []string{}
+	ctx.VisitAllModules(func(m blueprint.Module) {
+		if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, android.TestOnlyProviderKey); ok {
+			if provider.TestOnly {
+				actualTestOnly = append(actualTestOnly, m.Name())
+			}
+		}
+	})
+	expectedTestOnlyModules := []string{
+		"host-derived-test",
+		"derived-test",
+		// android_test and java_test_host are tests too.
+		"host-base",
+		"base",
+	}
+
+	notEqual, left, right := android.ListSetDifference(expectedTestOnlyModules, actualTestOnly)
+	if notEqual {
+		t.Errorf("test-only: Expected but not found: %v, Found but not expected: %v", left, right)
+	}
+}
+
+// Use for situations where the entries map contains pairs:  [srcPath:installedPath1, srcPath2:installedPath2]
+// and we want to compare the RHS of the pairs, i.e. installedPath1, installedPath2
+func assertEntryPairValues(t *testing.T, actual []string, expected []string) {
+	for i, e := range actual {
+		parts := strings.Split(e, ":")
+		if len(parts) != 2 {
+			t.Errorf("Expected entry to have a value delimited by :, received: %s", e)
+			return
+		}
+		android.AssertStringEquals(t, "", parts[1], expected[i])
+	}
+}
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index 959ae4c..ee286f6 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -35,6 +35,7 @@
         "blueprint",
         "blueprint-bootstrap",
         "blueprint-microfactory",
+        "soong-android",
         "soong-finder",
         "soong-remoteexec",
         "soong-shared",
@@ -46,7 +47,7 @@
         "soong-ui-tracer",
     ],
     srcs: [
-        "bazel_metrics.go",
+        "androidmk_denylist.go",
         "build.go",
         "cleanbuild.go",
         "config.go",
@@ -75,7 +76,6 @@
         "proc_sync_test.go",
         "rbe_test.go",
         "staging_snapshot_test.go",
-        "upload_test.go",
         "util_test.go",
     ],
     darwin: {
diff --git a/ui/build/androidmk_denylist.go b/ui/build/androidmk_denylist.go
new file mode 100644
index 0000000..a29f413
--- /dev/null
+++ b/ui/build/androidmk_denylist.go
@@ -0,0 +1,47 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package build
+
+import (
+	"strings"
+)
+
+var androidmk_denylist []string = []string{
+	"chained_build_config/",
+	"cts/",
+	"dalvik/",
+	"developers/",
+	"frameworks/",
+	// Do not block other directories in kernel/, see b/319658303.
+	"kernel/configs/",
+	"kernel/prebuilts/",
+	"kernel/tests/",
+	"libcore/",
+	"libnativehelper/",
+	"pdk/",
+	// Add back toolchain/ once defensive Android.mk files are removed
+	//"toolchain/",
+}
+
+func blockAndroidMks(ctx Context, androidMks []string) {
+	for _, mkFile := range androidMks {
+		for _, d := range androidmk_denylist {
+			if strings.HasPrefix(mkFile, d) {
+				ctx.Fatalf("Found blocked Android.mk file: %s. "+
+					"Please see androidmk_denylist.go for the blocked directories and contact build system team if the file should not be blocked.", mkFile)
+			}
+		}
+	}
+}
diff --git a/ui/build/bazel_metrics.go b/ui/build/bazel_metrics.go
deleted file mode 100644
index 3f9fbb1..0000000
--- a/ui/build/bazel_metrics.go
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2023 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//	http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package build
-
-// This file contains functionality to parse bazel profile data into
-// a bazel_metrics proto, defined in build/soong/ui/metrics/bazel_metrics_proto
-// These metrics are later uploaded in upload.go
-
-import (
-	"bufio"
-	"os"
-	"strconv"
-	"strings"
-
-	"android/soong/shared"
-	"google.golang.org/protobuf/proto"
-
-	bazel_metrics_proto "android/soong/ui/metrics/bazel_metrics_proto"
-)
-
-func parseTimingToNanos(str string) int64 {
-	millisString := removeDecimalPoint(str)
-	timingMillis, _ := strconv.ParseInt(millisString, 10, 64)
-	return timingMillis * 1000000
-}
-
-func parsePercentageToTenThousandths(str string) int32 {
-	percentageString := removeDecimalPoint(str)
-	//remove the % at the end of the string
-	percentage := strings.ReplaceAll(percentageString, "%", "")
-	percentagePortion, _ := strconv.ParseInt(percentage, 10, 32)
-	return int32(percentagePortion)
-}
-
-func removeDecimalPoint(numString string) string {
-	// The format is always 0.425 or 10.425
-	return strings.ReplaceAll(numString, ".", "")
-}
-
-func parseTotal(line string) int64 {
-	words := strings.Fields(line)
-	timing := words[3]
-	return parseTimingToNanos(timing)
-}
-
-func parsePhaseTiming(line string) bazel_metrics_proto.PhaseTiming {
-	words := strings.Fields(line)
-	getPhaseNameAndTimingAndPercentage := func([]string) (string, int64, int32) {
-		// Sample lines include:
-		// Total launch phase time   0.011 s    2.59%
-		// Total target pattern evaluation phase time  0.011 s    2.59%
-		var beginning int
-		var end int
-		for ind, word := range words {
-			if word == "Total" {
-				beginning = ind + 1
-			} else if beginning > 0 && word == "phase" {
-				end = ind
-				break
-			}
-		}
-		phaseName := strings.Join(words[beginning:end], " ")
-
-		// end is now "phase" - advance by 2 for timing and 4 for percentage
-		percentageString := words[end+4]
-		timingString := words[end+2]
-		timing := parseTimingToNanos(timingString)
-		percentagePortion := parsePercentageToTenThousandths(percentageString)
-		return phaseName, timing, percentagePortion
-	}
-
-	phaseName, timing, portion := getPhaseNameAndTimingAndPercentage(words)
-	phaseTiming := bazel_metrics_proto.PhaseTiming{}
-	phaseTiming.DurationNanos = &timing
-	phaseTiming.PortionOfBuildTime = &portion
-
-	phaseTiming.PhaseName = &phaseName
-	return phaseTiming
-}
-
-// This method takes a file created by bazel's --analyze-profile mode and
-// writes bazel metrics data to the provided filepath.
-func ProcessBazelMetrics(bazelProfileFile string, bazelMetricsFile string, ctx Context, config Config) {
-	if bazelProfileFile == "" {
-		return
-	}
-
-	readBazelProto := func(filepath string) bazel_metrics_proto.BazelMetrics {
-		//serialize the proto, write it
-		bazelMetrics := bazel_metrics_proto.BazelMetrics{}
-
-		file, err := os.ReadFile(filepath)
-		if err != nil {
-			ctx.Fatalln("Error reading metrics file\n", err)
-		}
-
-		scanner := bufio.NewScanner(strings.NewReader(string(file)))
-		scanner.Split(bufio.ScanLines)
-
-		var phaseTimings []*bazel_metrics_proto.PhaseTiming
-		for scanner.Scan() {
-			line := scanner.Text()
-			if strings.HasPrefix(line, "Total run time") {
-				total := parseTotal(line)
-				bazelMetrics.Total = &total
-			} else if strings.HasPrefix(line, "Total") {
-				phaseTiming := parsePhaseTiming(line)
-				phaseTimings = append(phaseTimings, &phaseTiming)
-			}
-		}
-		bazelMetrics.PhaseTimings = phaseTimings
-		bazelMetrics.BesId = proto.String(config.besId)
-
-		return bazelMetrics
-	}
-
-	if _, err := os.Stat(bazelProfileFile); err != nil {
-		// We can assume bazel didn't run if the profile doesn't exist
-		return
-	}
-	bazelProto := readBazelProto(bazelProfileFile)
-	bazelProto.ExitCode = proto.Int32(config.bazelExitCode)
-	shared.Save(&bazelProto, bazelMetricsFile)
-}
diff --git a/ui/build/build.go b/ui/build/build.go
index 14d23a7..9a9eccd 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -15,11 +15,13 @@
 package build
 
 import (
+	"fmt"
 	"io/ioutil"
 	"os"
 	"path/filepath"
 	"sync"
 	"text/template"
+	"time"
 
 	"android/soong/ui/metrics"
 )
@@ -29,6 +31,7 @@
 func SetupOutDir(ctx Context, config Config) {
 	ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "Android.mk"))
 	ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "CleanSpec.mk"))
+	ensureEmptyDirectoriesExist(ctx, config.TempDir())
 
 	// Potentially write a marker file for whether kati is enabled. This is used by soong_build to
 	// potentially run the AndroidMk singleton and postinstall commands.
@@ -56,6 +59,31 @@
 	} else {
 		ctx.Fatalln("Missing BUILD_DATETIME_FILE")
 	}
+
+	// BUILD_NUMBER should be set to the source control value that
+	// represents the current state of the source code.  E.g., a
+	// perforce changelist number or a git hash.  Can be an arbitrary string
+	// (to allow for source control that uses something other than numbers),
+	// but must be a single word and a valid file name.
+	//
+	// If no BUILD_NUMBER is set, create a useful "I am an engineering build
+	// from this date/time" value.  Make it start with a non-digit so that
+	// anyone trying to parse it as an integer will probably get "0".
+	buildNumber, ok := config.environ.Get("BUILD_NUMBER")
+	if ok {
+		writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", buildNumber)
+	} else {
+		var username string
+		if username, ok = config.environ.Get("BUILD_USERNAME"); !ok {
+			ctx.Fatalln("Missing BUILD_USERNAME")
+		}
+		buildNumber = fmt.Sprintf("eng.%.6s.%s", username, time.Now().Format("20060102.150405" /* YYYYMMDD.HHMMSS */))
+		writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", username)
+	}
+	// Write the build number to a file so it can be read back in
+	// without changing the command line every time.  Avoids rebuilds
+	// when using ninja.
+	writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_number.txt", buildNumber)
 }
 
 var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
@@ -107,22 +135,6 @@
 	RunBuildTests  = 1 << iota
 )
 
-// checkBazelMode fails the build if there are conflicting arguments for which bazel
-// build mode to use.
-func checkBazelMode(ctx Context, config Config) {
-	count := 0
-	if config.bazelProdMode {
-		count++
-	}
-	if config.bazelStagingMode {
-		count++
-	}
-	if count > 1 {
-		ctx.Fatalln("Conflicting bazel mode.\n" +
-			"Do not specify more than one of --bazel-mode and --bazel-mode-staging ")
-	}
-}
-
 // checkProblematicFiles fails the build if existing Android.mk or CleanSpec.mk files are found at the root of the tree.
 func checkProblematicFiles(ctx Context) {
 	files := []string{"Android.mk", "CleanSpec.mk"}
@@ -234,8 +246,6 @@
 
 	defer waitForDist(ctx)
 
-	checkBazelMode(ctx, config)
-
 	// checkProblematicFiles aborts the build if Android.mk or CleanSpec.mk are found at the root of the tree.
 	checkProblematicFiles(ctx)
 
@@ -246,8 +256,6 @@
 	// checkCaseSensitivity issues a warning if a case-insensitive file system is being used.
 	checkCaseSensitivity(ctx, config)
 
-	ensureEmptyDirectoriesExist(ctx, config.TempDir())
-
 	SetupPath(ctx, config)
 
 	what := evaluateWhatToRun(config, ctx.Verboseln)
@@ -257,11 +265,16 @@
 	}
 
 	rbeCh := make(chan bool)
+	var rbePanic any
 	if config.StartRBE() {
 		cleanupRBELogsDir(ctx, config)
+		checkRBERequirements(ctx, config)
 		go func() {
+			defer func() {
+				rbePanic = recover()
+				close(rbeCh)
+			}()
 			startRBE(ctx, config)
-			close(rbeCh)
 		}()
 		defer DumpRBEMetrics(ctx, config, filepath.Join(config.LogsDir(), "rbe_metrics.pb"))
 	} else {
@@ -319,6 +332,11 @@
 	}
 
 	<-rbeCh
+	if rbePanic != nil {
+		// If there was a ctx.Fatal in startRBE, rethrow it.
+		panic(rbePanic)
+	}
+
 	if what&RunNinja != 0 {
 		if what&RunKati != 0 {
 			installCleanIfNecessary(ctx, config)
diff --git a/ui/build/config.go b/ui/build/config.go
index 5d1505a..7426a78 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -22,6 +22,7 @@
 	"math/rand"
 	"os"
 	"os/exec"
+	"os/user"
 	"path/filepath"
 	"runtime"
 	"strconv"
@@ -30,6 +31,7 @@
 	"time"
 
 	"android/soong/shared"
+	"android/soong/ui/metrics"
 
 	"google.golang.org/protobuf/proto"
 
@@ -70,12 +72,9 @@
 	checkbuild               bool
 	dist                     bool
 	jsonModuleGraph          bool
-	apiBp2build              bool // Generate BUILD files for Soong modules that contribute APIs
-	bp2build                 bool
 	queryview                bool
 	reportMkMetrics          bool // Collect and report mk2bp migration progress metrics.
 	soongDocs                bool
-	multitreeBuild           bool // This is a multitree build.
 	skipConfig               bool
 	skipKati                 bool
 	skipKatiNinja            bool
@@ -85,10 +84,8 @@
 	searchApiDir             bool // Scan the Android.bp files generated in out/api_surfaces
 	skipMetricsUpload        bool
 	buildStartedTime         int64 // For metrics-upload-only - manually specify a build-started time
-	buildFromTextStub        bool
-	ensureAllowlistIntegrity bool   // For CI builds - make sure modules are mixed-built
-	bazelExitCode            int32  // For b runs - necessary for updating NonZeroExit
-	besId                    string // For b runs, to identify the BuildEventService logs
+	buildFromSourceStub      bool
+	ensureAllowlistIntegrity bool // For CI builds - make sure modules are mixed-built
 
 	// From the product config
 	katiArgs        []string
@@ -107,21 +104,21 @@
 
 	pathReplaced bool
 
-	bazelProdMode    bool
-	bazelStagingMode bool
-
 	// Set by multiproduct_kati
 	emptyNinjaFile bool
 
 	metricsUploader string
 
-	bazelForceEnabledModules string
-
 	includeTags    []string
 	sourceRootDirs []string
 
 	// Data source to write ninja weight list
 	ninjaWeightListSource NinjaWeightListSource
+
+	// This file is a detailed dump of all soong-defined modules for debugging purposes.
+	// There's quite a bit of overlap with module-info.json and soong module graph. We
+	// could consider merging them.
+	moduleDebugFile string
 }
 
 type NinjaWeightListSource uint
@@ -205,34 +202,6 @@
 	return nil
 }
 
-func defaultBazelProdMode(cfg *configImpl) bool {
-	// Environment flag to disable Bazel for users which experience
-	// broken bazel-handled builds, or significant performance regressions.
-	if cfg.IsBazelMixedBuildForceDisabled() {
-		return false
-	}
-	// Darwin-host builds are currently untested with Bazel.
-	if runtime.GOOS == "darwin" {
-		return false
-	}
-	return true
-}
-
-func UploadOnlyConfig(ctx Context, args ...string) Config {
-	ret := &configImpl{
-		environ:       OsEnvironment(),
-		sandboxConfig: &SandboxConfig{},
-	}
-	ret.parseArgs(ctx, args)
-	srcDir := absPath(ctx, ".")
-	bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
-	if err := loadEnvConfig(ctx, ret, bc); err != nil {
-		ctx.Fatalln("Failed to parse env config files: %v", err)
-	}
-	ret.metricsUploader = GetMetricsUploader(srcDir, ret.environ)
-	return Config{ret}
-}
-
 func NewConfig(ctx Context, args ...string) Config {
 	ret := &configImpl{
 		environ:               OsEnvironment(),
@@ -240,6 +209,11 @@
 		ninjaWeightListSource: DEFAULT,
 	}
 
+	// Skip soong tests by default on Linux
+	if runtime.GOOS == "linux" {
+		ret.skipSoongTests = true
+	}
+
 	// Default matching ninja
 	ret.parallel = runtime.NumCPU() + 2
 	ret.keepGoing = 1
@@ -303,6 +277,10 @@
 		ret.sandboxConfig.SetSrcDirIsRO(srcDirIsWritable == "false")
 	}
 
+	if os.Getenv("GENERATE_SOONG_DEBUG") == "true" {
+		ret.moduleDebugFile, _ = filepath.Abs(shared.JoinPath(ret.SoongOutDir(), "soong-debug-info.json"))
+	}
+
 	ret.environ.Unset(
 		// We're already using it
 		"USE_SOONG_UI",
@@ -355,6 +333,9 @@
 		"ANDROID_DEV_SCRIPTS",
 		"ANDROID_EMULATOR_PREBUILTS",
 		"ANDROID_PRE_BUILD_PATHS",
+
+		// We read it here already, don't let others share in the fun
+		"GENERATE_SOONG_DEBUG",
 	)
 
 	if ret.UseGoma() || ret.ForceUseGoma() {
@@ -405,20 +386,21 @@
 
 	// Configure Java-related variables, including adding it to $PATH
 	java8Home := filepath.Join("prebuilts/jdk/jdk8", ret.HostPrebuiltTag())
-	java9Home := filepath.Join("prebuilts/jdk/jdk9", ret.HostPrebuiltTag())
-	java11Home := filepath.Join("prebuilts/jdk/jdk11", ret.HostPrebuiltTag())
-	java17Home := filepath.Join("prebuilts/jdk/jdk17", ret.HostPrebuiltTag())
+	java21Home := filepath.Join("prebuilts/jdk/jdk21", ret.HostPrebuiltTag())
 	javaHome := func() string {
 		if override, ok := ret.environ.Get("OVERRIDE_ANDROID_JAVA_HOME"); ok {
 			return override
 		}
 		if toolchain11, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN"); ok && toolchain11 != "true" {
-			ctx.Fatalln("The environment variable EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN is no longer supported. An OpenJDK 11 toolchain is now the global default.")
+			ctx.Fatalln("The environment variable EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN is no longer supported. An OpenJDK 21 toolchain is now the global default.")
 		}
 		if toolchain17, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK17_TOOLCHAIN"); ok && toolchain17 != "true" {
-			ctx.Fatalln("The environment variable EXPERIMENTAL_USE_OPENJDK17_TOOLCHAIN is no longer supported. An OpenJDK 17 toolchain is now the global default.")
+			ctx.Fatalln("The environment variable EXPERIMENTAL_USE_OPENJDK17_TOOLCHAIN is no longer supported. An OpenJDK 21 toolchain is now the global default.")
 		}
-		return java17Home
+		if toolchain21, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK21_TOOLCHAIN"); ok && toolchain21 != "true" {
+			ctx.Fatalln("The environment variable EXPERIMENTAL_USE_OPENJDK21_TOOLCHAIN is no longer supported. An OpenJDK 21 toolchain is now the global default.")
+		}
+		return java21Home
 	}()
 	absJavaHome := absPath(ctx, javaHome)
 
@@ -433,8 +415,6 @@
 	ret.environ.Set("JAVA_HOME", absJavaHome)
 	ret.environ.Set("ANDROID_JAVA_HOME", javaHome)
 	ret.environ.Set("ANDROID_JAVA8_HOME", java8Home)
-	ret.environ.Set("ANDROID_JAVA9_HOME", java9Home)
-	ret.environ.Set("ANDROID_JAVA11_HOME", java11Home)
 	ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
 
 	// b/286885495, https://bugzilla.redhat.com/show_bug.cgi?id=2227130: some versions of Fedora include patches
@@ -442,10 +422,6 @@
 	// zip files produced by soong_zip.  Disable zipbomb detection.
 	ret.environ.Set("UNZIP_DISABLE_ZIPBOMB_DETECTION", "TRUE")
 
-	if ret.MultitreeBuild() {
-		ret.environ.Set("MULTITREE_BUILD", "true")
-	}
-
 	outDir := ret.OutDir()
 	buildDateTimeFile := filepath.Join(outDir, "build_date.txt")
 	if buildDateTime, ok := ret.environ.Get("BUILD_DATETIME"); ok && buildDateTime != "" {
@@ -456,22 +432,22 @@
 
 	ret.environ.Set("BUILD_DATETIME_FILE", buildDateTimeFile)
 
+	if _, ok := ret.environ.Get("BUILD_USERNAME"); !ok {
+		username := "unknown"
+		if u, err := user.Current(); err == nil {
+			username = u.Username
+		} else {
+			ctx.Println("Failed to get current user:", err)
+		}
+		ret.environ.Set("BUILD_USERNAME", username)
+	}
+
 	if ret.UseRBE() {
 		for k, v := range getRBEVars(ctx, Config{ret}) {
 			ret.environ.Set(k, v)
 		}
 	}
 
-	if ret.BuildFromTextStub() {
-		// TODO(b/271443071): support hidden api check for from-text stub build
-		ret.environ.Set("UNSAFE_DISABLE_HIDDENAPI_FLAGS", "true")
-	}
-
-	bpd := ret.BazelMetricsDir()
-	if err := os.RemoveAll(bpd); err != nil {
-		ctx.Fatalf("Unable to remove bazel profile directory %q: %v", bpd, err)
-	}
-
 	c := Config{ret}
 	storeConfigMetrics(ctx, c)
 	return c
@@ -483,6 +459,42 @@
 	return NewConfig(ctx, getConfigArgs(action, dir, ctx, args)...)
 }
 
+// Prepare for getting make variables.  For them to be accurate, we need to have
+// obtained PRODUCT_RELEASE_CONFIG_MAPS.
+//
+// Returns:
+//
+//	Whether config should be called again.
+//
+// TODO: when converting product config to a declarative language, make sure
+// that PRODUCT_RELEASE_CONFIG_MAPS is properly handled as a separate step in
+// that process.
+func SetProductReleaseConfigMaps(ctx Context, config Config) bool {
+	ctx.BeginTrace(metrics.RunKati, "SetProductReleaseConfigMaps")
+	defer ctx.EndTrace()
+
+	if config.SkipConfig() {
+		// This duplicates the logic from Build to skip product config
+		// if the user has explicitly said to.
+		return false
+	}
+
+	releaseConfigVars := []string{
+		"PRODUCT_RELEASE_CONFIG_MAPS",
+	}
+
+	origValue, _ := config.environ.Get("PRODUCT_RELEASE_CONFIG_MAPS")
+	// Get the PRODUCT_RELEASE_CONFIG_MAPS for this product, to avoid polluting the environment
+	// when we run product config to get the rest of the make vars.
+	releaseMapVars, err := dumpMakeVars(ctx, config, nil, releaseConfigVars, false, "")
+	if err != nil {
+		ctx.Fatalln("Error getting PRODUCT_RELEASE_CONFIG_MAPS:", err)
+	}
+	productReleaseConfigMaps := releaseMapVars["PRODUCT_RELEASE_CONFIG_MAPS"]
+	os.Setenv("PRODUCT_RELEASE_CONFIG_MAPS", productReleaseConfigMaps)
+	return origValue != productReleaseConfigMaps
+}
+
 // storeConfigMetrics selects a set of configuration information and store in
 // the metrics system for further analysis.
 func storeConfigMetrics(ctx Context, config Config) {
@@ -516,12 +528,10 @@
 
 func buildConfig(config Config) *smpb.BuildConfig {
 	c := &smpb.BuildConfig{
-		ForceUseGoma:                proto.Bool(config.ForceUseGoma()),
-		UseGoma:                     proto.Bool(config.UseGoma()),
-		UseRbe:                      proto.Bool(config.UseRBE()),
-		BazelMixedBuild:             proto.Bool(config.BazelBuildEnabled()),
-		ForceDisableBazelMixedBuild: proto.Bool(config.IsBazelMixedBuildForceDisabled()),
-		NinjaWeightListSource:       getNinjaWeightListSourceInMetric(config.NinjaWeightListSource()),
+		ForceUseGoma:          proto.Bool(config.ForceUseGoma()),
+		UseGoma:               proto.Bool(config.UseGoma()),
+		UseRbe:                proto.Bool(config.UseRBE()),
+		NinjaWeightListSource: getNinjaWeightListSourceInMetric(config.NinjaWeightListSource()),
 	}
 	c.Targets = append(c.Targets, config.arguments...)
 
@@ -767,16 +777,12 @@
 			c.skipConfig = true
 		} else if arg == "--skip-soong-tests" {
 			c.skipSoongTests = true
+		} else if arg == "--no-skip-soong-tests" {
+			c.skipSoongTests = false
 		} else if arg == "--skip-metrics-upload" {
 			c.skipMetricsUpload = true
 		} else if arg == "--mk-metrics" {
 			c.reportMkMetrics = true
-		} else if arg == "--multitree-build" {
-			c.multitreeBuild = true
-		} else if arg == "--bazel-mode" {
-			c.bazelProdMode = true
-		} else if arg == "--bazel-mode-staging" {
-			c.bazelStagingMode = true
 		} else if arg == "--search-api-dir" {
 			c.searchApiDir = true
 		} else if strings.HasPrefix(arg, "--ninja_weight_source=") {
@@ -803,16 +809,14 @@
 			} else {
 				ctx.Fatalf("unknown option for ninja_weight_source: %s", source)
 			}
-		} else if arg == "--build-from-text-stub" {
-			c.buildFromTextStub = true
+		} else if arg == "--build-from-source-stub" {
+			c.buildFromSourceStub = true
 		} else if strings.HasPrefix(arg, "--build-command=") {
 			buildCmd := strings.TrimPrefix(arg, "--build-command=")
 			// remove quotations
 			buildCmd = strings.TrimPrefix(buildCmd, "\"")
 			buildCmd = strings.TrimSuffix(buildCmd, "\"")
 			ctx.Metrics.SetBuildCommand([]string{buildCmd})
-		} else if strings.HasPrefix(arg, "--bazel-force-enabled-modules=") {
-			c.bazelForceEnabledModules = strings.TrimPrefix(arg, "--bazel-force-enabled-modules=")
 		} else if strings.HasPrefix(arg, "--build-started-time-unix-millis=") {
 			buildTimeStr := strings.TrimPrefix(arg, "--build-started-time-unix-millis=")
 			val, err := strconv.ParseInt(buildTimeStr, 10, 64)
@@ -823,16 +827,6 @@
 			}
 		} else if arg == "--ensure-allowlist-integrity" {
 			c.ensureAllowlistIntegrity = true
-		} else if strings.HasPrefix(arg, "--bazel-exit-code=") {
-			bazelExitCodeStr := strings.TrimPrefix(arg, "--bazel-exit-code=")
-			val, err := strconv.Atoi(bazelExitCodeStr)
-			if err == nil {
-				c.bazelExitCode = int32(val)
-			} else {
-				ctx.Fatalf("Error parsing bazel-exit-code", err)
-			}
-		} else if strings.HasPrefix(arg, "--bes-id=") {
-			c.besId = strings.TrimPrefix(arg, "--bes-id=")
 		} else if len(arg) > 0 && arg[0] == '-' {
 			parseArgNum := func(def int) int {
 				if len(arg) > 2 {
@@ -867,10 +861,6 @@
 			c.dist = true
 		} else if arg == "json-module-graph" {
 			c.jsonModuleGraph = true
-		} else if arg == "bp2build" {
-			c.bp2build = true
-		} else if arg == "api_bp2build" {
-			c.apiBp2build = true
 		} else if arg == "queryview" {
 			c.queryview = true
 		} else if arg == "soong_docs" {
@@ -882,9 +872,6 @@
 			c.arguments = append(c.arguments, arg)
 		}
 	}
-	if (!c.bazelProdMode) && (!c.bazelStagingMode) {
-		c.bazelProdMode = defaultBazelProdMode(c)
-	}
 }
 
 func validateNinjaWeightList(weightListFilePath string) (err error) {
@@ -970,13 +957,12 @@
 		return true
 	}
 
-	if !c.JsonModuleGraph() && !c.Bp2Build() && !c.Queryview() && !c.SoongDocs() && !c.ApiBp2build() {
+	if !c.JsonModuleGraph() && !c.Queryview() && !c.SoongDocs() {
 		// Command line was empty, the default Ninja target is built
 		return true
 	}
 
-	// bp2build + dist may be used to dist bp2build logs but does not require SoongBuildInvocation
-	if c.Dist() && !c.Bp2Build() {
+	if c.Dist() {
 		return true
 	}
 
@@ -1006,14 +992,6 @@
 	return c.ninjaArgs
 }
 
-func (c *configImpl) BazelOutDir() string {
-	return filepath.Join(c.OutDir(), "bazel")
-}
-
-func (c *configImpl) bazelOutputBase() string {
-	return filepath.Join(c.BazelOutDir(), "output")
-}
-
 func (c *configImpl) SoongOutDir() string {
 	return filepath.Join(c.OutDir(), "soong")
 }
@@ -1052,14 +1030,6 @@
 	return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+tag)
 }
 
-func (c *configImpl) Bp2BuildFilesMarkerFile() string {
-	return shared.JoinPath(c.SoongOutDir(), "bp2build_files_marker")
-}
-
-func (c *configImpl) Bp2BuildWorkspaceMarkerFile() string {
-	return shared.JoinPath(c.SoongOutDir(), "bp2build_workspace_marker")
-}
-
 func (c *configImpl) SoongDocsHtml() string {
 	return shared.JoinPath(c.SoongOutDir(), "docs/soong_build.html")
 }
@@ -1068,10 +1038,6 @@
 	return shared.JoinPath(c.SoongOutDir(), "queryview.marker")
 }
 
-func (c *configImpl) ApiBp2buildMarkerFile() string {
-	return shared.JoinPath(c.SoongOutDir(), "api_bp2build.marker")
-}
-
 func (c *configImpl) ModuleGraphFile() string {
 	return shared.JoinPath(c.SoongOutDir(), "module-graph.json")
 }
@@ -1109,14 +1075,6 @@
 	return c.jsonModuleGraph
 }
 
-func (c *configImpl) Bp2Build() bool {
-	return c.bp2build
-}
-
-func (c *configImpl) ApiBp2build() bool {
-	return c.apiBp2build
-}
-
 func (c *configImpl) Queryview() bool {
 	return c.queryview
 }
@@ -1129,10 +1087,6 @@
 	return c.verbose
 }
 
-func (c *configImpl) MultitreeBuild() bool {
-	return c.multitreeBuild
-}
-
 func (c *configImpl) NinjaWeightListSource() NinjaWeightListSource {
 	return c.ninjaWeightListSource
 }
@@ -1162,7 +1116,7 @@
 }
 
 func (c *configImpl) BuildFromTextStub() bool {
-	return c.buildFromTextStub
+	return !c.buildFromSourceStub
 }
 
 func (c *configImpl) TargetProduct() string {
@@ -1308,7 +1262,7 @@
 
 func (c *configImpl) UseRBE() bool {
 	// These alternate modes of running Soong do not use RBE / reclient.
-	if c.Bp2Build() || c.Queryview() || c.ApiBp2build() || c.JsonModuleGraph() {
+	if c.Queryview() || c.JsonModuleGraph() {
 		return false
 	}
 
@@ -1325,10 +1279,6 @@
 	return false
 }
 
-func (c *configImpl) BazelBuildEnabled() bool {
-	return c.bazelProdMode || c.bazelStagingMode
-}
-
 func (c *configImpl) StartRBE() bool {
 	if !c.UseRBE() {
 		return false
@@ -1349,6 +1299,19 @@
 			return v
 		}
 	}
+	return c.rbeTmpDir()
+}
+
+func (c *configImpl) rbeDownloadTmpDir() string {
+	for _, f := range []string{"RBE_download_tmp_dir", "FLAG_download_tmp_dir"} {
+		if v, ok := c.environ.Get(f); ok {
+			return v
+		}
+	}
+	return c.rbeTmpDir()
+}
+
+func (c *configImpl) rbeTmpDir() string {
 	buildTmpDir := shared.TempDirForOutDir(c.SoongOutDir())
 	return filepath.Join(buildTmpDir, "rbe")
 }
@@ -1423,7 +1386,9 @@
 }
 
 func (c *configImpl) rbeSockAddr(dir string) (string, error) {
-	maxNameLen := len(syscall.RawSockaddrUnix{}.Path)
+	// Absolute path socket addresses have a prefix of //. This should
+	// be included in the length limit.
+	maxNameLen := len(syscall.RawSockaddrUnix{}.Path) - 2
 	base := fmt.Sprintf("reproxy_%v.sock", rbeRandPrefix)
 
 	name := filepath.Join(dir, base)
@@ -1555,6 +1520,10 @@
 	return filepath.Join(c.SoongOutDir(), "make_vars-"+c.TargetProduct()+".mk")
 }
 
+func (c *configImpl) SoongBuildMetrics() string {
+	return filepath.Join(c.LogsDir(), "soong_build_metrics.pb")
+}
+
 func (c *configImpl) ProductOut() string {
 	return filepath.Join(c.OutDir(), "target", "product", c.TargetDevice())
 }
@@ -1664,12 +1633,6 @@
 	return absDir
 }
 
-// BazelMetricsDir returns the <logs dir>/bazel_metrics directory
-// where the bazel profiles are located.
-func (c *configImpl) BazelMetricsDir() string {
-	return filepath.Join(c.LogsDir(), "bazel_metrics")
-}
-
 // MkFileMetrics returns the file path for make-related metrics.
 func (c *configImpl) MkMetrics() string {
 	return filepath.Join(c.LogsDir(), "mk_metrics.pb")
@@ -1683,28 +1646,6 @@
 	return c.emptyNinjaFile
 }
 
-func (c *configImpl) IsBazelMixedBuildForceDisabled() bool {
-	return c.Environment().IsEnvTrue("BUILD_BROKEN_DISABLE_BAZEL")
-}
-
-func (c *configImpl) IsPersistentBazelEnabled() bool {
-	return c.Environment().IsEnvTrue("USE_PERSISTENT_BAZEL")
-}
-
-// GetBazeliskBazelVersion returns the Bazel version to use for this build,
-// or the empty string if the current canonical prod Bazel should be used.
-// This environment variable should only be set to debug the build system.
-// The Bazel version, if set, will be passed to Bazelisk, and Bazelisk will
-// handle downloading and invoking the correct Bazel binary.
-func (c *configImpl) GetBazeliskBazelVersion() string {
-	value, _ := c.Environment().Get("USE_BAZEL_VERSION")
-	return value
-}
-
-func (c *configImpl) BazelModulesForceEnabledByFlag() string {
-	return c.bazelForceEnabledModules
-}
-
 func (c *configImpl) SkipMetricsUpload() bool {
 	return c.skipMetricsUpload
 }
@@ -1722,10 +1663,6 @@
 	return time.UnixMilli(c.buildStartedTime)
 }
 
-func (c *configImpl) BazelExitCode() int32 {
-	return c.bazelExitCode
-}
-
 func GetMetricsUploader(topDir string, env *Environment) string {
 	if p, ok := env.Get("METRICS_UPLOADER"); ok {
 		metricsUploader := filepath.Join(topDir, p)
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index 545f727..b1222fe 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -860,23 +860,24 @@
 }
 
 func TestGetConfigArgsBuildModulesInDirectory(t *testing.T) {
-	tests := []buildActionTestCase{{
-		description:  "normal execution in a directory",
-		dirsInTrees:  []string{"0/1/2"},
-		buildFiles:   []string{"0/1/2/Android.mk"},
-		args:         []string{"fake-module"},
-		curDir:       "0/1/2",
-		tidyOnly:     "",
-		expectedArgs: []string{"fake-module", "MODULES-IN-0-1-2"},
-	}, {
-		description:  "build file in parent directory",
-		dirsInTrees:  []string{"0/1/2"},
-		buildFiles:   []string{"0/1/Android.mk"},
-		args:         []string{},
-		curDir:       "0/1/2",
-		tidyOnly:     "",
-		expectedArgs: []string{"MODULES-IN-0-1"},
-	},
+	tests := []buildActionTestCase{
+		{
+			description:  "normal execution in a directory",
+			dirsInTrees:  []string{"0/1/2"},
+			buildFiles:   []string{"0/1/2/Android.mk"},
+			args:         []string{"fake-module"},
+			curDir:       "0/1/2",
+			tidyOnly:     "",
+			expectedArgs: []string{"fake-module", "MODULES-IN-0-1-2"},
+		}, {
+			description:  "build file in parent directory",
+			dirsInTrees:  []string{"0/1/2"},
+			buildFiles:   []string{"0/1/Android.mk"},
+			args:         []string{},
+			curDir:       "0/1/2",
+			tidyOnly:     "",
+			expectedArgs: []string{"MODULES-IN-0-1"},
+		},
 		{
 			description:  "build file in parent directory, multiple module names passed in",
 			dirsInTrees:  []string{"0/1/2"},
@@ -903,15 +904,6 @@
 			tidyOnly:     "",
 			expectedArgs: []string{},
 		}, {
-			description:  "multitree build action executed at root directory",
-			dirsInTrees:  []string{},
-			buildFiles:   []string{},
-			rootSymlink:  false,
-			args:         []string{"--multitree-build"},
-			curDir:       ".",
-			tidyOnly:     "",
-			expectedArgs: []string{"--multitree-build"},
-		}, {
 			description:  "build action executed at root directory in symlink",
 			dirsInTrees:  []string{},
 			buildFiles:   []string{},
@@ -953,7 +945,8 @@
 			curDir:       "",
 			tidyOnly:     "",
 			expectedArgs: []string{"-j", "-k", "fake_module"},
-		}}
+		},
+	}
 	for _, tt := range tests {
 		t.Run("build action BUILD_MODULES_IN_DIR, "+tt.description, func(t *testing.T) {
 			testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY)
@@ -1017,157 +1010,57 @@
 		name                string
 		environ             Environment
 		arguments           []string
-		useBazel            bool
-		bazelProdMode       bool
-		bazelStagingMode    bool
 		expectedBuildConfig *smpb.BuildConfig
 	}{
 		{
 			name:    "none set",
 			environ: Environment{},
 			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:                proto.Bool(false),
-				UseGoma:                     proto.Bool(false),
-				UseRbe:                      proto.Bool(false),
-				BazelMixedBuild:             proto.Bool(false),
-				ForceDisableBazelMixedBuild: proto.Bool(false),
-				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
+				ForceUseGoma:          proto.Bool(false),
+				UseGoma:               proto.Bool(false),
+				UseRbe:                proto.Bool(false),
+				NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 		{
 			name:    "force use goma",
 			environ: Environment{"FORCE_USE_GOMA=1"},
 			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:                proto.Bool(true),
-				UseGoma:                     proto.Bool(false),
-				UseRbe:                      proto.Bool(false),
-				BazelMixedBuild:             proto.Bool(false),
-				ForceDisableBazelMixedBuild: proto.Bool(false),
-				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
+				ForceUseGoma:          proto.Bool(true),
+				UseGoma:               proto.Bool(false),
+				UseRbe:                proto.Bool(false),
+				NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 		{
 			name:    "use goma",
 			environ: Environment{"USE_GOMA=1"},
 			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:                proto.Bool(false),
-				UseGoma:                     proto.Bool(true),
-				UseRbe:                      proto.Bool(false),
-				BazelMixedBuild:             proto.Bool(false),
-				ForceDisableBazelMixedBuild: proto.Bool(false),
-				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
+				ForceUseGoma:          proto.Bool(false),
+				UseGoma:               proto.Bool(true),
+				UseRbe:                proto.Bool(false),
+				NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 		{
 			name:    "use rbe",
 			environ: Environment{"USE_RBE=1"},
 			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:                proto.Bool(false),
-				UseGoma:                     proto.Bool(false),
-				UseRbe:                      proto.Bool(true),
-				BazelMixedBuild:             proto.Bool(false),
-				ForceDisableBazelMixedBuild: proto.Bool(false),
-				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
-			},
-		},
-		{
-			name:    "disable mixed builds",
-			environ: Environment{"BUILD_BROKEN_DISABLE_BAZEL=1"},
-			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:                proto.Bool(false),
-				UseGoma:                     proto.Bool(false),
-				UseRbe:                      proto.Bool(false),
-				BazelMixedBuild:             proto.Bool(false),
-				ForceDisableBazelMixedBuild: proto.Bool(true),
-				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
-			},
-		},
-		{
-			name:     "use bazel as ninja",
-			environ:  Environment{},
-			useBazel: true,
-			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:                proto.Bool(false),
-				UseGoma:                     proto.Bool(false),
-				UseRbe:                      proto.Bool(false),
-				BazelMixedBuild:             proto.Bool(false),
-				ForceDisableBazelMixedBuild: proto.Bool(false),
-				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
-			},
-		},
-		{
-			name:          "bazel mixed build from prod mode",
-			environ:       Environment{},
-			bazelProdMode: true,
-			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:                proto.Bool(false),
-				UseGoma:                     proto.Bool(false),
-				UseRbe:                      proto.Bool(false),
-				BazelMixedBuild:             proto.Bool(true),
-				ForceDisableBazelMixedBuild: proto.Bool(false),
-				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
-			},
-		},
-		{
-			name:             "bazel mixed build from staging mode",
-			environ:          Environment{},
-			bazelStagingMode: true,
-			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:                proto.Bool(false),
-				UseGoma:                     proto.Bool(false),
-				UseRbe:                      proto.Bool(false),
-				BazelMixedBuild:             proto.Bool(true),
-				ForceDisableBazelMixedBuild: proto.Bool(false),
-				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
-			},
-		},
-		{
-			name:      "specified targets",
-			environ:   Environment{},
-			useBazel:  true,
-			arguments: []string{"droid", "dist"},
-			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:                proto.Bool(false),
-				UseGoma:                     proto.Bool(false),
-				UseRbe:                      proto.Bool(false),
-				BazelMixedBuild:             proto.Bool(false),
-				Targets:                     []string{"droid", "dist"},
-				ForceDisableBazelMixedBuild: proto.Bool(false),
-				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
-			},
-		},
-		{
-			name: "all set",
-			environ: Environment{
-				"FORCE_USE_GOMA=1",
-				"USE_GOMA=1",
-				"USE_RBE=1",
-				"BUILD_BROKEN_DISABLE_BAZEL=1",
-			},
-			useBazel:      true,
-			bazelProdMode: true,
-			expectedBuildConfig: &smpb.BuildConfig{
-				ForceUseGoma:                proto.Bool(true),
-				UseGoma:                     proto.Bool(true),
-				UseRbe:                      proto.Bool(true),
-				BazelMixedBuild:             proto.Bool(true),
-				ForceDisableBazelMixedBuild: proto.Bool(true),
-				NinjaWeightListSource:       smpb.BuildConfig_NOT_USED.Enum(),
+				ForceUseGoma:          proto.Bool(false),
+				UseGoma:               proto.Bool(false),
+				UseRbe:                proto.Bool(true),
+				NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(),
 			},
 		},
 	}
 
-	ctx := testContext()
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
 			c := &configImpl{
-				environ:          &tc.environ,
-				bazelProdMode:    tc.bazelProdMode,
-				bazelStagingMode: tc.bazelStagingMode,
-				arguments:        tc.arguments,
+				environ:   &tc.environ,
+				arguments: tc.arguments,
 			}
 			config := Config{c}
-			checkBazelMode(ctx, config)
 			actualBuildConfig := buildConfig(config)
 			if expected := tc.expectedBuildConfig; !proto.Equal(expected, actualBuildConfig) {
 				t.Errorf("Build config mismatch.\n"+
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index efe7478..e17bd54 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -191,6 +191,9 @@
 		"TARGET_BUILD_APPS",
 		"TARGET_BUILD_UNBUNDLED",
 
+		// Additional release config maps
+		"PRODUCT_RELEASE_CONFIG_MAPS",
+
 		// compiler wrappers set up by make
 		"CC_WRAPPER",
 		"CXX_WRAPPER",
@@ -234,7 +237,6 @@
 		"BUILD_BROKEN_SRC_DIR_RW_ALLOWLIST",
 
 		// Not used, but useful to be in the soong.log
-		"BOARD_VNDK_VERSION",
 		"TARGET_BUILD_TYPE",
 		"HOST_ARCH",
 		"HOST_2ND_ARCH",
diff --git a/ui/build/finder.go b/ui/build/finder.go
index 62079fe..573df21 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -74,10 +74,6 @@
 			"AndroidProducts.mk",
 			// General Soong build definitions, using the Blueprint syntax.
 			"Android.bp",
-			// Bazel build definitions.
-			"BUILD.bazel",
-			// Bazel build definitions.
-			"BUILD",
 			// Kati clean definitions.
 			"CleanSpec.mk",
 			// Ownership definition.
@@ -85,13 +81,11 @@
 			// Test configuration for modules in directories that contain this
 			// file.
 			"TEST_MAPPING",
-			// Bazel top-level file to mark a directory as a Bazel workspace.
-			"WORKSPACE",
 			// METADATA file of packages
 			"METADATA",
 		},
-		// Bazel Starlark configuration files and all .mk files for product/board configuration.
-		IncludeSuffixes: []string{".bzl", ".mk"},
+		// .mk files for product/board configuration.
+		IncludeSuffixes: []string{".mk"},
 	}
 	dumpDir := config.FileListDir()
 	f, err = finder.New(cacheParams, filesystem, logger.New(ioutil.Discard),
@@ -111,17 +105,6 @@
 	return dirs
 }
 
-// Finds the list of Bazel-related files (BUILD, WORKSPACE and Starlark) in the tree.
-func findBazelFiles(entries finder.DirEntries) (dirNames []string, fileNames []string) {
-	matches := []string{}
-	for _, foundName := range entries.FileNames {
-		if foundName == "BUILD.bazel" || foundName == "BUILD" || foundName == "WORKSPACE" || strings.HasSuffix(foundName, ".bzl") {
-			matches = append(matches, foundName)
-		}
-	}
-	return entries.DirNames, matches
-}
-
 func findProductAndBoardConfigFiles(entries finder.DirEntries) (dirNames []string, fileNames []string) {
 	matches := []string{}
 	for _, foundName := range entries.FileNames {
@@ -145,6 +128,7 @@
 
 	// Stop searching a subdirectory recursively after finding an Android.mk.
 	androidMks := f.FindFirstNamedAt(".", "Android.mk")
+	blockAndroidMks(ctx, androidMks)
 	err := dumpListToFile(ctx, config, androidMks, filepath.Join(dumpDir, "Android.mk.list"))
 	if err != nil {
 		ctx.Fatalf("Could not export module list: %v", err)
@@ -177,13 +161,6 @@
 		ctx.Fatalf("Could not export product list: %v", err)
 	}
 
-	// Recursively look for all Bazel related files.
-	bazelFiles := f.FindMatching(".", findBazelFiles)
-	err = dumpListToFile(ctx, config, bazelFiles, filepath.Join(dumpDir, "bazel.list"))
-	if err != nil {
-		ctx.Fatalf("Could not export bazel BUILD list: %v", err)
-	}
-
 	// Recursively look for all OWNERS files.
 	owners := f.FindNamedAt(".", "OWNERS")
 	err = dumpListToFile(ctx, config, owners, filepath.Join(dumpDir, "OWNERS.list"))
diff --git a/ui/build/kati.go b/ui/build/kati.go
index aea56d3..d599c99 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -15,6 +15,8 @@
 package build
 
 import (
+	"android/soong/ui/metrics"
+	"android/soong/ui/status"
 	"crypto/md5"
 	"fmt"
 	"io/ioutil"
@@ -22,10 +24,6 @@
 	"os/user"
 	"path/filepath"
 	"strings"
-	"time"
-
-	"android/soong/ui/metrics"
-	"android/soong/ui/status"
 )
 
 var spaceSlashReplacer = strings.NewReplacer("/", "_", " ", "_")
@@ -102,8 +100,6 @@
 		"--no_ninja_prelude",
 		// Support declaring phony outputs in AOSP Ninja.
 		"--use_ninja_phony_output",
-		// Support declaring symlink outputs in AOSP Ninja.
-		"--use_ninja_symlink_outputs",
 		// Regenerate the Ninja file if environment inputs have changed. e.g.
 		// CLI flags, .mk file timestamps, env vars, $(wildcard ..) and some
 		// $(shell ..) results.
@@ -198,32 +194,14 @@
 		}
 	}
 	writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_hostname.txt", hostname)
-
-	// BUILD_NUMBER should be set to the source control value that
-	// represents the current state of the source code.  E.g., a
-	// perforce changelist number or a git hash.  Can be an arbitrary string
-	// (to allow for source control that uses something other than numbers),
-	// but must be a single word and a valid file name.
-	//
-	// If no BUILD_NUMBER is set, create a useful "I am an engineering build
-	// from this date/time" value.  Make it start with a non-digit so that
-	// anyone trying to parse it as an integer will probably get "0".
-	cmd.Environment.Unset("HAS_BUILD_NUMBER")
-	buildNumber, ok := cmd.Environment.Get("BUILD_NUMBER")
+	_, ok = cmd.Environment.Get("BUILD_NUMBER")
 	// Unset BUILD_NUMBER during kati run to avoid kati rerun, kati will use BUILD_NUMBER from a file.
 	cmd.Environment.Unset("BUILD_NUMBER")
 	if ok {
 		cmd.Environment.Set("HAS_BUILD_NUMBER", "true")
-		writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", buildNumber)
 	} else {
-		buildNumber = fmt.Sprintf("eng.%.6s.%s", username, time.Now().Format("20060102.150405" /* YYYYMMDD.HHMMSS */))
 		cmd.Environment.Set("HAS_BUILD_NUMBER", "false")
-		writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", username)
 	}
-	// Write the build number to a file so it can be read back in
-	// without changing the command line every time.  Avoids rebuilds
-	// when using ninja.
-	writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_number.txt", buildNumber)
 
 	// Apply the caller's function closure to mutate the environment variables.
 	envFunc(cmd.Environment)
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 61aaad8..551b8ab 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -194,6 +194,10 @@
 
 			// LLVM compiler wrapper options
 			"TOOLCHAIN_RUSAGE_OUTPUT",
+
+			// We don't want this build broken flag to cause reanalysis, so allow it through to the
+			// actions.
+			"BUILD_BROKEN_INCORRECT_PARTITION_IMAGES",
 		}, config.BuildBrokenNinjaUsesEnvVars()...)...)
 	}
 
@@ -267,11 +271,13 @@
 		// The Ninja file hasn't been modified since the last time it was
 		// checked, so Ninja could be stuck. Output some diagnostics.
 		ctx.Verbosef("ninja may be stuck; last update to %v was %v. dumping process tree...", c.logPath, newModTime)
+		ctx.Printf("ninja may be stuck, check %v for list of running processes.",
+			filepath.Join(config.LogsDir(), config.logsPrefix+"soong.log"))
 
 		// The "pstree" command doesn't exist on Mac, but "pstree" on Linux
 		// gives more convenient output than "ps" So, we try pstree first, and
 		// ps second
-		commandText := fmt.Sprintf("pstree -pal %v || ps -ef", os.Getpid())
+		commandText := fmt.Sprintf("pstree -palT %v || ps -ef", os.Getpid())
 
 		cmd := Command(ctx, config, "dump process tree", "bash", "-c", commandText)
 		output := cmd.CombinedOutputOrFatal()
diff --git a/ui/build/path.go b/ui/build/path.go
index 29128d8..51ebff1 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -180,7 +180,7 @@
 			// Compute the error message along with the process tree, including
 			// parents, for this log line.
 			procPrints := []string{
-				"See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.",
+				"See https://android.googlesource.com/platform/build/+/main/Changes.md#PATH_Tools for more information.",
 			}
 			if len(log.Parents) > 0 {
 				procPrints = append(procPrints, "Process tree:")
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index b3e871f..81c678d 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -87,13 +87,13 @@
 // run during the build. For more documentation, see path_interposer.go .
 var Configuration = map[string]PathConfig{
 	"bash":           Allowed,
-	"dd":             Allowed,
 	"diff":           Allowed,
 	"dlv":            Allowed,
 	"expr":           Allowed,
 	"fuser":          Allowed,
 	"gcert":          Allowed,
-	"getopt":         Allowed,
+	"gcertstatus":    Allowed,
+	"gcloud":         Allowed,
 	"git":            Allowed,
 	"hexdump":        Allowed,
 	"jar":            Allowed,
@@ -101,7 +101,6 @@
 	"javap":          Allowed,
 	"lsof":           Allowed,
 	"openssl":        Allowed,
-	"prodcertstatus": Allowed,
 	"pstree":         Allowed,
 	"rsync":          Allowed,
 	"sh":             Allowed,
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 3b9d301..5142a41 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -55,13 +55,14 @@
 
 func getRBEVars(ctx Context, config Config) map[string]string {
 	vars := map[string]string{
-		"RBE_log_dir":       config.rbeProxyLogsDir(),
-		"RBE_re_proxy":      config.rbeReproxy(),
-		"RBE_exec_root":     config.rbeExecRoot(),
-		"RBE_output_dir":    config.rbeProxyLogsDir(),
-		"RBE_proxy_log_dir": config.rbeProxyLogsDir(),
-		"RBE_cache_dir":     config.rbeCacheDir(),
-		"RBE_platform":      "container-image=" + remoteexec.DefaultImage,
+		"RBE_log_dir":          config.rbeProxyLogsDir(),
+		"RBE_re_proxy":         config.rbeReproxy(),
+		"RBE_exec_root":        config.rbeExecRoot(),
+		"RBE_output_dir":       config.rbeProxyLogsDir(),
+		"RBE_proxy_log_dir":    config.rbeProxyLogsDir(),
+		"RBE_cache_dir":        config.rbeCacheDir(),
+		"RBE_download_tmp_dir": config.rbeDownloadTmpDir(),
+		"RBE_platform":         "container-image=" + remoteexec.DefaultImage,
 	}
 	if config.StartRBE() {
 		name, err := config.rbeSockAddr(absPath(ctx, config.TempDir()))
@@ -94,14 +95,10 @@
 	}
 }
 
-func startRBE(ctx Context, config Config) {
+func checkRBERequirements(ctx Context, config Config) {
 	if !config.GoogleProdCredsExist() && prodCredsAuthType(config) {
 		ctx.Fatalf("Unable to start RBE reproxy\nFAILED: Missing LOAS credentials.")
 	}
-	ctx.BeginTrace(metrics.RunSetupTool, "rbe_bootstrap")
-	defer ctx.EndTrace()
-
-	ctx.Status.Status("Starting rbe...")
 
 	if u := ulimitOrFatal(ctx, config, "-u"); u < rbeLeastNProcs {
 		ctx.Fatalf("max user processes is insufficient: %d; want >= %d.\n", u, rbeLeastNProcs)
@@ -114,6 +111,13 @@
 			ctx.Fatalf("Unable to create logs dir (%v) for RBE: %v", config.rbeProxyLogsDir, err)
 		}
 	}
+}
+
+func startRBE(ctx Context, config Config) {
+	ctx.BeginTrace(metrics.RunSetupTool, "rbe_bootstrap")
+	defer ctx.EndTrace()
+
+	ctx.Status.Status("Starting rbe...")
 
 	cmd := Command(ctx, config, "startRBE bootstrap", rbeCommand(ctx, config, bootstrapCmd))
 
@@ -159,7 +163,7 @@
 		return
 	}
 	fmt.Fprintln(ctx.Writer, "")
-	fmt.Fprintln(ctx.Writer, "\033[33mWARNING: Missing LOAS credentials, please run `gcert`. This will result in failing builds in the future, see go/rbe-android-default-announcement.\033[0m")
+	fmt.Fprintln(ctx.Writer, "\033[33mWARNING: Missing LOAS credentials, please run `gcert`. This is required for a successful build execution. See go/rbe-android-default-announcement for more information.\033[0m")
 	fmt.Fprintln(ctx.Writer, "")
 }
 
diff --git a/ui/build/soong.go b/ui/build/soong.go
index a4cf7fb..79584c6 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -15,14 +15,20 @@
 package build
 
 import (
+	"android/soong/ui/tracer"
 	"fmt"
+	"io/fs"
 	"os"
 	"path/filepath"
 	"strconv"
 	"strings"
+	"sync"
+	"sync/atomic"
+	"time"
 
 	"android/soong/bazel"
 	"android/soong/ui/metrics"
+	"android/soong/ui/metrics/metrics_proto"
 	"android/soong/ui/status"
 
 	"android/soong/shared"
@@ -30,19 +36,19 @@
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/microfactory"
+	"github.com/google/blueprint/pathtools"
+
+	"google.golang.org/protobuf/proto"
 )
 
 const (
 	availableEnvFile = "soong.environment.available"
 	usedEnvFile      = "soong.environment.used"
 
-	soongBuildTag        = "build"
-	bp2buildFilesTag     = "bp2build_files"
-	bp2buildWorkspaceTag = "bp2build_workspace"
-	jsonModuleGraphTag   = "modulegraph"
-	queryviewTag         = "queryview"
-	apiBp2buildTag       = "api_bp2build"
-	soongDocsTag         = "soong_docs"
+	soongBuildTag      = "build"
+	jsonModuleGraphTag = "modulegraph"
+	queryviewTag       = "queryview"
+	soongDocsTag       = "soong_docs"
 
 	// bootstrapEpoch is used to determine if an incremental build is incompatible with the current
 	// version of bootstrap and needs cleaning before continuing the build.  Increment this for
@@ -51,6 +57,13 @@
 	bootstrapEpoch = 1
 )
 
+var (
+	// Used during parallel update of symlinks in out directory to reflect new
+	// TOP dir.
+	symlinkWg            sync.WaitGroup
+	numFound, numUpdated uint32
+)
+
 func writeEnvironmentFile(_ Context, envFile string, envDeps map[string]string) error {
 	data, err := shared.EnvFileContents(envDeps)
 	if err != nil {
@@ -161,18 +174,36 @@
 	debugPort    string
 }
 
-func (pb PrimaryBuilderFactory) primaryBuilderInvocation() bootstrap.PrimaryBuilderInvocation {
+func getGlobPathName(config Config) string {
+	globPathName, ok := config.TargetProductOrErr()
+	if ok != nil {
+		globPathName = soongBuildTag
+	}
+	return globPathName
+}
+
+func getGlobPathNameFromPrimaryBuilderFactory(config Config, pb PrimaryBuilderFactory) string {
+	if pb.name == soongBuildTag {
+		// Glob path for soong build would be separated per product target
+		return getGlobPathName(config)
+	}
+	return pb.name
+}
+
+func (pb PrimaryBuilderFactory) primaryBuilderInvocation(config Config) bootstrap.PrimaryBuilderInvocation {
 	commonArgs := make([]string, 0, 0)
 
 	if !pb.config.skipSoongTests {
 		commonArgs = append(commonArgs, "-t")
 	}
 
-	if pb.config.multitreeBuild {
-		commonArgs = append(commonArgs, "--multitree-build")
+	if pb.config.buildFromSourceStub {
+		commonArgs = append(commonArgs, "--build-from-source-stub")
 	}
-	if pb.config.buildFromTextStub {
-		commonArgs = append(commonArgs, "--build-from-text-stub")
+
+	if pb.config.moduleDebugFile != "" {
+		commonArgs = append(commonArgs, "--soong_module_debug")
+		commonArgs = append(commonArgs, pb.config.moduleDebugFile)
 	}
 
 	commonArgs = append(commonArgs, "-l", filepath.Join(pb.config.FileListDir(), "Android.bp.list"))
@@ -195,9 +226,10 @@
 
 	var allArgs []string
 	allArgs = append(allArgs, pb.specificArgs...)
+	globPathName := getGlobPathNameFromPrimaryBuilderFactory(config, pb)
 	allArgs = append(allArgs,
-		"--globListDir", pb.name,
-		"--globFile", pb.config.NamedGlobFile(pb.name))
+		"--globListDir", globPathName,
+		"--globFile", pb.config.NamedGlobFile(globPathName))
 
 	allArgs = append(allArgs, commonArgs...)
 	allArgs = append(allArgs, environmentArgs(pb.config, pb.name)...)
@@ -209,8 +241,11 @@
 	}
 	allArgs = append(allArgs, "Android.bp")
 
+	globfiles := bootstrap.GlobFileListFiles(bootstrap.GlobDirectory(config.SoongOutDir(), globPathName))
+
 	return bootstrap.PrimaryBuilderInvocation{
 		Inputs:      []string{"Android.bp"},
+		Implicits:   globfiles,
 		Outputs:     []string{pb.output},
 		Args:        allArgs,
 		Description: pb.description,
@@ -247,11 +282,9 @@
 
 func bootstrapGlobFileList(config Config) []string {
 	return []string{
-		config.NamedGlobFile(soongBuildTag),
-		config.NamedGlobFile(bp2buildFilesTag),
+		config.NamedGlobFile(getGlobPathName(config)),
 		config.NamedGlobFile(jsonModuleGraphTag),
 		config.NamedGlobFile(queryviewTag),
-		config.NamedGlobFile(apiBp2buildTag),
 		config.NamedGlobFile(soongDocsTag),
 	}
 }
@@ -269,32 +302,14 @@
 	if config.EmptyNinjaFile() {
 		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--empty-ninja-file")
 	}
-	if config.bazelProdMode {
-		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode")
-	}
-	if config.bazelStagingMode {
-		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode-staging")
-	}
-	if config.IsPersistentBazelEnabled() {
-		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--use-bazel-proxy")
-	}
-	if len(config.bazelForceEnabledModules) > 0 {
-		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-force-enabled-modules="+config.bazelForceEnabledModules)
-	}
-	if config.MultitreeBuild() {
-		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--multitree-build")
-	}
-	if config.buildFromTextStub {
-		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--build-from-text-stub")
+	if config.buildFromSourceStub {
+		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--build-from-source-stub")
 	}
 	if config.ensureAllowlistIntegrity {
 		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--ensure-allowlist-integrity")
 	}
 
 	queryviewDir := filepath.Join(config.SoongOutDir(), "queryview")
-	// The BUILD files will be generated in out/soong/.api_bp2build (no symlinks to src files)
-	// The final workspace will be generated in out/soong/api_bp2build
-	apiBp2buildDir := filepath.Join(config.SoongOutDir(), ".api_bp2build")
 
 	pbfs := []PrimaryBuilderFactory{
 		{
@@ -305,24 +320,6 @@
 			specificArgs: mainSoongBuildExtraArgs,
 		},
 		{
-			name:        bp2buildFilesTag,
-			description: fmt.Sprintf("converting Android.bp files to BUILD files at %s/bp2build", config.SoongOutDir()),
-			config:      config,
-			output:      config.Bp2BuildFilesMarkerFile(),
-			specificArgs: append(baseArgs,
-				"--bp2build_marker", config.Bp2BuildFilesMarkerFile(),
-			),
-		},
-		{
-			name:        bp2buildWorkspaceTag,
-			description: "Creating Bazel symlink forest",
-			config:      config,
-			output:      config.Bp2BuildWorkspaceMarkerFile(),
-			specificArgs: append(baseArgs,
-				"--symlink_forest_marker", config.Bp2BuildWorkspaceMarkerFile(),
-			),
-		},
-		{
 			name:        jsonModuleGraphTag,
 			description: fmt.Sprintf("generating the Soong module graph at %s", config.ModuleGraphFile()),
 			config:      config,
@@ -342,15 +339,6 @@
 			),
 		},
 		{
-			name:        apiBp2buildTag,
-			description: fmt.Sprintf("generating BUILD files for API contributions at %s", apiBp2buildDir),
-			config:      config,
-			output:      config.ApiBp2buildMarkerFile(),
-			specificArgs: append(baseArgs,
-				"--bazel_api_bp2build_dir", apiBp2buildDir,
-			),
-		},
-		{
 			name:        soongDocsTag,
 			description: fmt.Sprintf("generating Soong docs at %s", config.SoongDocsHtml()),
 			config:      config,
@@ -395,33 +383,10 @@
 		if debuggedInvocations[pbf.name] {
 			pbf.debugPort = delvePort
 		}
-		pbi := pbf.primaryBuilderInvocation()
-		// Some invocations require adjustment:
-		switch pbf.name {
-		case soongBuildTag:
-			if config.BazelBuildEnabled() {
-				// Mixed builds call Bazel from soong_build and they therefore need the
-				// Bazel workspace to be available. Make that so by adding a dependency on
-				// the bp2build marker file to the action that invokes soong_build .
-				pbi.OrderOnlyInputs = append(pbi.OrderOnlyInputs, config.Bp2BuildWorkspaceMarkerFile())
-			}
-		case bp2buildWorkspaceTag:
-			pbi.Inputs = append(pbi.Inputs,
-				config.Bp2BuildFilesMarkerFile(),
-				filepath.Join(config.FileListDir(), "bazel.list"))
-		case bp2buildFilesTag:
-			pbi.Inputs = append(pbi.Inputs, filepath.Join(config.FileListDir(), "METADATA.list"))
-		}
+		pbi := pbf.primaryBuilderInvocation(config)
 		invocations = append(invocations, pbi)
 	}
 
-	// The glob .ninja files are subninja'd. However, they are generated during
-	// the build itself so we write an empty file if the file does not exist yet
-	// so that the subninja doesn't fail on clean builds
-	for _, globFile := range bootstrapGlobFileList(config) {
-		writeEmptyFile(ctx, globFile)
-	}
-
 	blueprintArgs := bootstrap.Args{
 		ModuleListFile: filepath.Join(config.FileListDir(), "Android.bp.list"),
 		OutFile:        shared.JoinPath(config.SoongOutDir(), "bootstrap.ninja"),
@@ -443,6 +408,28 @@
 		primaryBuilderInvocations: invocations,
 	}
 
+	// The glob ninja files are generated during the main build phase. However, the
+	// primary buildifer invocation depends on all of its glob files, even before
+	// it's been run. Generate a "empty" glob ninja file on the first run,
+	// so that the files can be there to satisfy the dependency.
+	for _, pb := range pbfs {
+		globPathName := getGlobPathNameFromPrimaryBuilderFactory(config, pb)
+		globNinjaFile := config.NamedGlobFile(globPathName)
+		if _, err := os.Stat(globNinjaFile); os.IsNotExist(err) {
+			err := bootstrap.WriteBuildGlobsNinjaFile(&bootstrap.GlobSingleton{
+				GlobLister: func() pathtools.MultipleGlobResults { return nil },
+				GlobFile:   globNinjaFile,
+				GlobDir:    bootstrap.GlobDirectory(config.SoongOutDir(), globPathName),
+				SrcDir:     ".",
+			}, blueprintConfig)
+			if err != nil {
+				ctx.Fatal(err)
+			}
+		} else if err != nil {
+			ctx.Fatal(err)
+		}
+	}
+
 	// since `bootstrap.ninja` is regenerated unconditionally, we ignore the deps, i.e. little
 	// reason to write a `bootstrap.ninja.d` file
 	_, err := bootstrap.RunBlueprint(blueprintArgs, bootstrap.DoEverything, blueprintCtx, blueprintConfig)
@@ -466,10 +453,118 @@
 	}
 }
 
+func updateSymlinks(ctx Context, dir, prevCWD, cwd string) error {
+	defer symlinkWg.Done()
+
+	visit := func(path string, d fs.DirEntry, err error) error {
+		if d.IsDir() && path != dir {
+			symlinkWg.Add(1)
+			go updateSymlinks(ctx, path, prevCWD, cwd)
+			return filepath.SkipDir
+		}
+		f, err := d.Info()
+		if err != nil {
+			return err
+		}
+		// If the file is not a symlink, we don't have to update it.
+		if f.Mode()&os.ModeSymlink != os.ModeSymlink {
+			return nil
+		}
+
+		atomic.AddUint32(&numFound, 1)
+		target, err := os.Readlink(path)
+		if err != nil {
+			return err
+		}
+		if strings.HasPrefix(target, prevCWD) &&
+			(len(target) == len(prevCWD) || target[len(prevCWD)] == '/') {
+			target = filepath.Join(cwd, target[len(prevCWD):])
+			if err := os.Remove(path); err != nil {
+				return err
+			}
+			if err := os.Symlink(target, path); err != nil {
+				return err
+			}
+			atomic.AddUint32(&numUpdated, 1)
+		}
+		return nil
+	}
+
+	if err := filepath.WalkDir(dir, visit); err != nil {
+		return err
+	}
+	return nil
+}
+
+func fixOutDirSymlinks(ctx Context, config Config, outDir string) error {
+	cwd, err := os.Getwd()
+	if err != nil {
+		return err
+	}
+
+	// Record the .top as the very last thing in the function.
+	tf := filepath.Join(outDir, ".top")
+	defer func() {
+		if err := os.WriteFile(tf, []byte(cwd), 0644); err != nil {
+			fmt.Fprintf(os.Stderr, fmt.Sprintf("Unable to log CWD: %v", err))
+		}
+	}()
+
+	// Find the previous working directory if it was recorded.
+	var prevCWD string
+	pcwd, err := os.ReadFile(tf)
+	if err != nil {
+		if os.IsNotExist(err) {
+			// No previous working directory recorded, nothing to do.
+			return nil
+		}
+		return err
+	}
+	prevCWD = strings.Trim(string(pcwd), "\n")
+
+	if prevCWD == cwd {
+		// We are in the same source dir, nothing to update.
+		return nil
+	}
+
+	symlinkWg.Add(1)
+	if err := updateSymlinks(ctx, outDir, prevCWD, cwd); err != nil {
+		return err
+	}
+	symlinkWg.Wait()
+	ctx.Println(fmt.Sprintf("Updated %d/%d symlinks in dir %v", numUpdated, numFound, outDir))
+	return nil
+}
+
+func migrateOutputSymlinks(ctx Context, config Config) error {
+	// Figure out the real out directory ("out" could be a symlink).
+	outDir := config.OutDir()
+	s, err := os.Lstat(outDir)
+	if err != nil {
+		if os.IsNotExist(err) {
+			// No out dir exists, no symlinks to migrate.
+			return nil
+		}
+		return err
+	}
+	if s.Mode()&os.ModeSymlink == os.ModeSymlink {
+		target, err := filepath.EvalSymlinks(outDir)
+		if err != nil {
+			return err
+		}
+		outDir = target
+	}
+	return fixOutDirSymlinks(ctx, config, outDir)
+}
+
 func runSoong(ctx Context, config Config) {
 	ctx.BeginTrace(metrics.RunSoong, "soong")
 	defer ctx.EndTrace()
 
+	if err := migrateOutputSymlinks(ctx, config); err != nil {
+		ctx.Fatalf("failed to migrate output directory to current TOP dir: %v", err)
+	}
+
 	// We have two environment files: .available is the one with every variable,
 	// .used with the ones that were actually used. The latter is used to
 	// determine whether Soong needs to be re-run since why re-run it if only
@@ -481,16 +576,7 @@
 
 	soongBuildEnv := config.Environment().Copy()
 	soongBuildEnv.Set("TOP", os.Getenv("TOP"))
-	// For Bazel mixed builds.
-	soongBuildEnv.Set("BAZEL_PATH", "./build/bazel/bin/bazel")
-	// Bazel's HOME var is set to an output subdirectory which doesn't exist. This
-	// prevents Bazel from file I/O in the actual user HOME directory.
-	soongBuildEnv.Set("BAZEL_HOME", absPath(ctx, filepath.Join(config.BazelOutDir(), "bazelhome")))
-	soongBuildEnv.Set("BAZEL_OUTPUT_BASE", config.bazelOutputBase())
-	soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
-	soongBuildEnv.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir())
 	soongBuildEnv.Set("LOG_DIR", config.LogsDir())
-	soongBuildEnv.Set("BAZEL_DEPS_FILE", absPath(ctx, filepath.Join(config.BazelOutDir(), "bazel.list")))
 
 	// For Soong bootstrapping tests
 	if os.Getenv("ALLOW_MISSING_DEPENDENCIES") == "true" {
@@ -508,9 +594,9 @@
 
 		checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(soongBuildTag))
 
-		if config.BazelBuildEnabled() || config.Bp2Build() {
-			checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(bp2buildFilesTag))
-		}
+		// Remove bazel files in the event that bazel is disabled for the build.
+		// These files may have been left over from a previous bazel-enabled build.
+		cleanBazelFiles(config)
 
 		if config.JsonModuleGraph() {
 			checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(jsonModuleGraphTag))
@@ -520,10 +606,6 @@
 			checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(queryviewTag))
 		}
 
-		if config.ApiBp2build() {
-			checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(apiBp2buildTag))
-		}
-
 		if config.SoongDocs() {
 			checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(soongDocsTag))
 		}
@@ -536,14 +618,6 @@
 		ctx.BeginTrace(metrics.RunSoong, "bootstrap")
 		defer ctx.EndTrace()
 
-		if config.IsPersistentBazelEnabled() {
-			bazelProxy := bazel.NewProxyServer(ctx.Logger, config.OutDir(), filepath.Join(config.SoongOutDir(), "workspace"), config.GetBazeliskBazelVersion())
-			if err := bazelProxy.Start(); err != nil {
-				ctx.Fatalf("Failed to create bazel proxy")
-			}
-			defer bazelProxy.Close()
-		}
-
 		fifo := filepath.Join(config.OutDir(), ".ninja_fifo")
 		nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo)
 		defer nr.Close()
@@ -587,18 +661,10 @@
 		targets = append(targets, config.ModuleGraphFile())
 	}
 
-	if config.Bp2Build() {
-		targets = append(targets, config.Bp2BuildWorkspaceMarkerFile())
-	}
-
 	if config.Queryview() {
 		targets = append(targets, config.QueryviewMarkerFile())
 	}
 
-	if config.ApiBp2build() {
-		targets = append(targets, config.ApiBp2buildMarkerFile())
-	}
-
 	if config.SoongDocs() {
 		targets = append(targets, config.SoongDocsHtml())
 	}
@@ -608,8 +674,12 @@
 		targets = append(targets, config.SoongNinjaFile())
 	}
 
+	beforeSoongTimestamp := time.Now()
+
 	ninja(targets...)
 
+	loadSoongBuildMetrics(ctx, config, beforeSoongTimestamp)
+
 	distGzipFile(ctx, config, config.SoongNinjaFile(), "soong")
 	distFile(ctx, config, config.SoongVarsFile(), "soong")
 
@@ -623,6 +693,67 @@
 	}
 }
 
+// loadSoongBuildMetrics reads out/soong_build_metrics.pb if it was generated by soong_build and copies the
+// events stored in it into the soong_ui trace to provide introspection into how long the different phases of
+// soong_build are taking.
+func loadSoongBuildMetrics(ctx Context, config Config, oldTimestamp time.Time) {
+	soongBuildMetricsFile := config.SoongBuildMetrics()
+	if metricsStat, err := os.Stat(soongBuildMetricsFile); err != nil {
+		ctx.Verbosef("Failed to stat %s: %s", soongBuildMetricsFile, err)
+		return
+	} else if !metricsStat.ModTime().After(oldTimestamp) {
+		ctx.Verbosef("%s timestamp not later after running soong, expected %s > %s",
+			soongBuildMetricsFile, metricsStat.ModTime(), oldTimestamp)
+		return
+	}
+
+	metricsData, err := os.ReadFile(soongBuildMetricsFile)
+	if err != nil {
+		ctx.Verbosef("Failed to read %s: %s", soongBuildMetricsFile, err)
+		return
+	}
+
+	soongBuildMetrics := metrics_proto.SoongBuildMetrics{}
+	err = proto.Unmarshal(metricsData, &soongBuildMetrics)
+	if err != nil {
+		ctx.Verbosef("Failed to unmarshal %s: %s", soongBuildMetricsFile, err)
+		return
+	}
+	for _, event := range soongBuildMetrics.Events {
+		desc := event.GetDescription()
+		if dot := strings.LastIndexByte(desc, '.'); dot >= 0 {
+			desc = desc[dot+1:]
+		}
+		ctx.Tracer.Complete(desc, ctx.Thread,
+			event.GetStartTime(), event.GetStartTime()+event.GetRealTime())
+	}
+	for _, event := range soongBuildMetrics.PerfCounters {
+		timestamp := event.GetTime()
+		for _, group := range event.Groups {
+			counters := make([]tracer.Counter, 0, len(group.Counters))
+			for _, counter := range group.Counters {
+				counters = append(counters, tracer.Counter{
+					Name:  counter.GetName(),
+					Value: counter.GetValue(),
+				})
+			}
+			ctx.Tracer.CountersAtTime(group.GetName(), ctx.Thread, timestamp, counters)
+		}
+	}
+}
+
+func cleanBazelFiles(config Config) {
+	files := []string{
+		shared.JoinPath(config.SoongOutDir(), "bp2build"),
+		shared.JoinPath(config.SoongOutDir(), "workspace"),
+		shared.JoinPath(config.SoongOutDir(), bazel.SoongInjectionDirName),
+		shared.JoinPath(config.OutDir(), "bazel")}
+
+	for _, f := range files {
+		os.RemoveAll(f)
+	}
+}
+
 func runMicrofactory(ctx Context, config Config, name string, pkg string, mapping map[string]string) {
 	ctx.BeginTrace(metrics.RunSoong, name)
 	defer ctx.EndTrace()
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index 2efc732..3095139 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -15,47 +15,16 @@
 package build
 
 import (
+	"android/soong/ui/metrics"
+	"android/soong/ui/status"
 	"bufio"
 	"fmt"
 	"path/filepath"
-	"regexp"
 	"runtime"
 	"sort"
 	"strings"
-	"sync"
-
-	"android/soong/ui/metrics"
-	"android/soong/ui/status"
 )
 
-var (
-	// bazel output paths are in __main__/bazel-out/<config-specific-path>/bin
-	bazelOutputPathRegexOnce sync.Once
-	bazelOutputPathRegexp    *regexp.Regexp
-)
-
-func bazelOutputPathPattern(config Config) *regexp.Regexp {
-	bazelOutputPathRegexOnce.Do(func() {
-		// Bazel output files are in <Bazel output base>/execroot/__main__/bazel-out/<config>/bin
-		bazelOutRoot := filepath.Join(regexp.QuoteMeta(config.bazelOutputBase()), "execroot", "__main__", "bazel-out")
-		bazelOutputPathRegexp = regexp.MustCompile(bazelOutRoot + "/[^/]+/bin")
-	})
-	return bazelOutputPathRegexp
-}
-
-func ignoreBazelPath(config Config, path string) bool {
-	bazelRoot := filepath.Join(config.bazelOutputBase(), "execroot")
-	// Don't check bazel output regexp unless it is Bazel path
-	if strings.HasPrefix(path, bazelRoot) {
-		bazelOutputRegexp := bazelOutputPathPattern(config)
-		// if the file is a bazel path that is _not_ a Bazel generated file output, we rely on Bazel to
-		// ensure the paths to exist. If it _is_ a Bazel output path, we expect that it should be built
-		// by Ninja.
-		return !bazelOutputRegexp.MatchString(path)
-	}
-	return false
-}
-
 // Checks for files in the out directory that have a rule that depends on them but no rule to
 // create them. This catches a common set of build failures where a rule to generate a file is
 // deleted (either by deleting a module in an Android.mk file, or by modifying the build system
@@ -94,6 +63,7 @@
 
 	outDir := config.OutDir()
 	modulePathsDir := filepath.Join(outDir, ".module_paths")
+	rawFilesDir := filepath.Join(outDir, "soong", "raw")
 	variablesFilePath := filepath.Join(outDir, "soong", "soong.variables")
 
 	// dexpreopt.config is an input to the soong_docs action, which runs the
@@ -119,6 +89,7 @@
 			continue
 		}
 		if strings.HasPrefix(line, modulePathsDir) ||
+			strings.HasPrefix(line, rawFilesDir) ||
 			line == variablesFilePath ||
 			line == dexpreoptConfigFilePath ||
 			line == buildDatetimeFilePath ||
@@ -128,9 +99,6 @@
 			continue
 		}
 
-		if ignoreBazelPath(config, line) {
-			continue
-		}
 		danglingRules[line] = true
 	}
 
diff --git a/ui/build/upload_test.go b/ui/build/upload_test.go
deleted file mode 100644
index 1fcded9..0000000
--- a/ui/build/upload_test.go
+++ /dev/null
@@ -1,299 +0,0 @@
-// Copyright 2020 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package build
-
-import (
-	"errors"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"reflect"
-	"sort"
-	"strconv"
-	"strings"
-	"testing"
-	"time"
-
-	"android/soong/ui/logger"
-)
-
-func writeBazelProfileFile(dir string) error {
-	contents := `
-
-=== PHASE SUMMARY INFORMATION ===
-
-Total launch phase time                              1.193 s   15.77%
-Total init phase time                                1.092 s   14.44%
-Total target pattern evaluation phase time           0.580 s    7.67%
-Total interleaved loading-and-analysis phase time    3.646 s   48.21%
-Total preparation phase time                         0.022 s    0.30%
-Total execution phase time                           0.993 s   13.13%
-Total finish phase time                              0.036 s    0.48%
----------------------------------------------------------------------
-Total run time                                       7.563 s  100.00%
-
-Critical path (178 ms):
-       Time Percentage   Description
-     178 ms  100.00%   action 'BazelWorkspaceStatusAction stable-status.txt'
-
-`
-	file := filepath.Join(dir, "bazel_metrics.txt")
-	return os.WriteFile(file, []byte(contents), 0666)
-}
-
-func TestPruneMetricsFiles(t *testing.T) {
-	rootDir := t.TempDir()
-
-	dirs := []string{
-		filepath.Join(rootDir, "d1"),
-		filepath.Join(rootDir, "d1", "d2"),
-		filepath.Join(rootDir, "d1", "d2", "d3"),
-	}
-
-	files := []string{
-		filepath.Join(rootDir, "d1", "f1"),
-		filepath.Join(rootDir, "d1", "d2", "f1"),
-		filepath.Join(rootDir, "d1", "d2", "d3", "f1"),
-	}
-
-	for _, d := range dirs {
-		if err := os.MkdirAll(d, 0777); err != nil {
-			t.Fatalf("got %v, expecting nil error for making directory %q", err, d)
-		}
-	}
-
-	for _, f := range files {
-		if err := ioutil.WriteFile(f, []byte{}, 0777); err != nil {
-			t.Fatalf("got %v, expecting nil error on writing file %q", err, f)
-		}
-	}
-
-	want := []string{
-		filepath.Join(rootDir, "d1", "f1"),
-		filepath.Join(rootDir, "d1", "d2", "f1"),
-		filepath.Join(rootDir, "d1", "d2", "d3", "f1"),
-	}
-
-	got := pruneMetricsFiles([]string{rootDir})
-
-	sort.Strings(got)
-	sort.Strings(want)
-
-	if !reflect.DeepEqual(got, want) {
-		t.Errorf("got %q, want %q after pruning metrics files", got, want)
-	}
-}
-
-func TestUploadMetrics(t *testing.T) {
-	ctx := testContext()
-	tests := []struct {
-		description string
-		uploader    string
-		createFiles bool
-		files       []string
-	}{{
-		description: "no metrics uploader",
-	}, {
-		description: "non-existent metrics files no upload",
-		uploader:    "echo",
-		files:       []string{"metrics_file_1", "metrics_file_2", "metrics_file_3, bazel_metrics.pb"},
-	}, {
-		description: "trigger upload",
-		uploader:    "echo",
-		createFiles: true,
-		files:       []string{"metrics_file_1", "metrics_file_2, bazel_metrics.pb"},
-	}}
-
-	for _, tt := range tests {
-		t.Run(tt.description, func(t *testing.T) {
-			defer logger.Recover(func(err error) {
-				t.Fatalf("got unexpected error: %v", err)
-			})
-
-			outDir, err := ioutil.TempDir("", "")
-			if err != nil {
-				t.Fatalf("failed to create out directory: %v", outDir)
-			}
-			defer os.RemoveAll(outDir)
-
-			// Supply our own tmpDir to delete the temp dir once the test is done.
-			orgTmpDir := tmpDir
-			tmpDir = func(string, string) (string, error) {
-				retDir := filepath.Join(outDir, "tmp_upload_dir")
-				if err := os.Mkdir(retDir, 0755); err != nil {
-					t.Fatalf("failed to create temporary directory %q: %v", retDir, err)
-				}
-				return retDir, nil
-			}
-			defer func() { tmpDir = orgTmpDir }()
-
-			metricsUploadDir := filepath.Join(outDir, ".metrics_uploader")
-			if err := os.Mkdir(metricsUploadDir, 0755); err != nil {
-				t.Fatalf("failed to create %q directory for oauth valid check: %v", metricsUploadDir, err)
-			}
-
-			var metricsFiles []string
-			if tt.createFiles {
-				for _, f := range tt.files {
-					filename := filepath.Join(outDir, f)
-					metricsFiles = append(metricsFiles, filename)
-					if err := ioutil.WriteFile(filename, []byte("test file"), 0644); err != nil {
-						t.Fatalf("failed to create a fake metrics file %q for uploading: %v", filename, err)
-					}
-				}
-			}
-			if err := writeBazelProfileFile(outDir); err != nil {
-				t.Fatalf("failed to create bazel profile file in dir: %v", outDir)
-			}
-
-			config := Config{&configImpl{
-				environ: &Environment{
-					"OUT_DIR=" + outDir,
-				},
-				buildDateTime:   strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10),
-				metricsUploader: tt.uploader,
-			}}
-
-			UploadMetrics(ctx, config, false, time.Now(), metricsFiles...)
-		})
-	}
-}
-
-func TestUploadMetricsErrors(t *testing.T) {
-	ctx := testContext()
-	tests := []struct {
-		description string
-		tmpDir      string
-		tmpDirErr   error
-		expectedErr string
-	}{{
-		description: "getTmpDir returned error",
-		tmpDirErr:   errors.New("getTmpDir failed"),
-		expectedErr: "getTmpDir failed",
-	}, {
-		description: "copyFile operation error",
-		tmpDir:      "/fake_dir",
-		expectedErr: "failed to copy",
-	}}
-
-	for _, tt := range tests {
-		t.Run(tt.description, func(t *testing.T) {
-			defer logger.Recover(func(err error) {
-				got := err.Error()
-				if !strings.Contains(got, tt.expectedErr) {
-					t.Errorf("got %q, want %q to be contained in error", got, tt.expectedErr)
-				}
-			})
-
-			outDir, err := ioutil.TempDir("", "")
-			if err != nil {
-				t.Fatalf("failed to create out directory: %v", outDir)
-			}
-			defer os.RemoveAll(outDir)
-
-			orgTmpDir := tmpDir
-			tmpDir = func(string, string) (string, error) {
-				return tt.tmpDir, tt.tmpDirErr
-			}
-			defer func() { tmpDir = orgTmpDir }()
-
-			metricsFile := filepath.Join(outDir, "metrics_file_1")
-			if err := ioutil.WriteFile(metricsFile, []byte("test file"), 0644); err != nil {
-				t.Fatalf("failed to create a fake metrics file %q for uploading: %v", metricsFile, err)
-			}
-
-			config := Config{&configImpl{
-				environ: &Environment{
-					"OUT_DIR=/bad",
-				},
-				metricsUploader: "echo",
-			}}
-
-			UploadMetrics(ctx, config, true, time.Now(), metricsFile)
-			t.Errorf("got nil, expecting %q as a failure", tt.expectedErr)
-		})
-	}
-}
-
-func TestParsePercentageToTenThousandths(t *testing.T) {
-	// 2.59% should be returned as 259 - representing 259/10000 of the build
-	percentage := parsePercentageToTenThousandths("2.59%")
-	if percentage != 259 {
-		t.Errorf("Expected percentage to be returned as ten-thousandths. Expected 259, have %d\n", percentage)
-	}
-
-	// Test without a leading digit
-	percentage = parsePercentageToTenThousandths(".52%")
-	if percentage != 52 {
-		t.Errorf("Expected percentage to be returned as ten-thousandths. Expected 52, have %d\n", percentage)
-	}
-}
-
-func TestParseTimingToNanos(t *testing.T) {
-	// This parses from seconds (with millis precision) and returns nanos
-	timingNanos := parseTimingToNanos("0.111")
-	if timingNanos != 111000000 {
-		t.Errorf("Error parsing timing. Expected 111000, have %d\n", timingNanos)
-	}
-
-	// Test without a leading digit
-	timingNanos = parseTimingToNanos(".112")
-	if timingNanos != 112000000 {
-		t.Errorf("Error parsing timing. Expected 112000, have %d\n", timingNanos)
-	}
-}
-
-func TestParsePhaseTiming(t *testing.T) {
-	// Sample lines include:
-	// Total launch phase time   0.011 s    2.59%
-	// Total target pattern evaluation phase time  0.012 s    4.59%
-
-	line1 := "Total launch phase time   0.011 s    2.59%"
-	timing := parsePhaseTiming(line1)
-
-	if timing.GetPhaseName() != "launch" {
-		t.Errorf("Failed to parse phase name. Expected launch, have %s\n", timing.GetPhaseName())
-	} else if timing.GetDurationNanos() != 11000000 {
-		t.Errorf("Failed to parse duration nanos. Expected 11000000, have %d\n", timing.GetDurationNanos())
-	} else if timing.GetPortionOfBuildTime() != 259 {
-		t.Errorf("Failed to parse portion of build time. Expected 259, have %d\n", timing.GetPortionOfBuildTime())
-	}
-
-	// Test with a multiword phase name
-	line2 := "Total target pattern evaluation phase  time  0.012 s    4.59%"
-
-	timing = parsePhaseTiming(line2)
-	if timing.GetPhaseName() != "target pattern evaluation" {
-		t.Errorf("Failed to parse phase name. Expected target pattern evaluation, have %s\n", timing.GetPhaseName())
-	} else if timing.GetDurationNanos() != 12000000 {
-		t.Errorf("Failed to parse duration nanos. Expected 12000000, have %d\n", timing.GetDurationNanos())
-	} else if timing.GetPortionOfBuildTime() != 459 {
-		t.Errorf("Failed to parse portion of build time. Expected 459, have %d\n", timing.GetPortionOfBuildTime())
-	}
-}
-
-func TestParseTotal(t *testing.T) {
-	// Total line is in the form of:
-	// Total run time                                       7.563 s  100.00%
-
-	line := "Total run time                                       7.563 s  100.00%"
-
-	total := parseTotal(line)
-
-	// Only the seconds field is parsed, as nanos
-	if total != 7563000000 {
-		t.Errorf("Failed to parse total build time. Expected 7563000000, have %d\n", total)
-	}
-}
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index d68ced8..4a275a8 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -32,7 +32,6 @@
 // of what an event is and how the metrics system is a stack based system.
 
 import (
-	"fmt"
 	"os"
 	"runtime"
 	"strings"
@@ -228,20 +227,6 @@
 	m.metrics.BuildDateTimestamp = proto.Int64(buildTimestamp.UnixNano() / int64(time.Second))
 }
 
-func (m *Metrics) UpdateTotalRealTimeAndNonZeroExit(data []byte, bazelExitCode int32) error {
-	if err := proto.Unmarshal(data, &m.metrics); err != nil {
-		return fmt.Errorf("Failed to unmarshal proto: %w", err)
-	}
-	startTime := *m.metrics.Total.StartTime
-	endTime := uint64(time.Now().UnixNano())
-
-	*m.metrics.Total.RealTime = *proto.Uint64(endTime - startTime)
-
-	bazelError := bazelExitCode != 0
-	m.metrics.NonZeroExit = proto.Bool(bazelError)
-	return nil
-}
-
 // SetBuildCommand adds the build command specified by the user to the
 // list of collected metrics.
 func (m *Metrics) SetBuildCommand(cmd []string) {
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index f3e677a..b75f572 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -279,7 +279,7 @@
 
 // Deprecated: Use ModuleTypeInfo_BuildSystem.Descriptor instead.
 func (ModuleTypeInfo_BuildSystem) EnumDescriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{5, 0}
+	return file_metrics_proto_rawDescGZIP(), []int{8, 0}
 }
 
 type ExpConfigFetcher_ConfigStatus int32
@@ -341,7 +341,7 @@
 
 // Deprecated: Use ExpConfigFetcher_ConfigStatus.Descriptor instead.
 func (ExpConfigFetcher_ConfigStatus) EnumDescriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{9, 0}
+	return file_metrics_proto_rawDescGZIP(), []int{12, 0}
 }
 
 type MetricsBase struct {
@@ -999,6 +999,177 @@
 	return ""
 }
 
+type PerfCounters struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The timestamp of these counters in nanoseconds.
+	Time *uint64 `protobuf:"varint,1,opt,name=time" json:"time,omitempty"`
+	// A list of counter names and values.
+	Groups []*PerfCounterGroup `protobuf:"bytes,2,rep,name=groups" json:"groups,omitempty"`
+}
+
+func (x *PerfCounters) Reset() {
+	*x = PerfCounters{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metrics_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PerfCounters) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PerfCounters) ProtoMessage() {}
+
+func (x *PerfCounters) ProtoReflect() protoreflect.Message {
+	mi := &file_metrics_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PerfCounters.ProtoReflect.Descriptor instead.
+func (*PerfCounters) Descriptor() ([]byte, []int) {
+	return file_metrics_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *PerfCounters) GetTime() uint64 {
+	if x != nil && x.Time != nil {
+		return *x.Time
+	}
+	return 0
+}
+
+func (x *PerfCounters) GetGroups() []*PerfCounterGroup {
+	if x != nil {
+		return x.Groups
+	}
+	return nil
+}
+
+type PerfCounterGroup struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The name of this counter group (e.g. "cpu" or "memory")
+	Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+	// The counters in this group
+	Counters []*PerfCounter `protobuf:"bytes,2,rep,name=counters" json:"counters,omitempty"`
+}
+
+func (x *PerfCounterGroup) Reset() {
+	*x = PerfCounterGroup{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metrics_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PerfCounterGroup) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PerfCounterGroup) ProtoMessage() {}
+
+func (x *PerfCounterGroup) ProtoReflect() protoreflect.Message {
+	mi := &file_metrics_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PerfCounterGroup.ProtoReflect.Descriptor instead.
+func (*PerfCounterGroup) Descriptor() ([]byte, []int) {
+	return file_metrics_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *PerfCounterGroup) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (x *PerfCounterGroup) GetCounters() []*PerfCounter {
+	if x != nil {
+		return x.Counters
+	}
+	return nil
+}
+
+type PerfCounter struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The name of this counter.
+	Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+	// The value of this counter.
+	Value *int64 `protobuf:"varint,2,opt,name=value" json:"value,omitempty"`
+}
+
+func (x *PerfCounter) Reset() {
+	*x = PerfCounter{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metrics_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PerfCounter) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PerfCounter) ProtoMessage() {}
+
+func (x *PerfCounter) ProtoReflect() protoreflect.Message {
+	mi := &file_metrics_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PerfCounter.ProtoReflect.Descriptor instead.
+func (*PerfCounter) Descriptor() ([]byte, []int) {
+	return file_metrics_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *PerfCounter) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (x *PerfCounter) GetValue() int64 {
+	if x != nil && x.Value != nil {
+		return *x.Value
+	}
+	return 0
+}
+
 type ProcessResourceInfo struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -1029,7 +1200,7 @@
 func (x *ProcessResourceInfo) Reset() {
 	*x = ProcessResourceInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[4]
+		mi := &file_metrics_proto_msgTypes[7]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1042,7 +1213,7 @@
 func (*ProcessResourceInfo) ProtoMessage() {}
 
 func (x *ProcessResourceInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[4]
+	mi := &file_metrics_proto_msgTypes[7]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1055,7 +1226,7 @@
 
 // Deprecated: Use ProcessResourceInfo.ProtoReflect.Descriptor instead.
 func (*ProcessResourceInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{4}
+	return file_metrics_proto_rawDescGZIP(), []int{7}
 }
 
 func (x *ProcessResourceInfo) GetName() string {
@@ -1149,7 +1320,7 @@
 func (x *ModuleTypeInfo) Reset() {
 	*x = ModuleTypeInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[5]
+		mi := &file_metrics_proto_msgTypes[8]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1162,7 +1333,7 @@
 func (*ModuleTypeInfo) ProtoMessage() {}
 
 func (x *ModuleTypeInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[5]
+	mi := &file_metrics_proto_msgTypes[8]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1175,7 +1346,7 @@
 
 // Deprecated: Use ModuleTypeInfo.ProtoReflect.Descriptor instead.
 func (*ModuleTypeInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{5}
+	return file_metrics_proto_rawDescGZIP(), []int{8}
 }
 
 func (x *ModuleTypeInfo) GetBuildSystem() ModuleTypeInfo_BuildSystem {
@@ -1213,7 +1384,7 @@
 func (x *CriticalUserJourneyMetrics) Reset() {
 	*x = CriticalUserJourneyMetrics{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[6]
+		mi := &file_metrics_proto_msgTypes[9]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1226,7 +1397,7 @@
 func (*CriticalUserJourneyMetrics) ProtoMessage() {}
 
 func (x *CriticalUserJourneyMetrics) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[6]
+	mi := &file_metrics_proto_msgTypes[9]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1239,7 +1410,7 @@
 
 // Deprecated: Use CriticalUserJourneyMetrics.ProtoReflect.Descriptor instead.
 func (*CriticalUserJourneyMetrics) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{6}
+	return file_metrics_proto_rawDescGZIP(), []int{9}
 }
 
 func (x *CriticalUserJourneyMetrics) GetName() string {
@@ -1268,7 +1439,7 @@
 func (x *CriticalUserJourneysMetrics) Reset() {
 	*x = CriticalUserJourneysMetrics{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[7]
+		mi := &file_metrics_proto_msgTypes[10]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1281,7 +1452,7 @@
 func (*CriticalUserJourneysMetrics) ProtoMessage() {}
 
 func (x *CriticalUserJourneysMetrics) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[7]
+	mi := &file_metrics_proto_msgTypes[10]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1294,7 +1465,7 @@
 
 // Deprecated: Use CriticalUserJourneysMetrics.ProtoReflect.Descriptor instead.
 func (*CriticalUserJourneysMetrics) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{7}
+	return file_metrics_proto_rawDescGZIP(), []int{10}
 }
 
 func (x *CriticalUserJourneysMetrics) GetCujs() []*CriticalUserJourneyMetrics {
@@ -1323,12 +1494,14 @@
 	Events []*PerfInfo `protobuf:"bytes,6,rep,name=events" json:"events,omitempty"`
 	// Mixed Builds information
 	MixedBuildsInfo *MixedBuildsInfo `protobuf:"bytes,7,opt,name=mixed_builds_info,json=mixedBuildsInfo" json:"mixed_builds_info,omitempty"`
+	// Performance during for soong_build execution.
+	PerfCounters []*PerfCounters `protobuf:"bytes,8,rep,name=perf_counters,json=perfCounters" json:"perf_counters,omitempty"`
 }
 
 func (x *SoongBuildMetrics) Reset() {
 	*x = SoongBuildMetrics{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[8]
+		mi := &file_metrics_proto_msgTypes[11]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1341,7 +1514,7 @@
 func (*SoongBuildMetrics) ProtoMessage() {}
 
 func (x *SoongBuildMetrics) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[8]
+	mi := &file_metrics_proto_msgTypes[11]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1354,7 +1527,7 @@
 
 // Deprecated: Use SoongBuildMetrics.ProtoReflect.Descriptor instead.
 func (*SoongBuildMetrics) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{8}
+	return file_metrics_proto_rawDescGZIP(), []int{11}
 }
 
 func (x *SoongBuildMetrics) GetModules() uint32 {
@@ -1406,6 +1579,13 @@
 	return nil
 }
 
+func (x *SoongBuildMetrics) GetPerfCounters() []*PerfCounters {
+	if x != nil {
+		return x.PerfCounters
+	}
+	return nil
+}
+
 type ExpConfigFetcher struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -1425,7 +1605,7 @@
 func (x *ExpConfigFetcher) Reset() {
 	*x = ExpConfigFetcher{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[9]
+		mi := &file_metrics_proto_msgTypes[12]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1438,7 +1618,7 @@
 func (*ExpConfigFetcher) ProtoMessage() {}
 
 func (x *ExpConfigFetcher) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[9]
+	mi := &file_metrics_proto_msgTypes[12]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1451,7 +1631,7 @@
 
 // Deprecated: Use ExpConfigFetcher.ProtoReflect.Descriptor instead.
 func (*ExpConfigFetcher) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{9}
+	return file_metrics_proto_rawDescGZIP(), []int{12}
 }
 
 func (x *ExpConfigFetcher) GetStatus() ExpConfigFetcher_ConfigStatus {
@@ -1489,7 +1669,7 @@
 func (x *MixedBuildsInfo) Reset() {
 	*x = MixedBuildsInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[10]
+		mi := &file_metrics_proto_msgTypes[13]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1502,7 +1682,7 @@
 func (*MixedBuildsInfo) ProtoMessage() {}
 
 func (x *MixedBuildsInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[10]
+	mi := &file_metrics_proto_msgTypes[13]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1515,7 +1695,7 @@
 
 // Deprecated: Use MixedBuildsInfo.ProtoReflect.Descriptor instead.
 func (*MixedBuildsInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{10}
+	return file_metrics_proto_rawDescGZIP(), []int{13}
 }
 
 func (x *MixedBuildsInfo) GetMixedBuildEnabledModules() []string {
@@ -1552,7 +1732,7 @@
 func (x *CriticalPathInfo) Reset() {
 	*x = CriticalPathInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[11]
+		mi := &file_metrics_proto_msgTypes[14]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1565,7 +1745,7 @@
 func (*CriticalPathInfo) ProtoMessage() {}
 
 func (x *CriticalPathInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[11]
+	mi := &file_metrics_proto_msgTypes[14]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1578,7 +1758,7 @@
 
 // Deprecated: Use CriticalPathInfo.ProtoReflect.Descriptor instead.
 func (*CriticalPathInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{11}
+	return file_metrics_proto_rawDescGZIP(), []int{14}
 }
 
 func (x *CriticalPathInfo) GetElapsedTimeMicros() uint64 {
@@ -1623,7 +1803,7 @@
 func (x *JobInfo) Reset() {
 	*x = JobInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[12]
+		mi := &file_metrics_proto_msgTypes[15]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1636,7 +1816,7 @@
 func (*JobInfo) ProtoMessage() {}
 
 func (x *JobInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[12]
+	mi := &file_metrics_proto_msgTypes[15]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1649,7 +1829,7 @@
 
 // Deprecated: Use JobInfo.ProtoReflect.Descriptor instead.
 func (*JobInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{12}
+	return file_metrics_proto_rawDescGZIP(), []int{15}
 }
 
 func (x *JobInfo) GetElapsedTimeMicros() uint64 {
@@ -1856,132 +2036,153 @@
 	0x6f, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f,
 	0x6e, 0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72,
 	0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb9,
-	0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
-	0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x75, 0x73,
-	0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69,
-	0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74,
-	0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04,
-	0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72,
-	0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73, 0x4b, 0x62,
-	0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66,
-	0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x69, 0x6e,
-	0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11,
-	0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74,
-	0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x50, 0x61,
-	0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f, 0x5f, 0x69,
-	0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x69,
-	0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f, 0x5f, 0x6f,
-	0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a,
-	0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a, 0x76, 0x6f,
-	0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f,
-	0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18,
-	0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
-	0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e, 0x76, 0x6f,
-	0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f,
-	0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a,
-	0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65,
-	0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x0e, 0x4d,
-	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x5b, 0x0a,
-	0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c,
-	0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
-	0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79,
-	0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52, 0x0b, 0x62,
-	0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6e,
-	0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20,
-	0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
-	0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d,
-	0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a,
-	0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41, 0x4b, 0x45,
-	0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73,
+	0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x61,
+	0x0a, 0x0c, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x12, 0x12,
+	0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x69,
+	0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
+	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75,
+	0x6e, 0x74, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70,
+	0x73, 0x22, 0x64, 0x0a, 0x10, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,
+	0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x08, 0x63, 0x6f, 0x75,
+	0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f,
+	0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x08, 0x63,
+	0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0x37, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x66, 0x43,
+	0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
+	0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x22, 0xb9, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f,
+	0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10,
+	0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65,
+	0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d,
+	0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69,
+	0x63, 0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f,
+	0x6b, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73,
+	0x4b, 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65,
+	0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d,
+	0x69, 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a,
+	0x0a, 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75,
+	0x6c, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72,
+	0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f,
+	0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x09, 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f,
+	0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a,
+	0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
+	0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65,
+	0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e,
+	0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
+	0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e,
+	0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a,
+	0x0e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12,
+	0x5b, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
+	0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75,
+	0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64,
+	0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52,
+	0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b,
+	0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a,
+	0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75,
+	0x6c, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74,
+	0x65, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12,
+	0x09, 0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41,
+	0x4b, 0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c,
+	0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
+	0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65,
+	0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73,
+	0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x73, 0x12, 0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
+	0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73,
 	0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
-	0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
-	0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72,
-	0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72,
-	0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12,
-	0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e,
+	0x52, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x22, 0x94, 0x03, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67,
+	0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07,
+	0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d,
+	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e,
+	0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e,
+	0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f,
+	0x63, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74,
+	0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28,
+	0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69,
+	0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41,
+	0x6c, 0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f,
+	0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x0b, 0x6d, 0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06,
+	0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73,
+	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65,
+	0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69,
+	0x6c, 0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24,
+	0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
+	0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73,
+	0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
+	0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x46, 0x0a, 0x0d, 0x70, 0x65, 0x72, 0x66, 0x5f, 0x63, 0x6f,
+	0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73,
+	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x52,
+	0x0c, 0x70, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0xdb, 0x01,
+	0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68,
+	0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
+	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66,
+	0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+	0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a,
+	0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69,
+	0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72,
+	0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74,
+	0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10,
+	0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a,
+	0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53,
+	0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, 0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f,
+	0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12,
+	0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65,
+	0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
+	0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f,
+	0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69,
+	0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
+	0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22,
+	0x8a, 0x02, 0x0a, 0x10, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68,
+	0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f,
+	0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69,
+	0x63, 0x72, 0x6f, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c,
+	0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f,
+	0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61,
+	0x6c, 0x50, 0x61, 0x74, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12,
+	0x41, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68,
+	0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62,
+	0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62,
+	0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61,
+	0x74, 0x68, 0x12, 0x48, 0x0a, 0x11, 0x6c, 0x6f, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69,
+	0x6e, 0x67, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e,
 	0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72,
-	0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72,
-	0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x04,
-	0x63, 0x75, 0x6a, 0x73, 0x22, 0xcc, 0x02, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x42, 0x75,
-	0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d, 0x6f, 0x64,
-	0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73,
-	0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f,
-	0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74, 0x6f, 0x74,
-	0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10,
-	0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69, 0x7a, 0x65,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c,
-	0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x65,
-	0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d,
-	0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x65, 0x76,
-	0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f,
-	0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74,
-	0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
-	0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73,
-	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
-	0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e,
-	0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49,
-	0x6e, 0x66, 0x6f, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69,
-	0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74,
-	0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
-	0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45,
-	0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e,
-	0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74,
-	0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65,
-	0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04,
-	0x52, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66,
-	0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43,
-	0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49,
-	0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11,
-	0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, 0x10,
-	0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
-	0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62,
-	0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64,
-	0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65,
-	0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64,
-	0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75,
-	0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64,
-	0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65,
-	0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x8a, 0x02, 0x0a, 0x10, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63,
-	0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c,
-	0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f,
-	0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64,
-	0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x63, 0x72,
-	0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65,
-	0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x63,
-	0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x4d,
-	0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x41, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61,
-	0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73,
-	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
-	0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x63, 0x72, 0x69, 0x74,
-	0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x11, 0x6c, 0x6f, 0x6e, 0x67,
-	0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x05, 0x20,
-	0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c,
-	0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66,
-	0x6f, 0x52, 0x0f, 0x6c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x4a, 0x6f,
-	0x62, 0x73, 0x22, 0x62, 0x0a, 0x07, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a,
-	0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69,
-	0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70,
-	0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x27, 0x0a,
-	0x0f, 0x6a, 0x6f, 0x62, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6a, 0x6f, 0x62, 0x44, 0x65, 0x73, 0x63, 0x72,
-	0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
-	0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69,
-	0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6c, 0x6f, 0x6e,
+	0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x62, 0x0a, 0x07,
+	0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73,
+	0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d,
+	0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6a, 0x6f, 0x62, 0x5f, 0x64,
+	0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0e, 0x6a, 0x6f, 0x62, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+	0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e,
+	0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74,
+	0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
 }
 
 var (
@@ -1997,7 +2198,7 @@
 }
 
 var file_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
-var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
+var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 16)
 var file_metrics_proto_goTypes = []interface{}{
 	(MetricsBase_BuildVariant)(0),          // 0: soong_build_metrics.MetricsBase.BuildVariant
 	(MetricsBase_Arch)(0),                  // 1: soong_build_metrics.MetricsBase.Arch
@@ -2008,15 +2209,18 @@
 	(*BuildConfig)(nil),                    // 6: soong_build_metrics.BuildConfig
 	(*SystemResourceInfo)(nil),             // 7: soong_build_metrics.SystemResourceInfo
 	(*PerfInfo)(nil),                       // 8: soong_build_metrics.PerfInfo
-	(*ProcessResourceInfo)(nil),            // 9: soong_build_metrics.ProcessResourceInfo
-	(*ModuleTypeInfo)(nil),                 // 10: soong_build_metrics.ModuleTypeInfo
-	(*CriticalUserJourneyMetrics)(nil),     // 11: soong_build_metrics.CriticalUserJourneyMetrics
-	(*CriticalUserJourneysMetrics)(nil),    // 12: soong_build_metrics.CriticalUserJourneysMetrics
-	(*SoongBuildMetrics)(nil),              // 13: soong_build_metrics.SoongBuildMetrics
-	(*ExpConfigFetcher)(nil),               // 14: soong_build_metrics.ExpConfigFetcher
-	(*MixedBuildsInfo)(nil),                // 15: soong_build_metrics.MixedBuildsInfo
-	(*CriticalPathInfo)(nil),               // 16: soong_build_metrics.CriticalPathInfo
-	(*JobInfo)(nil),                        // 17: soong_build_metrics.JobInfo
+	(*PerfCounters)(nil),                   // 9: soong_build_metrics.PerfCounters
+	(*PerfCounterGroup)(nil),               // 10: soong_build_metrics.PerfCounterGroup
+	(*PerfCounter)(nil),                    // 11: soong_build_metrics.PerfCounter
+	(*ProcessResourceInfo)(nil),            // 12: soong_build_metrics.ProcessResourceInfo
+	(*ModuleTypeInfo)(nil),                 // 13: soong_build_metrics.ModuleTypeInfo
+	(*CriticalUserJourneyMetrics)(nil),     // 14: soong_build_metrics.CriticalUserJourneyMetrics
+	(*CriticalUserJourneysMetrics)(nil),    // 15: soong_build_metrics.CriticalUserJourneysMetrics
+	(*SoongBuildMetrics)(nil),              // 16: soong_build_metrics.SoongBuildMetrics
+	(*ExpConfigFetcher)(nil),               // 17: soong_build_metrics.ExpConfigFetcher
+	(*MixedBuildsInfo)(nil),                // 18: soong_build_metrics.MixedBuildsInfo
+	(*CriticalPathInfo)(nil),               // 19: soong_build_metrics.CriticalPathInfo
+	(*JobInfo)(nil),                        // 20: soong_build_metrics.JobInfo
 }
 var file_metrics_proto_depIdxs = []int32{
 	0,  // 0: soong_build_metrics.MetricsBase.target_build_variant:type_name -> soong_build_metrics.MetricsBase.BuildVariant
@@ -2028,27 +2232,30 @@
 	8,  // 6: soong_build_metrics.MetricsBase.soong_runs:type_name -> soong_build_metrics.PerfInfo
 	8,  // 7: soong_build_metrics.MetricsBase.ninja_runs:type_name -> soong_build_metrics.PerfInfo
 	8,  // 8: soong_build_metrics.MetricsBase.total:type_name -> soong_build_metrics.PerfInfo
-	13, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics
+	16, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics
 	6,  // 10: soong_build_metrics.MetricsBase.build_config:type_name -> soong_build_metrics.BuildConfig
 	7,  // 11: soong_build_metrics.MetricsBase.system_resource_info:type_name -> soong_build_metrics.SystemResourceInfo
 	8,  // 12: soong_build_metrics.MetricsBase.bazel_runs:type_name -> soong_build_metrics.PerfInfo
-	14, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher
-	16, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo
+	17, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher
+	19, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo
 	2,  // 15: soong_build_metrics.BuildConfig.ninja_weight_list_source:type_name -> soong_build_metrics.BuildConfig.NinjaWeightListSource
-	9,  // 16: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo
-	3,  // 17: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem
-	5,  // 18: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase
-	11, // 19: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics
-	8,  // 20: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo
-	15, // 21: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo
-	4,  // 22: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus
-	17, // 23: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo
-	17, // 24: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo
-	25, // [25:25] is the sub-list for method output_type
-	25, // [25:25] is the sub-list for method input_type
-	25, // [25:25] is the sub-list for extension type_name
-	25, // [25:25] is the sub-list for extension extendee
-	0,  // [0:25] is the sub-list for field type_name
+	12, // 16: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo
+	10, // 17: soong_build_metrics.PerfCounters.groups:type_name -> soong_build_metrics.PerfCounterGroup
+	11, // 18: soong_build_metrics.PerfCounterGroup.counters:type_name -> soong_build_metrics.PerfCounter
+	3,  // 19: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem
+	5,  // 20: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase
+	14, // 21: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics
+	8,  // 22: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo
+	18, // 23: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo
+	9,  // 24: soong_build_metrics.SoongBuildMetrics.perf_counters:type_name -> soong_build_metrics.PerfCounters
+	4,  // 25: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus
+	20, // 26: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo
+	20, // 27: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo
+	28, // [28:28] is the sub-list for method output_type
+	28, // [28:28] is the sub-list for method input_type
+	28, // [28:28] is the sub-list for extension type_name
+	28, // [28:28] is the sub-list for extension extendee
+	0,  // [0:28] is the sub-list for field type_name
 }
 
 func init() { file_metrics_proto_init() }
@@ -2106,7 +2313,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ProcessResourceInfo); i {
+			switch v := v.(*PerfCounters); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2118,7 +2325,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ModuleTypeInfo); i {
+			switch v := v.(*PerfCounterGroup); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2130,7 +2337,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*CriticalUserJourneyMetrics); i {
+			switch v := v.(*PerfCounter); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2142,7 +2349,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*CriticalUserJourneysMetrics); i {
+			switch v := v.(*ProcessResourceInfo); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2154,7 +2361,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*SoongBuildMetrics); i {
+			switch v := v.(*ModuleTypeInfo); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2166,7 +2373,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ExpConfigFetcher); i {
+			switch v := v.(*CriticalUserJourneyMetrics); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2178,7 +2385,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*MixedBuildsInfo); i {
+			switch v := v.(*CriticalUserJourneysMetrics); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2190,7 +2397,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*CriticalPathInfo); i {
+			switch v := v.(*SoongBuildMetrics); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2202,6 +2409,42 @@
 			}
 		}
 		file_metrics_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ExpConfigFetcher); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metrics_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MixedBuildsInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metrics_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CriticalPathInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metrics_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*JobInfo); i {
 			case 0:
 				return &v.state
@@ -2220,7 +2463,7 @@
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_metrics_proto_rawDesc,
 			NumEnums:      5,
-			NumMessages:   13,
+			NumMessages:   16,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index b437da7..11fcba7 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -213,6 +213,30 @@
   optional string error_message = 8;
 }
 
+message PerfCounters {
+  // The timestamp of these counters in nanoseconds.
+  optional uint64 time = 1;
+
+  // A list of counter names and values.
+  repeated PerfCounterGroup groups = 2;
+}
+
+message PerfCounterGroup {
+  // The name of this counter group (e.g. "cpu" or "memory")
+  optional string name = 1;
+
+  // The counters in this group
+  repeated PerfCounter counters = 2;
+}
+
+message PerfCounter {
+  // The name of this counter.
+  optional string name = 1;
+
+  // The value of this counter.
+  optional int64 value = 2;
+}
+
 message ProcessResourceInfo {
   // The name of the process for identification.
   optional string name = 1;
@@ -295,6 +319,9 @@
 
   // Mixed Builds information
   optional MixedBuildsInfo mixed_builds_info = 7;
+
+  // Performance during for soong_build execution.
+  repeated PerfCounters perf_counters = 8;
 }
 
 message ExpConfigFetcher {
diff --git a/ui/status/ninja.go b/ui/status/ninja.go
index fb760ac..8c3ff29 100644
--- a/ui/status/ninja.go
+++ b/ui/status/ninja.go
@@ -20,6 +20,7 @@
 	"io"
 	"os"
 	"regexp"
+	"runtime"
 	"strings"
 	"syscall"
 	"time"
@@ -40,10 +41,11 @@
 	}
 
 	n := &NinjaReader{
-		status: status,
-		fifo:   fifo,
-		done:   make(chan bool),
-		cancel: make(chan bool),
+		status:     status,
+		fifo:       fifo,
+		forceClose: make(chan bool),
+		done:       make(chan bool),
+		cancelOpen: make(chan bool),
 	}
 
 	go n.run()
@@ -52,10 +54,11 @@
 }
 
 type NinjaReader struct {
-	status ToolStatus
-	fifo   string
-	done   chan bool
-	cancel chan bool
+	status     ToolStatus
+	fifo       string
+	forceClose chan bool
+	done       chan bool
+	cancelOpen chan bool
 }
 
 const NINJA_READER_CLOSE_TIMEOUT = 5 * time.Second
@@ -63,18 +66,34 @@
 // Close waits for NinjaReader to finish reading from the fifo, or 5 seconds.
 func (n *NinjaReader) Close() {
 	// Signal the goroutine to stop if it is blocking opening the fifo.
-	close(n.cancel)
+	close(n.cancelOpen)
 
+	// Ninja should already have exited or been killed, wait 5 seconds for the FIFO to be closed and any
+	// remaining messages to be processed through the NinjaReader.run goroutine.
 	timeoutCh := time.After(NINJA_READER_CLOSE_TIMEOUT)
-
 	select {
 	case <-n.done:
-		// Nothing
+		return
 	case <-timeoutCh:
-		n.status.Error(fmt.Sprintf("ninja fifo didn't finish after %s", NINJA_READER_CLOSE_TIMEOUT.String()))
+		// Channel is not closed yet
 	}
 
-	return
+	n.status.Error(fmt.Sprintf("ninja fifo didn't finish after %s", NINJA_READER_CLOSE_TIMEOUT.String()))
+
+	// Force close the reader even if the FIFO didn't close.
+	close(n.forceClose)
+
+	// Wait again for the reader thread to acknowledge the close before giving up and assuming it isn't going
+	// to send anything else.
+	timeoutCh = time.After(NINJA_READER_CLOSE_TIMEOUT)
+	select {
+	case <-n.done:
+		return
+	case <-timeoutCh:
+		// Channel is not closed yet
+	}
+
+	n.status.Verbose(fmt.Sprintf("ninja fifo didn't finish even after force closing after %s", NINJA_READER_CLOSE_TIMEOUT.String()))
 }
 
 func (n *NinjaReader) run() {
@@ -98,7 +117,7 @@
 	select {
 	case f = <-fileCh:
 		// Nothing
-	case <-n.cancel:
+	case <-n.cancelOpen:
 		return
 	}
 
@@ -108,43 +127,90 @@
 
 	running := map[uint32]*Action{}
 
+	msgChan := make(chan *ninja_frontend.Status)
+
+	// Read from the ninja fifo and decode the protobuf in a goroutine so the main NinjaReader.run goroutine
+	// can listen
+	go func() {
+		defer close(msgChan)
+		for {
+			size, err := readVarInt(r)
+			if err != nil {
+				if err != io.EOF {
+					n.status.Error(fmt.Sprintf("Got error reading from ninja: %s", err))
+				}
+				return
+			}
+
+			buf := make([]byte, size)
+			_, err = io.ReadFull(r, buf)
+			if err != nil {
+				if err == io.EOF {
+					n.status.Print(fmt.Sprintf("Missing message of size %d from ninja\n", size))
+				} else {
+					n.status.Error(fmt.Sprintf("Got error reading from ninja: %s", err))
+				}
+				return
+			}
+
+			msg := &ninja_frontend.Status{}
+			err = proto.Unmarshal(buf, msg)
+			if err != nil {
+				n.status.Print(fmt.Sprintf("Error reading message from ninja: %v", err))
+				continue
+			}
+
+			msgChan <- msg
+		}
+	}()
+
 	for {
-		size, err := readVarInt(r)
-		if err != nil {
-			if err != io.EOF {
-				n.status.Error(fmt.Sprintf("Got error reading from ninja: %s", err))
+		var msg *ninja_frontend.Status
+		var msgOk bool
+		select {
+		case <-n.forceClose:
+			// Close() has been called, but the reader goroutine didn't get EOF after 5 seconds
+			break
+		case msg, msgOk = <-msgChan:
+			// msg is ready or closed
+		}
+
+		if !msgOk {
+			// msgChan is closed
+			break
+		}
+
+		if msg.BuildStarted != nil {
+			parallelism := uint32(runtime.NumCPU())
+			if msg.BuildStarted.GetParallelism() > 0 {
+				parallelism = msg.BuildStarted.GetParallelism()
 			}
-			return
-		}
+			// It is estimated from total time / parallelism assumming the build is packing enough.
+			estimatedDurationFromTotal := time.Duration(msg.BuildStarted.GetEstimatedTotalTime()/parallelism) * time.Millisecond
+			// It is estimated from critical path time which is useful for small size build.
+			estimatedDurationFromCriticalPath := time.Duration(msg.BuildStarted.GetCriticalPathTime()) * time.Millisecond
+			// Select the longer one.
+			estimatedDuration := max(estimatedDurationFromTotal, estimatedDurationFromCriticalPath)
 
-		buf := make([]byte, size)
-		_, err = io.ReadFull(r, buf)
-		if err != nil {
-			if err == io.EOF {
-				n.status.Print(fmt.Sprintf("Missing message of size %d from ninja\n", size))
-			} else {
-				n.status.Error(fmt.Sprintf("Got error reading from ninja: %s", err))
+			if estimatedDuration > 0 {
+				n.status.SetEstimatedTime(time.Now().Add(estimatedDuration))
+				n.status.Verbose(fmt.Sprintf("parallelism: %d, estimated from total time: %s, critical path time: %s",
+					parallelism,
+					estimatedDurationFromTotal,
+					estimatedDurationFromCriticalPath))
+
 			}
-			return
 		}
-
-		msg := &ninja_frontend.Status{}
-		err = proto.Unmarshal(buf, msg)
-		if err != nil {
-			n.status.Print(fmt.Sprintf("Error reading message from ninja: %v", err))
-			continue
-		}
-
-		// Ignore msg.BuildStarted
 		if msg.TotalEdges != nil {
 			n.status.SetTotalActions(int(msg.TotalEdges.GetTotalEdges()))
 		}
 		if msg.EdgeStarted != nil {
 			action := &Action{
-				Description: msg.EdgeStarted.GetDesc(),
-				Outputs:     msg.EdgeStarted.Outputs,
-				Inputs:      msg.EdgeStarted.Inputs,
-				Command:     msg.EdgeStarted.GetCommand(),
+				Description:   msg.EdgeStarted.GetDesc(),
+				Outputs:       msg.EdgeStarted.Outputs,
+				Inputs:        msg.EdgeStarted.Inputs,
+				Command:       msg.EdgeStarted.GetCommand(),
+				ChangedInputs: msg.EdgeStarted.ChangedInputs,
 			}
 			n.status.StartAction(action)
 			running[msg.EdgeStarted.GetId()] = action
diff --git a/ui/status/ninja_frontend/README b/ui/status/ninja_frontend/README
index 8c4b451..767bbf1 100644
--- a/ui/status/ninja_frontend/README
+++ b/ui/status/ninja_frontend/README
@@ -1,3 +1,3 @@
-This comes from https://android.googlesource.com/platform/external/ninja/+/master/src/frontend.proto
+This comes from https://android.googlesource.com/platform/external/ninja/+/main/src/frontend.proto
 
 The only difference is the specification of a go_package. To regenerate frontend.pb.go, run regen.sh.
diff --git a/ui/status/ninja_frontend/frontend.pb.go b/ui/status/ninja_frontend/frontend.pb.go
index d0c4953..fce7ca2 100644
--- a/ui/status/ninja_frontend/frontend.pb.go
+++ b/ui/status/ninja_frontend/frontend.pb.go
@@ -14,7 +14,7 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.28.1
+// 	protoc-gen-go v1.30.0
 // 	protoc        v3.21.12
 // source: frontend.proto
 
@@ -240,6 +240,10 @@
 	Parallelism *uint32 `protobuf:"varint,1,opt,name=parallelism" json:"parallelism,omitempty"`
 	// Verbose value passed to ninja.
 	Verbose *bool `protobuf:"varint,2,opt,name=verbose" json:"verbose,omitempty"`
+	// Critical path's running time in milliseconds
+	CriticalPathTime *uint32 `protobuf:"varint,3,opt,name=critical_path_time,json=criticalPathTime" json:"critical_path_time,omitempty"`
+	// Total running time of every need-to-build edge in milliseconds
+	EstimatedTotalTime *uint32 `protobuf:"varint,4,opt,name=estimated_total_time,json=estimatedTotalTime" json:"estimated_total_time,omitempty"`
 }
 
 func (x *Status_BuildStarted) Reset() {
@@ -288,6 +292,20 @@
 	return false
 }
 
+func (x *Status_BuildStarted) GetCriticalPathTime() uint32 {
+	if x != nil && x.CriticalPathTime != nil {
+		return *x.CriticalPathTime
+	}
+	return 0
+}
+
+func (x *Status_BuildStarted) GetEstimatedTotalTime() uint32 {
+	if x != nil && x.EstimatedTotalTime != nil {
+		return *x.EstimatedTotalTime
+	}
+	return 0
+}
+
 type Status_BuildFinished struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -345,6 +363,8 @@
 	Command *string `protobuf:"bytes,6,opt,name=command" json:"command,omitempty"`
 	// Edge uses console.
 	Console *bool `protobuf:"varint,7,opt,name=console" json:"console,omitempty"`
+	// Changed inputs.
+	ChangedInputs []string `protobuf:"bytes,8,rep,name=changed_inputs,json=changedInputs" json:"changed_inputs,omitempty"`
 }
 
 func (x *Status_EdgeStarted) Reset() {
@@ -428,6 +448,13 @@
 	return false
 }
 
+func (x *Status_EdgeStarted) GetChangedInputs() []string {
+	if x != nil {
+		return x.ChangedInputs
+	}
+	return nil
+}
+
 type Status_EdgeFinished struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -660,7 +687,7 @@
 
 var file_frontend_proto_rawDesc = []byte{
 	0x0a, 0x0e, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
-	0x12, 0x05, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x22, 0xc8, 0x0a, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74,
+	0x12, 0x05, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x22, 0xdb, 0x0b, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74,
 	0x75, 0x73, 0x12, 0x39, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x65, 0x64, 0x67, 0x65,
 	0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x2e,
 	0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x45, 0x64, 0x67, 0x65,
@@ -687,67 +714,77 @@
 	0x67, 0x65, 0x1a, 0x2d, 0x0a, 0x0a, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x73,
 	0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x65, 0x64, 0x67, 0x65, 0x73, 0x18,
 	0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x45, 0x64, 0x67, 0x65,
-	0x73, 0x1a, 0x4a, 0x0a, 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65,
-	0x64, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x69, 0x73, 0x6d,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c,
-	0x69, 0x73, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x1a, 0x0f, 0x0a,
-	0x0d, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x1a, 0xb6,
-	0x01, 0x0a, 0x0b, 0x45, 0x64, 0x67, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x12, 0x0e,
-	0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d,
-	0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x0d, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x16, 0x0a,
-	0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x69,
-	0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73,
-	0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12,
-	0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64,
-	0x65, 0x73, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x06,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x18, 0x0a,
-	0x07, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07,
-	0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x1a, 0xf3, 0x03, 0x0a, 0x0c, 0x45, 0x64, 0x67, 0x65,
-	0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f,
-	0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54,
-	0x69, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20,
-	0x01, 0x28, 0x11, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6f,
-	0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74,
-	0x70, 0x75, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65,
-	0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65,
-	0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18,
-	0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d,
-	0x65, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62, 0x18,
-	0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73, 0x4b, 0x62, 0x12,
-	0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61,
-	0x75, 0x6c, 0x74, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x69, 0x6e, 0x6f,
-	0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d,
-	0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73,
-	0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x50, 0x61, 0x67,
-	0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f, 0x5f, 0x69, 0x6e,
-	0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6f,
-	0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f, 0x5f, 0x6f, 0x75,
-	0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x69,
-	0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a, 0x76, 0x6f, 0x6c,
-	0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73,
-	0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x76,
-	0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53,
-	0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e, 0x76, 0x6f, 0x6c,
-	0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73,
-	0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x69,
-	0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78,
-	0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67,
-	0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x1a, 0x92, 0x01,
-	0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x05, 0x6c, 0x65, 0x76,
-	0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x6e, 0x69, 0x6e, 0x6a, 0x61,
-	0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e,
-	0x4c, 0x65, 0x76, 0x65, 0x6c, 0x3a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x52, 0x05, 0x6c, 0x65, 0x76,
-	0x65, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x34, 0x0a, 0x05,
-	0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x00, 0x12,
-	0x0b, 0x0a, 0x07, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05,
-	0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47,
-	0x10, 0x03, 0x42, 0x2a, 0x48, 0x03, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
-	0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2f,
-	0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x5f, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64,
+	0x73, 0x1a, 0xaa, 0x01, 0x0a, 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74,
+	0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x69, 0x73,
+	0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65,
+	0x6c, 0x69, 0x73, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x12, 0x2c,
+	0x0a, 0x12, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f,
+	0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x63, 0x72, 0x69, 0x74,
+	0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x14,
+	0x65, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f,
+	0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x65, 0x73, 0x74, 0x69,
+	0x6d, 0x61, 0x74, 0x65, 0x64, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x1a, 0x0f,
+	0x0a, 0x0d, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x1a,
+	0xe8, 0x01, 0x0a, 0x0b, 0x45, 0x64, 0x67, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x12,
+	0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12,
+	0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x0d, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x16,
+	0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06,
+	0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74,
+	0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73,
+	0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+	0x64, 0x65, 0x73, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18,
+	0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x18,
+	0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52,
+	0x07, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x68, 0x61, 0x6e,
+	0x67, 0x65, 0x64, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73,
+	0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x53,
+	0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x1a, 0xf3, 0x03, 0x0a, 0x0c, 0x45,
+	0x64, 0x67, 0x65, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69,
+	0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x65,
+	0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x65,
+	0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x11, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16,
+	0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
+	0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74,
+	0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54,
+	0x69, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x69,
+	0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d,
+	0x54, 0x69, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f,
+	0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73,
+	0x4b, 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65,
+	0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d,
+	0x69, 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a,
+	0x0a, 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75,
+	0x6c, 0x74, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72,
+	0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f,
+	0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x09, 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f,
+	0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a,
+	0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
+	0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65,
+	0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e,
+	0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
+	0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e,
+	0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04,
+	0x74, 0x61, 0x67, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73,
+	0x1a, 0x92, 0x01, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x05,
+	0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x6e, 0x69,
+	0x6e, 0x6a, 0x61, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61,
+	0x67, 0x65, 0x2e, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x3a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x52, 0x05,
+	0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22,
+	0x34, 0x0a, 0x05, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f,
+	0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12,
+	0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45,
+	0x42, 0x55, 0x47, 0x10, 0x03, 0x42, 0x2a, 0x48, 0x03, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f,
+	0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x73, 0x74, 0x61, 0x74,
+	0x75, 0x73, 0x2f, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x5f, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
+	0x64,
 }
 
 var (
diff --git a/ui/status/ninja_frontend/frontend.proto b/ui/status/ninja_frontend/frontend.proto
index 6cb4a0d..faa0d34 100644
--- a/ui/status/ninja_frontend/frontend.proto
+++ b/ui/status/ninja_frontend/frontend.proto
@@ -30,6 +30,10 @@
     optional uint32 parallelism = 1;
     // Verbose value passed to ninja.
     optional bool verbose = 2;
+    // Critical path's running time in milliseconds
+    optional uint32 critical_path_time = 3;
+    // Total running time of every need-to-build edge in milliseconds
+    optional uint32 estimated_total_time = 4;
   }
 
   message BuildFinished {
@@ -50,6 +54,8 @@
     optional string command = 6;
     // Edge uses console.
     optional bool console = 7;
+    // Changed inputs since last build.
+    repeated string changed_inputs = 8;
   }
 
   message EdgeFinished {
diff --git a/ui/status/status.go b/ui/status/status.go
index f3e58b6..52ed56a 100644
--- a/ui/status/status.go
+++ b/ui/status/status.go
@@ -19,6 +19,7 @@
 
 import (
 	"sync"
+	"time"
 )
 
 // Action describes an action taken (or as Ninja calls them, Edges).
@@ -40,6 +41,10 @@
 	// It's optional, but one of either Description or Command should be
 	// set.
 	Command string
+
+	// ChangedInputs is the (optional) list of inputs that have changed
+	// since last time this action was run.
+	ChangedInputs []string
 }
 
 // ActionResult describes the result of running an Action.
@@ -107,6 +112,8 @@
 	// FinishedActions are the number of actions that have been finished
 	// with FinishAction.
 	FinishedActions int
+
+	EstimatedTime time.Time
 }
 
 // ToolStatus is the interface used by tools to report on their Actions, and to
@@ -118,6 +125,7 @@
 	// This call be will ignored if it sets a number that is less than the
 	// current number of started actions.
 	SetTotalActions(total int)
+	SetEstimatedTime(estimatedTime time.Time)
 
 	// StartAction specifies that the associated action has been started by
 	// the tool.
@@ -267,6 +275,13 @@
 	s.counts.TotalActions += diff
 }
 
+func (s *Status) SetEstimatedTime(estimatedTime time.Time) {
+	s.lock.Lock()
+	defer s.lock.Unlock()
+
+	s.counts.EstimatedTime = estimatedTime
+}
+
 func (s *Status) startAction(action *Action) {
 	s.lock.Lock()
 	defer s.lock.Unlock()
@@ -329,6 +344,10 @@
 	}
 }
 
+func (d *toolStatus) SetEstimatedTime(estimatedTime time.Time) {
+	d.status.SetEstimatedTime(estimatedTime)
+}
+
 func (d *toolStatus) StartAction(action *Action) {
 	totalDiff := 0
 
diff --git a/ui/terminal/format.go b/ui/terminal/format.go
index 4205bdc..241a1dd 100644
--- a/ui/terminal/format.go
+++ b/ui/terminal/format.go
@@ -51,9 +51,22 @@
 	return ""
 }
 
+func remainingTimeString(t time.Time) string {
+	now := time.Now()
+	if t.After(now) {
+		return t.Sub(now).Round(time.Duration(time.Second)).String()
+	}
+	return time.Duration(0).Round(time.Duration(time.Second)).String()
+}
 func (s formatter) progress(counts status.Counts) string {
 	if s.format == "" {
-		return fmt.Sprintf("[%3d%% %d/%d] ", 100*counts.FinishedActions/counts.TotalActions, counts.FinishedActions, counts.TotalActions)
+		output := fmt.Sprintf("[%3d%% %d/%d", 100*counts.FinishedActions/counts.TotalActions, counts.FinishedActions, counts.TotalActions)
+
+		if !counts.EstimatedTime.IsZero() {
+			output += fmt.Sprintf(" %s remaining", remainingTimeString(counts.EstimatedTime))
+		}
+		output += "] "
+		return output
 	}
 
 	buf := &strings.Builder{}
@@ -93,6 +106,13 @@
 			fmt.Fprintf(buf, "%3d%%", 100*counts.FinishedActions/counts.TotalActions)
 		case 'e':
 			fmt.Fprintf(buf, "%.3f", time.Since(s.start).Seconds())
+		case 'l':
+			if counts.EstimatedTime.IsZero() {
+				// No esitimated data
+				buf.WriteRune('?')
+			} else {
+				fmt.Fprintf(buf, "%s", remainingTimeString(counts.EstimatedTime))
+			}
 		default:
 			buf.WriteString("unknown placeholder '")
 			buf.WriteByte(c)
diff --git a/ui/tracer/status.go b/ui/tracer/status.go
index f973613..8acf561 100644
--- a/ui/tracer/status.go
+++ b/ui/tracer/status.go
@@ -15,9 +15,10 @@
 package tracer
 
 import (
-	"android/soong/ui/status"
 	"strings"
 	"time"
+
+	"android/soong/ui/status"
 )
 
 func (t *tracerImpl) StatusTracer() status.StatusOutput {
@@ -110,6 +111,7 @@
 			VoluntaryContextSwitches:   result.Stats.VoluntaryContextSwitches,
 			InvoluntaryContextSwitches: result.Stats.InvoluntaryContextSwitches,
 			Tags:                       s.parseTags(result.Stats.Tags),
+			ChangedInputs:              result.Action.ChangedInputs,
 		},
 	})
 }
@@ -125,6 +127,7 @@
 	VoluntaryContextSwitches   uint64            `json:"voluntary_context_switches"`
 	InvoluntaryContextSwitches uint64            `json:"involuntary_context_switches"`
 	Tags                       map[string]string `json:"tags"`
+	ChangedInputs              []string          `json:"changed_inputs"`
 }
 
 func (s *statusOutput) Flush()                                        {}
diff --git a/ui/tracer/tracer.go b/ui/tracer/tracer.go
index b8fc87b..33b3d89 100644
--- a/ui/tracer/tracer.go
+++ b/ui/tracer/tracer.go
@@ -46,6 +46,8 @@
 	End(thread Thread)
 	Complete(name string, thread Thread, begin, end uint64)
 
+	CountersAtTime(name string, thread Thread, time uint64, counters []Counter)
+
 	ImportMicrofactoryLog(filename string)
 
 	StatusTracer() status.StatusOutput
@@ -247,3 +249,48 @@
 		Tid:   uint64(thread),
 	})
 }
+
+type Counter struct {
+	Name  string
+	Value int64
+}
+
+type countersMarshaller []Counter
+
+var _ json.Marshaler = countersMarshaller(nil)
+
+func (counters countersMarshaller) MarshalJSON() ([]byte, error) {
+	// This produces similar output to a map[string]int64, but maintains the order of the slice.
+	buf := bytes.Buffer{}
+	buf.WriteRune('{')
+	for i, counter := range counters {
+		name, err := json.Marshal(counter.Name)
+		if err != nil {
+			return nil, err
+		}
+		buf.Write(name)
+		buf.WriteByte(':')
+		value, err := json.Marshal(counter.Value)
+		if err != nil {
+			return nil, err
+		}
+		buf.Write(value)
+		if i != len(counters)-1 {
+			buf.WriteRune(',')
+		}
+	}
+	buf.WriteRune('}')
+	return buf.Bytes(), nil
+}
+
+// CountersAtTime writes a Counter event at the given timestamp in nanoseconds.
+func (t *tracerImpl) CountersAtTime(name string, thread Thread, time uint64, counters []Counter) {
+	t.writeEvent(&viewerEvent{
+		Name:  name,
+		Phase: "C",
+		Time:  time / 1000,
+		Pid:   0,
+		Tid:   uint64(thread),
+		Arg:   countersMarshaller(counters),
+	})
+}
diff --git a/xml/Android.bp b/xml/Android.bp
index d4753de..1542930 100644
--- a/xml/Android.bp
+++ b/xml/Android.bp
@@ -9,7 +9,6 @@
         "blueprint",
         "blueprint-pathtools",
         "soong",
-        "soong-bp2build",
         "soong-android",
         "soong-etc",
     ],
@@ -19,7 +18,6 @@
     ],
     testSrcs: [
         "xml_test.go",
-        "xml_conversion_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/xml/xml.go b/xml/xml.go
index 8c0c072..c281078 100644
--- a/xml/xml.go
+++ b/xml/xml.go
@@ -16,7 +16,6 @@
 
 import (
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/etc"
 
 	"github.com/google/blueprint"
@@ -68,8 +67,6 @@
 }
 
 type prebuiltEtcXml struct {
-	android.BazelModuleBase
-
 	etc.PrebuiltEtc
 
 	properties prebuiltEtcXmlProperties
@@ -132,40 +129,5 @@
 	etc.InitPrebuiltEtcModule(&module.PrebuiltEtc, "etc")
 	// This module is device-only
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
-	android.InitBazelModule(module)
 	return module
 }
-
-type bazelPrebuiltEtcXmlAttributes struct {
-	Src               bazel.LabelAttribute
-	Filename          bazel.LabelAttribute
-	Dir               string
-	Installable       bazel.BoolAttribute
-	Filename_from_src bazel.BoolAttribute
-	Schema            *string
-}
-
-func (p *prebuiltEtcXml) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	baseAttrs := p.PrebuiltEtc.Bp2buildHelper(ctx)
-
-	var schema *string
-	if p.properties.Schema != nil {
-		schema = p.properties.Schema
-	}
-
-	attrs := &bazelPrebuiltEtcXmlAttributes{
-		Src:               baseAttrs.Src,
-		Filename:          baseAttrs.Filename,
-		Dir:               baseAttrs.Dir,
-		Installable:       baseAttrs.Installable,
-		Filename_from_src: baseAttrs.Filename_from_src,
-		Schema:            schema,
-	}
-
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "prebuilt_xml",
-		Bzl_load_location: "//build/bazel/rules/prebuilt_xml.bzl",
-	}
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: p.Name()}, attrs)
-}
diff --git a/xml/xml_conversion_test.go b/xml/xml_conversion_test.go
deleted file mode 100644
index 6606ddc..0000000
--- a/xml/xml_conversion_test.go
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package xml
-
-import (
-	"android/soong/android"
-	"android/soong/bp2build"
-
-	"testing"
-)
-
-func runXmlPrebuiltEtcTestCase(t *testing.T, tc bp2build.Bp2buildTestCase) {
-	t.Helper()
-	(&tc).ModuleTypeUnderTest = "prebuilt_etc_xml"
-	(&tc).ModuleTypeUnderTestFactory = PrebuiltEtcXmlFactory
-	bp2build.RunBp2BuildTestCase(t, registerXmlModuleTypes, tc)
-}
-
-func registerXmlModuleTypes(ctx android.RegistrationContext) {
-}
-
-func TestXmlPrebuiltEtcSimple(t *testing.T) {
-	runXmlPrebuiltEtcTestCase(t, bp2build.Bp2buildTestCase{
-		Description: "prebuilt_etc_xml - simple example",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc_xml {
-    name: "foo",
-    src: "fooSrc",
-    filename: "fooFileName",
-    sub_dir: "fooDir",
-    schema: "foo.dtd",
-}
-`,
-		ExpectedBazelTargets: []string{
-			bp2build.MakeBazelTarget("prebuilt_xml", "foo", bp2build.AttrNameToString{
-				"src":      `"fooSrc"`,
-				"filename": `"fooFileName"`,
-				"dir":      `"etc/fooDir"`,
-				"schema":   `"foo.dtd"`,
-			})}})
-}
-
-func TestXmlPrebuiltEtcFilenameFromSrc(t *testing.T) {
-	runXmlPrebuiltEtcTestCase(t, bp2build.Bp2buildTestCase{
-		Description: "prebuilt_etc_xml - filenameFromSrc True  ",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc_xml {
-    name: "foo",
-    src: "fooSrc",
-    filename_from_src: true,
-    sub_dir: "fooDir",
-    schema: "foo.dtd",
-}
-`,
-		ExpectedBazelTargets: []string{
-			bp2build.MakeBazelTarget("prebuilt_xml", "foo", bp2build.AttrNameToString{
-				"src":      `"fooSrc"`,
-				"filename": `"fooSrc"`,
-				"dir":      `"etc/fooDir"`,
-				"schema":   `"foo.dtd"`,
-			})}})
-}
-
-func TestXmlPrebuiltEtcFilenameAndFilenameFromSrc(t *testing.T) {
-	runXmlPrebuiltEtcTestCase(t, bp2build.Bp2buildTestCase{
-		Description: "prebuilt_etc_xml - filename provided and filenameFromSrc True  ",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc_xml {
-    name: "foo",
-    src: "fooSrc",
-    filename: "fooFileName",
-    filename_from_src: true,
-    sub_dir: "fooDir",
-    schema: "foo.dtd",
-}
-`,
-		ExpectedBazelTargets: []string{
-			bp2build.MakeBazelTarget("prebuilt_xml", "foo", bp2build.AttrNameToString{
-				"src":      `"fooSrc"`,
-				"filename": `"fooFileName"`,
-				"dir":      `"etc/fooDir"`,
-				"schema":   `"foo.dtd"`,
-			})}})
-}
-
-func TestXmlPrebuiltEtcFileNameFromSrcMultipleSrcs(t *testing.T) {
-	runXmlPrebuiltEtcTestCase(t, bp2build.Bp2buildTestCase{
-		Description: "prebuilt_etc - filename_from_src is true but there are multiple srcs",
-		Filesystem:  map[string]string{},
-		Blueprint: `
-prebuilt_etc_xml {
-    name: "foo",
-    filename_from_src: true,
-    arch: {
-        arm: {
-            src: "barSrc",
-        },
-        arm64: {
-            src: "bazSrc",
-        },
-    }
-}
-`,
-		ExpectedBazelTargets: []string{
-			bp2build.MakeBazelTarget("prebuilt_xml", "foo", bp2build.AttrNameToString{
-				"filename_from_src": `True`,
-				"dir":               `"etc"`,
-				"src": `select({
-        "//build/bazel/platforms/arch:arm": "barSrc",
-        "//build/bazel/platforms/arch:arm64": "bazSrc",
-        "//conditions:default": None,
-    })`,
-			})}})
-}
diff --git a/zip/cmd/main.go b/zip/cmd/main.go
index 5231fae..37537ab 100644
--- a/zip/cmd/main.go
+++ b/zip/cmd/main.go
@@ -174,6 +174,7 @@
 	traceFile := flags.String("trace", "", "write trace to file")
 	sha256Checksum := flags.Bool("sha256", false, "add a zip header to each file containing its SHA256 digest")
 	doNotWrite := flags.Bool("n", false, "Nothing is written to disk -- all other work happens")
+	quiet := flags.Bool("quiet", false, "do not print warnings to console")
 
 	flags.Var(&rootPrefix{}, "P", "path prefix within the zip at which to place files")
 	flags.Var(&listFiles{}, "l", "file containing list of files to zip")
@@ -238,6 +239,7 @@
 		IgnoreMissingFiles:       *ignoreMissingFiles,
 		Sha256Checksum:           *sha256Checksum,
 		DoNotWrite:               *doNotWrite,
+		Quiet:                    *quiet,
 	})
 	if err != nil {
 		fmt.Fprintln(os.Stderr, "error:", err.Error())
diff --git a/zip/zip.go b/zip/zip.go
index 30a2ee7..f91a5f2 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -283,6 +283,7 @@
 	IgnoreMissingFiles       bool
 	Sha256Checksum           bool
 	DoNotWrite               bool
+	Quiet                    bool
 
 	Stderr     io.Writer
 	Filesystem pathtools.FileSystem
@@ -340,7 +341,9 @@
 					Err:  os.ErrNotExist,
 				}
 				if args.IgnoreMissingFiles {
-					fmt.Fprintln(z.stderr, "warning:", err)
+					if !args.Quiet {
+						fmt.Fprintln(z.stderr, "warning:", err)
+					}
 				} else {
 					return err
 				}
@@ -357,7 +360,9 @@
 					Err:  os.ErrNotExist,
 				}
 				if args.IgnoreMissingFiles {
-					fmt.Fprintln(z.stderr, "warning:", err)
+					if !args.Quiet {
+						fmt.Fprintln(z.stderr, "warning:", err)
+					}
 				} else {
 					return err
 				}
@@ -368,7 +373,9 @@
 					Err:  syscall.ENOTDIR,
 				}
 				if args.IgnoreMissingFiles {
-					fmt.Fprintln(z.stderr, "warning:", err)
+					if !args.Quiet {
+						fmt.Fprintln(z.stderr, "warning:", err)
+					}
 				} else {
 					return err
 				}