[automerger skipped] Merge "Add jihoonkang and mrziwang to OWNERS" into udc-mainline-prod am: 66eca9b580 -s ours

am skip reason: Merged-In I39145a7115e8e3bda4fb4cb92561742089ad2414 with SHA-1 85b7932892 is already in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/build/soong/+/26065717

Change-Id: I2e95ab64c755f8d607d99d3d946fd25b0ae778d9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
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 8996fe8..01025fb 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 99142
 # This file is included by several other projects as the list of people
 # approving build related projects.
 
@@ -12,3 +13,5 @@
 spandandas@google.com
 weiwli@google.com
 yudiliu@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 70311cb..f471c47 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
@@ -565,6 +563,12 @@
 by all of the vendor's other modules using the normal namespace and visibility
 rules.
 
+`soongConfigTraceMutator` enables modules affected by soong config variables to
+write outputs into a hashed directory path. It does this by recording accesses
+to soong config variables on each module, and then accumulating records of each
+module's all dependencies. `m soong_config_trace` builds information about
+hashes to `$OUT_DIR/soong/soong_config_trace.json`.
+
 ## Build logic
 
 The build logic is written in Go using the
@@ -599,7 +603,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
 
@@ -644,8 +648,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
new file mode 100644
index 0000000..402cf16
--- /dev/null
+++ b/aconfig/Android.bp
@@ -0,0 +1,31 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-aconfig",
+    pkgPath: "android/soong/aconfig",
+    deps: [
+        "blueprint",
+        "blueprint-pathtools",
+        "sbox_proto",
+        "soong",
+        "soong-android",
+    ],
+    srcs: [
+        "aconfig_declarations.go",
+        "aconfig_values.go",
+        "aconfig_value_set.go",
+        "all_aconfig_declarations.go",
+        "exported_java_aconfig_library.go",
+        "init.go",
+        "testing.go",
+    ],
+    testSrcs: [
+        "aconfig_declarations_test.go",
+        "aconfig_values_test.go",
+        "aconfig_value_set_test.go",
+        "all_aconfig_declarations_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go
new file mode 100644
index 0000000..78f506a
--- /dev/null
+++ b/aconfig/aconfig_declarations.go
@@ -0,0 +1,166 @@
+// 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 (
+	"fmt"
+	"strings"
+
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+)
+
+type DeclarationsModule struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+
+	// Properties for "aconfig_declarations"
+	properties struct {
+		// aconfig files, relative to this Android.bp file
+		Srcs []string `android:"path"`
+
+		// Release config flag package
+		Package string
+
+		// Values from TARGET_RELEASE / RELEASE_ACONFIG_VALUE_SETS
+		Values []string `blueprint:"mutated"`
+
+		// Container(system/vendor/apex) that this module belongs to
+		Container string
+	}
+
+	intermediatePath android.WritablePath
+}
+
+func DeclarationsFactory() android.Module {
+	module := &DeclarationsModule{}
+
+	android.InitAndroidModule(module)
+	android.InitDefaultableModule(module)
+	module.AddProperties(&module.properties)
+
+	return module
+}
+
+type implicitValuesTagType struct {
+	blueprint.BaseDependencyTag
+}
+
+var implicitValuesTag = implicitValuesTagType{}
+
+func (module *DeclarationsModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// Validate Properties
+	if len(module.properties.Srcs) == 0 {
+		ctx.PropertyErrorf("srcs", "missing source files")
+		return
+	}
+	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()
+	if len(valuesFromConfig) > 0 {
+		ctx.AddDependency(ctx.Module(), implicitValuesTag, valuesFromConfig...)
+	}
+}
+
+func (module *DeclarationsModule) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		// The default output of this module is the intermediates format, which is
+		// not installable and in a private format that no other rules can handle
+		// correctly.
+		return []android.Path{module.intermediatePath}, nil
+	default:
+		return nil, fmt.Errorf("unsupported aconfig_declarations module reference tag %q", tag)
+	}
+}
+
+func joinAndPrefix(prefix string, values []string) string {
+	var sb strings.Builder
+	for _, v := range values {
+		sb.WriteString(prefix)
+		sb.WriteString(v)
+	}
+	return sb.String()
+}
+
+func optionalVariable(prefix string, value string) string {
+	var sb strings.Builder
+	if value != "" {
+		sb.WriteString(prefix)
+		sb.WriteString(value)
+	}
+	return sb.String()
+}
+
+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 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
+	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...)
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        aconfigRule,
+		Output:      intermediateCacheFilePath,
+		Inputs:      inputFiles,
+		Description: "aconfig_declarations",
+		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),
+		},
+	})
+
+	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,
+		IntermediateCacheOutputPath: intermediateCacheFilePath,
+		IntermediateDumpOutputPath:  intermediateDumpFilePath,
+	})
+
+}
diff --git a/aconfig/aconfig_declarations_test.go b/aconfig/aconfig_declarations_test.go
new file mode 100644
index 0000000..d508af7
--- /dev/null
+++ b/aconfig/aconfig_declarations_test.go
@@ -0,0 +1,50 @@
+// 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 aconfig
+
+import (
+	"strings"
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestAconfigDeclarations(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)
+
+	// Check that the provider has the right contents
+	depData, _ := android.SingletonModuleProvider(result, module, android.AconfigDeclarationsProviderKey)
+	android.AssertStringEquals(t, "package", depData.Package, "com.example.package")
+	android.AssertStringEquals(t, "container", depData.Container, "com.android.foo")
+	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())
+	}
+}
diff --git a/aconfig/aconfig_value_set.go b/aconfig/aconfig_value_set.go
new file mode 100644
index 0000000..7ba76c0
--- /dev/null
+++ b/aconfig/aconfig_value_set.go
@@ -0,0 +1,86 @@
+// 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"
+	"github.com/google/blueprint"
+)
+
+// Properties for "aconfig_value_set"
+type ValueSetModule struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+
+	properties struct {
+		// aconfig_values modules
+		Values []string
+	}
+}
+
+func ValueSetFactory() android.Module {
+	module := &ValueSetModule{}
+
+	android.InitAndroidModule(module)
+	android.InitDefaultableModule(module)
+	module.AddProperties(&module.properties)
+
+	return module
+}
+
+// Dependency tag for values property
+type valueSetType struct {
+	blueprint.BaseDependencyTag
+}
+
+var valueSetTag = valueSetType{}
+
+// Provider published by aconfig_value_set
+type valueSetProviderData struct {
+	// The package of each of the
+	// (map of package --> aconfig_module)
+	AvailablePackages map[string]android.Paths
+}
+
+var valueSetProviderKey = blueprint.NewProvider[valueSetProviderData]()
+
+func (module *ValueSetModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+	deps := ctx.AddDependency(ctx.Module(), valueSetTag, module.properties.Values...)
+	for _, dep := range deps {
+		_, ok := dep.(*ValuesModule)
+		if !ok {
+			ctx.PropertyErrorf("values", "values must be a aconfig_values module")
+			return
+		}
+	}
+}
+
+func (module *ValueSetModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// Accumulate the packages of the values modules listed, and set that as an
+	// valueSetProviderKey provider that aconfig modules can read and use
+	// to append values to their aconfig actions.
+	packages := make(map[string]android.Paths)
+	ctx.VisitDirectDeps(func(dep android.Module) {
+		if depData, ok := android.OtherModuleProvider(ctx, dep, valuesProviderKey); ok {
+			srcs := make([]android.Path, len(depData.Values))
+			copy(srcs, depData.Values)
+			packages[depData.Package] = srcs
+		}
+
+	})
+	android.SetProvider(ctx, valueSetProviderKey, valueSetProviderData{
+		AvailablePackages: packages,
+	})
+}
diff --git a/aconfig/aconfig_value_set_test.go b/aconfig/aconfig_value_set_test.go
new file mode 100644
index 0000000..7d18999
--- /dev/null
+++ b/aconfig/aconfig_value_set_test.go
@@ -0,0 +1,43 @@
+// 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 aconfig
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestAconfigValueSet(t *testing.T) {
+	bp := `
+				aconfig_values {
+					name: "one",
+					srcs: [ "blah.aconfig_values" ],
+					package: "foo.package"
+				}
+
+				aconfig_value_set {
+					name: "module_name",
+          values: [ "one" ],
+				}
+			`
+	result := runTest(t, android.FixtureExpectsNoErrors, bp)
+
+	module := result.ModuleForTests("module_name", "").Module().(*ValueSetModule)
+
+	// Check that the provider has the right contents
+	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
new file mode 100644
index 0000000..239b10c
--- /dev/null
+++ b/aconfig/aconfig_values.go
@@ -0,0 +1,68 @@
+// 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"
+	"github.com/google/blueprint"
+)
+
+// Properties for "aconfig_value"
+type ValuesModule struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+
+	properties struct {
+		// aconfig files, relative to this Android.bp file
+		Srcs []string `android:"path"`
+
+		// Release config flag package
+		Package string
+	}
+}
+
+func ValuesFactory() android.Module {
+	module := &ValuesModule{}
+
+	android.InitAndroidModule(module)
+	android.InitDefaultableModule(module)
+	module.AddProperties(&module.properties)
+
+	return module
+}
+
+// Provider published by aconfig_value_set
+type valuesProviderData struct {
+	// The package that this values module values
+	Package string
+
+	// The values aconfig files, relative to the root of the tree
+	Values android.Paths
+}
+
+var valuesProviderKey = blueprint.NewProvider[valuesProviderData]()
+
+func (module *ValuesModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if len(module.properties.Package) == 0 {
+		ctx.PropertyErrorf("package", "missing package property")
+	}
+
+	// Provide the our source files list to the aconfig_value_set as a list of files
+	providerData := valuesProviderData{
+		Package: module.properties.Package,
+		Values:  android.PathsForModuleSrc(ctx, module.properties.Srcs),
+	}
+	android.SetProvider(ctx, valuesProviderKey, providerData)
+}
diff --git a/aconfig/aconfig_values_test.go b/aconfig/aconfig_values_test.go
new file mode 100644
index 0000000..526579c
--- /dev/null
+++ b/aconfig/aconfig_values_test.go
@@ -0,0 +1,39 @@
+// 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 aconfig
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestAconfigValues(t *testing.T) {
+	bp := `
+				aconfig_values {
+					name: "module_name",
+					srcs: [ "blah.aconfig_values" ],
+					package: "foo.package"
+				}
+			`
+	result := runTest(t, android.FixtureExpectsNoErrors, bp)
+
+	module := result.ModuleForTests("module_name", "").Module().(*ValuesModule)
+
+	// Check that the provider has the right contents
+	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
new file mode 100644
index 0000000..b6c9023
--- /dev/null
+++ b/aconfig/all_aconfig_declarations.go
@@ -0,0 +1,78 @@
+// 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"
+	"fmt"
+)
+
+// A singleton module that collects all of the aconfig flags declared in the
+// tree into a single combined file for export to the external flag setting
+// server (inside Google it's Gantry).
+//
+// Note that this is ALL aconfig_declarations modules present in the tree, not just
+// ones that are relevant to the product currently being built, so that that infra
+// doesn't need to pull from multiple builds and merge them.
+func AllAconfigDeclarationsFactory() android.Singleton {
+	return &allAconfigDeclarationsSingleton{}
+}
+
+type allAconfigDeclarationsSingleton struct {
+	intermediatePath 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) {
+		decl, ok := android.SingletonModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey)
+		if !ok {
+			return
+		}
+		cacheFiles = append(cacheFiles, decl.IntermediateCacheOutputPath)
+		packages[decl.Package]++
+	})
+
+	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
+	this.intermediatePath = android.PathForIntermediates(ctx, "all_aconfig_declarations.pb")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        AllDeclarationsRule,
+		Inputs:      cacheFiles,
+		Output:      this.intermediatePath,
+		Description: "all_aconfig_declarations",
+		Args: map[string]string{
+			"cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "),
+		},
+	})
+	ctx.Phony("all_aconfig_declarations", this.intermediatePath)
+}
+
+func (this *allAconfigDeclarationsSingleton) MakeVars(ctx android.MakeVarsContext) {
+	ctx.DistForGoal("droid", this.intermediatePath)
+}
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..494f7e6
--- /dev/null
+++ b/aconfig/codegen/Android.bp
@@ -0,0 +1,32 @@
+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: [
+        "cc_aconfig_library.go",
+        "init.go",
+        "java_aconfig_library.go",
+        "rust_aconfig_library.go",
+        "testing.go",
+    ],
+    testSrcs: [
+        "java_aconfig_library_test.go",
+        "cc_aconfig_library_test.go",
+        "rust_aconfig_library_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/aconfig/codegen/cc_aconfig_library.go b/aconfig/codegen/cc_aconfig_library.go
new file mode 100644
index 0000000..50cd4de
--- /dev/null
+++ b/aconfig/codegen/cc_aconfig_library.go
@@ -0,0 +1,149 @@
+// 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"
+	"android/soong/cc"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+
+	"fmt"
+	"strings"
+)
+
+type ccDeclarationsTagType struct {
+	blueprint.BaseDependencyTag
+}
+
+var ccDeclarationsTag = ccDeclarationsTagType{}
+
+const baseLibDep = "server_configurable_flags"
+
+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 {
+	properties *CcAconfigLibraryProperties
+
+	generatedDir android.WritablePath
+	headerDir    android.WritablePath
+	generatedCpp android.WritablePath
+	generatedH   android.WritablePath
+}
+
+func CcAconfigLibraryFactory() android.Module {
+	callbacks := &CcAconfigLibraryCallbacks{
+		properties: &CcAconfigLibraryProperties{},
+	}
+	return cc.GeneratedCcLibraryModuleFactory("cc_aconfig_library", callbacks)
+}
+
+func (this *CcAconfigLibraryCallbacks) GeneratorInit(ctx cc.BaseModuleContext) {
+}
+
+func (this *CcAconfigLibraryCallbacks) GeneratorProps() []interface{} {
+	return []interface{}{this.properties}
+}
+
+func (this *CcAconfigLibraryCallbacks) GeneratorDeps(ctx cc.DepsContext, deps cc.Deps) cc.Deps {
+	// Add a dependency for the declarations module
+	declarations := this.properties.Aconfig_declarations
+	if len(declarations) == 0 {
+		ctx.PropertyErrorf("aconfig_declarations", "aconfig_declarations property required")
+	} else {
+		ctx.AddDependency(ctx.Module(), ccDeclarationsTag, declarations)
+	}
+
+	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: It'd be really nice if we could reexport this library and not make everyone do it.
+
+	return deps
+}
+
+func (this *CcAconfigLibraryCallbacks) GeneratorSources(ctx cc.ModuleContext) cc.GeneratedSource {
+	result := cc.GeneratedSource{}
+
+	// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
+	declarationsModules := ctx.GetDirectDepsWithTag(ccDeclarationsTag)
+	if len(declarationsModules) != 1 {
+		panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
+	}
+	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)
+
+	this.headerDir = android.PathForModuleGen(ctx, "include")
+	result.IncludeDirs = []android.Path{this.headerDir}
+	result.ReexportedDirs = []android.Path{this.headerDir}
+
+	basename := strings.ReplaceAll(declarations.Package, ".", "_")
+
+	this.generatedCpp = android.PathForModuleGen(ctx, basename+".cc")
+	result.Sources = []android.Path{this.generatedCpp}
+
+	this.generatedH = android.PathForModuleGen(ctx, "include", basename+".h")
+	result.Headers = []android.Path{this.generatedH}
+
+	return result
+}
+
+func (this *CcAconfigLibraryCallbacks) GeneratorFlags(ctx cc.ModuleContext, flags cc.Flags, deps cc.PathDeps) cc.Flags {
+	return flags
+}
+
+func (this *CcAconfigLibraryCallbacks) GeneratorBuildActions(ctx cc.ModuleContext, flags cc.Flags, deps cc.PathDeps) {
+	// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
+	declarationsModules := ctx.GetDirectDepsWithTag(ccDeclarationsTag)
+	if len(declarationsModules) != 1 {
+		panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
+	}
+	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.IntermediateCacheOutputPath,
+		Outputs: []android.WritablePath{
+			this.generatedCpp,
+			this.generatedH,
+		},
+		Description: "cc_aconfig_library",
+		Args: map[string]string{
+			"gendir": this.generatedDir.String(),
+			"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..05449bc
--- /dev/null
+++ b/aconfig/codegen/cc_aconfig_library_test.go
@@ -0,0 +1,198 @@
+// 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_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_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,
+		}
+	`
+	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",
+			}
+		`))
+
+	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..0bff9d2
--- /dev/null
+++ b/aconfig/codegen/init.go
@@ -0,0 +1,83 @@
+// 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}`,
+			CommandDeps: []string{
+				"$aconfig",
+			},
+		}, "gendir", "mode")
+
+	// 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("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..e6817e0
--- /dev/null
+++ b/aconfig/codegen/java_aconfig_library.go
@@ -0,0 +1,110 @@
+// 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 {
+	// 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)
+	}
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        javaRule,
+		Input:       declarations.IntermediateCacheOutputPath,
+		Output:      srcJarPath,
+		Description: "aconfig.srcjar",
+		Args: map[string]string{
+			"mode": mode,
+		},
+	})
+
+	return srcJarPath
+}
+
+func isModeSupported(mode string) bool {
+	return android.InList(mode, aconfigSupportedModes)
+}
diff --git a/aconfig/codegen/java_aconfig_library_test.go b/aconfig/codegen/java_aconfig_library_test.go
new file mode 100644
index 0000000..85d2675
--- /dev/null
+++ b/aconfig/codegen/java_aconfig_library_test.go
@@ -0,0 +1,235 @@
+// 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/java"
+)
+
+// Note: These tests cover the code in the java package. It'd be ideal of that code could
+// be in the aconfig package.
+
+// With the bp parameter that defines a my_module, make sure it has the LOCAL_ACONFIG_FILES entries
+func runJavaAndroidMkTest(t *testing.T, bp string) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		java.PrepareForTestWithJavaDefaultModules).
+		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
+		RunTestWithBp(t, bp+`
+			aconfig_declarations {
+				name: "my_aconfig_declarations_foo",
+				package: "com.example.package.foo",
+				srcs: ["foo.aconfig"],
+			}
+
+			java_aconfig_library {
+				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",
+			}
+		`)
+
+	module := result.ModuleForTests("my_module", "android_common").Module()
+
+	entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0]
+
+	makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"]
+	android.EnsureListContainsSuffix(t, makeVar, "android_common/aconfig_merged.pb")
+}
+
+func TestAndroidMkJavaLibrary(t *testing.T) {
+	bp := `
+		java_library {
+			name: "my_module",
+			srcs: [
+				"src/foo.java",
+			],
+			static_libs: [
+				"my_java_aconfig_library_foo",
+				"my_java_aconfig_library_bar",
+			],
+			platform_apis: true,
+		}
+	`
+
+	runJavaAndroidMkTest(t, bp)
+}
+
+func TestAndroidMkAndroidApp(t *testing.T) {
+	bp := `
+		android_app {
+			name: "my_module",
+			srcs: [
+				"src/foo.java",
+			],
+			static_libs: [
+				"my_java_aconfig_library_foo",
+				"my_java_aconfig_library_bar",
+			],
+			platform_apis: true,
+		}
+	`
+
+	runJavaAndroidMkTest(t, bp)
+}
+
+func TestAndroidMkBinary(t *testing.T) {
+	bp := `
+		java_binary {
+			name: "my_module",
+			srcs: [
+				"src/foo.java",
+			],
+			static_libs: [
+				"my_java_aconfig_library_foo",
+				"my_java_aconfig_library_bar",
+			],
+			platform_apis: true,
+			main_class: "foo",
+		}
+	`
+
+	runJavaAndroidMkTest(t, bp)
+}
+
+func TestAndroidMkAndroidLibrary(t *testing.T) {
+	bp := `
+		android_library {
+			name: "my_module",
+			srcs: [
+				"src/foo.java",
+			],
+			static_libs: [
+				"my_java_aconfig_library_foo",
+				"my_java_aconfig_library_bar",
+			],
+			platform_apis: true,
+		}
+	`
+
+	runJavaAndroidMkTest(t, bp)
+}
+
+func TestAndroidMkBinaryThatLinksAgainstAar(t *testing.T) {
+	// Tests AndroidLibrary's propagation of flags through JavaInfo
+	bp := `
+		android_library {
+			name: "some_library",
+			srcs: [
+				"src/foo.java",
+			],
+			static_libs: [
+				"my_java_aconfig_library_foo",
+				"my_java_aconfig_library_bar",
+			],
+			platform_apis: true,
+		}
+		java_binary {
+			name: "my_module",
+			srcs: [
+				"src/bar.java",
+			],
+			static_libs: [
+				"some_library",
+			],
+			platform_apis: true,
+			main_class: "foo",
+		}
+	`
+
+	runJavaAndroidMkTest(t, bp)
+}
+
+func testCodegenMode(t *testing.T, bpMode string, ruleMode string) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		java.PrepareForTestWithJavaDefaultModules).
+		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
+		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))
+
+	module := result.ModuleForTests("my_java_aconfig_library", "android_common")
+	rule := module.Rule("java_aconfig_library")
+	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, "mode: `production`,", "production")
+}
+
+func TestTestMode(t *testing.T) {
+	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/codegen/rust_aconfig_library.go b/aconfig/codegen/rust_aconfig_library.go
new file mode 100644
index 0000000..2ab54b6
--- /dev/null
+++ b/aconfig/codegen/rust_aconfig_library.go
@@ -0,0 +1,97 @@
+package codegen
+
+import (
+	"fmt"
+
+	"android/soong/android"
+	"android/soong/rust"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+type rustDeclarationsTagType struct {
+	blueprint.BaseDependencyTag
+}
+
+var rustDeclarationsTag = rustDeclarationsTagType{}
+
+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 {
+	*rust.BaseSourceProvider
+
+	Properties RustAconfigLibraryProperties
+}
+
+func NewRustAconfigLibrary(hod android.HostOrDeviceSupported) (*rust.Module, *aconfigDecorator) {
+	aconfig := &aconfigDecorator{
+		BaseSourceProvider: rust.NewSourceProvider(),
+		Properties:         RustAconfigLibraryProperties{},
+	}
+
+	module := rust.NewSourceProviderModule(android.HostAndDeviceSupported, aconfig, false, false)
+	return module, aconfig
+}
+
+// rust_aconfig_library generates aconfig rust code from the provided aconfig declaration. This module type will
+// create library variants that can be used as a crate dependency by adding it to the rlibs, dylibs, and rustlibs
+// properties of other modules.
+func RustAconfigLibraryFactory() android.Module {
+	module, _ := NewRustAconfigLibrary(android.HostAndDeviceSupported)
+	return module.Init()
+}
+
+func (a *aconfigDecorator) SourceProviderProps() []interface{} {
+	return append(a.BaseSourceProvider.SourceProviderProps(), &a.Properties)
+}
+
+func (a *aconfigDecorator) GenerateSource(ctx rust.ModuleContext, deps rust.PathDeps) android.Path {
+	generatedDir := android.PathForModuleGen(ctx)
+	generatedSource := android.PathForModuleGen(ctx, "src", "lib.rs")
+
+	declarationsModules := ctx.GetDirectDepsWithTag(rustDeclarationsTag)
+
+	if len(declarationsModules) != 1 {
+		panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
+	}
+	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.IntermediateCacheOutputPath,
+		Outputs: []android.WritablePath{
+			generatedSource,
+		},
+		Description: "rust_aconfig_library",
+		Args: map[string]string{
+			"gendir": generatedDir.String(),
+			"mode":   mode,
+		},
+	})
+	a.BaseSourceProvider.OutputFiles = android.Paths{generatedSource}
+	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, "libflags_rust")
+	deps.Rustlibs = append(deps.Rustlibs, "liblazy_static")
+	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..60bc9f7
--- /dev/null
+++ b/aconfig/codegen/rust_aconfig_library_test.go
@@ -0,0 +1,160 @@
+package codegen
+
+import (
+	"fmt"
+	"testing"
+
+	"android/soong/android"
+	"android/soong/rust"
+)
+
+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"],
+			}
+			rust_library {
+				name: "liblazy_static", // test mock
+				crate_name: "lazy_static",
+				srcs: ["src/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.PrepareForTestWithRustIncludeVndk).
+		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"],
+			}
+			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.PrepareForTestWithRustIncludeVndk).
+		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"],
+			}
+			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
new file mode 100644
index 0000000..3e9d297
--- /dev/null
+++ b/aconfig/init.go
@@ -0,0 +1,101 @@
+// 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"
+
+	"github.com/google/blueprint"
+)
+
+var (
+	pctx = android.NewPackageContext("android/soong/aconfig")
+
+	// For aconfig_declarations: Generate cache file
+	aconfigRule = pctx.AndroidStaticRule("aconfig",
+		blueprint.RuleParams{
+			Command: `${aconfig} create-cache` +
+				` --package ${package}` +
+				` ${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}` +
+			CommandDeps: []string{
+				"${aconfig}",
+			},
+			Restat: true,
+		}, "release_version", "package", "declarations", "values", "default-permission")
+
+	// For create-device-config-sysprops: Generate aconfig flag value map text file
+	aconfigTextRule = pctx.AndroidStaticRule("aconfig_text",
+		blueprint.RuleParams{
+			Command: `${aconfig} dump-cache --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 --format protobuf --out ${out} ${cache_files}`,
+			CommandDeps: []string{
+				"${aconfig}",
+			},
+		}, "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 --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)
+	pctx.HostBinToolVariable("aconfig", "aconfig")
+	pctx.HostBinToolVariable("soong_zip", "soong_zip")
+}
+
+func RegisterBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("aconfig_declarations", DeclarationsFactory)
+	ctx.RegisterModuleType("aconfig_values", ValuesFactory)
+	ctx.RegisterModuleType("aconfig_value_set", ValueSetFactory)
+	ctx.RegisterParallelSingletonType("all_aconfig_declarations", AllAconfigDeclarationsFactory)
+	ctx.RegisterParallelSingletonType("exported_java_aconfig_library", ExportedJavaDeclarationsLibraryFactory)
+}
diff --git a/aconfig/testing.go b/aconfig/testing.go
new file mode 100644
index 0000000..f6489ec
--- /dev/null
+++ b/aconfig/testing.go
@@ -0,0 +1,29 @@
+// 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 aconfig
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+var PrepareForTestWithAconfigBuildComponents = android.FixtureRegisterWithContext(RegisterBuildComponents)
+
+func runTest(t *testing.T, errorHandler android.FixtureErrorHandler, bp string) *android.TestResult {
+	return android.GroupFixturePreparers(PrepareForTestWithAconfigBuildComponents).
+		ExtendWithErrorHandler(errorHandler).
+		RunTestWithBp(t, bp)
+}
diff --git a/aidl_library/aidl_library.go b/aidl_library/aidl_library.go
index 5985103..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,72 +51,24 @@
 
 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
 	// The include dirs to the direct aidl files and those provided from transitive aidl_library deps
-	IncludeDirs android.DepSet
+	IncludeDirs android.DepSet[android.Path]
 	// The direct hdrs and hdrs from transitive deps
-	Hdrs android.DepSet
+	Hdrs android.DepSet[android.Path]
 }
 
 // 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.PREORDER)
-	hdrsDepSetBuilder := android.NewDepSetBuilder(android.PREORDER)
+	includeDirsDepSetBuilder := android.NewDepSetBuilder[android.Path](android.PREORDER)
+	hdrsDepSetBuilder := android.NewDepSetBuilder[android.Path](android.PREORDER)
 
 	if len(lib.properties.Srcs) == 0 && len(lib.properties.Hdrs) == 0 {
 		ctx.ModuleErrorf("at least srcs or hdrs prop must be non-empty")
@@ -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 d9dd245..01eab0e 100644
--- a/aidl_library/aidl_library_test.go
+++ b/aidl_library/aidl_library_test.go
@@ -46,13 +46,13 @@
 	).RunTest(t).TestContext
 
 	foo := ctx.ModuleForTests("foo", "").Module().(*AidlLibrary)
-	actualInfo := ctx.ModuleProvider(foo, AidlLibraryProvider).(AidlLibraryInfo)
+	actualInfo, _ := android.SingletonModuleProvider(ctx, foo, AidlLibraryProvider)
 
 	android.AssertArrayString(
 		t,
 		"aidl include dirs",
 		[]string{"package_foo/a", "package_bar/x"},
-		actualInfo.IncludeDirs.ToList().Strings(),
+		android.Paths(actualInfo.IncludeDirs.ToList()).Strings(),
 	)
 
 	android.AssertPathsRelativeToTopEquals(
@@ -95,13 +95,13 @@
 	).RunTest(t).TestContext
 
 	foo := ctx.ModuleForTests("foo", "").Module().(*AidlLibrary)
-	actualInfo := ctx.ModuleProvider(foo, AidlLibraryProvider).(AidlLibraryInfo)
+	actualInfo, _ := android.SingletonModuleProvider(ctx, foo, AidlLibraryProvider)
 
 	android.AssertArrayString(
 		t,
 		"aidl include dirs",
 		[]string{"package_foo", "package_bar"},
-		actualInfo.IncludeDirs.ToList().Strings(),
+		android.Paths(actualInfo.IncludeDirs.ToList()).Strings(),
 	)
 
 	android.AssertPathsRelativeToTopEquals(
diff --git a/android/Android.bp b/android/Android.bp
index b13d7cd..e73f355 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -13,11 +13,10 @@
         "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-metrics_proto",
         "soong-android-allowlists",
@@ -29,16 +28,17 @@
         "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",
@@ -49,8 +49,8 @@
         "defaults.go",
         "defs.go",
         "depset_generic.go",
-        "depset_paths.go",
         "deptag.go",
+        "early_module_context.go",
         "expand.go",
         "filegroup.go",
         "fixture.go",
@@ -62,10 +62,11 @@
         "license_metadata.go",
         "license_sdk_member.go",
         "licenses.go",
-        "makefile_goal.go",
         "makevars.go",
         "metrics.go",
         "module.go",
+        "module_context.go",
+        "module_info_json.go",
         "mutator.go",
         "namespace.go",
         "neverallow.go",
@@ -79,9 +80,12 @@
         "path_properties.go",
         "paths.go",
         "phony.go",
+        "plugin.go",
         "prebuilt.go",
         "prebuilt_build_tool.go",
         "proto.go",
+        "provider.go",
+        "raw_files.go",
         "register.go",
         "rule_builder.go",
         "sandbox.go",
@@ -104,11 +108,8 @@
         "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",
         "depset_test.go",
diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go
new file mode 100644
index 0000000..be9beb1
--- /dev/null
+++ b/android/aconfig_providers.go
@@ -0,0 +1,226 @@
+// 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"
+	"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
+	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]()
+
+// 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, aconfigFiles := range *mergedAconfigFiles {
+		(*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
+}
+
+var aconfigPropagatingProviderKey = blueprint.NewProvider[aconfigPropagatingDeclarationsInfo]()
+
+func aconfigUpdateAndroidBuildActions(ctx ModuleContext) {
+	mergedAconfigFiles := make(map[string]Paths)
+	ctx.VisitDirectDepsIgnoreBlueprint(func(module Module) {
+		// 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...)
+			}
+		}
+		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, aconfigFiles := range mergedAconfigFiles {
+			mergedAconfigFiles[container] = mergeAconfigFiles(ctx, container, aconfigFiles, true)
+		}
+
+		SetProvider(ctx, aconfigPropagatingProviderKey, aconfigPropagatingDeclarationsInfo{
+			AconfigFiles: mergedAconfigFiles,
+		})
+	}
+}
+
+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 = LastUniquePaths(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
index d061649..6c3a219 100644
--- a/android/all_teams.go
+++ b/android/all_teams.go
@@ -4,8 +4,6 @@
 	"android/soong/android/team_proto"
 	"path/filepath"
 
-	"github.com/google/blueprint/proptools"
-	"google.golang.org/protobuf/encoding/prototext"
 	"google.golang.org/protobuf/proto"
 )
 
@@ -21,7 +19,7 @@
 }
 
 func registerAllTeamBuildComponents(ctx RegistrationContext) {
-	ctx.RegisterSingletonType("all_teams", AllTeamsFactory)
+	ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
 }
 
 // For each module, list the team or the bpFile the module is defined in.
@@ -103,13 +101,12 @@
 	allTeams := this.lookupTeamForAllModules()
 
 	this.outputPath = PathForOutput(ctx, ownershipDirectory, allTeamsFile)
-	// udc branch diff, use textproto and encode it.
-	data, err := prototext.Marshal(allTeams)
+	data, err := proto.Marshal(allTeams)
 	if err != nil {
 		ctx.Errorf("Unable to marshal team data. %s", err)
 	}
 
-	WriteFileRuleVerbatim(ctx, this.outputPath, proptools.NinjaEscape(string(data)))
+	WriteFileRuleVerbatim(ctx, this.outputPath, string(data))
 	ctx.Phony("all_teams", this.outputPath)
 }
 
@@ -132,20 +129,30 @@
 			teamProperties, found = this.lookupDefaultTeam(m.bpFile)
 		}
 
-		// udc branch diff, only write modules with teams to keep ninja file smaller.
+		trendy_team_id := ""
 		if found {
-			trendy_team_id := *teamProperties.Trendy_team_id
-			var files []string
-			teamData := new(team_proto.Team)
+			trendy_team_id = *teamProperties.Trendy_team_id
+		}
+
+		var files []string
+		teamData := new(team_proto.Team)
+		if trendy_team_id != "" {
 			*teamData = team_proto.Team{
 				TrendyTeamId: proto.String(trendy_team_id),
 				TargetName:   proto.String(moduleName),
 				Path:         proto.String(m.bpFile),
 				File:         files,
 			}
-			teamsProto[i] = teamData
-			i++
+		} else {
+			// Clients rely on the TrendyTeamId optional field not being set.
+			*teamData = team_proto.Team{
+				TargetName: proto.String(moduleName),
+				Path:       proto.String(m.bpFile),
+				File:       files,
+			}
 		}
+		teamsProto[i] = teamData
+		i++
 	}
-	return &team_proto.AllTeams{Teams: teamsProto[:i]}
+	return &team_proto.AllTeams{Teams: teamsProto}
 }
diff --git a/android/all_teams_test.go b/android/all_teams_test.go
index 6302d86..a02b86e 100644
--- a/android/all_teams_test.go
+++ b/android/all_teams_test.go
@@ -18,7 +18,6 @@
 	"log"
 	"testing"
 
-	"google.golang.org/protobuf/encoding/prototext"
 	"google.golang.org/protobuf/proto"
 )
 
@@ -28,7 +27,7 @@
 		PrepareForTestWithTeamBuildComponents,
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.RegisterModuleType("fake", fakeModuleFactory)
-			ctx.RegisterSingletonType("all_teams", AllTeamsFactory)
+			ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
 		}),
 	).RunTestWithBp(t, `
 		fake {
@@ -66,6 +65,7 @@
 	expectedTeams := map[string]*string{
 		"main_test": proto.String("cool_team"),
 		"tool":      proto.String("22222"),
+		"noteam":    nil,
 	}
 
 	AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams)
@@ -79,9 +79,8 @@
 	protoPath := allOutputs[0]
 
 	out := config.MaybeOutput(protoPath)
-	outProto := []byte(ContentFromFileRuleForTests(t, out))
-	// udc diff
-	if err := prototext.Unmarshal(outProto, teams); err != nil {
+	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
@@ -176,7 +175,7 @@
 		PrepareForTestWithPackageModule,
 		FixtureRegisterWithContext(func(ctx RegistrationContext) {
 			ctx.RegisterModuleType("fake", fakeModuleFactory)
-			ctx.RegisterSingletonType("all_teams", AllTeamsFactory)
+			ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
 		}),
 		FixtureAddTextFile("Android.bp", rootBp),
 		FixtureAddTextFile("dir1/Android.bp", dir1Bp),
@@ -202,7 +201,8 @@
 		"modulepd2":          proto.String("trendy://team_top"),
 		"modulepd3":          proto.String("trendy://team_top"),
 		"modulepd3b":         proto.String("111"),
-		// udc diff, no nil teams
+		"module_dir1":        nil,
+		"module_dir123":      nil,
 	}
 	AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams)
 }
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 5ccffc3..a52bff3 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -14,1807 +14,23 @@
 
 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
-
-	DEFAULT_NINJA_WEIGHT = 1000
+	// 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.
+	HIGH_PRIORITIZED_WEIGHT = 10 * DEFAULT_PRIORITIZED_WEIGHT
+	// Modules with inputs greater than the threshold should have high priority.
+	// Adjust this threshold if there are lots of wrong predictions.
+	INPUT_SIZE_THRESHOLD = 50
 )
 
 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/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/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/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/fmtlib":                        Bp2BuildDefaultTrueRecursively,
-		"external/guava":                         Bp2BuildDefaultTrueRecursively,
-		"external/google-benchmark":              Bp2BuildDefaultTrueRecursively,
-		"external/googletest":                    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/six":                    Bp2BuildDefaultTrueRecursively,
-		"external/rappor":                        Bp2BuildDefaultTrueRecursively,
-		"external/scudo":                         Bp2BuildDefaultTrueRecursively,
-		"external/selinux/libselinux":            Bp2BuildDefaultTrueRecursively,
-		"external/selinux/libsepol":              Bp2BuildDefaultTrueRecursively,
-		"external/speex":                         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/codec2/components/aom":          Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/codecs":                         Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/liberror":                       Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/libshmem":                       Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/audioaidlconversion":            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/services/tests/servicestests/aidl":  Bp2BuildDefaultTrue,
-		"frameworks/base/proto":                              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/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/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/libs/permission":                  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/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/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/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/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/toolchain-extras":                         Bp2BuildDefaultTrue,
-		"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/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":                             Bp2BuildDefaultTrueRecursively,
-		"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_license":/* 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,
-	}
-
-	Bp2buildModuleAlwaysConvertList = []string{
-		"libidmap2_policies",
-		"libSurfaceFlingerProp",
-		// cc mainline modules
-		"code_coverage.policy",
-		"code_coverage.policy.other",
-		"codec2_soft_exports",
-		"codecs_g711dec",
-		"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",
-		"flatbuffer_headers",
-		"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",
-		"libstagefright_amrnbenc",
-		"libstagefright_amrnbdec",
-		"libstagefright_amrwbdec",
-		"libstagefright_amrwbenc",
-		"libstagefright_amrnb_common",
-		"libstagefright_enc_common",
-		"libstagefright_flacdec",
-		"libstagefright_foundation",
-		"libstagefright_foundation_headers",
-		"libstagefright_headers",
-		"libstagefright_m4vh263dec",
-		"libstagefright_m4vh263enc",
-		"libstagefright_mp3dec",
-		"libstagefright_mp3dec_headers",
-		"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",
-
-		//external/avb
-		"avbtool",
-		"libavb",
-		"avb_headers",
-
-		//external/libxml2
-		"xmllint",
-		"libxml2",
-
-		//external/fec
-		"libfec_rs",
-
-		//frameworks/base/core/java
-		"IDropBoxManagerService_aidl",
-
-		//system/core/libsparse
-		"libsparse",
-
-		//system/extras/ext4_utils
-		"libext4_utils",
-		"mke2fs_conf",
-
-		//system/extras/libfec
-		"libfec",
-
-		//system/extras/squashfs_utils
-		"libsquashfs_utils",
-
-		//system/extras/verity/fec
-		"fec",
-		"boot_signer",
-
-		//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
-		"framework_native_aidl_binder",
-		"framework_native_aidl_gui",
-
-		//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",
-		"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
-		"kotlinx_coroutines",
-		"kotlinx_coroutines-device",
-		"kotlinx_coroutines-host",
-		"annotations",
-		"kotlinx-coroutines-android-annotation-stubs",
-
-		// for building com.android.neuralnetworks
-		"libimapper_stablec",
-		"libimapper_providerutils",
-
-		// min_sdk_version in android_app
-		"CtsShimUpgrade",
-
-		// Mainline Module Apps
-		"CaptivePortalLogin",
-	}
-
-	Bp2buildModuleTypeAlwaysConvertList = []string{
-		"aidl_interface_headers",
-		"bpf",
-		"combined_apis",
-		"license",
-		"linker_config",
-		"java_import",
-		"java_import_host",
-		"java_sdk_library",
-		"sysprop_library",
-	}
-
-	// 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{
-		// 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
-		"libactivitymanager_aidl", // TODO(b/207426160): Unsupported use of aidl sources (via Dactivity_manager_procstate_aidl) in a cc_library
-
-		// 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
-		"art_libartbase_headers", // TODO(b/236268577): Header libraries do not support export_shared_libs_headers
-		"apexer_test",            // Requires aapt2
-		"apexer_test_host_tools",
-		"host_apex_verifier",
-		"tjbench", // TODO(b/240563612): Stem property
-
-		// 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.
-
-		// python protos
-		"libprotobuf-python", // Has a handcrafted alternative
-
-		// 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
-		"auto_value_plugin_resources",      // 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.
-
-		// in cmd attribute of genrule rule //system/timezone/output_data:robolectric_tzdata: label '//system/timezone/output_data:iana/tzdata' in $(location) expression is not a declared prerequisite of this rule
-		"robolectric_tzdata",
-
-		// 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
-		"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-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
-		"libfastdeploy_host",                                      // depends on unconverted modules: libandroidfw, libusb, AdbWinApi
-		"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
-		"truth-host-prebuilt",           // depends on unconverted modules: truth-prebuilt
-		"truth-prebuilt",                // depends on unconverted modules: asm-7.0, guava
-
-		// '//bionic/libc:libc_bp2build_cc_library_static' is duplicated in the 'deps' attribute of rule
-		"toybox-static",
-
-		// 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.
-		"libvintf",
-		"vintf",
-		"libassemblevintf",
-		"assemble_vintf",
-		"libvintffm",
-		"vintffm",
-		"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
-		"memunreachable_unit_test",
-		"libprocinfo_test",
-		"ziparchive-tests",
-		"gtest_isolated_tests",
-		"libunwindstack_unit_test",
-		"task_profiles_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", "aapt2_tests", // failing due to data path issues
-
-		// 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
-		"Mpeg4H263DecoderTest", // depends on unconverted modules: libstagefright_foundation
-		"Mpeg4H263EncoderTest",
-		"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",
-		"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",
-		"libexpectedutils_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",
-		"minijail0_cli_unittest_gtest",
-		"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
-		"syscall_filter_unittest_gtest",
-		"sysprop_test", // depends on unconverted modules: libcom.android.sysprop.tests
-		"thread_exit_cb_helper",
-		"tls_properties_helper",
-		"ulp",
-		"vec_test",
-		"yuvconstants",
-		"yuvconvert",
-		"zipalign_tests",
-
-		// 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
-		"releasetools_fsverity_metadata_generator",
-		"verity_utils",
-		"check_ota_package_signature",
-		"check_target_files_vintf",
-		"releasetools_check_target_files_vintf",
-		"releasetools_verity_utils",
-		"build_image",
-		"ota_from_target_files",
-		"releasetools_ota_from_target_files",
-		"releasetools_build_image",
-		"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",
-
-		// python_test_host with test data
-		"sbom_writers_test",
-	}
-
-	MixedBuildsDisabledList = []string{
-		"libruy_static", "libtflite_kernel_utils", // TODO(b/237315968); Depend on prebuilt stl, not from source
-
-		"art_libdexfile_dex_instruction_list_header", // breaks libart_mterp.armng, header not found
-
-		"libbrotli",               // http://b/198585397, ld.lld: error: bionic/libc/arch-arm64/generic/bionic/memmove.S:95:(.text+0x10): relocation R_AARCH64_CONDBR19 out of range: -1404176 is not in [-1048576, 1048575]; references __memcpy
-		"minijail_constants_json", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
-
-		"cap_names.h",                                  // TODO(b/204913827) runfiles need to be handled in mixed builds
-		"libcap",                                       // TODO(b/204913827) runfiles need to be handled in mixed builds
-		"libprotobuf-cpp-full", "libprotobuf-cpp-lite", // Unsupported product&vendor suffix. b/204811222 and b/204810610.
-
-		// Depends on libprotobuf-cpp-*
-		"libadb_pairing_connection",
-		"libadb_pairing_connection_static",
-		"libadb_pairing_server", "libadb_pairing_server_static",
-
-		// TODO(b/240563612) Needing `stem` selection support for cc_binary
-		"crasher",
-
-		// java_import[_host] issues
-		// tradefed prebuilts depend on libprotobuf
-		"prebuilt_tradefed",
-		"prebuilt_tradefed-test-framework",
-		// handcrafted BUILD.bazel files in //prebuilts/...
-		"prebuilt_r8lib-prebuilt",
-		"prebuilt_sdk-core-lambda-stubs",
-		"prebuilt_android-support-collections-nodeps",
-		"prebuilt_android-arch-core-common-nodeps",
-		"prebuilt_android-arch-lifecycle-common-java8-nodeps",
-		"prebuilt_android-arch-lifecycle-common-nodeps",
-		"prebuilt_android-support-annotations-nodeps",
-		"prebuilt_android-arch-paging-common-nodeps",
-		"prebuilt_android-arch-room-common-nodeps",
-		// TODO(b/217750501) exclude_dirs property not supported
-		"prebuilt_kotlin-reflect",
-		"prebuilt_kotlin-stdlib",
-		"prebuilt_kotlin-stdlib-jdk7",
-		"prebuilt_kotlin-stdlib-jdk8",
-		"prebuilt_kotlin-test",
-		// TODO(b/217750501) exclude_files property not supported
-		"prebuilt_currysrc_org.eclipse",
-
-		// TODO(b/266459895): re-enable libunwindstack
-		"libunwindstack",
-		"libunwindstack_stdout_log",
-		"libunwindstack_no_dex",
-		"libunwindstack_utils",
-		"unwind_reg_info",
-		"libunwindstack_local",
-		"unwind_for_offline",
-		"unwind",
-		"unwind_info",
-		"unwind_symbols",
-		"libEGL",
-		"libGLESv2",
-		"libc_malloc_debug",
-		"libcodec2_hidl@1.0",
-		"libcodec2_hidl@1.1",
-		"libcodec2_hidl@1.2",
-		"libfdtrack",
-		"libgui",
-		"libgui_bufferqueue_static",
-		"libmedia_codecserviceregistrant",
-		"libstagefright_bufferqueue_helper_novndk",
-		"libutils_test",
-		"libutilscallstack",
-		"mediaswcodec",
-	}
-
-	// 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",
-	}
-
-	// 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{
-		"com.android.neuralnetworks",
-		"libneuralnetworks",
-		"libneuralnetworks_static",
-	}
-
-	// These should be the libs that are included by the apexes in the ProdMixedBuildsEnabledList
-	ProdDclaMixedBuildsEnabledList = []string{
-		"libbase",
-		"libc++",
-		"libcrypto",
-		"libcutils",
-	}
-
-	// 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",
-	// "libstagefright_flacdec",
-	// "libutils",
-
-	// TODO(b/273282046): Make this list customizable to support various targets.
-	// The list of modules which are expected to spend lots of build time.
-	// With `--ninja_weight_source=soong`, ninja builds these modules and deps first.
-	HugeModulesMap = map[string]int{
-		"AccountManagementApp":                          DEFAULT_NINJA_WEIGHT,
-		"ActivityManagerPerfTestsStubApp1":              DEFAULT_NINJA_WEIGHT,
-		"ActivityManagerPerfTestsStubApp2":              DEFAULT_NINJA_WEIGHT,
-		"ActivityManagerPerfTestsStubApp3":              DEFAULT_NINJA_WEIGHT,
-		"api-stubs-docs-non-updatable":                  DEFAULT_NINJA_WEIGHT,
-		"AppCompatibilityTest":                          DEFAULT_NINJA_WEIGHT,
-		"AppTransitionTests":                            DEFAULT_NINJA_WEIGHT,
-		"art_compiler_tests":                            DEFAULT_NINJA_WEIGHT,
-		"art.module.intra.core.api.stubs.source":        DEFAULT_NINJA_WEIGHT,
-		"art.module.public.api.stubs.source":            DEFAULT_NINJA_WEIGHT,
-		"AttestationVerificationTest":                   DEFAULT_NINJA_WEIGHT,
-		"BatteryUsageStatsProtoTests":                   DEFAULT_NINJA_WEIGHT,
-		"bluetooth_test_gd_unit":                        DEFAULT_NINJA_WEIGHT,
-		"Bluetooth":                                     DEFAULT_NINJA_WEIGHT,
-		"BluetoothInstrumentationTests":                 DEFAULT_NINJA_WEIGHT,
-		"Calendar":                                      DEFAULT_NINJA_WEIGHT,
-		"CalendarProvider":                              DEFAULT_NINJA_WEIGHT,
-		"Camera2":                                       DEFAULT_NINJA_WEIGHT,
-		"CarRotaryControllerUnitTests":                  DEFAULT_NINJA_WEIGHT,
-		"CarSettingsForUnitTesting":                     DEFAULT_NINJA_WEIGHT,
-		"CarSettingsUnitTests":                          DEFAULT_NINJA_WEIGHT,
-		"CarSystemUI-tests":                             DEFAULT_NINJA_WEIGHT,
-		"CellBroadcastApp":                              DEFAULT_NINJA_WEIGHT,
-		"CellBroadcastLegacyApp":                        DEFAULT_NINJA_WEIGHT,
-		"CellBroadcastReceiverOemUnitTests":             DEFAULT_NINJA_WEIGHT,
-		"CellBroadcastServiceModule":                    DEFAULT_NINJA_WEIGHT,
-		"CompanionDeviceManager":                        DEFAULT_NINJA_WEIGHT,
-		"ConnectivityChecker":                           DEFAULT_NINJA_WEIGHT,
-		"Contacts":                                      DEFAULT_NINJA_WEIGHT,
-		"ContactsProvider":                              DEFAULT_NINJA_WEIGHT,
-		"ContentCapturePerfTests":                       DEFAULT_NINJA_WEIGHT,
-		"CorePerfTests":                                 DEFAULT_NINJA_WEIGHT,
-		"crosvm":                                        DEFAULT_NINJA_WEIGHT,
-		"CtsDomainVerificationDeviceMultiUserTestCases": DEFAULT_NINJA_WEIGHT,
-		"CtsLogdTestCases":                              DEFAULT_NINJA_WEIGHT,
-		"CtsMediaProviderTranscodeTests":                DEFAULT_NINJA_WEIGHT,
-		"CtsRollbackManagerHostTestHelperApp":           DEFAULT_NINJA_WEIGHT,
-		"CtsRollbackManagerHostTestHelperApp2":          DEFAULT_NINJA_WEIGHT,
-		"CtsRootPackageInstallerTestCases":              DEFAULT_NINJA_WEIGHT,
-		"CtsRootRollbackManagerHostTestHelperApp":       DEFAULT_NINJA_WEIGHT,
-		"CtsTranscodeTestAppSupportsHevc":               DEFAULT_NINJA_WEIGHT,
-		"CtsTranscodeTestAppSupportsSlowMotion":         DEFAULT_NINJA_WEIGHT,
-		"CuttlefishDisplayHotplugHelperApp":             DEFAULT_NINJA_WEIGHT,
-		"cvd-host_package":                              DEFAULT_NINJA_WEIGHT,
-		"DelegateTestApp":                               DEFAULT_NINJA_WEIGHT,
-		"DeskClock":                                     DEFAULT_NINJA_WEIGHT,
-		"Development":                                   DEFAULT_NINJA_WEIGHT,
-		"DeviceAdminTestApp":                            DEFAULT_NINJA_WEIGHT,
-		"DevicePolicyManagementRoleHolderTestApp":       DEFAULT_NINJA_WEIGHT,
-		"dex2oatd":                                      DEFAULT_NINJA_WEIGHT,
-		"DocumentsUI":                                   DEFAULT_NINJA_WEIGHT,
-		"EasterEgg":                                     DEFAULT_NINJA_WEIGHT,
-		"EffectProxyTest":                               DEFAULT_NINJA_WEIGHT,
-		"EmergencyInfo":                                 DEFAULT_NINJA_WEIGHT,
-		"EmptyTestApp":                                  DEFAULT_NINJA_WEIGHT,
-		"ExtServices":                                   DEFAULT_NINJA_WEIGHT,
-		"FacebookAppsScenarioTests":                     DEFAULT_NINJA_WEIGHT,
-		"flickerlib-core":                               DEFAULT_NINJA_WEIGHT,
-		"flickerlib":                                    DEFAULT_NINJA_WEIGHT,
-		"FlickerLibTest":                                DEFAULT_NINJA_WEIGHT,
-		"FlickerTests":                                  DEFAULT_NINJA_WEIGHT,
-		"framework-minus-apex":                          DEFAULT_NINJA_WEIGHT,
-		"framework-res":                                 DEFAULT_NINJA_WEIGHT,
-		"FrameworksCoreTests":                           DEFAULT_NINJA_WEIGHT,
-		"FrameworksMockingCoreTests":                    DEFAULT_NINJA_WEIGHT,
-		"FrameworksMockingServicesTests":                DEFAULT_NINJA_WEIGHT,
-		"FrameworksNetSmokeTests":                       DEFAULT_NINJA_WEIGHT,
-		"FrameworksNetTests":                            DEFAULT_NINJA_WEIGHT,
-		"FrameworksServicesTests":                       DEFAULT_NINJA_WEIGHT,
-		"FrameworksTelephonyTests":                      DEFAULT_NINJA_WEIGHT,
-		"FrameworksUiServicesTests":                     DEFAULT_NINJA_WEIGHT,
-		"FrameworksVcnTests":                            DEFAULT_NINJA_WEIGHT,
-		"Gallery2":                                      DEFAULT_NINJA_WEIGHT,
-		"GameCoreDevice":                                DEFAULT_NINJA_WEIGHT,
-		"GoogleBluetoothInstrumentationTests":           DEFAULT_NINJA_WEIGHT,
-		"guice_munged_srcs":                             DEFAULT_NINJA_WEIGHT,
-		"HalfSheetUX":                                   DEFAULT_NINJA_WEIGHT,
-		"ImePerfTests":                                  DEFAULT_NINJA_WEIGHT,
-		"imgdiag":                                       DEFAULT_NINJA_WEIGHT,
-		"ImsServiceEntitlement":                         DEFAULT_NINJA_WEIGHT,
-		"ImsServiceEntitlementUnitTests":                DEFAULT_NINJA_WEIGHT,
-		"InputTests":                                    DEFAULT_NINJA_WEIGHT,
-		"InstallTest":                                   DEFAULT_NINJA_WEIGHT,
-		"IntentResolver":                                DEFAULT_NINJA_WEIGHT,
-		"JankBench":                                     DEFAULT_NINJA_WEIGHT,
-		"jsilver":                                       DEFAULT_NINJA_WEIGHT,
-		"KeyChain":                                      DEFAULT_NINJA_WEIGHT,
-		"KeyChainTests":                                 DEFAULT_NINJA_WEIGHT,
-		"keystore2":                                     DEFAULT_NINJA_WEIGHT,
-		"LargeResourcesCompressed":                      DEFAULT_NINJA_WEIGHT,
-		"LatinIME":                                      DEFAULT_NINJA_WEIGHT,
-		"Launcher3QuickStepLib":                         DEFAULT_NINJA_WEIGHT,
-		"libaom":                                        DEFAULT_NINJA_WEIGHT,
-		"libart-broken":                                 DEFAULT_NINJA_WEIGHT,
-		"libart-compiler":                               DEFAULT_NINJA_WEIGHT,
-		"libart-disassembler":                           DEFAULT_NINJA_WEIGHT,
-		"libart":                                        DEFAULT_NINJA_WEIGHT,
-		"libartd":                                       DEFAULT_NINJA_WEIGHT,
-		"libaudiohal@7.1":                               DEFAULT_NINJA_WEIGHT,
-		"libbluetooth_core_rs":                          DEFAULT_NINJA_WEIGHT,
-		"libbluetooth_gd_unit_tests":                    DEFAULT_NINJA_WEIGHT,
-		"libbluetooth_gd":                               DEFAULT_NINJA_WEIGHT,
-		"libbluetooth_rs":                               DEFAULT_NINJA_WEIGHT,
-		"libbluetooth-for-tests":                        DEFAULT_NINJA_WEIGHT,
-		"libbt_common":                                  DEFAULT_NINJA_WEIGHT,
-		"libbt_packets_nonapex":                         DEFAULT_NINJA_WEIGHT,
-		"libbt_packets":                                 DEFAULT_NINJA_WEIGHT,
-		"libbt_shim_ffi":                                DEFAULT_NINJA_WEIGHT,
-		"libbt_shim":                                    DEFAULT_NINJA_WEIGHT,
-		"libbt-audio-hal-interface":                     DEFAULT_NINJA_WEIGHT,
-		"libbt-bta-core":                                DEFAULT_NINJA_WEIGHT,
-		"libbt-bta":                                     DEFAULT_NINJA_WEIGHT,
-		"libbt-common":                                  DEFAULT_NINJA_WEIGHT,
-		"libbt-hci":                                     DEFAULT_NINJA_WEIGHT,
-		"libbt-platform-protos-lite":                    DEFAULT_NINJA_WEIGHT,
-		"libbt-protos-lite":                             DEFAULT_NINJA_WEIGHT,
-		"libbt-sbc-decoder":                             DEFAULT_NINJA_WEIGHT,
-		"libc":                                          DEFAULT_NINJA_WEIGHT,
-		"libclap":                                       DEFAULT_NINJA_WEIGHT,
-		"libcodec2_soft_av1dec_gav1":                    DEFAULT_NINJA_WEIGHT,
-		"libcompositionengine_test":                     DEFAULT_NINJA_WEIGHT,
-		"libdevices":                                    DEFAULT_NINJA_WEIGHT,
-		"libfrontend_proto":                             DEFAULT_NINJA_WEIGHT,
-		"libhwtrust":                                    DEFAULT_NINJA_WEIGHT,
-		"libjni":                                        DEFAULT_NINJA_WEIGHT,
-		"libkeystore2":                                  DEFAULT_NINJA_WEIGHT,
-		"libkmr_ta":                                     DEFAULT_NINJA_WEIGHT,
-		"liblmp":                                        DEFAULT_NINJA_WEIGHT,
-		"libopenjdkjvmtid":                              DEFAULT_NINJA_WEIGHT,
-		"libprotobuf_deprecated":                        DEFAULT_NINJA_WEIGHT,
-		"libprotobuf":                                   DEFAULT_NINJA_WEIGHT,
-		"libregex":                                      DEFAULT_NINJA_WEIGHT,
-		"LibStatsPullTests":                             DEFAULT_NINJA_WEIGHT,
-		"libstd":                                        DEFAULT_NINJA_WEIGHT,
-		"libsurfaceflinger_unittest":                    DEFAULT_NINJA_WEIGHT,
-		"libsyn":                                        DEFAULT_NINJA_WEIGHT,
-		"libtokio":                                      DEFAULT_NINJA_WEIGHT,
-		"libuwb_core":                                   DEFAULT_NINJA_WEIGHT,
-		"libuwb_uci_jni_rust":                           DEFAULT_NINJA_WEIGHT,
-		"libuwb_uci_packets":                            DEFAULT_NINJA_WEIGHT,
-		"libvpx":                                        DEFAULT_NINJA_WEIGHT,
-		"libvulkan_enc":                                 DEFAULT_NINJA_WEIGHT,
-		"libwebrtc":                                     DEFAULT_NINJA_WEIGHT,
-		"LiveWallpapersPicker":                          DEFAULT_NINJA_WEIGHT,
-		"LockTaskApp":                                   DEFAULT_NINJA_WEIGHT,
-		"LongevityPlatformLibTests":                     DEFAULT_NINJA_WEIGHT,
-		"ManagedProvisioning":                           DEFAULT_NINJA_WEIGHT,
-		"ManagedProvisioningTests":                      DEFAULT_NINJA_WEIGHT,
-		"MediaProvider":                                 DEFAULT_NINJA_WEIGHT,
-		"MediaProviderClientTests":                      DEFAULT_NINJA_WEIGHT,
-		"MediaProviderLegacy":                           DEFAULT_NINJA_WEIGHT,
-		"messaging":                                     DEFAULT_NINJA_WEIGHT,
-		"metalava":                                      DEFAULT_NINJA_WEIGHT,
-		"MicrobenchmarkRunnerTests":                     DEFAULT_NINJA_WEIGHT,
-		"microdroid_manager":                            DEFAULT_NINJA_WEIGHT,
-		"minikin_tests":                                 DEFAULT_NINJA_WEIGHT,
-		"MLCTestApp":                                    DEFAULT_NINJA_WEIGHT,
-		"MmsService":                                    DEFAULT_NINJA_WEIGHT,
-		"MmsServiceTests":                               DEFAULT_NINJA_WEIGHT,
-		"module-lib-api-stubs-docs-non-updatable":       DEFAULT_NINJA_WEIGHT,
-		"motion_tool_lib_tests":                         DEFAULT_NINJA_WEIGHT,
-		"MtpService":                                    DEFAULT_NINJA_WEIGHT,
-		"MultiUserTests":                                DEFAULT_NINJA_WEIGHT,
-		"NearbyIntegrationUiTests":                      DEFAULT_NINJA_WEIGHT,
-		"net_test_bluetooth":                            DEFAULT_NINJA_WEIGHT,
-		"net_test_btif":                                 DEFAULT_NINJA_WEIGHT,
-		"net_test_main_shim":                            DEFAULT_NINJA_WEIGHT,
-		"net_test_stack":                                DEFAULT_NINJA_WEIGHT,
-		"net-tests-utils":                               DEFAULT_NINJA_WEIGHT,
-		"NetworkStackCoverageTests":                     DEFAULT_NINJA_WEIGHT,
-		"NetworkStackIntegrationTests":                  DEFAULT_NINJA_WEIGHT,
-		"NetworkStackNext":                              DEFAULT_NINJA_WEIGHT,
-		"NfcNci":                                        DEFAULT_NINJA_WEIGHT,
-		"NfcNciUnitTests":                               DEFAULT_NINJA_WEIGHT,
-		"NotEmptyTestApp":                               DEFAULT_NINJA_WEIGHT,
-		"NotificationFunctionalTests":                   DEFAULT_NINJA_WEIGHT,
-		"oatdumpd":                                      DEFAULT_NINJA_WEIGHT,
-		"OsuLogin":                                      DEFAULT_NINJA_WEIGHT,
-		"PackageInstaller":                              DEFAULT_NINJA_WEIGHT,
-		"PackageManagerComponentOverrideTests":          DEFAULT_NINJA_WEIGHT,
-		"PackageManagerPerfTests":                       DEFAULT_NINJA_WEIGHT,
-		"PackageManagerServiceServerTests":              DEFAULT_NINJA_WEIGHT,
-		"PackageManagerServiceUnitTests":                DEFAULT_NINJA_WEIGHT,
-		"PackageWatchdogTest":                           DEFAULT_NINJA_WEIGHT,
-		"PandoraServerLib":                              DEFAULT_NINJA_WEIGHT,
-		"pdl":                                           DEFAULT_NINJA_WEIGHT,
-		"perfetto_trace_java_protos":                    DEFAULT_NINJA_WEIGHT,
-		"perfetto_trace-full":                           DEFAULT_NINJA_WEIGHT,
-		"PermissionController":                          DEFAULT_NINJA_WEIGHT,
-		"PermissionControllerMockingTests":              DEFAULT_NINJA_WEIGHT,
-		"PixelAppCompTests":                             DEFAULT_NINJA_WEIGHT,
-		"platform-bootclasspath":                        DEFAULT_NINJA_WEIGHT,
-		"PlatformCommonScenarioTests":                   DEFAULT_NINJA_WEIGHT,
-		"PlatformComposeCoreTests":                      DEFAULT_NINJA_WEIGHT,
-		"platformprotoslite":                            DEFAULT_NINJA_WEIGHT,
-		"PlatformRuleTests":                             DEFAULT_NINJA_WEIGHT,
-		"precompiled_sepolicy-without_apex":             DEFAULT_NINJA_WEIGHT,
-		"PresencePolling":                               DEFAULT_NINJA_WEIGHT,
-		"PrintSpooler":                                  DEFAULT_NINJA_WEIGHT,
-		"QuickSearchBox":                                DEFAULT_NINJA_WEIGHT,
-		"RemoteDPCTestApp":                              DEFAULT_NINJA_WEIGHT,
-		"RemoteProvisioningServiceTests":                DEFAULT_NINJA_WEIGHT,
-		"RkpdAppUnitTests":                              DEFAULT_NINJA_WEIGHT,
-		"Robolectric_shadows_framework":                 DEFAULT_NINJA_WEIGHT,
-		"RoleHolderApp":                                 DEFAULT_NINJA_WEIGHT,
-		"SdkSandbox":                                    DEFAULT_NINJA_WEIGHT,
-		"service-appsearch":                             DEFAULT_NINJA_WEIGHT,
-		"service-connectivity":                          DEFAULT_NINJA_WEIGHT,
-		"service-uwb":                                   DEFAULT_NINJA_WEIGHT,
-		"service-wifi":                                  DEFAULT_NINJA_WEIGHT,
-		"services-non-updatable-stubs":                  DEFAULT_NINJA_WEIGHT,
-		"services":                                      DEFAULT_NINJA_WEIGHT,
-		"Settings-core":                                 DEFAULT_NINJA_WEIGHT,
-		"Settings":                                      DEFAULT_NINJA_WEIGHT,
-		"SettingsIntelligence":                          DEFAULT_NINJA_WEIGHT,
-		"SettingsLibTests":                              DEFAULT_NINJA_WEIGHT,
-		"SettingsProvider":                              DEFAULT_NINJA_WEIGHT,
-		"Shell":                                         DEFAULT_NINJA_WEIGHT,
-		"SimAppDialog":                                  DEFAULT_NINJA_WEIGHT,
-		"sl4a":                                          DEFAULT_NINJA_WEIGHT,
-		"SmsApp":                                        DEFAULT_NINJA_WEIGHT,
-		"SoundPicker":                                   DEFAULT_NINJA_WEIGHT,
-		"StagedInstallTest":                             DEFAULT_NINJA_WEIGHT,
-		"StatementService":                              DEFAULT_NINJA_WEIGHT,
-		"StatsdFrameworkTestApp":                        DEFAULT_NINJA_WEIGHT,
-		"StatsdFrameworkTestAppNoPermission":            DEFAULT_NINJA_WEIGHT,
-		"statsdprotolite":                               DEFAULT_NINJA_WEIGHT,
-		"Stk":                                           DEFAULT_NINJA_WEIGHT,
-		"StorageManager":                                DEFAULT_NINJA_WEIGHT,
-		"system-api-stubs-docs-non-updatable":           DEFAULT_NINJA_WEIGHT,
-		"SystemUI-core":                                 DEFAULT_NINJA_WEIGHT,
-		"SystemUI-tests-base":                           DEFAULT_NINJA_WEIGHT,
-		"SystemUI-tests":                                DEFAULT_NINJA_WEIGHT,
-		"SystemUI":                                      DEFAULT_NINJA_WEIGHT,
-		"SystemUIComposeFeatures":                       DEFAULT_NINJA_WEIGHT,
-		"SystemUIComposeFeaturesTests":                  DEFAULT_NINJA_WEIGHT,
-		"SystemUITests":                                 DEFAULT_NINJA_WEIGHT,
-		"Tag":                                           DEFAULT_NINJA_WEIGHT,
-		"Telecom":                                       DEFAULT_NINJA_WEIGHT,
-		"TelecomUnitTests":                              DEFAULT_NINJA_WEIGHT,
-		"telephony-common":                              DEFAULT_NINJA_WEIGHT,
-		"TelephonyProvider":                             DEFAULT_NINJA_WEIGHT,
-		"TeleService":                                   DEFAULT_NINJA_WEIGHT,
-		"test-api-stubs-docs-non-updatable":             DEFAULT_NINJA_WEIGHT,
-		"TetheringIntegrationTests":                     DEFAULT_NINJA_WEIGHT,
-		"TetheringNext":                                 DEFAULT_NINJA_WEIGHT,
-		"ThemePickerTests":                              DEFAULT_NINJA_WEIGHT,
-		"Traceur":                                       DEFAULT_NINJA_WEIGHT,
-		"UsbManagerTests":                               DEFAULT_NINJA_WEIGHT,
-		"UsbTests":                                      DEFAULT_NINJA_WEIGHT,
-		"virtmgr":                                       DEFAULT_NINJA_WEIGHT,
-		"WallpaperPicker2TestLib":                       DEFAULT_NINJA_WEIGHT,
-		"WallpaperPicker2Tests":                         DEFAULT_NINJA_WEIGHT,
-		"WifiDialog":                                    DEFAULT_NINJA_WEIGHT,
-		"wm-proto-parsers":                              DEFAULT_NINJA_WEIGHT,
-		"WMShellFlickerTests":                           DEFAULT_NINJA_WEIGHT,
-		"WmTests":                                       DEFAULT_NINJA_WEIGHT,
-		"wpa_supplicant":                                DEFAULT_NINJA_WEIGHT,
+	// 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{
+		"rust_":       HIGH_PRIORITIZED_WEIGHT,
+		"droidstubs":  DEFAULT_PRIORITIZED_WEIGHT,
+		"art_":        DEFAULT_PRIORITIZED_WEIGHT,
+		"ndk_library": DEFAULT_PRIORITIZED_WEIGHT,
 	}
 )
diff --git a/android/androidmk.go b/android/androidmk.go
index aa411d1..07f7c58 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -30,6 +30,7 @@
 	"reflect"
 	"runtime"
 	"sort"
+	"strconv"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -42,7 +43,7 @@
 }
 
 func RegisterAndroidMkBuildComponents(ctx RegistrationContext) {
-	ctx.RegisterSingletonType("androidmk", AndroidMkSingleton)
+	ctx.RegisterParallelSingletonType("androidmk", AndroidMkSingleton)
 }
 
 // Enable androidmk support.
@@ -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 5a25297..4d36a93 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -84,9 +84,12 @@
 	//
 	// See Prebuilt.ApexInfoMutator for more information.
 	ForPrebuiltApex bool
+
+	// Returns the name of the test apexes that this module is included in.
+	TestApexes []string
 }
 
-var ApexInfoProvider = blueprint.NewMutatorProvider(ApexInfo{}, "apex")
+var ApexInfoProvider = blueprint.NewMutatorProvider[ApexInfo]("apex")
 
 func (i ApexInfo) AddJSONData(d *map[string]interface{}) {
 	(*d)["Apex"] = map[string]interface{}{
@@ -142,7 +145,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
@@ -287,6 +297,9 @@
 
 	// See ApexModule.UniqueApexVariants()
 	UniqueApexVariationsForDeps bool `blueprint:"mutated"`
+
+	// The test apexes that includes this apex variant
+	TestApexes []string `blueprint:"mutated"`
 }
 
 // Marker interface that identifies dependencies that are excluded from APEX contents.
@@ -429,6 +442,11 @@
 	return nil
 }
 
+// Returns the test apexes that this module is included in.
+func (m *ApexModuleBase) TestApexes() []string {
+	return m.ApexProperties.TestApexes
+}
+
 // Implements ApexModule
 func (m *ApexModuleBase) UniqueApexVariations() bool {
 	// If needed, this will bel overridden by concrete types inheriting
@@ -559,12 +577,14 @@
 			// Platform APIs is allowed for this module only when all APEXes containing
 			// the module are with `use_platform_apis: true`.
 			merged[index].UsePlatformApis = merged[index].UsePlatformApis && apexInfo.UsePlatformApis
+			merged[index].TestApexes = append(merged[index].TestApexes, apexInfo.TestApexes...)
 		} else {
 			seen[mergedName] = len(merged)
 			apexInfo.ApexVariationName = mergedName
 			apexInfo.InApexVariants = CopyOf(apexInfo.InApexVariants)
 			apexInfo.InApexModules = CopyOf(apexInfo.InApexModules)
 			apexInfo.ApexContents = append([]*ApexContents(nil), apexInfo.ApexContents...)
+			apexInfo.TestApexes = CopyOf(apexInfo.TestApexes)
 			merged = append(merged, apexInfo)
 		}
 		aliases = append(aliases, [2]string{variantName, mergedName})
@@ -612,8 +632,10 @@
 	mctx.SetDefaultDependencyVariation(&defaultVariation)
 
 	variations := []string{defaultVariation}
+	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 {
@@ -627,6 +649,9 @@
 		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
 	}
 
 	for _, alias := range aliases {
@@ -936,3 +961,18 @@
 	// 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
+}
diff --git a/android/apex_contributions.go b/android/apex_contributions.go
new file mode 100644
index 0000000..236abf6
--- /dev/null
+++ b/android/apex_contributions.go
@@ -0,0 +1,173 @@
+// 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.RegisterSingletonModuleType("all_apex_contributions", allApexContributionsFactory)
+}
+
+type apexContributions struct {
+	ModuleBase
+	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)
+	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) {
+}
+
+// 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{}
+	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 0bf4c9c..ddc730d 100644
--- a/android/apex_test.go
+++ b/android/apex_test.go
@@ -33,10 +33,10 @@
 		{
 			name: "single",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantAliases: [][2]string{
 				{"foo", "apex10000"},
@@ -45,11 +45,11 @@
 		{
 			name: "merge",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", FutureApiLevel, false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{"bar", FutureApiLevel, false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false}},
+				{"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false, nil}},
 			wantAliases: [][2]string{
 				{"bar", "apex10000"},
 				{"foo", "apex10000"},
@@ -58,12 +58,12 @@
 		{
 			name: "don't merge version",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{"bar", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex30", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
-				{"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+				{"apex30", uncheckedFinalApiLevel(30), false, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
+				{"apex10000", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex30"},
@@ -73,11 +73,11 @@
 		{
 			name: "merge updatable",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+				{"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex10000"},
@@ -87,15 +87,15 @@
 		{
 			name: "don't merge when for prebuilt_apex",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{"bar", FutureApiLevel, true, false, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
 				// 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},
+				{"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
-				{"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
+				{"apex10000", FutureApiLevel, true, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
+				{"baz", FutureApiLevel, true, false, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex, nil},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex10000"},
@@ -105,11 +105,11 @@
 		{
 			name: "merge different UsePlatformApis but don't allow using platform api",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, false, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+				{"apex10000", FutureApiLevel, false, false, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex10000"},
@@ -119,11 +119,11 @@
 		{
 			name: "merge same UsePlatformApis and allow using platform api",
 			in: []ApexInfo{
-				{"foo", FutureApiLevel, false, true, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
-				{"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+				{"foo", FutureApiLevel, false, true, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex, nil},
+				{"bar", FutureApiLevel, false, true, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantMerged: []ApexInfo{
-				{"apex10000", FutureApiLevel, false, true, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+				{"apex10000", FutureApiLevel, false, true, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex, nil},
 			},
 			wantAliases: [][2]string{
 				{"bar", "apex10000"},
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 137fd9d..c019f99 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -15,16 +15,15 @@
 package android
 
 import (
+	"android/soong/starlark_import"
 	"encoding/json"
 	"fmt"
 	"strconv"
-
-	"android/soong/bazel"
-	"android/soong/starlark_fmt"
+	"strings"
 )
 
 func init() {
-	RegisterSingletonType("api_levels", ApiLevelsSingleton)
+	RegisterParallelSingletonType("api_levels", ApiLevelsSingleton)
 }
 
 const previewAPILevelBase = 9000
@@ -239,6 +238,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.
@@ -277,10 +284,6 @@
 // relocations itself.
 var FirstPackedRelocationsVersion = uncheckedFinalApiLevel(23)
 
-// The first API level that does not require NDK code to link
-// libandroid_support.
-var FirstNonLibAndroidSupportVersion = uncheckedFinalApiLevel(21)
-
 // LastWithoutModuleLibCoreSystemModules is the last API level where prebuilts/sdk does not contain
 // a core-for-system-modules.jar for the module-lib API scope.
 var LastWithoutModuleLibCoreSystemModules = uncheckedFinalApiLevel(31)
@@ -288,13 +291,17 @@
 // 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.
-func ReplaceFinalizedCodenames(config Config, raw string) string {
-	num, ok := getFinalCodenamesMap(config)[raw]
+func ReplaceFinalizedCodenames(config Config, raw string) (string, error) {
+	finalCodenamesMap, err := getFinalCodenamesMap(config)
+	if err != nil {
+		return raw, err
+	}
+	num, ok := finalCodenamesMap[raw]
 	if !ok {
-		return raw
+		return raw, nil
 	}
 
-	return strconv.Itoa(num)
+	return strconv.Itoa(num), nil
 }
 
 // ApiLevelFrom converts the given string `raw` to an ApiLevel.
@@ -329,7 +336,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")
 	}
@@ -344,7 +351,11 @@
 		}
 	}
 
-	canonical, ok := getApiLevelsMapReleasedVersions()[raw]
+	apiLevelsReleasedVersions, err := getApiLevelsMapReleasedVersions()
+	if err != nil {
+		return NoneApiLevel, err
+	}
+	canonical, ok := apiLevelsReleasedVersions[raw]
 	if !ok {
 		asInt, err := strconv.Atoi(raw)
 		if err != nil {
@@ -369,6 +380,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))
@@ -410,38 +437,21 @@
 	return PathForOutput(ctx, "api_levels.json")
 }
 
-func getApiLevelsMapReleasedVersions() map[string]int {
-	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,
-	}
+func getApiLevelsMapReleasedVersions() (map[string]int, error) {
+	return starlark_import.GetStarlarkValue[map[string]int]("api_levels_released_versions")
 }
 
 var finalCodenamesMapKey = NewOnceKey("FinalCodenamesMap")
 
-func getFinalCodenamesMap(config Config) map[string]int {
+func getFinalCodenamesMap(config Config) (map[string]int, error) {
+	type resultStruct struct {
+		result map[string]int
+		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
-	return config.Once(finalCodenamesMapKey, func() interface{} {
-		apiLevelsMap := getApiLevelsMapReleasedVersions()
+	// 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()
 
 		// TODO: Differentiate "current" and "future".
 		// The code base calls it FutureApiLevel, but the spelling is "current",
@@ -454,41 +464,44 @@
 		// added in S, both of these are usable when building for "current" when
 		// neither R nor S are final, but the S APIs stop being available in a
 		// final R build.
-		if Bool(config.productVariables.Platform_sdk_final) {
+		if err == nil && Bool(config.productVariables.Platform_sdk_final) {
 			apiLevelsMap["current"] = config.PlatformSdkVersion().FinalOrFutureInt()
 		}
 
-		return apiLevelsMap
-	}).(map[string]int)
+		return resultStruct{apiLevelsMap, err}
+	}).(resultStruct)
+	return result.result, result.err
 }
 
 var apiLevelsMapKey = NewOnceKey("ApiLevelsMap")
 
 // ApiLevelsMap has entries for preview API levels
-func GetApiLevelsMap(config Config) map[string]int {
+func GetApiLevelsMap(config Config) (map[string]int, error) {
+	type resultStruct struct {
+		result map[string]int
+		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
-	return config.Once(apiLevelsMapKey, func() interface{} {
-		apiLevelsMap := getApiLevelsMapReleasedVersions()
-		for i, codename := range config.PlatformVersionAllPreviewCodenames() {
-			apiLevelsMap[codename] = previewAPILevelBase + i
+	// 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 {
+			for i, codename := range config.PlatformVersionAllPreviewCodenames() {
+				apiLevelsMap[codename] = previewAPILevelBase + i
+			}
 		}
 
-		return apiLevelsMap
-	}).(map[string]int)
+		return resultStruct{apiLevelsMap, err}
+	}).(resultStruct)
+	return result.result, result.err
 }
 
 func (a *apiLevelsSingleton) GenerateBuildActions(ctx SingletonContext) {
-	apiLevelsMap := GetApiLevelsMap(ctx.Config())
+	apiLevelsMap, err := GetApiLevelsMap(ctx.Config())
+	if err != nil {
+		ctx.Errorf("%s\n", err)
+		return
+	}
 	apiLevelsJson := GetApiLevelsJson(ctx)
 	createApiLevelsJson(ctx, apiLevelsJson, apiLevelsMap)
 }
-
-func StarlarkApiLevelConfigs(config Config) string {
-	return fmt.Sprintf(bazel.GeneratedBazelFileWarning+`
-_api_levels_released_versions = %s
-
-api_levels_released_versions = _api_levels_released_versions
-`, starlark_fmt.PrintStringIntDict(getApiLevelsMapReleasedVersions(), 0),
-	)
-}
diff --git a/android/arch.go b/android/arch.go
index d3e7d2a..c39db02 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -425,7 +425,7 @@
 	// 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)
 
 	base := module.base()
 
@@ -571,7 +571,7 @@
 	// 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)
 
 	base := module.base()
 
@@ -1885,10 +1885,10 @@
 		buildTargets = filterMultilibTargets(targets, "lib64")
 		// Reverse the targets so that the first architecture can depend on the second
 		// architecture module in order to merge the outputs.
-		reverseSliceInPlace(buildTargets)
+		ReverseSliceInPlace(buildTargets)
 	case "darwin_universal_common_first":
 		archTargets := filterMultilibTargets(targets, "lib64")
-		reverseSliceInPlace(archTargets)
+		ReverseSliceInPlace(archTargets)
 		buildTargets = append(getCommonTargets(targets), archTargets...)
 	default:
 		return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", "prefer32" or "first_prefer32" found %q`,
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..3cf4b41
--- /dev/null
+++ b/android/arch_module_context.go
@@ -0,0 +1,83 @@
+// 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.
+	os            OsType
+	target        Target
+	targetPrimary bool
+	multiTargets  []Target
+	primaryArch   bool
+}
+
+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..b9c1153
--- /dev/null
+++ b/android/base_module_context.go
@@ -0,0 +1,566 @@
+// 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"
+	"github.com/google/blueprint"
+	"regexp"
+	"strings"
+)
+
+// 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
+}
+
+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
+}
+
+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()
+}
diff --git a/android/bazel.go b/android/bazel.go
deleted file mode 100644
index 1646883..0000000
--- a/android/bazel.go
+++ /dev/null
@@ -1,545 +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"
-	"strings"
-
-	"github.com/google/blueprint"
-	"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 = "."
-)
-
-// 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"`
-}
-
-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(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)
-	}
-	return "" // no label for unconverted module
-}
-
-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 true if 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) bool {
-	module := ctx.Module()
-	apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo)
-	withinApex := !apexInfo.IsForPlatform()
-	mixedBuildEnabled := ctx.Config().IsMixedBuildsEnabled() &&
-		ctx.Os() != Windows && // Windows toolchains are not currently supported.
-		ctx.Os() != LinuxBionic && // Linux Bionic toolchains are not currently supported.
-		ctx.Os() != LinuxMusl && // Linux musl toolchains are not currently supported (b/259266326).
-		ctx.Arch().ArchType != Riscv64 && // TODO(b/262192655) Riscv64 toolchains are not currently supported.
-		module.Enabled() &&
-		convertedToBazel(ctx, module) &&
-		ctx.Config().BazelContext.IsModuleNameAllowed(module.Name(), withinApex)
-	ctx.Config().LogMixedBuild(ctx, mixedBuildEnabled)
-	return mixedBuildEnabled
-}
-
-// ConvertedToBazel returns whether this module has been converted (with bp2build or manually) to Bazel.
-func convertedToBazel(ctx BazelConversionContext, module blueprint.Module) bool {
-	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 (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 := ctx.OtherModuleDir(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 := module.Name()
-	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", convertWithBp2build).Parallel()
-}
-
-func convertWithBp2build(ctx TopDownMutatorContext) {
-	bModule, ok := ctx.Module().(Bazelable)
-	if !ok || !bModule.shouldConvertWithBp2build(ctx, ctx.Module()) {
-		return
-	}
-
-	bModule.ConvertWithBp2build(ctx)
-}
-
-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 9c273d9..0000000
--- a/android/bazel_handler.go
+++ /dev/null
@@ -1,1498 +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"
-	"fmt"
-	"os"
-	"os/exec"
-	"path"
-	"path/filepath"
-	"runtime"
-	"sort"
-	"strings"
-	"sync"
-
-	"android/soong/android/allowlists"
-	"android/soong/bazel/cquery"
-	"android/soong/shared"
-	"android/soong/starlark_fmt"
-
-	"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")
-	allowedBazelEnvironmentVars = []string{
-		// clang-tidy
-		"ALLOW_LOCAL_TIDY_TRUE",
-		"DEFAULT_TIDY_HEADER_DIRS",
-		"TIDY_TIMEOUT",
-		"WITH_TIDY",
-		"WITH_TIDY_FLAGS",
-		"TIDY_EXTERNAL_VENDOR",
-
-		"SKIP_ABI_CHECKS",
-		"UNSAFE_DISABLE_APEX_ALLOWED_DEPS_CHECK",
-		"AUTO_ZERO_INITIALIZE",
-		"AUTO_PATTERN_INITIALIZE",
-		"AUTO_UNINITIALIZE",
-		"USE_CCACHE",
-		"LLVM_NEXT",
-		"ALLOW_UNKNOWN_WARNING_OPTION",
-
-		"UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT",
-
-		// Overrides the version in the apex_manifest.json. The version is unique for
-		// each branch (internal, aosp, mainline releases, dessert releases).  This
-		// enables modules built on an older branch to be installed against a newer
-		// device for development purposes.
-		"OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION",
-	}
-)
-
-func init() {
-	RegisterMixedBuildsMutator(InitRegistrationContext)
-}
-
-func RegisterMixedBuildsMutator(ctx RegistrationContext) {
-	ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) {
-		ctx.BottomUp("mixed_builds_prep", mixedBuildsPrepareMutator).Parallel()
-	})
-}
-
-func mixedBuildsPrepareMutator(ctx BottomUpMutatorContext) {
-	if m := ctx.Module(); m.Enabled() {
-		if mixedBuildMod, ok := m.(MixedBuildBuildable); ok {
-			queueMixedBuild := mixedBuildMod.IsMixedBuildSupported(ctx) && MixedBuildsEnabled(ctx)
-			if queueMixedBuild {
-				mixedBuildMod.QueueBazelCall(ctx)
-			} else if _, ok := ctx.Config().bazelForceEnabledModules[m.Name()]; ok {
-				// TODO(b/273910287) - remove this once --ensure_allowlist_integrity is added
-				ctx.ModuleErrorf("Attempted to force enable an unready module: %s. Did you forget to Bp2BuildDefaultTrue its directory?\n", m.Name())
-			}
-		}
-	}
-}
-
-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
-}
-
-func (c ApexConfigKey) String() string {
-	return fmt.Sprintf("%s_%s", withinApexToString(c.WithinApex), c.ApexSdkVersion)
-}
-
-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 executable binary resultant from building together the python sources
-	// TODO(b/232976601): Remove.
-	GetPythonBinary(label string, cfgKey configKey) (string, 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)
-
-	// ** 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
-
-	IsModuleDclaAllowed(moduleName string) 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
-}
-
-type bazelRunner interface {
-	createBazelCommand(config Config, paths *bazelPaths, runName bazel.RunName, command bazelCommand, extraFlags ...string) *exec.Cmd
-	issueBazelCommand(bazelCmd *exec.Cmd, 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
-	// If true, modules are bazel-enabled by default, unless present in bazelDisabledModules.
-	modulesDefaultToBazel 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
-
-	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) 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) GetPythonBinary(label string, _ configKey) (string, error) {
-	result, ok := m.LabelToPythonBinary[label]
-	if !ok {
-		return "", fmt.Errorf("no target with label %q in LabelToPythonBinary", 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) InvokeBazel(_ Config, _ invokeBazelContext) error {
-	panic("unimplemented")
-}
-
-func (m MockBazelContext) IsModuleNameAllowed(_ string, _ bool) bool {
-	return true
-}
-
-func (m MockBazelContext) IsModuleDclaAllowed(_ string) 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) GetPythonBinary(label string, cfgKey configKey) (string, error) {
-	key := makeCqueryKey(label, cquery.GetPythonBinary, cfgKey)
-	if rawString, ok := bazelCtx.results[key]; ok {
-		bazelOutput := strings.TrimSpace(rawString)
-		return cquery.GetPythonBinary.ParseResult(bazelOutput), nil
-	}
-	return "", 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 (n noopBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
-	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) GetPythonBinary(_ string, _ configKey) (string, 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) InvokeBazel(_ Config, _ invokeBazelContext) error {
-	panic("unimplemented")
-}
-
-func (m noopBazelContext) OutputBase() string {
-	return ""
-}
-
-func (n noopBazelContext) IsModuleNameAllowed(_ string, _ bool) bool {
-	return false
-}
-
-func (n noopBazelContext) IsModuleDclaAllowed(_ string) 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
-		}
-	case BazelDevMode:
-		addToStringSet(disabledModules, allowlists.MixedBuildsDisabledList)
-	default:
-		panic("Expected BazelProdMode, BazelStagingMode, or BazelDevMode")
-	}
-	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 && c.BuildMode != BazelDevMode {
-		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,
-		modulesDefaultToBazel:   c.BuildMode == BazelDevMode,
-		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.IsModuleDclaAllowed(moduleName) {
-		return true
-	}
-
-	return context.modulesDefaultToBazel
-}
-
-func (context *mixedBuildBazelContext) IsModuleDclaAllowed(moduleName string) bool {
-	return context.bazelDclaEnabledModules[moduleName]
-}
-
-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 mockBazelRunner struct {
-	bazelCommandResults map[bazelCommand]string
-	// use *exec.Cmd as a key to get the bazelCommand, the map will be used in issueBazelCommand()
-	// Register createBazelCommand() invocations. Later, an
-	// issueBazelCommand() invocation can be mapped to the *exec.Cmd instance
-	// and then to the expected result via bazelCommandResults
-	tokens     map[*exec.Cmd]bazelCommand
-	commands   []bazelCommand
-	extraFlags []string
-}
-
-func (r *mockBazelRunner) createBazelCommand(_ Config, _ *bazelPaths, _ bazel.RunName,
-	command bazelCommand, extraFlags ...string) *exec.Cmd {
-	r.commands = append(r.commands, command)
-	r.extraFlags = append(r.extraFlags, strings.Join(extraFlags, " "))
-	cmd := &exec.Cmd{}
-	if r.tokens == nil {
-		r.tokens = make(map[*exec.Cmd]bazelCommand)
-	}
-	r.tokens[cmd] = command
-	return cmd
-}
-
-func (r *mockBazelRunner) issueBazelCommand(bazelCmd *exec.Cmd, _ *metrics.EventHandler) (string, string, error) {
-	if command, ok := r.tokens[bazelCmd]; ok {
-		return r.bazelCommandResults[command], "", nil
-	}
-	return "", "", nil
-}
-
-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(bazelCmd *exec.Cmd, eventHandler *metrics.EventHandler) (string, string, error) {
-	if r.useBazelProxy {
-		eventHandler.Begin("client_proxy")
-		defer eventHandler.End("client_proxy")
-		proxyClient := bazel.NewProxyClient(r.outDir)
-		// Omit the arg containing the Bazel binary, as that is handled by the proxy
-		// server.
-		bazelFlags := bazelCmd.Args[1:]
-		// TODO(b/270989498): Refactor these functions to not take exec.Cmd, as its
-		// not actually executed for client proxying.
-		resp, err := proxyClient.IssueCommand(bazel.CmdRequest{bazelFlags, bazelCmd.Env})
-
-		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")
-		stderr := &bytes.Buffer{}
-		bazelCmd.Stderr = stderr
-		if output, err := bazelCmd.Output(); err != nil {
-			return "", string(stderr.Bytes()),
-				fmt.Errorf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
-					err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderr)
-		} else {
-			return string(output), string(stderr.Bytes()), nil
-		}
-	}
-}
-
-func (r *builtinBazelRunner) createBazelCommand(config Config, paths *bazelPaths, runName bazel.RunName, command bazelCommand,
-	extraFlags ...string) *exec.Cmd {
-	cmdFlags := []string{
-		"--output_base=" + absolutePath(paths.outputBase),
-		command.command,
-		command.expression,
-		// TODO(asmundak): is it needed in every build?
-		"--profile=" + shared.BazelMetricsFilename(paths, runName),
-
-		// We don't need to set --host_platforms because it's set in bazelrc files
-		// that the bazel shell script wrapper passes
-
-		// Explicitly disable downloading rules (such as canonical C++ and Java rules) from the network.
-		"--experimental_repository_disable_download",
-
-		// Suppress noise
-		"--ui_event_filters=-INFO",
-		"--noshow_progress",
-		"--norun_validations",
-	}
-	cmdFlags = append(cmdFlags, extraFlags...)
-
-	bazelCmd := exec.Command(paths.bazelPath, cmdFlags...)
-	bazelCmd.Dir = absolutePath(paths.syntheticWorkspaceDir())
-	extraEnv := []string{
-		"HOME=" + paths.homeDir,
-		pwdPrefix(),
-		"BUILD_DIR=" + absolutePath(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(paths.outDir()),
-		// Disables local host detection of gcc; toolchain information is defined
-		// explicitly in BUILD files.
-		"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1",
-	}
-	for _, envvar := range allowedBazelEnvironmentVars {
-		val := config.Getenv(envvar)
-		if val == "" {
-			continue
-		}
-		extraEnv = append(extraEnv, fmt.Sprintf("%s=%s", envvar, val))
-	}
-	bazelCmd.Env = append(os.Environ(), extraEnv...)
-
-	return bazelCmd
-}
-
-func printableCqueryCommand(bazelCmd *exec.Cmd) string {
-	outputString := strings.Join(bazelCmd.Env, " ") + " \"" + strings.Join(bazelCmd.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 = "{PRODUCT}-{VARIANT}"
-    else:
-        target = "{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/products/{PRODUCT}-{VARIANT}:%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,
-    }
-
-    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",
-    ],
-)
-
-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),
-        "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",
-    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 := ""
-		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]
-		}
-		allLabels = append(allLabels, fmt.Sprintf("\":%s\"", targetString))
-		labelsString := strings.Join(labels, ",\n            ")
-		configNodesSection += fmt.Sprintf(configNodeFormatString, targetString, archString, osString, withinApex, apexSdkVerString,
-			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("{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}"):
-    fail("expected platform name of the form '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_android_<arch>' or '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_linux_<arch>', but was " + str(platforms))
-  platform_name = platform_name.removeprefix("{TARGET_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 '{TARGET_PRODUCT}-{TARGET_BUILD_VARIANT}_android_<arch>' or '{TARGET_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")
-
-  if within_apex:
-    config_key += "|within_apex"
-  if apex_sdk_version != None and len(apex_sdk_version) > 0:
-    config_key += "|" + apex_sdk_version
-
-  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"}
-)
-
-// 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")
-	}
-
-	cqueryCommandWithFlag := context.createBazelCommand(config, context.paths, bazel.CqueryBuildRootRunName, cqueryCmd, extraFlags...)
-	cqueryOutput, cqueryErrorMessage, cqueryErr := context.issueBazelCommand(cqueryCommandWithFlag, eventHandler)
-	if cqueryErr != nil {
-		return cqueryErr
-	}
-	cqueryCommandPrint := fmt.Sprintf("cquery command line:\n  %s \n\n\n", printableCqueryCommand(cqueryCommandWithFlag))
-	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, context.paths, bazel.AqueryBuildRootRunName, aqueryCmd,
-		extraFlags...), 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, context.paths, bazel.BazelBuildPhonyRootRunName, buildCmd), 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)
-	}
-
-	for _, depset := range ctx.Config().BazelContext.AqueryDepsets() {
-		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")
-	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)
-			createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx)
-			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 "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))
-		}
-	}
-}
-
-// Register bazel-owned build statements (obtained from the aquery invocation).
-func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext) {
-	// executionRoot is the action cwd.
-	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)
-	}
-
-	// The actual Bazel action.
-	if len(buildStatement.Command) > 16*1024 {
-		commandFile := PathForBazelOut(ctx, buildStatement.OutputPaths[0]+".sh")
-		WriteFileRule(ctx, commandFile, buildStatement.Command)
-
-		cmd.Text("bash").Text(buildStatement.OutputPaths[0] + ".sh").Implicit(commandFile)
-	} else {
-		cmd.Text(buildStatement.Command)
-	}
-
-	for _, outputPath := range buildStatement.OutputPaths {
-		cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
-	}
-	for _, inputPath := range buildStatement.InputPaths {
-		cmd.Implicit(PathForBazelOut(ctx, inputPath))
-	}
-	for _, inputDepsetHash := range buildStatement.InputDepsetHashes {
-		otherDepsetName := bazelDepsetName(inputDepsetHash)
-		cmd.Implicit(PathForPhony(ctx, otherDepsetName))
-	}
-
-	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
-	}
-
-	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,
-		}
-	}
-
-	return configKey
-}
-
-func bazelDepsetName(contentHash string) string {
-	return fmt.Sprintf("bazel_depset_%s", contentHash)
-}
-
-func EnvironmentVarsFile(config Config) string {
-	return fmt.Sprintf(bazel.GeneratedBazelFileWarning+`
-_env = %s
-
-env = _env
-`,
-		starlark_fmt.PrintStringList(allowedBazelEnvironmentVars, 0),
-	)
-}
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
deleted file mode 100644
index c67d7fb..0000000
--- a/android/bazel_handler_test.go
+++ /dev/null
@@ -1,319 +0,0 @@
-package android
-
-import (
-	"encoding/json"
-	"os"
-	"path/filepath"
-	"reflect"
-	"strings"
-	"testing"
-
-	"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{}
-
-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",
-	}
-	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>>out/foo/foo.txt`,
-		`@//foo:bar|arm64_armv8-a|android>>out/foo/bar.txt`,
-	}
-	bazelContext, _ := testBazelContext(t, map[bazelCommand]string{
-		bazelCommand{command: "cquery", expression: "deps(@soong_injection//mixed_builds:buildroot, 2)"}: 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{
-			bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}: 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)
-		if actual, expected := cmd.buf.String(), testCase.command; 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"}
-	verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1,+foo2,-bar1,-bar2`)
-
-	testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
-	testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
-	verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1,-bar1`)
-
-	testConfig.productVariables.NativeCoveragePaths = []string{"foo1"}
-	testConfig.productVariables.NativeCoverageExcludePaths = nil
-	verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+foo1`)
-
-	testConfig.productVariables.NativeCoveragePaths = nil
-	testConfig.productVariables.NativeCoverageExcludePaths = []string{"bar1"}
-	verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=-bar1`)
-
-	testConfig.productVariables.NativeCoveragePaths = []string{"*"}
-	testConfig.productVariables.NativeCoverageExcludePaths = nil
-	verifyExtraFlags(t, testConfig, `--collect_code_coverage --instrumentation_filter=+.*`)
-
-	testConfig.productVariables.ClangCoverage = boolPtr(false)
-	actual := verifyExtraFlags(t, testConfig, ``)
-	if strings.Contains(actual, "--collect_code_coverage") ||
-		strings.Contains(actual, "--instrumentation_filter=") {
-		t.Errorf("Expected code coverage disabled, but got %#v", actual)
-	}
-}
-
-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{
-		modulesDefaultToBazel:   false,
-		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 verifyExtraFlags(t *testing.T, config Config, expected string) string {
-	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)
-	}
-
-	flags := bazelContext.bazelRunner.(*mockBazelRunner).extraFlags
-	if expected := 3; len(flags) != expected {
-		t.Errorf("Expected %d extra flags got %#v", expected, flags)
-	}
-
-	actual := flags[1]
-	if !strings.Contains(actual, expected) {
-		t.Errorf("Expected %#v got %#v", expected, actual)
-	}
-
-	return actual
-}
-
-func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*mixedBuildBazelContext, string) {
-	t.Helper()
-	p := bazelPaths{
-		soongOutDir:  t.TempDir(),
-		outputBase:   "outputbase",
-		workspaceDir: "workspace_dir",
-	}
-	aqueryCommand := bazelCommand{command: "aquery", expression: "deps(@soong_injection//mixed_builds:buildroot)"}
-	if _, exists := bazelCommandResults[aqueryCommand]; !exists {
-		bazelCommandResults[aqueryCommand] = ""
-	}
-	runner := &mockBazelRunner{bazelCommandResults: bazelCommandResults}
-	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 bad7baf..0000000
--- a/android/bazel_paths.go
+++ /dev/null
@@ -1,593 +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
-	}
-	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 path_deps 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 path_deps 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, 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(ctx BazelConversionPathContext, path bazel.Label) bazel.Label {
-	var newPath bazel.Label
-
-	// Don't transform OriginalModuleName
-	newPath.OriginalModuleName = path.OriginalModuleName
-
-	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(ctx.Config(), ctx.ModuleDir(), 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 := ctx.ModuleDir()
-		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(ctx BazelConversionPathContext, paths bazel.LabelList) bazel.LabelList {
-	var newPaths bazel.LabelList
-	for _, include := range paths.Includes {
-		newPaths.Includes = append(newPaths.Includes, transformSubpackagePath(ctx, include))
-	}
-	for _, exclude := range paths.Excludes {
-		newPaths.Excludes = append(newPaths.Excludes, transformSubpackagePath(ctx, 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
-// path_deps 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) {
-		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 := ctx.OtherModuleName(module)
-	moduleDir := ctx.OtherModuleDir(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 450bf76..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, 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 87b2c8f..0000000
--- a/android/bazel_test.go
+++ /dev/null
@@ -1,438 +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)
-		}
-	}
-}
diff --git a/android/buildinfo_prop.go b/android/buildinfo_prop.go
index 46f6488..8e19ad5 100644
--- a/android/buildinfo_prop.go
+++ b/android/buildinfo_prop.go
@@ -23,7 +23,7 @@
 
 func init() {
 	ctx := InitRegistrationContext
-	ctx.RegisterSingletonModuleType("buildinfo_prop", buildinfoPropFactory)
+	ctx.RegisterParallelSingletonModuleType("buildinfo_prop", buildinfoPropFactory)
 }
 
 type buildinfoPropProperties struct {
diff --git a/android/config.go b/android/config.go
index dfbb46f..2a3cf10 100644
--- a/android/config.go
+++ b/android/config.go
@@ -18,7 +18,7 @@
 // product variables necessary for soong_build's operation.
 
 import (
-	"bytes"
+	"android/soong/shared"
 	"encoding/json"
 	"fmt"
 	"os"
@@ -80,28 +80,21 @@
 
 type CmdArgs struct {
 	bootstrap.Args
-	RunGoTests  bool
-	OutDir      string
-	SoongOutDir string
+	RunGoTests     bool
+	OutDir         string
+	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
-	BazelModeDev             bool
-	BazelModeStaging         bool
-	BazelForceEnabledModules string
+	BuildFromSourceStub bool
 
-	UseBazelProxy bool
-
-	BuildFromTextStub bool
+	EnsureAllowlistIntegrity bool
 }
 
 // Build modes that soong_build can run as.
@@ -109,39 +102,16 @@
 	// 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 many allowlisted build modules. The allowlist
-	// is considered a "developer mode" allowlist, as some modules may be
-	// allowlisted on an experimental basis.
-	BazelDevMode
-
-	// 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
 )
 
 // SoongOutDir returns the build output directory for the configuration.
@@ -149,6 +119,11 @@
 	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
 }
@@ -174,6 +149,28 @@
 	return c.config.TestProductVariables != nil
 }
 
+// DisableHiddenApiChecks returns true if hiddenapi checks have been disabled.
+// For 'eng' target variant hiddenapi checks are disabled by default for performance optimisation,
+// but can be enabled by setting environment variable ENABLE_HIDDENAPI_FLAGS=true.
+// For other target variants hiddenapi check are enabled by default but can be disabled by
+// setting environment variable UNSAFE_DISABLE_HIDDENAPI_FLAGS=true.
+// If both ENABLE_HIDDENAPI_FLAGS=true and UNSAFE_DISABLE_HIDDENAPI_FLAGS=true, then
+// ENABLE_HIDDENAPI_FLAGS=true will be triggered and hiddenapi checks will be considered enabled.
+func (c Config) DisableHiddenApiChecks() bool {
+	return !c.IsEnvTrue("ENABLE_HIDDENAPI_FLAGS") &&
+		(c.IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") ||
+			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 {
+	return c.IsEnvTrue("DISABLE_VERIFY_OVERLAPS") || !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).
@@ -181,6 +178,46 @@
 	return String(c.config.productVariables.DeviceMaxPageSizeSupported)
 }
 
+// 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
+func (c Config) ReleaseVersion() string {
+	return c.config.productVariables.ReleaseVersion
+}
+
+// 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)
+}
+
+// Enables ABI monitoring of NDK libraries
+func (c Config) ReleaseNdkAbiMonitored() bool {
+	return c.config.productVariables.GetBuildFlagBool("RELEASE_NDK_ABI_MONITORED")
+}
+
+func (c Config) ReleaseHiddenApiExportableStubs() bool {
+	return c.config.productVariables.GetBuildFlagBool("RELEASE_HIDDEN_API_EXPORTABLE_STUBS")
+}
+
 // 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.
@@ -195,14 +232,10 @@
 // product configuration values are read from Kati-generated soong.variables.
 type config struct {
 	// Options configurable with soong.variables
-	productVariables productVariables
+	productVariables ProductVariables
 
 	// Only available on configs created by TestConfig
-	TestProductVariables *productVariables
-
-	// A specialized context object for Bazel/Soong mixed builds and migration
-	// purposes.
-	BazelContext BazelContext
+	TestProductVariables *ProductVariables
 
 	ProductVariablesFileName string
 
@@ -245,9 +278,7 @@
 	fs         pathtools.FileSystem
 	mockBpList string
 
-	BuildMode                      SoongBuildMode
-	Bp2buildPackageConfig          Bp2BuildConversionAllowlist
-	Bp2buildSoongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions
+	BuildMode SoongBuildMode
 
 	// If MultitreeBuild is true then this is one inner tree of a multitree
 	// build directed by the multitree orchestrator.
@@ -263,28 +294,17 @@
 
 	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{}
+	// If buildFromSourceStub is true then the Java API stubs are
+	// built from the source Java files, not the signature text files.
+	buildFromSourceStub bool
 
-	// 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{}
+	// 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
+	// failure
+	ensureAllowlistIntegrity bool
 
-	// 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
+	// List of Api libraries that contribute to Api surfaces.
+	apiLibraries map[string]struct{}
 }
 
 type deviceConfig struct {
@@ -302,7 +322,7 @@
 
 // loadFromConfigFile loads and decodes configuration options from a JSON file
 // in the current working directory.
-func loadFromConfigFile(configurable *productVariables, filename string) error {
+func loadFromConfigFile(configurable *ProductVariables, filename string) error {
 	// Try to open the file
 	configFileReader, err := os.Open(filename)
 	defer configFileReader.Close()
@@ -354,7 +374,7 @@
 
 // atomically writes the config file in case two copies of soong_build are running simultaneously
 // (for example, docs generation and ninja manifest generation)
-func saveToConfigFile(config *productVariables, filename string) error {
+func saveToConfigFile(config *ProductVariables, filename string) error {
 	data, err := json.MarshalIndent(&config, "", "    ")
 	if err != nil {
 		return fmt.Errorf("cannot marshal config data: %s", err.Error())
@@ -383,65 +403,52 @@
 	return nil
 }
 
-func saveToBazelConfigFile(config *productVariables, outDir string) error {
+type productVariableStarlarkRepresentation struct {
+	soongType   string
+	selectable  bool
+	archVariant bool
+}
+
+func saveToBazelConfigFile(config *ProductVariables, outDir string) error {
 	dir := filepath.Join(outDir, bazel.SoongInjectionDirName, "product_config")
 	err := createDirIfNonexistent(dir, os.ModePerm)
 	if err != nil {
 		return fmt.Errorf("Could not create dir %s: %s", dir, err)
 	}
 
-	nonArchVariantProductVariables := []string{}
-	archVariantProductVariables := []string{}
+	allProductVariablesType := reflect.TypeOf((*ProductVariables)(nil)).Elem()
+	productVariablesInfo := make(map[string]productVariableStarlarkRepresentation)
 	p := variableProperties{}
 	t := reflect.TypeOf(p.Product_variables)
 	for i := 0; i < t.NumField(); i++ {
 		f := t.Field(i)
-		nonArchVariantProductVariables = append(nonArchVariantProductVariables, strings.ToLower(f.Name))
-		if proptools.HasTag(f, "android", "arch_variant") {
-			archVariantProductVariables = append(archVariantProductVariables, strings.ToLower(f.Name))
+		archVariant := proptools.HasTag(f, "android", "arch_variant")
+		if mainProductVariablesStructField, ok := allProductVariablesType.FieldByName(f.Name); ok {
+			productVariablesInfo[f.Name] = productVariableStarlarkRepresentation{
+				soongType:   stringRepresentationOfSimpleType(mainProductVariablesStructField.Type),
+				selectable:  true,
+				archVariant: archVariant,
+			}
+		} else {
+			panic("Unknown variable " + f.Name)
 		}
 	}
 
-	nonArchVariantProductVariablesJson := starlark_fmt.PrintStringList(nonArchVariantProductVariables, 0)
-	if err != nil {
-		return fmt.Errorf("cannot marshal product variable data: %s", err.Error())
-	}
-
-	archVariantProductVariablesJson := starlark_fmt.PrintStringList(archVariantProductVariables, 0)
-	if err != nil {
-		return fmt.Errorf("cannot marshal arch variant product variable data: %s", err.Error())
-	}
-
-	configJson, err := json.MarshalIndent(&config, "", "    ")
-	if err != nil {
-		return fmt.Errorf("cannot marshal config data: %s", err.Error())
-	}
-	// The backslashes need to be escaped because this text is going to be put
-	// inside a Starlark string literal.
-	configJson = bytes.ReplaceAll(configJson, []byte("\\"), []byte("\\\\"))
-
-	bzl := []string{
-		bazel.GeneratedBazelFileWarning,
-		fmt.Sprintf(`_product_vars = json.decode("""%s""")`, configJson),
-		fmt.Sprintf(`_product_var_constraints = %s`, nonArchVariantProductVariablesJson),
-		fmt.Sprintf(`_arch_variant_product_var_constraints = %s`, archVariantProductVariablesJson),
-		"\n", `
-product_vars = _product_vars
-
-# TODO(b/269577299) Remove these when everything switches over to loading them from product_variable_constants.bzl
-product_var_constraints = _product_var_constraints
-arch_variant_product_var_constraints = _arch_variant_product_var_constraints
-`,
-	}
-	err = pathtools.WriteFileIfChanged(filepath.Join(dir, "product_variables.bzl"),
-		[]byte(strings.Join(bzl, "\n")), 0644)
-	if err != nil {
-		return fmt.Errorf("Could not write .bzl config file %s", err)
-	}
 	err = pathtools.WriteFileIfChanged(filepath.Join(dir, "product_variable_constants.bzl"), []byte(fmt.Sprintf(`
-product_var_constraints = %s
-arch_variant_product_var_constraints = %s
-`, nonArchVariantProductVariablesJson, archVariantProductVariablesJson)), 0644)
+# product_var_constant_info is a map of product variables to information about them. The fields are:
+# - soongType: The type of the product variable as it appears in soong's ProductVariables struct.
+#              examples are string, bool, int, *bool, *string, []string, etc. This may be an overly
+#              conservative estimation of the type, for example a *bool could oftentimes just be a
+#              bool that defaults to false.
+# - selectable: if this product variable can be selected on in Android.bp/build files. This means
+#               it's listed in the "variableProperties" soong struct. Currently all variables in
+#               this list are selectable because we only need the selectable ones at the moment,
+#               but the list may be expanded later.
+# - archVariant: If the variable is tagged as arch variant in the "variableProperties" struct.
+product_var_constant_info = %s
+product_var_constraints = [k for k, v in product_var_constant_info.items() if v.selectable]
+arch_variant_product_var_constraints = [k for k, v in product_var_constant_info.items() if v.selectable and v.archVariant]
+`, starlark_fmt.PrintAny(productVariablesInfo, 0))), 0644)
 	if err != nil {
 		return fmt.Errorf("Could not write .bzl config file %s", err)
 	}
@@ -454,6 +461,23 @@
 	return nil
 }
 
+func stringRepresentationOfSimpleType(ty reflect.Type) string {
+	switch ty.Kind() {
+	case reflect.String:
+		return "string"
+	case reflect.Bool:
+		return "bool"
+	case reflect.Int:
+		return "int"
+	case reflect.Slice:
+		return "[]" + stringRepresentationOfSimpleType(ty.Elem())
+	case reflect.Pointer:
+		return "*" + stringRepresentationOfSimpleType(ty.Elem())
+	default:
+		panic("unimplemented type: " + ty.Kind().String())
+	}
+}
+
 // NullConfig returns a mostly empty Config for use by standalone tools like dexpreopt_gen that
 // use the android package.
 func NullConfig(outDir, soongOutDir string) Config {
@@ -471,7 +495,7 @@
 func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) {
 	// Make a config with default options.
 	config := &config{
-		ProductVariablesFileName: filepath.Join(cmdArgs.SoongOutDir, productVariablesFileName),
+		ProductVariablesFileName: cmdArgs.SoongVariables,
 
 		env: availableEnv,
 
@@ -480,16 +504,12 @@
 		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{
@@ -580,30 +600,44 @@
 			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.BazelModeDev, "--bazel-mode-dev", BazelDevMode)
-	setBazelMode(cmdArgs.BazelMode, "--bazel-mode", BazelProdMode)
-	setBazelMode(cmdArgs.BazelModeStaging, "--bazel-mode-staging", BazelStagingMode)
 
-	for _, module := range strings.Split(cmdArgs.BazelForceEnabledModules, ",") {
-		config.bazelForceEnabledModules[module] = struct{}{}
+	// TODO(b/276958307): Replace the hardcoded list to a sdk_library local prop.
+	config.apiLibraries = map[string]struct{}{
+		"android.net.ipsec.ike":             {},
+		"art.module.public.api":             {},
+		"conscrypt.module.public.api":       {},
+		"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-permission":              {},
+		"framework-permission-s":            {},
+		"framework-scheduling":              {},
+		"framework-sdkextensions":           {},
+		"framework-statsd":                  {},
+		"framework-sdksandbox":              {},
+		"framework-tethering":               {},
+		"framework-uwb":                     {},
+		"framework-virtualization":          {},
+		"framework-wifi":                    {},
+		"i18n.module.public.api":            {},
 	}
-	config.BazelContext, err = NewBazelContext(config)
-	config.Bp2buildPackageConfig = GetBp2BuildAllowList()
+
+	config.productVariables.Build_from_text_stub = boolPtr(config.BuildFromTextStub())
 
 	return Config{config}, err
 }
@@ -638,37 +672,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
-		}
-		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 == BazelDevMode || c.BuildMode == BazelStagingMode
-	return globalMixedBuildsSupport && bazelModeEnabled
-}
-
 func (c *config) SetAllowMissingDependencies() {
 	c.productVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
 }
@@ -684,7 +687,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
 }
 
@@ -693,12 +696,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
 }
 
@@ -707,7 +710,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.
@@ -795,6 +798,10 @@
 	return c.katiEnabled
 }
 
+func (c *config) ProductVariables() ProductVariables {
+	return c.productVariables
+}
+
 func (c *config) BuildId() string {
 	return String(c.productVariables.BuildId)
 }
@@ -905,12 +912,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
 }
@@ -934,8 +947,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()
 	}
@@ -1293,8 +1304,16 @@
 	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) VendorApiLevelFrozen() bool {
+	return c.productVariables.GetBuildFlagBool("RELEASE_BOARD_API_LEVEL_FROZEN")
 }
 
 func (c *deviceConfig) Arches() []Arch {
@@ -1336,16 +1355,12 @@
 	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 {
@@ -1572,11 +1587,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 {
@@ -1591,10 +1613,6 @@
 	return Bool(c.productVariables.Aml_abis)
 }
 
-func (c *config) FlattenApex() bool {
-	return Bool(c.productVariables.Flatten_apex)
-}
-
 func (c *config) ForceApexSymlinkOptimization() bool {
 	return Bool(c.productVariables.ForceApexSymlinkOptimization)
 }
@@ -1627,10 +1645,6 @@
 	return c.productVariables.InterPartitionJavaLibraryAllowList
 }
 
-func (c *config) InstallExtraFlattenedApexes() bool {
-	return Bool(c.productVariables.InstallExtraFlattenedApexes)
-}
-
 func (c *config) ProductHiddenAPIStubs() []string {
 	return c.productVariables.ProductHiddenAPIStubs
 }
@@ -1655,10 +1669,6 @@
 	return c.productVariables.ProductPrivateSepolicyDirs
 }
 
-func (c *config) MissingUsesLibraries() []string {
-	return c.productVariables.MissingUsesLibraries
-}
-
 func (c *config) TargetMultitreeUpdateMeta() bool {
 	return c.productVariables.MultitreeUpdateMeta
 }
@@ -1714,30 +1724,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)
 }
@@ -1834,6 +1820,10 @@
 	return uncheckedFinalApiLevel(apiLevel)
 }
 
+func (c *deviceConfig) BuildBrokenPluginValidation() []string {
+	return c.config.productVariables.BuildBrokenPluginValidation
+}
+
 func (c *deviceConfig) BuildBrokenClangAsFlags() bool {
 	return c.config.productVariables.BuildBrokenClangAsFlags
 }
@@ -1870,20 +1860,28 @@
 	return InList(name, c.config.productVariables.BuildBrokenInputDirModules)
 }
 
-func (c *deviceConfig) BuildBrokenDepfile() bool {
-	return Bool(c.config.productVariables.BuildBrokenDepfile)
+func (c *deviceConfig) BuildBrokenDontCheckSystemSdk() bool {
+	return c.config.productVariables.BuildBrokenDontCheckSystemSdk
+}
+
+func (c *config) BuildWarningBadOptionalUsesLibsAllowlist() []string {
+	return c.productVariables.BuildWarningBadOptionalUsesLibsAllowlist
+}
+
+func (c *deviceConfig) GenruleSandboxing() bool {
+	return Bool(c.config.productVariables.GenruleSandboxing)
 }
 
 func (c *deviceConfig) RequiresInsecureExecmemForSwiftshader() bool {
 	return c.config.productVariables.RequiresInsecureExecmemForSwiftshader
 }
 
-func (c *config) SelinuxIgnoreNeverallows() bool {
-	return c.productVariables.SelinuxIgnoreNeverallows
+func (c *deviceConfig) Release_aidl_use_unfrozen() bool {
+	return Bool(c.config.productVariables.Release_aidl_use_unfrozen)
 }
 
-func (c *deviceConfig) SepolicySplit() bool {
-	return c.config.productVariables.SepolicySplit
+func (c *config) SelinuxIgnoreNeverallows() bool {
+	return c.productVariables.SelinuxIgnoreNeverallows
 }
 
 func (c *deviceConfig) SepolicyFreezeTestExtraDirs() []string {
@@ -1926,17 +1924,6 @@
 	return Bool(c.productVariables.HostMusl)
 }
 
-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{}{}
-	}
-}
-
 // ApiSurfaces directory returns the source path inside the api_surfaces repo
 // (relative to workspace root).
 func (c *config) ApiSurfacesDir(s ApiSurface, version string) string {
@@ -1948,15 +1935,86 @@
 		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 {
+		c.apiLibraries[lib] = struct{}{}
 	}
 }
+
+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_ADSERVICES",
+		"RELEASE_APEX_CONTRIBUTIONS_APPSEARCH",
+		"RELEASE_APEX_CONTRIBUTIONS_ART",
+		"RELEASE_APEX_CONTRIBUTIONS_BLUETOOTH",
+		"RELEASE_APEX_CONTRIBUTIONS_CONFIGINFRASTRUCTURE",
+		"RELEASE_APEX_CONTRIBUTIONS_CONNECTIVITY",
+		"RELEASE_APEX_CONTRIBUTIONS_CONSCRYPT",
+		"RELEASE_APEX_CONTRIBUTIONS_CRASHRECOVERY",
+		"RELEASE_APEX_CONTRIBUTIONS_DEVICELOCK",
+		"RELEASE_APEX_CONTRIBUTIONS_HEALTHFITNESS",
+		"RELEASE_APEX_CONTRIBUTIONS_IPSEC",
+		"RELEASE_APEX_CONTRIBUTIONS_MEDIA",
+		"RELEASE_APEX_CONTRIBUTIONS_MEDIAPROVIDER",
+		"RELEASE_APEX_CONTRIBUTIONS_ONDEVICEPERSONALIZATION",
+		"RELEASE_APEX_CONTRIBUTIONS_PERMISSION",
+		"RELEASE_APEX_CONTRIBUTIONS_REMOTEKEYPROVISIONING",
+		"RELEASE_APEX_CONTRIBUTIONS_SCHEDULING",
+		"RELEASE_APEX_CONTRIBUTIONS_SDKEXTENSIONS",
+		"RELEASE_APEX_CONTRIBUTIONS_STATSD",
+		"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
+}
diff --git a/android/config_bp2build.go b/android/config_bp2build.go
index 830890d..4c2fb5e 100644
--- a/android/config_bp2build.go
+++ b/android/config_bp2build.go
@@ -15,24 +15,11 @@
 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
@@ -61,18 +48,6 @@
 	}
 }
 
-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) {
@@ -95,15 +70,6 @@
 	return ev.pctx.VariableConfigMethod(name, method)
 }
 
-func (ev ExportedVariables) ExportStringStaticVariableWithEnvOverride(name, envVar, defaultVal string) {
-	ev.ExportVariableConfigMethod(name, func(config Config) string {
-		if override := config.Getenv(envVar); override != "" {
-			return override
-		}
-		return defaultVal
-	})
-}
-
 // ExportSourcePathVariable declares a static "source path" variable and exports
 // it to Bazel's toolchain.
 func (ev ExportedVariables) ExportSourcePathVariable(name string, value string) {
@@ -151,49 +117,6 @@
 	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
 
@@ -201,25 +124,6 @@
 	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
 
@@ -227,32 +131,6 @@
 	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
@@ -261,19 +139,6 @@
 	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:
@@ -290,237 +155,3 @@
 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/config_test.go b/android/config_test.go
index 9df5288..7d327a2 100644
--- a/android/config_test.go
+++ b/android/config_test.go
@@ -75,7 +75,7 @@
 
 // run validateConfigAnnotations against each type that might have json annotations
 func TestProductConfigAnnotations(t *testing.T) {
-	err := validateConfigAnnotations(&productVariables{})
+	err := validateConfigAnnotations(&ProductVariables{})
 	if err != nil {
 		t.Errorf(err.Error())
 	}
@@ -88,7 +88,7 @@
 	}
 }
 
-func verifyProductVariableMarshaling(t *testing.T, v productVariables) {
+func verifyProductVariableMarshaling(t *testing.T, v ProductVariables) {
 	dir := t.TempDir()
 	path := filepath.Join(dir, "test.variables")
 	err := saveToConfigFile(&v, path)
@@ -96,20 +96,20 @@
 		t.Errorf("Couldn't save default product config: %q", err)
 	}
 
-	var v2 productVariables
+	var v2 ProductVariables
 	err = loadFromConfigFile(&v2, path)
 	if err != nil {
 		t.Errorf("Couldn't load default product config: %q", err)
 	}
 }
 func TestDefaultProductVariableMarshaling(t *testing.T) {
-	v := productVariables{}
+	v := ProductVariables{}
 	v.SetDefaultConfig()
 	verifyProductVariableMarshaling(t, v)
 }
 
 func TestBootJarsMarshaling(t *testing.T) {
-	v := productVariables{}
+	v := ProductVariables{}
 	v.SetDefaultConfig()
 	v.BootJars = ConfiguredJarList{
 		apexes: []string{"apex"},
diff --git a/android/configured_jars.go b/android/configured_jars.go
index 53fef05..c7b808f 100644
--- a/android/configured_jars.go
+++ b/android/configured_jars.go
@@ -178,7 +178,7 @@
 func (l *ConfiguredJarList) BuildPaths(ctx PathContext, dir OutputPath) WritablePaths {
 	paths := make(WritablePaths, l.Len())
 	for i, jar := range l.jars {
-		paths[i] = dir.Join(ctx, ModuleStem(jar)+".jar")
+		paths[i] = dir.Join(ctx, ModuleStem(ctx.Config(), l.Apex(i), jar)+".jar")
 	}
 	return paths
 }
@@ -187,8 +187,8 @@
 // prefix.
 func (l *ConfiguredJarList) BuildPathsByModule(ctx PathContext, dir OutputPath) map[string]WritablePath {
 	paths := map[string]WritablePath{}
-	for _, jar := range l.jars {
-		paths[jar] = dir.Join(ctx, ModuleStem(jar)+".jar")
+	for i, jar := range l.jars {
+		paths[jar] = dir.Join(ctx, ModuleStem(ctx.Config(), l.Apex(i), jar)+".jar")
 	}
 	return paths
 }
@@ -228,24 +228,32 @@
 	return json.Marshal(list)
 }
 
-// ModuleStem hardcodes the stem of framework-minus-apex to return "framework".
-//
-// TODO(b/139391334): hard coded until we find a good way to query the stem of a
-// module before any other mutators are run.
-func ModuleStem(module string) string {
-	if module == "framework-minus-apex" {
-		return "framework"
+func OverrideConfiguredJarLocationFor(cfg Config, apex string, jar string) (newApex string, newJar string) {
+	for _, entry := range cfg.productVariables.ConfiguredJarLocationOverrides {
+		tuple := strings.Split(entry, ":")
+		if len(tuple) != 4 {
+			panic("malformed configured jar location override '%s', expected format: <old_apex>:<old_jar>:<new_apex>:<new_jar>")
+		}
+		if apex == tuple[0] && jar == tuple[1] {
+			return tuple[2], tuple[3]
+		}
 	}
-	return module
+	return apex, jar
+}
+
+// ModuleStem returns the overridden jar name.
+func ModuleStem(cfg Config, apex string, jar string) string {
+	_, newJar := OverrideConfiguredJarLocationFor(cfg, apex, jar)
+	return newJar
 }
 
 // DevicePaths computes the on-device paths for the list of (apex, jar) pairs,
 // based on the operating system.
 func (l *ConfiguredJarList) DevicePaths(cfg Config, ostype OsType) []string {
 	paths := make([]string, l.Len())
-	for i, jar := range l.jars {
-		apex := l.apexes[i]
-		name := ModuleStem(jar) + ".jar"
+	for i := 0; i < l.Len(); i++ {
+		apex, jar := OverrideConfiguredJarLocationFor(cfg, l.Apex(i), l.Jar(i))
+		name := jar + ".jar"
 
 		var subdir string
 		if apex == "platform" {
@@ -311,4 +319,9 @@
 	return ConfiguredJarList{}
 }
 
+// IsConfiguredJarForPlatform returns true if the given apex name is a special name for the platform.
+func IsConfiguredJarForPlatform(apex string) bool {
+	return apex == "platform" || apex == "system_ext"
+}
+
 var earlyBootJarsKey = NewOnceKey("earlyBootJars")
diff --git a/android/configured_jars_test.go b/android/configured_jars_test.go
new file mode 100644
index 0000000..4b586e4
--- /dev/null
+++ b/android/configured_jars_test.go
@@ -0,0 +1,46 @@
+// 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 (
+	"testing"
+)
+
+func TestOverrideConfiguredJarLocationFor(t *testing.T) {
+	cfg := NullConfig("", "")
+
+	cfg.productVariables = ProductVariables{
+		ConfiguredJarLocationOverrides: []string{
+			"platform:libfoo-old:com.android.foo:libfoo-new",
+			"com.android.bar:libbar-old:platform:libbar-new",
+		},
+	}
+
+	apex, jar := OverrideConfiguredJarLocationFor(cfg, "platform", "libfoo-old")
+	AssertStringEquals(t, "", "com.android.foo", apex)
+	AssertStringEquals(t, "", "libfoo-new", jar)
+
+	apex, jar = OverrideConfiguredJarLocationFor(cfg, "platform", "libbar-old")
+	AssertStringEquals(t, "", "platform", apex)
+	AssertStringEquals(t, "", "libbar-old", jar)
+
+	apex, jar = OverrideConfiguredJarLocationFor(cfg, "com.android.bar", "libbar-old")
+	AssertStringEquals(t, "", "platform", apex)
+	AssertStringEquals(t, "", "libbar-new", jar)
+
+	apex, jar = OverrideConfiguredJarLocationFor(cfg, "platform", "libbar-old")
+	AssertStringEquals(t, "", "platform", apex)
+	AssertStringEquals(t, "", "libbar-old", jar)
+}
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 31d6014..ff79002 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -117,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
@@ -164,7 +159,6 @@
 type DefaultsModule interface {
 	Module
 	Defaults
-	Bazelable
 }
 
 func (d *DefaultsModuleBase) properties() []interface{} {
@@ -177,10 +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) {}
-
 func InitDefaultsModule(module DefaultsModule) {
 	commonProperties := &commonProperties{}
 
@@ -190,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)
@@ -221,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..dab012d 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -15,13 +15,8 @@
 package android
 
 import (
-	"fmt"
-	"strings"
-	"testing"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
-	"github.com/google/blueprint/proptools"
 )
 
 var (
@@ -72,8 +67,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 +86,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,8 +100,8 @@
 
 	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
@@ -116,7 +109,7 @@
 	// content to file.
 	writeFile = pctx.AndroidStaticRule("writeFile",
 		blueprint.RuleParams{
-			Command:     `/bin/bash -c 'echo -e -n "$$0" > $out' $content`,
+			Command:     `rm -f $out && /bin/bash -c 'echo -e -n "$$0" > $out' $content`,
 			Description: "writing file $out",
 		},
 		"content")
@@ -142,108 +135,6 @@
 	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.
 func GlobToListFileRule(ctx ModuleContext, pattern string, excludes []string, file WritablePath) {
 	bootstrap.GlobFile(ctx.blueprintModuleContext(), pattern, excludes, file.String())
diff --git a/android/depset_generic.go b/android/depset_generic.go
index f00e462..45c1937 100644
--- a/android/depset_generic.go
+++ b/android/depset_generic.go
@@ -16,10 +16,9 @@
 
 import (
 	"fmt"
-	"reflect"
 )
 
-// depSet is designed to be conceptually compatible with Bazel's depsets:
+// DepSet is designed to be conceptually compatible with Bazel's depsets:
 // https://docs.bazel.build/versions/master/skylark/depsets.html
 
 type DepSetOrder int
@@ -43,142 +42,114 @@
 	}
 }
 
-// A depSet efficiently stores a slice of an arbitrary type from transitive dependencies without
-// copying. It is stored as a DAG of depSet nodes, each of which has some direct contents and a list
-// of dependency depSet nodes.
+type depSettableType comparable
+
+// A DepSet efficiently stores a slice of an arbitrary type from transitive dependencies without
+// copying. It is stored as a DAG of DepSet nodes, each of which has some direct contents and a list
+// of dependency DepSet nodes.
 //
-// A depSet has an order that will be used to walk the DAG when ToList() is called.  The order
+// A DepSet has an order that will be used to walk the DAG when ToList() is called.  The order
 // can be POSTORDER, PREORDER, or TOPOLOGICAL.  POSTORDER and PREORDER orders return a postordered
 // or preordered left to right flattened list.  TOPOLOGICAL returns a list that guarantees that
 // elements of children are listed after all of their parents (unless there are duplicate direct
-// elements in the depSet or any of its transitive dependencies, in which case the ordering of the
+// elements in the DepSet or any of its transitive dependencies, in which case the ordering of the
 // duplicated element is not guaranteed).
 //
-// A depSet is created by newDepSet or newDepSetBuilder.Build from the slice for direct contents
-// and the *depSets of dependencies. A depSet is immutable once created.
-//
-// This object uses reflection to remain agnostic to the type it contains.  It should be replaced
-// with generics once those exist in Go.  Callers should generally use a thin wrapper around depSet
-// that provides type-safe methods like DepSet for Paths.
-type depSet struct {
+// A DepSet is created by NewDepSet or NewDepSetBuilder.Build from the slice for direct contents
+// and the *DepSets of dependencies. A DepSet is immutable once created.
+type DepSet[T depSettableType] struct {
 	preorder   bool
 	reverse    bool
 	order      DepSetOrder
-	direct     interface{}
-	transitive []*depSet
+	direct     []T
+	transitive []*DepSet[T]
 }
 
-type depSetInterface interface {
-	embeddedDepSet() *depSet
-}
-
-func (d *depSet) embeddedDepSet() *depSet {
-	return d
-}
-
-var _ depSetInterface = (*depSet)(nil)
-
-// newDepSet returns an immutable depSet with the given order, direct and transitive contents.
-// direct must be a slice, but is not type-safe due to the lack of generics in Go.  It can be a
-// nil slice, but not a nil interface{}, i.e. []string(nil) but not nil.
-func newDepSet(order DepSetOrder, direct interface{}, transitive interface{}) *depSet {
-	var directCopy interface{}
-	transitiveDepSet := sliceToDepSets(transitive, order)
-
-	if order == TOPOLOGICAL {
-		directCopy = reverseSlice(direct)
-		reverseSliceInPlace(transitiveDepSet)
-	} else {
-		directCopy = copySlice(direct)
+// NewDepSet returns an immutable DepSet with the given order, direct and transitive contents.
+func NewDepSet[T depSettableType](order DepSetOrder, direct []T, transitive []*DepSet[T]) *DepSet[T] {
+	var directCopy []T
+	var transitiveCopy []*DepSet[T]
+	for _, t := range transitive {
+		if t.order != order {
+			panic(fmt.Errorf("incompatible order, new DepSet is %s but transitive DepSet is %s",
+				order, t.order))
+		}
 	}
 
-	return &depSet{
+	if order == TOPOLOGICAL {
+		// TOPOLOGICAL is implemented as a postorder traversal followed by reversing the output.
+		// Pre-reverse the inputs here so their order is maintained in the output.
+		directCopy = ReverseSlice(direct)
+		transitiveCopy = ReverseSlice(transitive)
+	} else {
+		directCopy = append([]T(nil), direct...)
+		transitiveCopy = append([]*DepSet[T](nil), transitive...)
+	}
+
+	return &DepSet[T]{
 		preorder:   order == PREORDER,
 		reverse:    order == TOPOLOGICAL,
 		order:      order,
 		direct:     directCopy,
-		transitive: transitiveDepSet,
+		transitive: transitiveCopy,
 	}
 }
 
-// depSetBuilder is used to create an immutable depSet.
-type depSetBuilder struct {
+// DepSetBuilder is used to create an immutable DepSet.
+type DepSetBuilder[T depSettableType] struct {
 	order      DepSetOrder
-	direct     reflect.Value
-	transitive []*depSet
+	direct     []T
+	transitive []*DepSet[T]
 }
 
-// newDepSetBuilder returns a depSetBuilder to create an immutable depSet with the given order and
-// type, represented by a slice of type that will be in the depSet.
-func newDepSetBuilder(order DepSetOrder, typ interface{}) *depSetBuilder {
-	empty := reflect.Zero(reflect.TypeOf(typ))
-	return &depSetBuilder{
-		order:  order,
-		direct: empty,
+// NewDepSetBuilder returns a DepSetBuilder to create an immutable DepSet with the given order and
+// type, represented by a slice of type that will be in the DepSet.
+func NewDepSetBuilder[T depSettableType](order DepSetOrder) *DepSetBuilder[T] {
+	return &DepSetBuilder[T]{
+		order: order,
 	}
 }
 
-// sliceToDepSets converts a slice of any type that implements depSetInterface (by having a depSet
-// embedded in it) into a []*depSet.
-func sliceToDepSets(in interface{}, order DepSetOrder) []*depSet {
-	slice := reflect.ValueOf(in)
-	length := slice.Len()
-	out := make([]*depSet, length)
-	for i := 0; i < length; i++ {
-		vi := slice.Index(i)
-		depSetIntf, ok := vi.Interface().(depSetInterface)
-		if !ok {
-			panic(fmt.Errorf("element %d is a %s, not a depSetInterface", i, vi.Type()))
-		}
-		depSet := depSetIntf.embeddedDepSet()
-		if depSet.order != order {
-			panic(fmt.Errorf("incompatible order, new depSet is %s but transitive depSet is %s",
-				order, depSet.order))
-		}
-		out[i] = depSet
-	}
-	return out
-}
-
-// DirectSlice adds direct contents to the depSet being built by a depSetBuilder. Newly added direct
-// contents are to the right of any existing direct contents.  The argument must be a slice, but
-// is not type-safe due to the lack of generics in Go.
-func (b *depSetBuilder) DirectSlice(direct interface{}) *depSetBuilder {
-	b.direct = reflect.AppendSlice(b.direct, reflect.ValueOf(direct))
+// DirectSlice adds direct contents to the DepSet being built by a DepSetBuilder. Newly added direct
+// contents are to the right of any existing direct contents.
+func (b *DepSetBuilder[T]) DirectSlice(direct []T) *DepSetBuilder[T] {
+	b.direct = append(b.direct, direct...)
 	return b
 }
 
-// Direct adds direct contents to the depSet being built by a depSetBuilder. Newly added direct
-// contents are to the right of any existing direct contents.  The argument must be the same type
-// as the element of the slice passed to newDepSetBuilder, but is not type-safe due to the lack of
-// generics in Go.
-func (b *depSetBuilder) Direct(direct interface{}) *depSetBuilder {
-	b.direct = reflect.Append(b.direct, reflect.ValueOf(direct))
+// Direct adds direct contents to the DepSet being built by a DepSetBuilder. Newly added direct
+// contents are to the right of any existing direct contents.
+func (b *DepSetBuilder[T]) Direct(direct ...T) *DepSetBuilder[T] {
+	b.direct = append(b.direct, direct...)
 	return b
 }
 
 // Transitive adds transitive contents to the DepSet being built by a DepSetBuilder. Newly added
-// transitive contents are to the right of any existing transitive contents.  The argument can
-// be any slice of type that has depSet embedded in it.
-func (b *depSetBuilder) Transitive(transitive interface{}) *depSetBuilder {
-	depSets := sliceToDepSets(transitive, b.order)
-	b.transitive = append(b.transitive, depSets...)
+// transitive contents are to the right of any existing transitive contents.
+func (b *DepSetBuilder[T]) Transitive(transitive ...*DepSet[T]) *DepSetBuilder[T] {
+	for _, t := range transitive {
+		if t.order != b.order {
+			panic(fmt.Errorf("incompatible order, new DepSet is %s but transitive DepSet is %s",
+				b.order, t.order))
+		}
+	}
+	b.transitive = append(b.transitive, transitive...)
 	return b
 }
 
-// Returns the depSet being built by this depSetBuilder.  The depSetBuilder retains its contents
+// Returns the DepSet being built by this DepSetBuilder.  The DepSetBuilder retains its contents
 // for creating more depSets.
-func (b *depSetBuilder) Build() *depSet {
-	return newDepSet(b.order, b.direct.Interface(), b.transitive)
+func (b *DepSetBuilder[T]) Build() *DepSet[T] {
+	return NewDepSet(b.order, b.direct, b.transitive)
 }
 
 // walk calls the visit method in depth-first order on a DepSet, preordered if d.preorder is set,
 // otherwise postordered.
-func (d *depSet) walk(visit func(interface{})) {
-	visited := make(map[*depSet]bool)
+func (d *DepSet[T]) walk(visit func([]T)) {
+	visited := make(map[*DepSet[T]]bool)
 
-	var dfs func(d *depSet)
-	dfs = func(d *depSet) {
+	var dfs func(d *DepSet[T])
+	dfs = func(d *DepSet[T]) {
 		visited[d] = true
 		if d.preorder {
 			visit(d.direct)
@@ -197,155 +168,23 @@
 	dfs(d)
 }
 
-// ToList returns the depSet flattened to a list.  The order in the list is based on the order
-// of the depSet.  POSTORDER and PREORDER orders return a postordered or preordered left to right
+// ToList returns the DepSet flattened to a list.  The order in the list is based on the order
+// of the DepSet.  POSTORDER and PREORDER orders return a postordered or preordered left to right
 // flattened list.  TOPOLOGICAL returns a list that guarantees that elements of children are listed
 // after all of their parents (unless there are duplicate direct elements in the DepSet or any of
 // its transitive dependencies, in which case the ordering of the duplicated element is not
 // guaranteed).
-//
-// This method uses a reflection-based implementation to find the unique elements in slice, which
-// is around 3x slower than a concrete implementation.  Type-safe wrappers around depSet can
-// provide their own implementation of ToList that calls depSet.toList with a method that
-// uses a concrete implementation.
-func (d *depSet) ToList() interface{} {
-	return d.toList(firstUnique)
-}
-
-// toList returns the depSet flattened to a list.  The order in the list is based on the order
-// of the depSet.  POSTORDER and PREORDER orders return a postordered or preordered left to right
-// flattened list.  TOPOLOGICAL returns a list that guarantees that elements of children are listed
-// after all of their parents (unless there are duplicate direct elements in the DepSet or any of
-// its transitive dependencies, in which case the ordering of the duplicated element is not
-// guaranteed).  The firstUniqueFunc is used to remove duplicates from the list.
-func (d *depSet) toList(firstUniqueFunc func(interface{}) interface{}) interface{} {
+func (d *DepSet[T]) ToList() []T {
 	if d == nil {
 		return nil
 	}
-	slice := reflect.Zero(reflect.TypeOf(d.direct))
-	d.walk(func(paths interface{}) {
-		slice = reflect.AppendSlice(slice, reflect.ValueOf(paths))
+	var list []T
+	d.walk(func(paths []T) {
+		list = append(list, paths...)
 	})
-	list := slice.Interface()
-	list = firstUniqueFunc(list)
+	list = firstUniqueInPlace(list)
 	if d.reverse {
-		reverseSliceInPlace(list)
+		ReverseSliceInPlace(list)
 	}
 	return list
 }
-
-// firstUnique returns all unique elements of a slice, keeping the first copy of each.  It
-// modifies the slice contents in place, and returns a subslice of the original slice.  The
-// argument must be a slice, but is not type-safe due to the lack of reflection in Go.
-//
-// Performance of the reflection-based firstUnique is up to 3x slower than a concrete type
-// version such as FirstUniqueStrings.
-func firstUnique(slice interface{}) interface{} {
-	// 4 was chosen based on Benchmark_firstUnique results.
-	if reflect.ValueOf(slice).Len() > 4 {
-		return firstUniqueMap(slice)
-	}
-	return firstUniqueList(slice)
-}
-
-// firstUniqueList is an implementation of firstUnique using an O(N^2) list comparison to look for
-// duplicates.
-func firstUniqueList(in interface{}) interface{} {
-	writeIndex := 0
-	slice := reflect.ValueOf(in)
-	length := slice.Len()
-outer:
-	for readIndex := 0; readIndex < length; readIndex++ {
-		readValue := slice.Index(readIndex)
-		for compareIndex := 0; compareIndex < writeIndex; compareIndex++ {
-			compareValue := slice.Index(compareIndex)
-			// These two Interface() calls seem to cause an allocation and significantly
-			// slow down this list-based implementation.  The map implementation below doesn't
-			// have this issue because reflect.Value.MapIndex takes a Value and appears to be
-			// able to do the map lookup without an allocation.
-			if readValue.Interface() == compareValue.Interface() {
-				// The value at readIndex already exists somewhere in the output region
-				// of the slice before writeIndex, skip it.
-				continue outer
-			}
-		}
-		if readIndex != writeIndex {
-			writeValue := slice.Index(writeIndex)
-			writeValue.Set(readValue)
-		}
-		writeIndex++
-	}
-	return slice.Slice(0, writeIndex).Interface()
-}
-
-var trueValue = reflect.ValueOf(true)
-
-// firstUniqueList is an implementation of firstUnique using an O(N) hash set lookup to look for
-// duplicates.
-func firstUniqueMap(in interface{}) interface{} {
-	writeIndex := 0
-	slice := reflect.ValueOf(in)
-	length := slice.Len()
-	seen := reflect.MakeMapWithSize(reflect.MapOf(slice.Type().Elem(), trueValue.Type()), slice.Len())
-	for readIndex := 0; readIndex < length; readIndex++ {
-		readValue := slice.Index(readIndex)
-		if seen.MapIndex(readValue).IsValid() {
-			continue
-		}
-		seen.SetMapIndex(readValue, trueValue)
-		if readIndex != writeIndex {
-			writeValue := slice.Index(writeIndex)
-			writeValue.Set(readValue)
-		}
-		writeIndex++
-	}
-	return slice.Slice(0, writeIndex).Interface()
-}
-
-// reverseSliceInPlace reverses the elements of a slice in place.  The argument must be a slice, but
-// is not type-safe due to the lack of reflection in Go.
-func reverseSliceInPlace(in interface{}) {
-	swapper := reflect.Swapper(in)
-	slice := reflect.ValueOf(in)
-	length := slice.Len()
-	for i, j := 0, length-1; i < j; i, j = i+1, j-1 {
-		swapper(i, j)
-	}
-}
-
-// reverseSlice returns a copy of a slice in reverse order.  The argument must be a slice, but is
-// not type-safe due to the lack of reflection in Go.
-func reverseSlice(in interface{}) interface{} {
-	slice := reflect.ValueOf(in)
-	if !slice.IsValid() || slice.IsNil() {
-		return in
-	}
-	if slice.Kind() != reflect.Slice {
-		panic(fmt.Errorf("%t is not a slice", in))
-	}
-	length := slice.Len()
-	if length == 0 {
-		return in
-	}
-	out := reflect.MakeSlice(slice.Type(), length, length)
-	for i := 0; i < length; i++ {
-		out.Index(i).Set(slice.Index(length - 1 - i))
-	}
-	return out.Interface()
-}
-
-// copySlice returns a copy of a slice.  The argument must be a slice, but is not type-safe due to
-// the lack of reflection in Go.
-func copySlice(in interface{}) interface{} {
-	slice := reflect.ValueOf(in)
-	if !slice.IsValid() || slice.IsNil() {
-		return in
-	}
-	length := slice.Len()
-	if length == 0 {
-		return in
-	}
-	out := reflect.MakeSlice(slice.Type(), length, length)
-	reflect.Copy(out, slice)
-	return out.Interface()
-}
diff --git a/android/depset_paths.go b/android/depset_paths.go
deleted file mode 100644
index ed561ba..0000000
--- a/android/depset_paths.go
+++ /dev/null
@@ -1,94 +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
-
-// This file implements DepSet, a thin type-safe wrapper around depSet that contains Paths.
-
-// A DepSet efficiently stores Paths from transitive dependencies without copying. It is stored
-// as a DAG of DepSet nodes, each of which has some direct contents and a list of dependency
-// DepSet nodes.
-//
-// A DepSet has an order that will be used to walk the DAG when ToList() is called.  The order
-// can be POSTORDER, PREORDER, or TOPOLOGICAL.  POSTORDER and PREORDER orders return a postordered
-// or preordered left to right flattened list.  TOPOLOGICAL returns a list that guarantees that
-// elements of children are listed after all of their parents (unless there are duplicate direct
-// elements in the DepSet or any of its transitive dependencies, in which case the ordering of the
-// duplicated element is not guaranteed).
-//
-// A DepSet is created by NewDepSet or NewDepSetBuilder.Build from the Paths for direct contents
-// and the *DepSets of dependencies. A DepSet is immutable once created.
-type DepSet struct {
-	depSet
-}
-
-// DepSetBuilder is used to create an immutable DepSet.
-type DepSetBuilder struct {
-	depSetBuilder
-}
-
-// NewDepSet returns an immutable DepSet with the given order, direct and transitive contents.
-func NewDepSet(order DepSetOrder, direct Paths, transitive []*DepSet) *DepSet {
-	return &DepSet{*newDepSet(order, direct, transitive)}
-}
-
-// NewDepSetBuilder returns a DepSetBuilder to create an immutable DepSet with the given order.
-func NewDepSetBuilder(order DepSetOrder) *DepSetBuilder {
-	return &DepSetBuilder{*newDepSetBuilder(order, Paths(nil))}
-}
-
-// Direct adds direct contents to the DepSet being built by a DepSetBuilder. Newly added direct
-// contents are to the right of any existing direct contents.
-func (b *DepSetBuilder) Direct(direct ...Path) *DepSetBuilder {
-	b.depSetBuilder.DirectSlice(direct)
-	return b
-}
-
-// Transitive adds transitive contents to the DepSet being built by a DepSetBuilder. Newly added
-// transitive contents are to the right of any existing transitive contents.
-func (b *DepSetBuilder) Transitive(transitive ...*DepSet) *DepSetBuilder {
-	b.depSetBuilder.Transitive(transitive)
-	return b
-}
-
-// Returns the DepSet being built by this DepSetBuilder.  The DepSetBuilder retains its contents
-// for creating more DepSets.
-func (b *DepSetBuilder) Build() *DepSet {
-	return &DepSet{*b.depSetBuilder.Build()}
-}
-
-// ToList returns the DepSet flattened to a list.  The order in the list is based on the order
-// of the DepSet.  POSTORDER and PREORDER orders return a postordered or preordered left to right
-// flattened list.  TOPOLOGICAL returns a list that guarantees that elements of children are listed
-// after all of their parents (unless there are duplicate direct elements in the DepSet or any of
-// its transitive dependencies, in which case the ordering of the duplicated element is not
-// guaranteed).
-func (d *DepSet) ToList() Paths {
-	if d == nil {
-		return nil
-	}
-	return d.toList(func(paths interface{}) interface{} {
-		return FirstUniquePaths(paths.(Paths))
-	}).(Paths)
-}
-
-// ToSortedList returns the direct and transitive contents of a DepSet in lexically sorted order
-// with duplicates removed.
-func (d *DepSet) ToSortedList() Paths {
-	if d == nil {
-		return nil
-	}
-	paths := d.ToList()
-	return SortedUniquePaths(paths)
-}
diff --git a/android/depset_test.go b/android/depset_test.go
index 955ccb0..376dffa 100644
--- a/android/depset_test.go
+++ b/android/depset_test.go
@@ -17,51 +17,40 @@
 import (
 	"fmt"
 	"reflect"
-	"strconv"
 	"strings"
 	"testing"
 )
 
 func ExampleDepSet_ToList_postordered() {
-	a := NewDepSetBuilder(POSTORDER).Direct(PathForTesting("a")).Build()
-	b := NewDepSetBuilder(POSTORDER).Direct(PathForTesting("b")).Transitive(a).Build()
-	c := NewDepSetBuilder(POSTORDER).Direct(PathForTesting("c")).Transitive(a).Build()
-	d := NewDepSetBuilder(POSTORDER).Direct(PathForTesting("d")).Transitive(b, c).Build()
+	a := NewDepSetBuilder[Path](POSTORDER).Direct(PathForTesting("a")).Build()
+	b := NewDepSetBuilder[Path](POSTORDER).Direct(PathForTesting("b")).Transitive(a).Build()
+	c := NewDepSetBuilder[Path](POSTORDER).Direct(PathForTesting("c")).Transitive(a).Build()
+	d := NewDepSetBuilder[Path](POSTORDER).Direct(PathForTesting("d")).Transitive(b, c).Build()
 
-	fmt.Println(d.ToList().Strings())
+	fmt.Println(Paths(d.ToList()).Strings())
 	// Output: [a b c d]
 }
 
 func ExampleDepSet_ToList_preordered() {
-	a := NewDepSetBuilder(PREORDER).Direct(PathForTesting("a")).Build()
-	b := NewDepSetBuilder(PREORDER).Direct(PathForTesting("b")).Transitive(a).Build()
-	c := NewDepSetBuilder(PREORDER).Direct(PathForTesting("c")).Transitive(a).Build()
-	d := NewDepSetBuilder(PREORDER).Direct(PathForTesting("d")).Transitive(b, c).Build()
+	a := NewDepSetBuilder[Path](PREORDER).Direct(PathForTesting("a")).Build()
+	b := NewDepSetBuilder[Path](PREORDER).Direct(PathForTesting("b")).Transitive(a).Build()
+	c := NewDepSetBuilder[Path](PREORDER).Direct(PathForTesting("c")).Transitive(a).Build()
+	d := NewDepSetBuilder[Path](PREORDER).Direct(PathForTesting("d")).Transitive(b, c).Build()
 
-	fmt.Println(d.ToList().Strings())
+	fmt.Println(Paths(d.ToList()).Strings())
 	// Output: [d b a c]
 }
 
 func ExampleDepSet_ToList_topological() {
-	a := NewDepSetBuilder(TOPOLOGICAL).Direct(PathForTesting("a")).Build()
-	b := NewDepSetBuilder(TOPOLOGICAL).Direct(PathForTesting("b")).Transitive(a).Build()
-	c := NewDepSetBuilder(TOPOLOGICAL).Direct(PathForTesting("c")).Transitive(a).Build()
-	d := NewDepSetBuilder(TOPOLOGICAL).Direct(PathForTesting("d")).Transitive(b, c).Build()
+	a := NewDepSetBuilder[Path](TOPOLOGICAL).Direct(PathForTesting("a")).Build()
+	b := NewDepSetBuilder[Path](TOPOLOGICAL).Direct(PathForTesting("b")).Transitive(a).Build()
+	c := NewDepSetBuilder[Path](TOPOLOGICAL).Direct(PathForTesting("c")).Transitive(a).Build()
+	d := NewDepSetBuilder[Path](TOPOLOGICAL).Direct(PathForTesting("d")).Transitive(b, c).Build()
 
-	fmt.Println(d.ToList().Strings())
+	fmt.Println(Paths(d.ToList()).Strings())
 	// Output: [d b c a]
 }
 
-func ExampleDepSet_ToSortedList() {
-	a := NewDepSetBuilder(POSTORDER).Direct(PathForTesting("a")).Build()
-	b := NewDepSetBuilder(POSTORDER).Direct(PathForTesting("b")).Transitive(a).Build()
-	c := NewDepSetBuilder(POSTORDER).Direct(PathForTesting("c")).Transitive(a).Build()
-	d := NewDepSetBuilder(POSTORDER).Direct(PathForTesting("d")).Transitive(b, c).Build()
-
-	fmt.Println(d.ToSortedList().Strings())
-	// Output: [a b c d]
-}
-
 // Tests based on Bazel's ExpanderTestBase.java to ensure compatibility
 // https://github.com/bazelbuild/bazel/blob/master/src/test/java/com/google/devtools/build/lib/collect/nestedset/ExpanderTestBase.java
 func TestDepSet(t *testing.T) {
@@ -74,13 +63,13 @@
 
 	tests := []struct {
 		name                             string
-		depSet                           func(t *testing.T, order DepSetOrder) *DepSet
+		depSet                           func(t *testing.T, order DepSetOrder) *DepSet[Path]
 		postorder, preorder, topological []string
 	}{
 		{
 			name: "simple",
-			depSet: func(t *testing.T, order DepSetOrder) *DepSet {
-				return NewDepSet(order, Paths{c, a, b}, nil)
+			depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
+				return NewDepSet[Path](order, Paths{c, a, b}, nil)
 			},
 			postorder:   []string{"c", "a", "b"},
 			preorder:    []string{"c", "a", "b"},
@@ -88,8 +77,8 @@
 		},
 		{
 			name: "simpleNoDuplicates",
-			depSet: func(t *testing.T, order DepSetOrder) *DepSet {
-				return NewDepSet(order, Paths{c, a, a, a, b}, nil)
+			depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
+				return NewDepSet[Path](order, Paths{c, a, a, a, b}, nil)
 			},
 			postorder:   []string{"c", "a", "b"},
 			preorder:    []string{"c", "a", "b"},
@@ -97,9 +86,9 @@
 		},
 		{
 			name: "nesting",
-			depSet: func(t *testing.T, order DepSetOrder) *DepSet {
-				subset := NewDepSet(order, Paths{c, a, e}, nil)
-				return NewDepSet(order, Paths{b, d}, []*DepSet{subset})
+			depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
+				subset := NewDepSet[Path](order, Paths{c, a, e}, nil)
+				return NewDepSet[Path](order, Paths{b, d}, []*DepSet[Path]{subset})
 			},
 			postorder:   []string{"c", "a", "e", "b", "d"},
 			preorder:    []string{"b", "d", "c", "a", "e"},
@@ -107,14 +96,14 @@
 		},
 		{
 			name: "builderReuse",
-			depSet: func(t *testing.T, order DepSetOrder) *DepSet {
+			depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
 				assertEquals := func(t *testing.T, w, g Paths) {
 					t.Helper()
 					if !reflect.DeepEqual(w, g) {
 						t.Errorf("want %q, got %q", w, g)
 					}
 				}
-				builder := NewDepSetBuilder(order)
+				builder := NewDepSetBuilder[Path](order)
 				assertEquals(t, nil, builder.Build().ToList())
 
 				builder.Direct(b)
@@ -123,7 +112,7 @@
 				builder.Direct(d)
 				assertEquals(t, Paths{b, d}, builder.Build().ToList())
 
-				child := NewDepSetBuilder(order).Direct(c, a, e).Build()
+				child := NewDepSetBuilder[Path](order).Direct(c, a, e).Build()
 				builder.Transitive(child)
 				return builder.Build()
 			},
@@ -133,9 +122,9 @@
 		},
 		{
 			name: "builderChaining",
-			depSet: func(t *testing.T, order DepSetOrder) *DepSet {
-				return NewDepSetBuilder(order).Direct(b).Direct(d).
-					Transitive(NewDepSetBuilder(order).Direct(c, a, e).Build()).Build()
+			depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
+				return NewDepSetBuilder[Path](order).Direct(b).Direct(d).
+					Transitive(NewDepSetBuilder[Path](order).Direct(c, a, e).Build()).Build()
 			},
 			postorder:   []string{"c", "a", "e", "b", "d"},
 			preorder:    []string{"b", "d", "c", "a", "e"},
@@ -143,9 +132,9 @@
 		},
 		{
 			name: "transitiveDepsHandledSeparately",
-			depSet: func(t *testing.T, order DepSetOrder) *DepSet {
-				subset := NewDepSetBuilder(order).Direct(c, a, e).Build()
-				builder := NewDepSetBuilder(order)
+			depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
+				subset := NewDepSetBuilder[Path](order).Direct(c, a, e).Build()
+				builder := NewDepSetBuilder[Path](order)
 				// The fact that we add the transitive subset between the Direct(b) and Direct(d)
 				// calls should not change the result.
 				builder.Direct(b)
@@ -159,9 +148,9 @@
 		},
 		{
 			name: "nestingNoDuplicates",
-			depSet: func(t *testing.T, order DepSetOrder) *DepSet {
-				subset := NewDepSetBuilder(order).Direct(c, a, e).Build()
-				return NewDepSetBuilder(order).Direct(b, d, e).Transitive(subset).Build()
+			depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
+				subset := NewDepSetBuilder[Path](order).Direct(c, a, e).Build()
+				return NewDepSetBuilder[Path](order).Direct(b, d, e).Transitive(subset).Build()
 			},
 			postorder:   []string{"c", "a", "e", "b", "d"},
 			preorder:    []string{"b", "d", "e", "c", "a"},
@@ -169,10 +158,10 @@
 		},
 		{
 			name: "chain",
-			depSet: func(t *testing.T, order DepSetOrder) *DepSet {
-				c := NewDepSetBuilder(order).Direct(c).Build()
-				b := NewDepSetBuilder(order).Direct(b).Transitive(c).Build()
-				a := NewDepSetBuilder(order).Direct(a).Transitive(b).Build()
+			depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
+				c := NewDepSetBuilder[Path](order).Direct(c).Build()
+				b := NewDepSetBuilder[Path](order).Direct(b).Transitive(c).Build()
+				a := NewDepSetBuilder[Path](order).Direct(a).Transitive(b).Build()
 
 				return a
 			},
@@ -182,11 +171,11 @@
 		},
 		{
 			name: "diamond",
-			depSet: func(t *testing.T, order DepSetOrder) *DepSet {
-				d := NewDepSetBuilder(order).Direct(d).Build()
-				c := NewDepSetBuilder(order).Direct(c).Transitive(d).Build()
-				b := NewDepSetBuilder(order).Direct(b).Transitive(d).Build()
-				a := NewDepSetBuilder(order).Direct(a).Transitive(b).Transitive(c).Build()
+			depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
+				d := NewDepSetBuilder[Path](order).Direct(d).Build()
+				c := NewDepSetBuilder[Path](order).Direct(c).Transitive(d).Build()
+				b := NewDepSetBuilder[Path](order).Direct(b).Transitive(d).Build()
+				a := NewDepSetBuilder[Path](order).Direct(a).Transitive(b).Transitive(c).Build()
 
 				return a
 			},
@@ -196,12 +185,12 @@
 		},
 		{
 			name: "extendedDiamond",
-			depSet: func(t *testing.T, order DepSetOrder) *DepSet {
-				d := NewDepSetBuilder(order).Direct(d).Build()
-				e := NewDepSetBuilder(order).Direct(e).Build()
-				b := NewDepSetBuilder(order).Direct(b).Transitive(d).Transitive(e).Build()
-				c := NewDepSetBuilder(order).Direct(c).Transitive(e).Transitive(d).Build()
-				a := NewDepSetBuilder(order).Direct(a).Transitive(b).Transitive(c).Build()
+			depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
+				d := NewDepSetBuilder[Path](order).Direct(d).Build()
+				e := NewDepSetBuilder[Path](order).Direct(e).Build()
+				b := NewDepSetBuilder[Path](order).Direct(b).Transitive(d).Transitive(e).Build()
+				c := NewDepSetBuilder[Path](order).Direct(c).Transitive(e).Transitive(d).Build()
+				a := NewDepSetBuilder[Path](order).Direct(a).Transitive(b).Transitive(c).Build()
 				return a
 			},
 			postorder:   []string{"d", "e", "b", "c", "a"},
@@ -210,13 +199,13 @@
 		},
 		{
 			name: "extendedDiamondRightArm",
-			depSet: func(t *testing.T, order DepSetOrder) *DepSet {
-				d := NewDepSetBuilder(order).Direct(d).Build()
-				e := NewDepSetBuilder(order).Direct(e).Build()
-				b := NewDepSetBuilder(order).Direct(b).Transitive(d).Transitive(e).Build()
-				c2 := NewDepSetBuilder(order).Direct(c2).Transitive(e).Transitive(d).Build()
-				c := NewDepSetBuilder(order).Direct(c).Transitive(c2).Build()
-				a := NewDepSetBuilder(order).Direct(a).Transitive(b).Transitive(c).Build()
+			depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
+				d := NewDepSetBuilder[Path](order).Direct(d).Build()
+				e := NewDepSetBuilder[Path](order).Direct(e).Build()
+				b := NewDepSetBuilder[Path](order).Direct(b).Transitive(d).Transitive(e).Build()
+				c2 := NewDepSetBuilder[Path](order).Direct(c2).Transitive(e).Transitive(d).Build()
+				c := NewDepSetBuilder[Path](order).Direct(c).Transitive(c2).Build()
+				a := NewDepSetBuilder[Path](order).Direct(a).Transitive(b).Transitive(c).Build()
 				return a
 			},
 			postorder:   []string{"d", "e", "b", "c2", "c", "a"},
@@ -225,10 +214,10 @@
 		},
 		{
 			name: "orderConflict",
-			depSet: func(t *testing.T, order DepSetOrder) *DepSet {
-				child1 := NewDepSetBuilder(order).Direct(a, b).Build()
-				child2 := NewDepSetBuilder(order).Direct(b, a).Build()
-				parent := NewDepSetBuilder(order).Transitive(child1).Transitive(child2).Build()
+			depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
+				child1 := NewDepSetBuilder[Path](order).Direct(a, b).Build()
+				child2 := NewDepSetBuilder[Path](order).Direct(b, a).Build()
+				parent := NewDepSetBuilder[Path](order).Transitive(child1).Transitive(child2).Build()
 				return parent
 			},
 			postorder:   []string{"a", "b"},
@@ -237,12 +226,12 @@
 		},
 		{
 			name: "orderConflictNested",
-			depSet: func(t *testing.T, order DepSetOrder) *DepSet {
-				a := NewDepSetBuilder(order).Direct(a).Build()
-				b := NewDepSetBuilder(order).Direct(b).Build()
-				child1 := NewDepSetBuilder(order).Transitive(a).Transitive(b).Build()
-				child2 := NewDepSetBuilder(order).Transitive(b).Transitive(a).Build()
-				parent := NewDepSetBuilder(order).Transitive(child1).Transitive(child2).Build()
+			depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
+				a := NewDepSetBuilder[Path](order).Direct(a).Build()
+				b := NewDepSetBuilder[Path](order).Direct(b).Build()
+				child1 := NewDepSetBuilder[Path](order).Transitive(a).Transitive(b).Build()
+				child2 := NewDepSetBuilder[Path](order).Transitive(b).Transitive(a).Build()
+				parent := NewDepSetBuilder[Path](order).Transitive(child1).Transitive(child2).Build()
 				return parent
 			},
 			postorder:   []string{"a", "b"},
@@ -255,19 +244,19 @@
 		t.Run(tt.name, func(t *testing.T) {
 			t.Run("postorder", func(t *testing.T) {
 				depSet := tt.depSet(t, POSTORDER)
-				if g, w := depSet.ToList().Strings(), tt.postorder; !reflect.DeepEqual(g, w) {
+				if g, w := Paths(depSet.ToList()).Strings(), tt.postorder; !reflect.DeepEqual(g, w) {
 					t.Errorf("expected ToList() = %q, got %q", w, g)
 				}
 			})
 			t.Run("preorder", func(t *testing.T) {
 				depSet := tt.depSet(t, PREORDER)
-				if g, w := depSet.ToList().Strings(), tt.preorder; !reflect.DeepEqual(g, w) {
+				if g, w := Paths(depSet.ToList()).Strings(), tt.preorder; !reflect.DeepEqual(g, w) {
 					t.Errorf("expected ToList() = %q, got %q", w, g)
 				}
 			})
 			t.Run("topological", func(t *testing.T) {
 				depSet := tt.depSet(t, TOPOLOGICAL)
-				if g, w := depSet.ToList().Strings(), tt.topological; !reflect.DeepEqual(g, w) {
+				if g, w := Paths(depSet.ToList()).Strings(), tt.topological; !reflect.DeepEqual(g, w) {
 					t.Errorf("expected ToList() = %q, got %q", w, g)
 				}
 			})
@@ -288,7 +277,7 @@
 				}
 			}
 		}()
-		NewDepSet(order1, nil, []*DepSet{NewDepSet(order2, nil, nil)})
+		NewDepSet(order1, nil, []*DepSet[Path]{NewDepSet[Path](order2, nil, nil)})
 		t.Fatal("expected panic")
 	}
 
@@ -304,87 +293,3 @@
 		})
 	}
 }
-
-func Test_firstUnique(t *testing.T) {
-	f := func(t *testing.T, imp func([]string) []string, in, want []string) {
-		t.Helper()
-		out := imp(in)
-		if !reflect.DeepEqual(out, want) {
-			t.Errorf("incorrect output:")
-			t.Errorf("     input: %#v", in)
-			t.Errorf("  expected: %#v", want)
-			t.Errorf("       got: %#v", out)
-		}
-	}
-
-	for _, testCase := range firstUniqueStringsTestCases {
-		t.Run("list", func(t *testing.T) {
-			f(t, func(s []string) []string {
-				return firstUniqueList(s).([]string)
-			}, testCase.in, testCase.out)
-		})
-		t.Run("map", func(t *testing.T) {
-			f(t, func(s []string) []string {
-				return firstUniqueMap(s).([]string)
-			}, testCase.in, testCase.out)
-		})
-	}
-}
-
-func Benchmark_firstUnique(b *testing.B) {
-	implementations := []struct {
-		name string
-		f    func([]string) []string
-	}{
-		{
-			name: "list",
-			f: func(slice []string) []string {
-				return firstUniqueList(slice).([]string)
-			},
-		},
-		{
-			name: "map",
-			f: func(slice []string) []string {
-				return firstUniqueMap(slice).([]string)
-			},
-		},
-		{
-			name: "optimal",
-			f: func(slice []string) []string {
-				return firstUnique(slice).([]string)
-			},
-		},
-	}
-	const maxSize = 1024
-	uniqueStrings := make([]string, maxSize)
-	for i := range uniqueStrings {
-		uniqueStrings[i] = strconv.Itoa(i)
-	}
-	sameString := make([]string, maxSize)
-	for i := range sameString {
-		sameString[i] = uniqueStrings[0]
-	}
-
-	f := func(b *testing.B, imp func([]string) []string, s []string) {
-		for i := 0; i < b.N; i++ {
-			b.ReportAllocs()
-			s = append([]string(nil), s...)
-			imp(s)
-		}
-	}
-
-	for n := 1; n <= maxSize; n <<= 1 {
-		b.Run(strconv.Itoa(n), func(b *testing.B) {
-			for _, implementation := range implementations {
-				b.Run(implementation.name, func(b *testing.B) {
-					b.Run("same", func(b *testing.B) {
-						f(b, implementation.f, sameString[:n])
-					})
-					b.Run("unique", func(b *testing.B) {
-						f(b, implementation.f, uniqueStrings[:n])
-					})
-				})
-			}
-		})
-	}
-}
diff --git a/android/early_module_context.go b/android/early_module_context.go
new file mode 100644
index 0000000..8f75773
--- /dev/null
+++ b/android/early_module_context.go
@@ -0,0 +1,169 @@
+// 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 (
+	"github.com/google/blueprint"
+	"os"
+	"text/scanner"
+)
+
+// 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
+}
+
+// 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)
+}
diff --git a/android/filegroup.go b/android/filegroup.go
index 66aa154..bc881ed 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -15,13 +15,8 @@
 package android
 
 import (
-	"path/filepath"
-	"regexp"
 	"strings"
 
-	"android/soong/bazel"
-	"android/soong/bazel/cquery"
-
 	"github.com/google/blueprint"
 )
 
@@ -38,141 +33,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())
-			}
-			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) {
-			attrs := &ProtoAttrs{
-				Srcs:                srcs,
-				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",
-			}
-			ctx.CreateBazelTargetModule(
-				bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
-				CommonAttributes{
-					Name: fg.Name() + convertedProtoLibrarySuffix,
-					Tags: bazel.MakeStringListAttribute(tags),
-				},
-				attrs)
-		}
-
-		// 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 fileGroupProperties struct {
 	// srcs lists files that will be included in this filegroup
 	Srcs []string `android:"path"`
@@ -192,16 +52,15 @@
 
 type fileGroup struct {
 	ModuleBase
-	BazelModuleBase
 	DefaultableModuleBase
-	FileGroupAsLibrary
 	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)
 
 // filegroup contains a list of files that are referenced by other modules
 // properties (such as "srcs") using the syntax ":<name>". filegroup are
@@ -210,7 +69,6 @@
 	module := &fileGroup{}
 	module.AddProperties(&module.properties)
 	InitAndroidModule(module)
-	InitBazelModule(module)
 	InitDefaultableModule(module)
 	return module
 }
@@ -237,7 +95,8 @@
 	if fg.properties.Path != nil {
 		fg.srcs = PathsWithModuleSrcSubDir(ctx, fg.srcs, String(fg.properties.Path))
 	}
-	ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: fg.srcs.Strings()})
+	SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: fg.srcs.Strings()})
+	CollectDependencyAconfigFiles(ctx, &fg.mergedAconfigFiles)
 }
 
 func (fg *fileGroup) Srcs() Paths {
@@ -250,101 +109,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 dbc3bc5..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) })
 }
@@ -369,7 +378,7 @@
 
 // Allow access to the product variables when preparing the fixture.
 type FixtureProductVariables struct {
-	*productVariables
+	*ProductVariables
 }
 
 // Modify product variables.
diff --git a/android/gen_notice.go b/android/gen_notice.go
index 091345b..1acc638 100644
--- a/android/gen_notice.go
+++ b/android/gen_notice.go
@@ -28,7 +28,7 @@
 
 // Register the gen_notice module type.
 func RegisterGenNoticeBuildComponents(ctx RegistrationContext) {
-	ctx.RegisterSingletonType("gen_notice_build_rules", GenNoticeBuildRulesFactory)
+	ctx.RegisterParallelSingletonType("gen_notice_build_rules", GenNoticeBuildRulesFactory)
 	ctx.RegisterModuleType("gen_notice", GenNoticeFactory)
 }
 
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 73000a9..463fd07 100644
--- a/android/license_metadata.go
+++ b/android/license_metadata.go
@@ -50,12 +50,19 @@
 		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
 	var allDepOutputFiles Paths
-	var allDepMetadataDepSets []*PathsDepSet
+	var allDepMetadataDepSets []*DepSet[Path]
 
 	ctx.VisitDirectDepsBlueprint(func(bpdep blueprint.Module) {
 		dep, _ := bpdep.(Module)
@@ -71,8 +78,7 @@
 			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)
@@ -127,7 +133,7 @@
 		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_text.Strings()), "-n "))
 
 	if isContainer {
-		transitiveDeps := newPathsDepSet(nil, allDepMetadataDepSets).ToList()
+		transitiveDeps := Paths(NewDepSet[Path](TOPOLOGICAL, nil, allDepMetadataDepSets).ToList())
 		args = append(args,
 			JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(transitiveDeps.Strings()), "-d "))
 		orderOnlyDeps = append(orderOnlyDeps, transitiveDeps...)
@@ -168,9 +174,9 @@
 		},
 	})
 
-	ctx.SetProvider(LicenseMetadataProvider, &LicenseMetadataInfo{
+	SetProvider(ctx, LicenseMetadataProvider, &LicenseMetadataInfo{
 		LicenseMetadataPath:   licenseMetadataFile,
-		LicenseMetadataDepSet: newPathsDepSet(Paths{licenseMetadataFile}, allDepMetadataDepSets),
+		LicenseMetadataDepSet: NewDepSet(TOPOLOGICAL, Paths{licenseMetadataFile}, allDepMetadataDepSets),
 	})
 }
 
@@ -193,12 +199,12 @@
 }
 
 // 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 {
 	LicenseMetadataPath   Path
-	LicenseMetadataDepSet *PathsDepSet
+	LicenseMetadataDepSet *DepSet[Path]
 }
 
 // licenseAnnotationsFromTag returns the LicenseAnnotations for a tag (if any) converted into
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/makefile_goal.go b/android/makefile_goal.go
deleted file mode 100644
index 07354a6..0000000
--- a/android/makefile_goal.go
+++ /dev/null
@@ -1,98 +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 (
-	"fmt"
-	"io"
-	"path/filepath"
-
-	"github.com/google/blueprint/proptools"
-)
-
-func init() {
-	RegisterModuleType("makefile_goal", MakefileGoalFactory)
-}
-
-type makefileGoalProperties struct {
-	// Sources.
-
-	// Makefile goal output file path, relative to PRODUCT_OUT.
-	Product_out_path *string
-}
-
-type makefileGoal struct {
-	ModuleBase
-
-	properties makefileGoalProperties
-
-	// Destination. Output file path of this module.
-	outputFilePath OutputPath
-}
-
-var _ AndroidMkEntriesProvider = (*makefileGoal)(nil)
-var _ OutputFileProducer = (*makefileGoal)(nil)
-
-// Input file of this makefile_goal module. Nil if none specified. May use variable names in makefiles.
-func (p *makefileGoal) inputPath() *string {
-	if p.properties.Product_out_path != nil {
-		return proptools.StringPtr(filepath.Join("$(PRODUCT_OUT)", proptools.String(p.properties.Product_out_path)))
-	}
-	return nil
-}
-
-// OutputFileProducer
-func (p *makefileGoal) OutputFiles(tag string) (Paths, error) {
-	if tag != "" {
-		return nil, fmt.Errorf("unsupported tag %q", tag)
-	}
-	return Paths{p.outputFilePath}, nil
-}
-
-// AndroidMkEntriesProvider
-func (p *makefileGoal) DepsMutator(ctx BottomUpMutatorContext) {
-	if p.inputPath() == nil {
-		ctx.PropertyErrorf("product_out_path", "Path relative to PRODUCT_OUT required")
-	}
-}
-
-func (p *makefileGoal) GenerateAndroidBuildActions(ctx ModuleContext) {
-	filename := filepath.Base(proptools.String(p.inputPath()))
-	p.outputFilePath = PathForModuleOut(ctx, filename).OutputPath
-
-	ctx.InstallFile(PathForModuleInstall(ctx, "etc"), ctx.ModuleName(), p.outputFilePath)
-}
-
-func (p *makefileGoal) AndroidMkEntries() []AndroidMkEntries {
-	return []AndroidMkEntries{AndroidMkEntries{
-		Class:      "ETC",
-		OutputFile: OptionalPathForPath(p.outputFilePath),
-		ExtraFooters: []AndroidMkExtraFootersFunc{
-			func(w io.Writer, name, prefix, moduleDir string) {
-				// Can't use Cp because inputPath() is not a valid Path.
-				fmt.Fprintf(w, "$(eval $(call copy-one-file,%s,%s))\n", proptools.String(p.inputPath()), p.outputFilePath)
-			},
-		},
-	}}
-}
-
-// Import a Makefile goal to Soong by copying the file built by
-// the goal to a path visible to Soong. This rule only works on boot images.
-func MakefileGoalFactory() Module {
-	module := &makefileGoal{}
-	module.AddProperties(&module.properties)
-	InitAndroidModule(module)
-	return module
-}
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 3d41a1d..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,22 +30,25 @@
 
 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() {
-	RegisterSingletonType("soong_metrics", soongMetricsSingletonFactory)
+	RegisterParallelSingletonType("soong_metrics", soongMetricsSingletonFactory)
 }
 
 func soongMetricsSingletonFactory() Singleton { return soongMetricsSingleton{} }
@@ -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 05f7682..5c7bbbf 100644
--- a/android/module.go
+++ b/android/module.go
@@ -15,18 +15,17 @@
 package android
 
 import (
+	"android/soong/bazel"
+	"crypto/md5"
+	"encoding/hex"
+	"encoding/json"
 	"fmt"
 	"net/url"
-	"os"
-	"path"
 	"path/filepath"
 	"reflect"
-	"regexp"
+	"slices"
 	"sort"
 	"strings"
-	"text/scanner"
-
-	"android/soong/bazel"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -37,465 +36,6 @@
 	DeviceStaticLibrary = "static_library"
 )
 
-// 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)
-
-	// 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
-
-	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
 
@@ -538,6 +78,8 @@
 	InstallInDebugRamdisk() bool
 	InstallInRecovery() bool
 	InstallInRoot() bool
+	InstallInOdm() bool
+	InstallInProduct() bool
 	InstallInVendor() bool
 	InstallForceOS() (*OsType, *ArchType)
 	PartitionTag(DeviceConfig) string
@@ -556,13 +98,6 @@
 	AddProperties(props ...interface{})
 	GetProperties() []interface{}
 
-	// IsConvertedByBp2build returns whether this module was converted via bp2build
-	IsConvertedByBp2build() bool
-	// 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
@@ -710,6 +245,31 @@
 	return l[:k+1]
 }
 
+// soongConfigTrace holds all references to VendorVars. Uses []string for blueprint:"mutated"
+type soongConfigTrace struct {
+	Bools   []string `json:",omitempty"`
+	Strings []string `json:",omitempty"`
+	IsSets  []string `json:",omitempty"`
+}
+
+func (c *soongConfigTrace) isEmpty() bool {
+	return len(c.Bools) == 0 && len(c.Strings) == 0 && len(c.IsSets) == 0
+}
+
+// Returns hash of serialized trace records (empty string if there's no trace recorded)
+func (c *soongConfigTrace) hash() string {
+	// Use MD5 for speed. We don't care collision or preimage attack
+	if c.isEmpty() {
+		return ""
+	}
+	j, err := json.Marshal(c)
+	if err != nil {
+		panic(fmt.Errorf("json marshal of %#v failed: %#v", *c, err))
+	}
+	hash := md5.Sum(j)
+	return hex.EncodeToString(hash[:])
+}
+
 type nameProperties struct {
 	// The name of the module.  Must be unique across all modules.
 	Name *string
@@ -766,7 +326,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
 
@@ -939,7 +499,8 @@
 
 	NamespaceExportedToMake bool `blueprint:"mutated"`
 
-	MissingDeps []string `blueprint:"mutated"`
+	MissingDeps        []string `blueprint:"mutated"`
+	CheckedMissingDeps bool     `blueprint:"mutated"`
 
 	// Name and variant strings stored by mutators to enable Module.String()
 	DebugName       string   `blueprint:"mutated"`
@@ -951,42 +512,16 @@
 	// 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),
+	// and there are variables other than soong_config, which isn't captured by soong config
+	// trace, but influence modules among products.
+	SoongConfigTrace     soongConfigTrace `blueprint:"mutated"`
+	SoongConfigTraceHash string           `blueprint:"mutated"`
 
 	// The team (defined by the owner/vendor) who owns the property.
 	Team *string `android:"path"`
-
-}
-
-// 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
-}
-
-// 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
 }
 
 type distProperties struct {
@@ -1232,189 +767,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)
-				}
-			}
-		}
-	}
-
-	productConfigEnabledLabels := []bazel.Label{}
-	// 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
-		productConfigEnabledLabels = productVariableConfigEnableLabels(ctx)
-
-		if len(productConfigEnabledLabels) > 0 {
-			// In this case, an existing product variable configuration overrides any
-			// module-level `enable: false` definition
-			newValue := true
-			enabledProperty.Value = &newValue
-		}
-	}
-
-	productConfigEnabledAttribute := bazel.MakeLabelListAttribute(bazel.LabelList{
-		productConfigEnabledLabels, nil,
-	})
-
-	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 productVariableConfigEnableLabels(ctx *topDownMutatorContext) []bazel.Label {
-	productVariableProps := ProductVariableProperties(ctx, ctx.Module())
-	productConfigEnablingTargets := []bazel.Label{}
-	const propName = "Enabled"
-	if productConfigProps, exists := productVariableProps[propName]; exists {
-		for productConfigProp, prop := range productConfigProps {
-			flag, ok := prop.(*bool)
-			if !ok {
-				ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName))
-			}
-
-			if *flag {
-				axis := productConfigProp.ConfigurationAxis()
-				targetLabel := axis.SelectKey(productConfigProp.SelectKey())
-				productConfigEnablingTargets = append(productConfigEnablingTargets, bazel.Label{
-					Label: targetLabel,
-				})
-			} else {
-				// TODO(b/210546943): handle negative case where `enabled: false`
-				ctx.ModuleErrorf("`enabled: false` is not currently supported for configuration variables. See b/210546943", proptools.PropertyNameForField(propName))
-			}
-		}
-	}
-
-	return productConfigEnablingTargets
-}
-
 // 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
@@ -1490,14 +842,19 @@
 
 	noAddressSanitizer   bool
 	installFiles         InstallPaths
-	installFilesDepSet   *installPathsDepSet
+	installFilesDepSet   *DepSet[InstallPath]
 	checkbuildFiles      Paths
 	packagingSpecs       []PackagingSpec
-	packagingSpecsDepSet *packagingSpecsDepSet
+	packagingSpecsDepSet *DepSet[PackagingSpec]
 	// 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
@@ -1520,84 +877,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) {
-	m.commonProperties.BazelConversionStatus.Bp2buildInfo = append(m.commonProperties.BazelConversionStatus.Bp2buildInfo, info)
-}
-
-// IsConvertedByBp2build returns whether this module was converted via bp2build.
-func (m *ModuleBase) IsConvertedByBp2build() bool {
-	return len(m.commonProperties.BazelConversionStatus.Bp2buildInfo) > 0
-}
-
-// 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{}) {
@@ -2062,9 +1354,9 @@
 
 // computeInstallDeps finds the installed paths of all dependencies that have a dependency
 // tag that is annotated as needing installation via the isInstallDepNeeded method.
-func (m *ModuleBase) computeInstallDeps(ctx ModuleContext) ([]*installPathsDepSet, []*packagingSpecsDepSet) {
-	var installDeps []*installPathsDepSet
-	var packagingSpecs []*packagingSpecsDepSet
+func (m *ModuleBase) computeInstallDeps(ctx ModuleContext) ([]*DepSet[InstallPath], []*DepSet[PackagingSpec]) {
+	var installDeps []*DepSet[InstallPath]
+	var packagingSpecs []*DepSet[PackagingSpec]
 	ctx.VisitDirectDeps(func(dep Module) {
 		if isInstallDepNeeded(dep, ctx.OtherModuleDependencyTag(dep)) {
 			// Installation is still handled by Make, so anything hidden from Make is not
@@ -2136,6 +1428,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)
 }
@@ -2341,14 +1641,31 @@
 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{
+		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,
@@ -2363,7 +1680,7 @@
 	// set m.installFilesDepSet to only the transitive dependencies to be used as the dependencies
 	// of installed files of this module.  It will be replaced by a depset including the installed
 	// files of this module at the end for use by modules that depend on this one.
-	m.installFilesDepSet = newInstallPathsDepSet(nil, dependencyInstallFiles)
+	m.installFilesDepSet = NewDepSet[InstallPath](TOPOLOGICAL, nil, dependencyInstallFiles)
 
 	// Temporarily continue to call blueprintCtx.GetMissingDependencies() to maintain the previous behavior of never
 	// reporting missing dependency errors in Blueprint when AllowMissingDependencies == true.
@@ -2389,7 +1706,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)
 	}
 
@@ -2411,34 +1728,58 @@
 		// 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)
-		}
+		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
@@ -2455,6 +1796,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
@@ -2470,23 +1812,93 @@
 		}
 	}
 
-	m.installFilesDepSet = newInstallPathsDepSet(m.installFiles, dependencyInstallFiles)
-	m.packagingSpecsDepSet = newPackagingSpecsDepSet(m.packagingSpecs, dependencyPackagingSpecs)
+	m.installFilesDepSet = NewDepSet[InstallPath](TOPOLOGICAL, m.installFiles, dependencyInstallFiles)
+	m.packagingSpecsDepSet = NewDepSet[PackagingSpec](TOPOLOGICAL, m.packagingSpecs, dependencyPackagingSpecs)
 
 	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) {
-			return mixedBuildMod, true
+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.
@@ -2515,163 +1927,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
@@ -2715,499 +1970,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)
-	}
-}
-
-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 (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() {
@@ -3231,272 +1993,16 @@
 	return proptools.Bool(m.commonProperties.Native_bridge_supported)
 }
 
-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) 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 ...Path) InstallPath {
-	return m.installFile(installPath, name, srcPath, deps, false, nil)
-}
-
-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, 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
+// 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
 		}
-
-		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,
-	})
-
-	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"
@@ -3705,46 +2211,10 @@
 	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() {
-	RegisterSingletonType("buildtarget", BuildTargetSingleton)
+	RegisterParallelSingletonType("buildtarget", BuildTargetSingleton)
+	RegisterParallelSingletonType("soongconfigtrace", soongConfigTraceSingletonFunc)
+	FinalDepsMutators(registerSoongConfigTraceMutator)
 }
 
 func BuildTargetSingleton() Singleton {
@@ -3907,22 +2377,53 @@
 	return blueprint.CheckBlueprintSyntax(bpctx.ModuleFactories(), filename, contents)
 }
 
-// installPathsDepSet is a thin type-safe wrapper around the generic depSet.  It always uses
-// topological order.
-type installPathsDepSet struct {
-	depSet
+func registerSoongConfigTraceMutator(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("soongconfigtrace", soongConfigTraceMutator).Parallel()
 }
 
-// newInstallPathsDepSet returns an immutable packagingSpecsDepSet with the given direct and
-// transitive contents.
-func newInstallPathsDepSet(direct InstallPaths, transitive []*installPathsDepSet) *installPathsDepSet {
-	return &installPathsDepSet{*newDepSet(TOPOLOGICAL, direct, transitive)}
+// soongConfigTraceMutator accumulates recorded soong_config trace from children. Also it normalizes
+// SoongConfigTrace to make it consistent.
+func soongConfigTraceMutator(ctx BottomUpMutatorContext) {
+	trace := &ctx.Module().base().commonProperties.SoongConfigTrace
+	ctx.VisitDirectDeps(func(m Module) {
+		childTrace := &m.base().commonProperties.SoongConfigTrace
+		trace.Bools = append(trace.Bools, childTrace.Bools...)
+		trace.Strings = append(trace.Strings, childTrace.Strings...)
+		trace.IsSets = append(trace.IsSets, childTrace.IsSets...)
+	})
+	trace.Bools = SortedUniqueStrings(trace.Bools)
+	trace.Strings = SortedUniqueStrings(trace.Strings)
+	trace.IsSets = SortedUniqueStrings(trace.IsSets)
+
+	ctx.Module().base().commonProperties.SoongConfigTraceHash = trace.hash()
 }
 
-// ToList returns the installPathsDepSet flattened to a list in topological order.
-func (d *installPathsDepSet) ToList() InstallPaths {
-	if d == nil {
-		return nil
+// soongConfigTraceSingleton writes a map from each module's config hash value to trace data.
+func soongConfigTraceSingletonFunc() Singleton {
+	return &soongConfigTraceSingleton{}
+}
+
+type soongConfigTraceSingleton struct {
+}
+
+func (s *soongConfigTraceSingleton) GenerateBuildActions(ctx SingletonContext) {
+	outFile := PathForOutput(ctx, "soong_config_trace.json")
+
+	traces := make(map[string]*soongConfigTrace)
+	ctx.VisitAllModules(func(module Module) {
+		trace := &module.base().commonProperties.SoongConfigTrace
+		if !trace.isEmpty() {
+			hash := module.base().commonProperties.SoongConfigTraceHash
+			traces[hash] = trace
+		}
+	})
+
+	j, err := json.Marshal(traces)
+	if err != nil {
+		ctx.Errorf("json marshal to %q failed: %#v", outFile, err)
+		return
 	}
-	return d.depSet.ToList().(InstallPaths)
+
+	WriteFileRule(ctx, outFile, string(j))
+	ctx.Phony("soong_config_trace", outFile)
 }
diff --git a/android/module_context.go b/android/module_context.go
new file mode 100644
index 0000000..1cab630
--- /dev/null
+++ b/android/module_context.go
@@ -0,0 +1,716 @@
+// 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
+}
+
+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,
+	}
+	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,
+	})
+
+	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) 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 0afa767..22e9160 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -15,8 +15,6 @@
 package android
 
 import (
-	"android/soong/bazel"
-
 	"github.com/google/blueprint"
 )
 
@@ -29,41 +27,6 @@
 //   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 {
@@ -95,9 +58,8 @@
 }
 
 type registerMutatorsContext struct {
-	mutators            sortableComponents
-	finalPhase          bool
-	bazelConversionMode bool
+	mutators   sortableComponents
+	finalPhase bool
 }
 
 type RegisterMutatorsContext interface {
@@ -220,21 +182,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
 
@@ -254,25 +201,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)
-
-	// 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)
 }
 
 type topDownMutatorContext struct {
@@ -397,7 +325,7 @@
 	// 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{})
 }
 
 type bottomUpMutatorContext struct {
@@ -407,10 +335,9 @@
 }
 
 func bottomUpMutatorContextFactory(ctx blueprint.BottomUpMutatorContext, a Module,
-	finalPhase, bazelConversionMode bool) BottomUpMutatorContext {
+	finalPhase bool) BottomUpMutatorContext {
 
 	moduleContext := a.base().baseModuleContextFactory(ctx)
-	moduleContext.bazelConversionMode = bazelConversionMode
 
 	return &bottomUpMutatorContext{
 		bp:                ctx,
@@ -421,10 +348,9 @@
 
 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))
+			m(bottomUpMutatorContextFactory(ctx, a, finalPhase))
 		}
 	}
 	mutator := &mutator{name: x.mutatorName(name), bottomUpMutator: f}
@@ -439,15 +365,21 @@
 }
 
 type IncomingTransitionContext interface {
+	ArchModuleContext
+
 	// 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
+
 	// Module returns the target of the dependency edge for which the transition
 	// is being computed
 	Module() Module
@@ -455,9 +387,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.
 //
@@ -522,18 +459,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.
@@ -541,15 +478,13 @@
 }
 
 type androidTransitionMutator struct {
-	finalPhase          bool
-	bazelConversionMode bool
-	mutator             TransitionMutator
+	finalPhase bool
+	mutator    TransitionMutator
 }
 
 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{""}
@@ -557,6 +492,7 @@
 }
 
 type outgoingTransitionContextImpl struct {
+	archModuleContext
 	bp blueprint.OutgoingTransitionContext
 }
 
@@ -568,15 +504,28 @@
 	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 (a *androidTransitionMutator) OutgoingTransition(bpctx blueprint.OutgoingTransitionContext, sourceVariation string) string {
+	if m, ok := bpctx.Module().(Module); ok {
+		ctx := &outgoingTransitionContextImpl{
+			archModuleContext: m.base().archModuleContextFactory(bpctx),
+			bp:                bpctx,
+		}
+		return a.mutator.OutgoingTransition(ctx, sourceVariation)
 	} else {
 		return ""
 	}
 }
 
 type incomingTransitionContextImpl struct {
+	archModuleContext
 	bp blueprint.IncomingTransitionContext
 }
 
@@ -588,9 +537,17 @@
 	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 (a *androidTransitionMutator) IncomingTransition(bpctx blueprint.IncomingTransitionContext, incomingVariation string) string {
+	if m, ok := bpctx.Module().(Module); ok {
+		ctx := &incomingTransitionContextImpl{
+			archModuleContext: m.base().archModuleContextFactory(bpctx),
+			bp:                bpctx,
+		}
+		return a.mutator.IncomingTransition(ctx, incomingVariation)
 	} else {
 		return ""
 	}
@@ -598,15 +555,14 @@
 
 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)
+		a.mutator.Mutate(bottomUpMutatorContextFactory(ctx, am, a.finalPhase), variation)
 	}
 }
 
 func (x *registerMutatorsContext) Transition(name string, m TransitionMutator) {
 	atm := &androidTransitionMutator{
-		finalPhase:          x.finalPhase,
-		bazelConversionMode: x.bazelConversionMode,
-		mutator:             m,
+		finalPhase: x.finalPhase,
+		mutator:    m,
 	}
 	mutator := &mutator{
 		name:              name,
@@ -615,9 +571,6 @@
 }
 
 func (x *registerMutatorsContext) mutatorName(name string) string {
-	if x.bazelConversionMode {
-		return name + "_bp2build"
-	}
 	return name
 }
 
@@ -625,7 +578,6 @@
 	f := func(ctx blueprint.TopDownMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
 			moduleContext := a.base().baseModuleContextFactory(ctx)
-			moduleContext.bazelConversionMode = x.bazelConversionMode
 			actx := &topDownMutatorContext{
 				bp:                ctx,
 				baseModuleContext: moduleContext,
@@ -690,141 +642,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)
-}
-
-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)
-}
-
-// 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:             t.OtherModuleDir(mod),
-		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
@@ -863,10 +680,16 @@
 }
 
 func (b *bottomUpMutatorContext) AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module {
+	if b.baseModuleContext.checkedMissingDeps() {
+		panic("Adding deps not allowed after checking for missing deps")
+	}
 	return b.bp.AddDependency(module, tag, name...)
 }
 
 func (b *bottomUpMutatorContext) AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string) {
+	if b.baseModuleContext.checkedMissingDeps() {
+		panic("Adding deps not allowed after checking for missing deps")
+	}
 	b.bp.AddReverseDependency(module, tag, name)
 }
 
@@ -916,11 +739,17 @@
 
 func (b *bottomUpMutatorContext) AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag,
 	names ...string) []blueprint.Module {
+	if b.baseModuleContext.checkedMissingDeps() {
+		panic("Adding deps not allowed after checking for missing deps")
+	}
 	return b.bp.AddVariationDependencies(variations, tag, names...)
 }
 
 func (b *bottomUpMutatorContext) AddFarVariationDependencies(variations []blueprint.Variation,
 	tag blueprint.DependencyTag, names ...string) []blueprint.Module {
+	if b.baseModuleContext.checkedMissingDeps() {
+		panic("Adding deps not allowed after checking for missing deps")
+	}
 
 	return b.bp.AddFarVariationDependencies(variations, tag, names...)
 }
@@ -930,10 +759,16 @@
 }
 
 func (b *bottomUpMutatorContext) ReplaceDependencies(name string) {
+	if b.baseModuleContext.checkedMissingDeps() {
+		panic("Adding deps not allowed after checking for missing deps")
+	}
 	b.bp.ReplaceDependencies(name)
 }
 
 func (b *bottomUpMutatorContext) ReplaceDependenciesIf(name string, predicate blueprint.ReplaceDependencyPredicate) {
+	if b.baseModuleContext.checkedMissingDeps() {
+		panic("Adding deps not allowed after checking for missing deps")
+	}
 	b.bp.ReplaceDependenciesIf(name, predicate)
 }
 
@@ -945,6 +780,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 2139c3c..62c5e59 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -55,11 +55,11 @@
 	AddNeverAllowRules(createJavaDeviceForHostRules()...)
 	AddNeverAllowRules(createCcSdkVariantRules()...)
 	AddNeverAllowRules(createUncompressDexRules()...)
-	AddNeverAllowRules(createMakefileGoalRules()...)
 	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",
 	}
 
@@ -236,24 +230,12 @@
 	}
 }
 
-func createMakefileGoalRules() []Rule {
-	allowlist := []string{
-		// libwifi_hal uses makefile_goal for its dependencies
-		"frameworks/opt/net/wifi/libwifi_hal",
-	}
-	return []Rule{
-		NeverAllow().
-			ModuleType("makefile_goal").
-			WithoutMatcher("product_out_path", Regexp("^boot[0-9a-zA-Z.-]*[.]img$")).
-			NotIn(allowlist...).
-			Because("Only boot images may be imported as a makefile goal if not in allowed projects"),
-	}
-}
-
 func createInitFirstStageRules() []Rule {
 	return []Rule{
 		NeverAllow().
+			Without("name", "init_first_stage_defaults").
 			Without("name", "init_first_stage").
+			Without("name", "init_first_stage.microdroid").
 			With("install_in_root", "true").
 			Because("install_in_root is only for init_first_stage."),
 	}
@@ -268,6 +250,21 @@
 	}
 }
 
+func createJavaExcludeStaticLibsRule() Rule {
+	return NeverAllow().
+		NotIn("build/soong", "libcore", "frameworks/base/api").
+		ModuleType("java_library").
+		WithMatcher("exclude_static_libs", isSetMatcherInstance).
+		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 5f5f9a1..b2620ef 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -313,45 +313,6 @@
 			"module \"outside_art_libraries\": violates neverallow",
 		},
 	},
-	{
-		name: "disallowed makefile_goal",
-		fs: map[string][]byte{
-			"Android.bp": []byte(`
-				makefile_goal {
-					name: "foo",
-					product_out_path: "boot/trap.img"
-				}
-			`),
-		},
-		expectedErrors: []string{
-			"Only boot images.* may be imported as a makefile goal",
-		},
-	},
-	{
-		name: "disallowed makefile_goal outside external",
-		fs: map[string][]byte{
-			"project/Android.bp": []byte(`
-				makefile_goal {
-					name: "foo",
-					product_out_path: "obj/EXE/foo",
-				}
-			`),
-		},
-		expectedErrors: []string{
-			"not in allowed projects",
-		},
-	},
-	{
-		name: "allow makefile_goal within external",
-		fs: map[string][]byte{
-			"frameworks/opt/net/wifi/libwifi_hal/Android.bp": []byte(`
-				makefile_goal {
-					name: "foo",
-					product_out_path: "obj/EXE/foo",
-				}
-			`),
-		},
-	},
 	// Tests for the rule prohibiting the use of framework
 	{
 		name: "prohibit framework",
@@ -383,6 +344,38 @@
 			`module "outside_allowed_list": violates neverallow`,
 		},
 	},
+	// Test for the rule restricting use of exclude_static_libs
+	{
+		name: `"exclude_static_libs" outside allowed directory`,
+		fs: map[string][]byte{
+			"a/b/Android.bp": []byte(`
+				java_library {
+					name: "baz",
+					exclude_static_libs: [
+						"bar",
+					],
+				}
+			`),
+		},
+		expectedErrors: []string{
+			`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(
@@ -391,7 +384,6 @@
 		ctx.RegisterModuleType("java_library", newMockJavaLibraryModule)
 		ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule)
 		ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule)
-		ctx.RegisterModuleType("makefile_goal", newMockMakefileGoalModule)
 	}),
 )
 
@@ -470,9 +462,11 @@
 }
 
 type mockJavaLibraryProperties struct {
-	Libs           []string
-	Sdk_version    *string
-	Uncompress_dex *bool
+	Libs                []string
+	Sdk_version         *string
+	Uncompress_dex      *bool
+	Exclude_static_libs []string
+	Headers_only        *bool
 }
 
 type mockJavaLibraryModule struct {
@@ -489,22 +483,3 @@
 
 func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
 }
-
-type mockMakefileGoalProperties struct {
-	Product_out_path *string
-}
-
-type mockMakefileGoalModule struct {
-	ModuleBase
-	properties mockMakefileGoalProperties
-}
-
-func newMockMakefileGoalModule() Module {
-	m := &mockMakefileGoalModule{}
-	m.AddProperties(&m.properties)
-	InitAndroidModule(m)
-	return m
-}
-
-func (p *mockMakefileGoalModule) GenerateAndroidBuildActions(ModuleContext) {
-}
diff --git a/android/ninja_deps.go b/android/ninja_deps.go
index 2f442d5..1d50a47 100644
--- a/android/ninja_deps.go
+++ b/android/ninja_deps.go
@@ -14,7 +14,10 @@
 
 package android
 
-import "sort"
+import (
+	"android/soong/starlark_import"
+	"sort"
+)
 
 func (c *config) addNinjaFileDeps(deps ...string) {
 	for _, dep := range deps {
@@ -40,4 +43,11 @@
 
 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 2d30a85..1341f53 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -28,7 +28,6 @@
 // module based on it.
 
 import (
-	"fmt"
 	"sort"
 	"sync"
 
@@ -47,8 +46,8 @@
 
 	// Internal funcs to handle interoperability between override modules and prebuilts.
 	// i.e. cases where an overriding module, too, is overridden by a prebuilt module.
-	setOverriddenByPrebuilt(overridden bool)
-	getOverriddenByPrebuilt() bool
+	setOverriddenByPrebuilt(prebuilt Module)
+	getOverriddenByPrebuilt() Module
 
 	// Directory containing the Blueprint definition of the overriding module
 	setModuleDir(string)
@@ -61,7 +60,7 @@
 
 	overridingProperties []interface{}
 
-	overriddenByPrebuilt bool
+	overriddenByPrebuilt Module
 
 	moduleDir string
 }
@@ -97,11 +96,11 @@
 	return proptools.String(o.moduleProperties.Base)
 }
 
-func (o *OverrideModuleBase) setOverriddenByPrebuilt(overridden bool) {
-	o.overriddenByPrebuilt = overridden
+func (o *OverrideModuleBase) setOverriddenByPrebuilt(prebuilt Module) {
+	o.overriddenByPrebuilt = prebuilt
 }
 
-func (o *OverrideModuleBase) getOverriddenByPrebuilt() bool {
+func (o *OverrideModuleBase) getOverriddenByPrebuilt() Module {
 	return o.overriddenByPrebuilt
 }
 
@@ -121,7 +120,7 @@
 	addOverride(o OverrideModule)
 	getOverrides() []OverrideModule
 
-	override(ctx BaseModuleContext, o OverrideModule)
+	override(ctx BaseModuleContext, m Module, o OverrideModule)
 	GetOverriddenBy() string
 	GetOverriddenByModuleDir() string
 
@@ -192,7 +191,8 @@
 }
 
 // Overrides a base module with the given OverrideModule.
-func (b *OverridableModuleBase) override(ctx BaseModuleContext, o OverrideModule) {
+func (b *OverridableModuleBase) override(ctx BaseModuleContext, m Module, o OverrideModule) {
+
 	for _, p := range b.overridableProperties {
 		for _, op := range o.getOverridingProperties() {
 			if proptools.TypeEqual(p, op) {
@@ -270,7 +270,7 @@
 				panic("PrebuiltDepTag leads to a non-prebuilt module " + dep.Name())
 			}
 			if prebuilt.UsePrebuilt() {
-				module.setOverriddenByPrebuilt(true)
+				module.setOverriddenByPrebuilt(dep)
 				return
 			}
 		})
@@ -302,10 +302,13 @@
 		// is specified.
 		ctx.AliasVariation(variants[0])
 		for i, o := range overrides {
-			mods[i+1].(OverridableModule).override(ctx, o)
-			if o.getOverriddenByPrebuilt() {
-				// The overriding module itself, too, is overridden by a prebuilt. Skip its installation.
-				mods[i+1].HideFromMake()
+			mods[i+1].(OverridableModule).override(ctx, mods[i+1], o)
+			if prebuilt := o.getOverriddenByPrebuilt(); prebuilt != nil {
+				// The overriding module itself, too, is overridden by a prebuilt.
+				// Perform the same check for replacement
+				checkInvariantsForSourceAndPrebuilt(ctx, mods[i+1], prebuilt)
+				// Copy the flag and hide it in make
+				mods[i+1].ReplacedByPrebuilt()
 			}
 		}
 	} else if o, ok := ctx.Module().(OverrideModule); ok {
@@ -334,39 +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 {
-	if overridable, ok := ctx.Module().(OverridableModule); ok {
-		if o := overridable.GetOverriddenBy(); o != "" {
-			return o
-		}
-	}
-	return ctx.OtherModuleName(ctx.Module())
-}
-
-// ModuleDirWithPossibleOverride returns the dir 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 moduleDirWithPossibleOverride(ctx BazelConversionContext) string {
-	if overridable, ok := ctx.Module().(OverridableModule); ok {
-		if o := overridable.GetOverriddenByModuleDir(); o != "" {
-			return o
-		}
-	}
-	return ctx.OtherModuleDir(ctx.Module())
-}
-
-// MaybeBp2buildLabelOfOverridingModule returns the bazel label of the
-// overriding module of an OverridableModule (e.g. override_apex label of a base
-// apex), or the module's label itself if not overridden.
-func MaybeBp2buildLabelOfOverridingModule(ctx BazelConversionContext) string {
-	moduleName := ModuleNameWithPossibleOverride(ctx)
-	moduleDir := moduleDirWithPossibleOverride(ctx)
-	if moduleDir == Bp2BuildTopLevel {
-		moduleDir = ""
-	}
-	return fmt.Sprintf("//%s:%s", moduleDir, moduleName)
-}
diff --git a/android/package.go b/android/package.go
index 682b350..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"
 )
@@ -41,52 +38,12 @@
 	Default_team                *string `android:"path"`
 }
 
-type bazelPackageAttributes struct {
-	Default_visibility       []string
-	Default_package_metadata bazel.LabelListAttribute
-}
-
 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.
 }
@@ -110,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
@@ -127,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 c764a6d..8873540 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"path/filepath"
+	"strings"
 
 	"github.com/google/blueprint"
 )
@@ -239,7 +240,14 @@
 // 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 +255,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
 }
 
@@ -282,23 +293,3 @@
 	builder.Build("zip_deps", fmt.Sprintf("Zipping deps for %s", ctx.ModuleName()))
 	return entries
 }
-
-// packagingSpecsDepSet is a thin type-safe wrapper around the generic depSet.  It always uses
-// topological order.
-type packagingSpecsDepSet struct {
-	depSet
-}
-
-// newPackagingSpecsDepSet returns an immutable packagingSpecsDepSet with the given direct and
-// transitive contents.
-func newPackagingSpecsDepSet(direct []PackagingSpec, transitive []*packagingSpecsDepSet) *packagingSpecsDepSet {
-	return &packagingSpecsDepSet{*newDepSet(TOPOLOGICAL, direct, transitive)}
-}
-
-// ToList returns the packagingSpecsDepSet flattened to a list in topological order.
-func (d *packagingSpecsDepSet) ToList() []PackagingSpec {
-	if d == nil {
-		return nil
-	}
-	return d.depSet.ToList().([]PackagingSpec)
-}
diff --git a/android/path_properties.go b/android/path_properties.go
index fdc4d91..bbfaa8c 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)
 }
diff --git a/android/paths.go b/android/paths.go
index eaa6a8d..95f53ea 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...)
@@ -396,7 +453,7 @@
 //
 // Properties passed as the paths argument must have been annotated with struct tag
 // `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
-// path_deps mutator.
+// pathdeps mutator.
 // If a requested module is not found as a dependency:
 //   - if ctx.Config().AllowMissingDependencies() is true, this module to be marked as having
 //     missing dependencies
@@ -425,7 +482,7 @@
 // excluding the items (similarly resolved
 // Properties passed as the paths argument must have been annotated with struct tag
 // `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
-// path_deps mutator.
+// pathdeps mutator.
 // If a requested module is not found as a dependency:
 //   - if ctx.Config().AllowMissingDependencies() is true, this module to be marked as having
 //     missing dependencies
@@ -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)
 }
@@ -560,7 +617,7 @@
 // and a list of the module names of missing module dependencies are returned as the second return.
 // Properties passed as the paths argument must have been annotated with struct tag
 // `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
-// path_deps mutator.
+// pathdeps mutator.
 func PathsAndMissingDepsForModuleSrcExcludes(ctx ModuleMissingDepsPathContext, paths, excludes []string) (Paths, []string) {
 	return PathsAndMissingDepsRelativeToModuleSourceDir(SourceInput{
 		Context:      ctx,
@@ -1029,16 +1086,16 @@
 	return p
 }
 
+func (p basePath) RelativeToTop() Path {
+	ensureTestOnly()
+	return p
+}
+
 // SourcePath is a Path representing a file path rooted from SrcDir
 type SourcePath struct {
 	basePath
 }
 
-func (p SourcePath) RelativeToTop() Path {
-	ensureTestOnly()
-	return p
-}
-
 var _ Path = SourcePath{}
 
 func (p SourcePath) withRel(rel string) SourcePath {
@@ -1126,6 +1183,16 @@
 	return path
 }
 
+// PathForArbitraryOutput creates a path for the given components. Unlike PathForOutput,
+// the path is relative to the root of the output folder, not the out/soong folder.
+func PathForArbitraryOutput(ctx PathContext, pathComponents ...string) Path {
+	p, err := validatePath(pathComponents...)
+	if err != nil {
+		reportPathError(ctx, err)
+	}
+	return basePath{path: filepath.Join(ctx.Config().OutDir(), p)}
+}
+
 // MaybeExistentPathForSource joins the provided path components and validates that the result
 // neither escapes the source dir nor is in the out dir.
 // It does not validate whether the path exists.
@@ -1472,10 +1539,11 @@
 	ModuleName() string
 	ModuleDir() string
 	ModuleSubDir() string
+	SoongConfigTraceHash() string
 }
 
 func pathForModuleOut(ctx ModuleOutPathContext) OutputPath {
-	return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir())
+	return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir(), ctx.SoongConfigTraceHash())
 }
 
 // PathForModuleOut returns a Path representing the paths... under the module's
@@ -1672,20 +1740,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) {
@@ -1701,12 +1769,7 @@
 	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 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
@@ -1736,9 +1799,6 @@
 		}
 		partitionPaths = []string{"host", osName + "-" + archName, partition}
 	}
-	if debug {
-		partitionPaths = append([]string{"debug"}, partitionPaths...)
-	}
 
 	partitionPath, err := validatePath(partitionPaths...)
 	if err != nil {
@@ -1782,12 +1842,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() {
@@ -1821,11 +1881,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()
@@ -1870,7 +1930,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)
 		}
@@ -1879,11 +1941,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
@@ -2005,6 +2081,9 @@
 	inDebugRamdisk  bool
 	inRecovery      bool
 	inRoot          bool
+	inOdm           bool
+	inProduct       bool
+	inVendor        bool
 	forceOS         *OsType
 	forceArch       *ArchType
 }
@@ -2047,6 +2126,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
 }
@@ -2147,6 +2238,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.
@@ -2195,23 +2299,3 @@
 	}
 	return false
 }
-
-// PathsDepSet is a thin type-safe wrapper around the generic depSet.  It always uses
-// topological order.
-type PathsDepSet struct {
-	depSet
-}
-
-// newPathsDepSet returns an immutable PathsDepSet with the given direct and
-// transitive contents.
-func newPathsDepSet(direct Paths, transitive []*PathsDepSet) *PathsDepSet {
-	return &PathsDepSet{*newDepSet(TOPOLOGICAL, direct, transitive)}
-}
-
-// ToList returns the PathsDepSet flattened to a list in topological order.
-func (d *PathsDepSet) ToList() Paths {
-	if d == nil {
-		return nil
-	}
-	return d.depSet.ToList().(Paths)
-}
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
new file mode 100644
index 0000000..d62fc94
--- /dev/null
+++ b/android/plugin.go
@@ -0,0 +1,140 @@
+// 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 (
+	"encoding/json"
+	"os"
+	"strings"
+
+	"github.com/google/blueprint"
+)
+
+func init() {
+	RegisterPluginSingletonBuildComponents(InitRegistrationContext)
+}
+
+func RegisterPluginSingletonBuildComponents(ctx RegistrationContext) {
+	ctx.RegisterParallelSingletonType("plugins", pluginSingletonFactory)
+}
+
+// pluginSingleton is a singleton to handle allowlisting of the final Android-<product_name>.mk file
+// output.
+func pluginSingletonFactory() Singleton {
+	return &pluginSingleton{}
+}
+
+type pluginSingleton struct{}
+
+var allowedPluginsByName = map[string]bool{
+	"aidl-soong-rules":                       true,
+	"arm_compute_library_nn_driver":          true,
+	"cuttlefish-soong-rules":                 true,
+	"gki-soong-rules":                        true,
+	"hidl-soong-rules":                       true,
+	"kernel-config-soong-rules":              true,
+	"soong-angle-codegen":                    true,
+	"soong-api":                              true,
+	"soong-art":                              true,
+	"soong-ca-certificates":                  true,
+	"soong-ca-certificates-apex":             true,
+	"soong-clang":                            true,
+	"soong-clang-prebuilts":                  true,
+	"soong-csuite":                           true,
+	"soong-fluoride":                         true,
+	"soong-fs_config":                        true,
+	"soong-icu":                              true,
+	"soong-java-config-error_prone":          true,
+	"soong-libchrome":                        true,
+	"soong-llvm":                             true,
+	"soong-robolectric":                      true,
+	"soong-rust-prebuilts":                   true,
+	"soong-selinux":                          true,
+	"soong-wayland-protocol-codegen":         true,
+	"treble_report_app":                      true,
+	"treble_report_local":                    true,
+	"treble_report_module":                   true,
+	"vintf-compatibility-matrix-soong-rules": true,
+	"xsdc-soong-rules":                       true,
+}
+
+var internalPluginsPaths = []string{
+	"vendor/google/build/soong/internal_plugins.json",
+}
+
+type pluginProvider interface {
+	IsPluginFor(string) bool
+}
+
+func maybeAddInternalPluginsToAllowlist(ctx SingletonContext) {
+	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
+			}
+		}
+	}
+}
+
+func (p *pluginSingleton) GenerateBuildActions(ctx SingletonContext) {
+	for _, p := range ctx.DeviceConfig().BuildBrokenPluginValidation() {
+		allowedPluginsByName[p] = true
+	}
+	maybeAddInternalPluginsToAllowlist(ctx)
+
+	disallowedPlugins := map[string]bool{}
+	ctx.VisitAllModulesBlueprint(func(module blueprint.Module) {
+		if ctx.ModuleType(module) != "bootstrap_go_package" {
+			return
+		}
+
+		p, ok := module.(pluginProvider)
+		if !ok || !p.IsPluginFor("soong_build") {
+			return
+		}
+
+		name := ctx.ModuleName(module)
+		if _, ok := allowedPluginsByName[name]; ok {
+			return
+		}
+
+		dir := ctx.ModuleDir(module)
+
+		// allow use of plugins within Soong to not allowlist everything
+		if strings.HasPrefix(dir, "build/soong") {
+			return
+		}
+
+		// allow third party users outside of external to create new plugins, i.e. non-google paths
+		// under vendor or hardware
+		if !strings.HasPrefix(dir, "external/") && IsThirdPartyPath(dir) {
+			return
+		}
+		disallowedPlugins[name] = true
+	})
+	if len(disallowedPlugins) > 0 {
+		ctx.Errorf("New plugins are not supported; however %q were found. Please reach out to the build team or use BUILD_BROKEN_PLUGIN_VALIDATION (see Changes.md for more info).", SortedStringKeys(disallowedPlugins))
+	}
+}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 9b5c0e9..a94f5b7 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -277,6 +277,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 +390,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,22 +416,51 @@
 
 // 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")
+		}
+
+	}
+}
+
+// checkInvariantsForSourceAndPrebuilt checks if invariants are kept when replacing
+// source with prebuilt. Note that the current module for the context is the source module.
+func checkInvariantsForSourceAndPrebuilt(ctx BaseModuleContext, s, p Module) {
+	if _, ok := s.(OverrideModule); ok {
+		// skip the check when the source module is `override_X` because it's only a placeholder
+		// for the actual source module. The check will be invoked for the actual module.
+		return
+	}
+	if sourcePartition, prebuiltPartition := s.PartitionTag(ctx.DeviceConfig()), p.PartitionTag(ctx.DeviceConfig()); sourcePartition != prebuiltPartition {
+		ctx.OtherModuleErrorf(p, "partition is different: %s(%s) != %s(%s)",
+			sourcePartition, ctx.ModuleName(), prebuiltPartition, ctx.OtherModuleName(p))
 	}
 }
 
 // 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 == "" {
@@ -430,14 +469,73 @@
 		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) {
+				checkInvariantsForSourceAndPrebuilt(ctx, s, prebuiltModule)
+
 				p.properties.UsePrebuilt = true
 				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 psi.IsSelected(moduleInFamily.Name()) {
+			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()
+			}
+		}
 	}
 }
 
@@ -447,7 +545,8 @@
 func PrebuiltPostDepsMutator(ctx BottomUpMutatorContext) {
 	m := ctx.Module()
 	if p := GetEmbeddedPrebuilt(m); p != nil {
-		name := m.base().BaseModuleName()
+		bmn, _ := m.(baseModuleName)
+		name := bmn.BaseModuleName()
 		if p.properties.UsePrebuilt {
 			if p.properties.SourceExists {
 				ctx.ReplaceDependenciesIf(name, func(from blueprint.Module, tag blueprint.DependencyTag, to blueprint.Module) bool {
@@ -464,9 +563,64 @@
 	}
 }
 
+// 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
+		if sln == m.base().BaseModuleName() {
+			return false
+		}
+
+		// Stub library created by java_sdk_library_import
+		if p := GetEmbeddedPrebuilt(m); p != nil {
+			return psi.IsSelected(PrebuiltNameFromSource(sln))
+		}
+
+		// Stub library created by java_sdk_library
+		return psi.IsSelected(sln)
+	}
+	return psi.IsSelected(m.Name())
+}
+
 // 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 {
+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) {
+		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.srcsSupplier != nil && len(p.srcsSupplier(ctx, prebuilt)) == 0 {
 		return false
 	}
diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go
index e5edf91..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,7 +101,7 @@
 
 // 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 {
+func NewPrebuiltBuildTool() Module {
 	module := &prebuiltBuildTool{}
 	module.AddProperties(&module.properties)
 	InitSingleSourcePrebuiltModule(module, &module.properties, "Src")
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index fa40d1f..4a69628 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -335,6 +335,78 @@
 			prebuilt: []OsType{Android, buildOS},
 		},
 		{
+			name: "apex_contributions supersedes any source preferred via use_source_config_var",
+			modules: `
+				source {
+					name: "bar",
+				}
+
+				prebuilt {
+					name: "bar",
+					use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
+					srcs: ["prebuilt_file"],
+				}
+				apex_contributions {
+					name: "my_mainline_module_contribution",
+					api_domain: "apexfoo",
+					// this metadata module contains prebuilt
+					contents: ["prebuilt_bar"],
+				}
+				all_apex_contributions {
+					name: "all_apex_contributions",
+				}
+				`,
+			preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+				variables.VendorVars = map[string]map[string]string{
+					"acme": {
+						"use_source": "true",
+					},
+				}
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contribution",
+				}
+			}),
+			// use_source_config_var indicates that source should be used
+			// but this is superseded by `my_mainline_module_contribution`
+			prebuilt: []OsType{Android, buildOS},
+		},
+		{
+			name: "apex_contributions supersedes any prebuilt preferred via use_source_config_var",
+			modules: `
+				source {
+					name: "bar",
+				}
+
+				prebuilt {
+					name: "bar",
+					use_source_config_var: {config_namespace: "acme", var_name: "use_source"},
+					srcs: ["prebuilt_file"],
+				}
+				apex_contributions {
+					name: "my_mainline_module_contribution",
+					api_domain: "apexfoo",
+					// this metadata module contains source
+					contents: ["bar"],
+				}
+				all_apex_contributions {
+					name: "all_apex_contributions",
+				}
+				`,
+			preparer: FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+				variables.VendorVars = map[string]map[string]string{
+					"acme": {
+						"use_source": "false",
+					},
+				}
+				variables.BuildFlags = map[string]string{
+					"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "my_mainline_module_contribution",
+				}
+			}),
+			// use_source_config_var indicates that prebuilt should be used
+			// but this is superseded by `my_mainline_module_contribution`
+			prebuilt: nil,
+		},
+		{
 			name: "prebuilt use_source_config_var={acme, use_source} - acme_use_source=true",
 			modules: `
 				source {
@@ -497,6 +569,58 @@
 	}
 }
 
+func testPrebuiltErrorWithFixture(t *testing.T, expectedError, bp string, fixture FixturePreparer) {
+	t.Helper()
+	fs := MockFS{
+		"prebuilt_file": nil,
+	}
+	GroupFixturePreparers(
+		PrepareForTestWithArchMutator,
+		PrepareForTestWithPrebuilts,
+		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) {
+	testPrebuiltError(t, `partition is different`, `
+		source {
+			name: "foo",
+			vendor: true,
+		}
+		prebuilt {
+			name: "foo",
+			prefer: true,
+			srcs: ["prebuilt_file"],
+		}`)
+}
+
+func TestPrebuiltShouldNotChangePartition_WithOverride(t *testing.T) {
+	testPrebuiltError(t, `partition is different`, `
+		source {
+			name: "foo",
+			vendor: true,
+		}
+		override_source {
+			name: "bar",
+			base: "foo",
+		}
+		prebuilt {
+			name: "bar",
+			prefer: true,
+			srcs: ["prebuilt_file"],
+		}`)
+}
+
 func registerTestPrebuiltBuildComponents(ctx RegistrationContext) {
 	registerTestPrebuiltModules(ctx)
 
@@ -513,6 +637,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 {
@@ -607,3 +732,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 cebbd59..0d8e097 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -17,8 +17,6 @@
 import (
 	"strings"
 
-	"android/soong/bazel"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -152,102 +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
-	Name       string
-	Proto_libs bazel.LabelList
-}
-
-type ProtoAttrs struct {
-	Srcs                bazel.LabelListAttribute
-	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",
-}
-
-// 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)
-		}
-	}
-
-	info.Name = m.Name() + "_proto"
-
-	if len(directProtoSrcs.Includes) > 0 {
-		attrs := ProtoAttrs{
-			Srcs: bazel.MakeLabelListAttribute(directProtoSrcs),
-		}
-		attrs.Deps.Append(bazel.MakeLabelListAttribute(protoLibraries))
-
-		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
-
-					if !proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) {
-						// 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())
-
-		ctx.CreateBazelTargetModule(
-			bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
-			CommonAttributes{Name: info.Name, Tags: tags},
-			&attrs,
-		)
-
-		protoLibraries.Add(&bazel.Label{
-			Label: ":" + info.Name,
-		})
-	}
-
-	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 1a3db9d..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,19 +61,15 @@
 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
 
 	name    string
 	factory SingletonFactory
 }
 
-func newSingleton(name string, factory SingletonFactory) singleton {
-	return singleton{false, name, factory}
-}
-
-func newPreSingleton(name string, factory SingletonFactory) singleton {
-	return singleton{true, name, factory}
+func newSingleton(name string, factory SingletonFactory, parallel bool) singleton {
+	return singleton{parallel: parallel, name: name, factory: factory}
 }
 
 func (s singleton) componentName() string {
@@ -83,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)
-	}
+	ctx.RegisterSingletonType(s.name, adaptor, s.parallel)
 }
 
 var _ sortableComponent = singleton{}
 
 var singletons sortableComponents
-var preSingletons sortableComponents
 
 type mutator struct {
 	name              string
@@ -145,12 +135,16 @@
 	moduleTypeByFactory[factory] = name
 }
 
-func RegisterSingletonType(name string, factory SingletonFactory) {
-	singletons = append(singletons, newSingleton(name, factory))
+func registerSingletonType(name string, factory SingletonFactory, parallel bool) {
+	singletons = append(singletons, newSingleton(name, factory, parallel))
 }
 
-func RegisterPreSingletonType(name string, factory SingletonFactory) {
-	preSingletons = append(preSingletons, newPreSingleton(name, factory))
+func RegisterSingletonType(name string, factory SingletonFactory) {
+	registerSingletonType(name, factory, false)
+}
+
+func RegisterParallelSingletonType(name string, factory SingletonFactory) {
+	registerSingletonType(name, factory, true)
 }
 
 type Context struct {
@@ -166,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)
 	}
@@ -220,17 +185,16 @@
 func collateGloballyRegisteredSingletons() sortableComponents {
 	allSingletons := append(sortableComponents(nil), singletons...)
 	allSingletons = append(allSingletons,
-		singleton{false, "bazeldeps", BazelSingleton},
-
 		// Register phony just before makevars so it can write out its phony rules as Make rules
-		singleton{false, "phony", phonySingletonFactory},
+		singleton{parallel: false, name: "phony", factory: phonySingletonFactory},
 
 		// Register makevars after other singletons so they can export values through makevars
-		singleton{false, "makevars", 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{false, "ninjadeps", ninjaDepsSingletonFactory},
+		singleton{parallel: false, name: "rawfiles", factory: rawFilesSingletonFactory},
+		singleton{parallel: false, name: "ninjadeps", factory: ninjaDepsSingletonFactory},
 	)
 
 	return allSingletons
@@ -259,7 +223,8 @@
 type RegistrationContext interface {
 	RegisterModuleType(name string, factory ModuleFactory)
 	RegisterSingletonModuleType(name string, factory SingletonModuleFactory)
-	RegisterPreSingletonType(name string, factory SingletonFactory)
+	RegisterParallelSingletonModuleType(name string, factory SingletonModuleFactory)
+	RegisterParallelSingletonType(name string, factory SingletonFactory)
 	RegisterSingletonType(name string, factory SingletonFactory)
 	PreArchMutators(f RegisterMutatorFunc)
 
@@ -290,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.
@@ -301,7 +265,6 @@
 type initRegistrationContext struct {
 	moduleTypes        map[string]ModuleFactory
 	singletonTypes     map[string]SingletonFactory
-	preSingletonTypes  map[string]SingletonFactory
 	moduleTypesForDocs map[string]reflect.Value
 }
 
@@ -315,8 +278,15 @@
 }
 
 func (ctx *initRegistrationContext) RegisterSingletonModuleType(name string, factory SingletonModuleFactory) {
+	ctx.registerSingletonModuleType(name, factory, false)
+}
+func (ctx *initRegistrationContext) RegisterParallelSingletonModuleType(name string, factory SingletonModuleFactory) {
+	ctx.registerSingletonModuleType(name, factory, true)
+}
+
+func (ctx *initRegistrationContext) registerSingletonModuleType(name string, factory SingletonModuleFactory, parallel bool) {
 	s, m := SingletonModuleFactoryAdaptor(name, factory)
-	ctx.RegisterSingletonType(name, s)
+	ctx.registerSingletonType(name, s, parallel)
 	ctx.RegisterModuleType(name, m)
 	// Overwrite moduleTypesForDocs with the original factory instead of the lambda returned by
 	// SingletonModuleFactoryAdaptor so that docs can find the module type documentation on the
@@ -324,20 +294,20 @@
 	RegisterModuleTypeForDocs(name, reflect.ValueOf(factory))
 }
 
-func (ctx *initRegistrationContext) RegisterSingletonType(name string, factory SingletonFactory) {
+func (ctx *initRegistrationContext) registerSingletonType(name string, factory SingletonFactory, parallel bool) {
 	if _, present := ctx.singletonTypes[name]; present {
 		panic(fmt.Sprintf("singleton type %q is already registered", name))
 	}
 	ctx.singletonTypes[name] = factory
-	RegisterSingletonType(name, factory)
+	registerSingletonType(name, factory, parallel)
 }
 
-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) RegisterSingletonType(name string, factory SingletonFactory) {
+	ctx.registerSingletonType(name, factory, false)
+}
+
+func (ctx *initRegistrationContext) RegisterParallelSingletonType(name string, factory SingletonFactory) {
+	ctx.registerSingletonType(name, factory, true)
 }
 
 func (ctx *initRegistrationContext) PreArchMutators(f RegisterMutatorFunc) {
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 155fbdf..e8dbd48 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -53,6 +53,7 @@
 	remoteable       RemoteRuleSupports
 	rbeParams        *remoteexec.REParams
 	outDir           WritablePath
+	sboxOutSubDir    string
 	sboxTools        bool
 	sboxInputs       bool
 	sboxManifestPath WritablePath
@@ -65,9 +66,18 @@
 		pctx:           pctx,
 		ctx:            ctx,
 		temporariesSet: make(map[WritablePath]bool),
+		sboxOutSubDir:  sboxOutSubDir,
 	}
 }
 
+// SetSboxOutDirDirAsEmpty sets the out subdirectory to an empty string
+// This is useful for sandboxing actions that change the execution root to a path in out/ (e.g mixed builds)
+// For such actions, SetSboxOutDirDirAsEmpty ensures that the path does not become $SBOX_SANDBOX_DIR/out/out/bazel/output/execroot/__main__/...
+func (rb *RuleBuilder) SetSboxOutDirDirAsEmpty() *RuleBuilder {
+	rb.sboxOutSubDir = ""
+	return rb
+}
+
 // RuleBuilderInstall is a tuple of install from and to locations.
 type RuleBuilderInstall struct {
 	From Path
@@ -326,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 {
@@ -464,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,
@@ -570,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),
 						},
 					},
@@ -582,12 +567,10 @@
 
 		// Add copy rules to the manifest to copy each output file from the sbox directory.
 		// to the output directory after running the commands.
-		sboxOutputs := make([]string, len(outputs))
-		for i, output := range outputs {
+		for _, output := range outputs {
 			rel := Rel(r.ctx, r.outDir.String(), output.String())
-			sboxOutputs[i] = filepath.Join(sboxOutDir, rel)
 			command.CopyAfter = append(command.CopyAfter, &sbox_proto.Copy{
-				From: proto.String(filepath.Join(sboxOutSubDir, rel)),
+				From: proto.String(filepath.Join(r.sboxOutSubDir, rel)),
 				To:   proto.String(output.String()),
 			})
 		}
@@ -611,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
@@ -715,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),
@@ -730,7 +741,6 @@
 		Validations:     r.Validations(),
 		Output:          output,
 		ImplicitOutputs: implicitOutputs,
-		SymlinkOutputs:  r.SymlinkOutputs(),
 		Depfile:         depFile,
 		Deps:            depFormat,
 		Description:     desc,
@@ -744,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 {
@@ -826,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
@@ -846,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
 		}
@@ -1178,42 +1187,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
@@ -1296,9 +1269,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 63e0bbe..6d5293e 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -830,6 +830,9 @@
 	// IsTargetBuildBeforeTiramisu return true if the target build release for which this snapshot is
 	// being generated is before Tiramisu, i.e. S.
 	IsTargetBuildBeforeTiramisu() bool
+
+	// ModuleErrorf reports an error at the line number of the module type in the module definition.
+	ModuleErrorf(fmt string, args ...interface{})
 }
 
 // ExportedComponentsInfo contains information about the components that this module exports to an
@@ -857,11 +860,11 @@
 	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]()
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 0ae8073..9355667 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:
@@ -84,22 +88,6 @@
 	}
 }
 
-// JavaLibraryName returns the soong module containing the Java APIs of that API surface.
-func (k SdkKind) JavaLibraryName(c Config) string {
-	name := k.DefaultJavaLibraryName()
-	return JavaApiLibraryName(c, name)
-}
-
-// JavaApiLibraryName returns the name of .txt equivalent of a java_library, but does
-// not check if either module exists.
-// TODO: Return .txt (single-tree or multi-tree equivalents) based on config
-func JavaApiLibraryName(c Config, name string) string {
-	if c.BuildFromTextStub() {
-		return name + ".from-text"
-	}
-	return name
-}
-
 func (k SdkKind) DefaultJavaLibraryName() string {
 	switch k {
 	case SdkPublic:
@@ -108,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:
@@ -119,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
@@ -153,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))
@@ -173,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
 	}
@@ -201,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
 		}
@@ -282,6 +295,8 @@
 			kind = SdkSystem
 		case "test":
 			kind = SdkTest
+		case "test_frameworks_core":
+			kind = SdkTestFrameworksCore
 		case "module":
 			kind = SdkModule
 		case "system_server":
@@ -298,39 +313,89 @@
 	}
 }
 
+// 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)
 }
 
 // Export the name of the soong modules representing the various Java API surfaces.
 func javaSdkMakeVars(ctx MakeVarsContext) {
-	ctx.Strict("ANDROID_PUBLIC_STUBS", SdkPublic.JavaLibraryName(ctx.Config()))
-	ctx.Strict("ANDROID_SYSTEM_STUBS", SdkSystem.JavaLibraryName(ctx.Config()))
-	ctx.Strict("ANDROID_TEST_STUBS", SdkTest.JavaLibraryName(ctx.Config()))
-	ctx.Strict("ANDROID_MODULE_LIB_STUBS", SdkModule.JavaLibraryName(ctx.Config()))
-	ctx.Strict("ANDROID_SYSTEM_SERVER_STUBS", SdkSystemServer.JavaLibraryName(ctx.Config()))
-	// TODO (jihoonkang): Create a .txt equivalent for core.current.stubs
-	ctx.Strict("ANDROID_CORE_STUBS", SdkCore.JavaLibraryName(ctx.Config()))
+	ctx.Strict("ANDROID_PUBLIC_STUBS", SdkPublic.DefaultJavaLibraryName())
+	ctx.Strict("ANDROID_SYSTEM_STUBS", SdkSystem.DefaultJavaLibraryName())
+	ctx.Strict("ANDROID_TEST_STUBS", SdkTest.DefaultJavaLibraryName())
+	ctx.Strict("ANDROID_MODULE_LIB_STUBS", SdkModule.DefaultJavaLibraryName())
+	ctx.Strict("ANDROID_SYSTEM_SERVER_STUBS", SdkSystemServer.DefaultJavaLibraryName())
+	ctx.Strict("ANDROID_CORE_STUBS", SdkCore.DefaultJavaLibraryName())
 }
diff --git a/android/sdk_version_test.go b/android/sdk_version_test.go
index ea99c4d..30bd002 100644
--- a/android/sdk_version_test.go
+++ b/android/sdk_version_test.go
@@ -75,7 +75,7 @@
 
 	config := NullConfig("", "")
 
-	config.productVariables = productVariables{
+	config.productVariables = ProductVariables{
 		Platform_sdk_version:              intPtr(31),
 		Platform_sdk_codename:             stringPtr("Tiramisu"),
 		Platform_version_active_codenames: []string{"Tiramisu"},
diff --git a/android/singleton.go b/android/singleton.go
index 7c6cf4f..e0e552e 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{})
@@ -135,6 +129,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 +170,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) {
@@ -282,3 +275,7 @@
 	}
 	return result
 }
+
+func (s *singletonContextAdaptor) moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
+	return s.SingletonContext.ModuleProvider(module, provider)
+}
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 5fa6012..90b49eb 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)
@@ -187,7 +188,6 @@
 
 type soongConfigModuleTypeModule struct {
 	ModuleBase
-	BazelModuleBase
 	properties soongconfig.ModuleTypeProperties
 }
 
@@ -304,6 +304,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 +327,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 +348,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 +415,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 +422,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))
@@ -421,9 +437,60 @@
 	}).(map[string]blueprint.ModuleFactory)
 }
 
+// tracingConfig is a wrapper to soongconfig.SoongConfig which records all accesses to SoongConfig.
+type tracingConfig struct {
+	config    soongconfig.SoongConfig
+	boolSet   map[string]bool
+	stringSet map[string]string
+	isSetSet  map[string]bool
+}
+
+func (c *tracingConfig) Bool(name string) bool {
+	c.boolSet[name] = c.config.Bool(name)
+	return c.boolSet[name]
+}
+
+func (c *tracingConfig) String(name string) string {
+	c.stringSet[name] = c.config.String(name)
+	return c.stringSet[name]
+}
+
+func (c *tracingConfig) IsSet(name string) bool {
+	c.isSetSet[name] = c.config.IsSet(name)
+	return c.isSetSet[name]
+}
+
+func (c *tracingConfig) getTrace() soongConfigTrace {
+	ret := soongConfigTrace{}
+
+	for k, v := range c.boolSet {
+		ret.Bools = append(ret.Bools, fmt.Sprintf("%q:%t", k, v))
+	}
+	for k, v := range c.stringSet {
+		ret.Strings = append(ret.Strings, fmt.Sprintf("%q:%q", k, v))
+	}
+	for k, v := range c.isSetSet {
+		ret.IsSets = append(ret.IsSets, fmt.Sprintf("%q:%t", k, v))
+	}
+
+	return ret
+}
+
+func newTracingConfig(config soongconfig.SoongConfig) *tracingConfig {
+	c := tracingConfig{
+		config:    config,
+		boolSet:   make(map[string]bool),
+		stringSet: make(map[string]string),
+		isSetSet:  make(map[string]bool),
+	}
+	return &c
+}
+
+var _ soongconfig.SoongConfig = (*tracingConfig)(nil)
+
 // 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
@@ -464,38 +531,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) {
-				config := ctx.Config().VendorConfig(moduleType.ConfigNamespace)
-				newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, config)
-				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()
+		})
 		return module, props
 	}
 }
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index cab3e2d..a6b2c51 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"path/filepath"
 	"testing"
 )
 
@@ -34,7 +35,8 @@
 type soongConfigTestModule struct {
 	ModuleBase
 	DefaultableModuleBase
-	props soongConfigTestModuleProperties
+	props      soongConfigTestModuleProperties
+	outputPath ModuleOutPath
 }
 
 type soongConfigTestModuleProperties struct {
@@ -49,7 +51,9 @@
 	return m
 }
 
-func (t soongConfigTestModule) GenerateAndroidBuildActions(ModuleContext) {}
+func (t *soongConfigTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+	t.outputPath = PathForModuleOut(ctx, "test")
+}
 
 var prepareForSoongConfigTestModule = FixtureRegisterWithContext(func(ctx RegistrationContext) {
 	ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
@@ -372,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)
 }
 
@@ -503,3 +506,197 @@
 		})
 	}
 }
+
+func TestSoongConfigModuleTrace(t *testing.T) {
+	bp := `
+		soong_config_module_type {
+			name: "acme_test",
+			module_type: "test",
+			config_namespace: "acme",
+			variables: ["board", "feature1", "FEATURE3", "unused_string_var"],
+			bool_variables: ["feature2", "unused_feature", "always_true"],
+			value_variables: ["size", "unused_size"],
+			properties: ["cflags", "srcs", "defaults"],
+		}
+
+		soong_config_module_type {
+			name: "acme_test_defaults",
+			module_type: "test_defaults",
+			config_namespace: "acme",
+			variables: ["board", "feature1", "FEATURE3", "unused_string_var"],
+			bool_variables: ["feature2", "unused_feature", "always_true"],
+			value_variables: ["size", "unused_size"],
+			properties: ["cflags", "srcs", "defaults"],
+		}
+
+		soong_config_string_variable {
+			name: "board",
+			values: ["soc_a", "soc_b", "soc_c"],
+		}
+
+		soong_config_string_variable {
+			name: "unused_string_var",
+			values: ["a", "b"],
+		}
+
+		soong_config_bool_variable {
+			name: "feature1",
+		}
+
+		soong_config_bool_variable {
+			name: "FEATURE3",
+		}
+
+		test_defaults {
+			name: "test_defaults",
+			cflags: ["DEFAULT"],
+		}
+
+		test {
+			name: "normal",
+			defaults: ["test_defaults"],
+		}
+
+		acme_test {
+			name: "board_1",
+			defaults: ["test_defaults"],
+			soong_config_variables: {
+				board: {
+					soc_a: {
+						cflags: ["-DSOC_A"],
+					},
+				},
+			},
+		}
+
+		acme_test {
+			name: "board_2",
+			defaults: ["test_defaults"],
+			soong_config_variables: {
+				board: {
+					soc_a: {
+						cflags: ["-DSOC_A"],
+					},
+				},
+			},
+		}
+
+		acme_test {
+			name: "size",
+			defaults: ["test_defaults"],
+			soong_config_variables: {
+				size: {
+					cflags: ["-DSIZE=%s"],
+				},
+			},
+		}
+
+		acme_test {
+			name: "board_and_size",
+			defaults: ["test_defaults"],
+			soong_config_variables: {
+				board: {
+					soc_a: {
+						cflags: ["-DSOC_A"],
+					},
+				},
+				size: {
+					cflags: ["-DSIZE=%s"],
+				},
+			},
+		}
+
+		acme_test_defaults {
+			name: "board_defaults",
+			soong_config_variables: {
+				board: {
+					soc_a: {
+						cflags: ["-DSOC_A"],
+					},
+				},
+			},
+		}
+
+		acme_test_defaults {
+			name: "size_defaults",
+			soong_config_variables: {
+				size: {
+					cflags: ["-DSIZE=%s"],
+				},
+			},
+		}
+
+		test {
+			name: "board_and_size_with_defaults",
+			defaults: ["board_defaults", "size_defaults"],
+		}
+    `
+
+	fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer {
+		return FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+			variables.VendorVars = vars
+		})
+	}
+
+	preparer := fixtureForVendorVars(map[string]map[string]string{
+		"acme": {
+			"board":    "soc_a",
+			"size":     "42",
+			"feature1": "true",
+			"feature2": "false",
+			// FEATURE3 unset
+			"unused_feature":    "true", // unused
+			"unused_size":       "1",    // unused
+			"unused_string_var": "a",    // unused
+			"always_true":       "true",
+		},
+	})
+
+	t.Run("soong config trace hash", func(t *testing.T) {
+		result := GroupFixturePreparers(
+			preparer,
+			PrepareForTestWithDefaults,
+			PrepareForTestWithSoongConfigModuleBuildComponents,
+			prepareForSoongConfigTestModule,
+			FixtureRegisterWithContext(func(ctx RegistrationContext) {
+				ctx.FinalDepsMutators(registerSoongConfigTraceMutator)
+			}),
+			FixtureWithRootAndroidBp(bp),
+		).RunTest(t)
+
+		// Hashes of modules not using soong config should be empty
+		normal := result.ModuleForTests("normal", "").Module().(*soongConfigTestModule)
+		AssertDeepEquals(t, "normal hash", normal.base().commonProperties.SoongConfigTraceHash, "")
+		AssertDeepEquals(t, "normal hash out", normal.outputPath.RelativeToTop().String(), "out/soong/.intermediates/normal/test")
+
+		board1 := result.ModuleForTests("board_1", "").Module().(*soongConfigTestModule)
+		board2 := result.ModuleForTests("board_2", "").Module().(*soongConfigTestModule)
+		size := result.ModuleForTests("size", "").Module().(*soongConfigTestModule)
+
+		// Trace mutator sets soong config trace hash correctly
+		board1Hash := board1.base().commonProperties.SoongConfigTrace.hash()
+		board1Output := board1.outputPath.RelativeToTop().String()
+		AssertDeepEquals(t, "board hash calc", board1Hash, board1.base().commonProperties.SoongConfigTraceHash)
+		AssertDeepEquals(t, "board hash path", board1Output, filepath.Join("out/soong/.intermediates/board_1", board1Hash, "test"))
+
+		sizeHash := size.base().commonProperties.SoongConfigTrace.hash()
+		sizeOutput := size.outputPath.RelativeToTop().String()
+		AssertDeepEquals(t, "size hash calc", sizeHash, size.base().commonProperties.SoongConfigTraceHash)
+		AssertDeepEquals(t, "size hash path", sizeOutput, filepath.Join("out/soong/.intermediates/size", sizeHash, "test"))
+
+		// Trace should be identical for modules using the same set of variables
+		AssertDeepEquals(t, "board trace", board1.base().commonProperties.SoongConfigTrace, board2.base().commonProperties.SoongConfigTrace)
+		AssertDeepEquals(t, "board hash", board1.base().commonProperties.SoongConfigTraceHash, board2.base().commonProperties.SoongConfigTraceHash)
+
+		// Trace hash should be different for different sets of soong variables
+		AssertBoolEquals(t, "board hash not equal to size hash", board1.base().commonProperties.SoongConfigTraceHash == size.commonProperties.SoongConfigTraceHash, false)
+
+		boardSize := result.ModuleForTests("board_and_size", "").Module().(*soongConfigTestModule)
+		boardSizeDefaults := result.ModuleForTests("board_and_size_with_defaults", "").Module()
+
+		// Trace should propagate
+		AssertDeepEquals(t, "board_size hash calc", boardSize.base().commonProperties.SoongConfigTrace.hash(), boardSize.base().commonProperties.SoongConfigTraceHash)
+		AssertDeepEquals(t, "board_size trace", boardSize.base().commonProperties.SoongConfigTrace, boardSizeDefaults.base().commonProperties.SoongConfigTrace)
+		AssertDeepEquals(t, "board_size hash", boardSize.base().commonProperties.SoongConfigTraceHash, boardSizeDefaults.base().commonProperties.SoongConfigTraceHash)
+	})
+}
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index 23c8afa..d525bdc 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"
@@ -236,110 +233,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.
@@ -796,6 +689,7 @@
 				continue
 			}
 			field = field.Elem()
+			kind = field.Kind()
 		}
 		switch kind {
 		case reflect.String:
diff --git a/android/soongconfig/modules_test.go b/android/soongconfig/modules_test.go
index a5fa349..db2c83c 100644
--- a/android/soongconfig/modules_test.go
+++ b/android/soongconfig/modules_test.go
@@ -299,7 +299,7 @@
 	Conditions_default *properties
 }
 
-type soongConfigVars struct {
+type boolSoongConfigVars struct {
 	Bool_var interface{}
 }
 
@@ -307,7 +307,11 @@
 	String_var interface{}
 }
 
-func Test_PropertiesToApply(t *testing.T) {
+type valueSoongConfigVars struct {
+	My_value_var interface{}
+}
+
+func Test_PropertiesToApply_Bool(t *testing.T) {
 	mt, _ := newModuleType(&ModuleTypeProperties{
 		Module_type:      "foo",
 		Config_namespace: "bar",
@@ -323,9 +327,9 @@
 		B: false,
 	}
 	actualProps := &struct {
-		Soong_config_variables soongConfigVars
+		Soong_config_variables boolSoongConfigVars
 	}{
-		Soong_config_variables: soongConfigVars{
+		Soong_config_variables: boolSoongConfigVars{
 			Bool_var: &boolVarProps{
 				A:                  boolVarPositive.A,
 				B:                  boolVarPositive.B,
@@ -369,6 +373,62 @@
 	}
 }
 
+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: &boolVarProps{
+				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_String_Error(t *testing.T) {
 	mt, _ := newModuleType(&ModuleTypeProperties{
 		Module_type:      "foo",
@@ -413,220 +473,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_proto/Android.bp b/android/team_proto/Android.bp
index 061e77e..7e2a4c1 100644
--- a/android/team_proto/Android.bp
+++ b/android/team_proto/Android.bp
@@ -27,3 +27,17 @@
         "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/test_asserts.go b/android/test_asserts.go
index 5cc7e4a..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)
 	}
 }
 
@@ -200,6 +200,22 @@
 	}
 }
 
+// Asserts that each of the Paths in actual end with the corresponding string
+// from expected. Useful to test that output paths contain expected items without
+// hard-coding where intermediate files might be located.
+func AssertPathsEndWith(t *testing.T, message string, expected []string, actual []Path) {
+	t.Helper()
+	if len(expected) != len(actual) {
+		t.Errorf("%s (length): expected %d, actual %d", message, len(expected), len(actual))
+		return
+	}
+	for i := range expected {
+		if !strings.HasSuffix(actual[i].String(), expected[i]) {
+			t.Errorf("%s (item %d): expected '%s', actual '%s'", message, i, expected[i], actual[i].String())
+		}
+	}
+}
+
 // AssertDeepEquals checks if the expected and actual values are equal using reflect.DeepEqual and
 // if they are not then it reports an error prefixed with the supplied message and including a
 // reason for why it failed.
diff --git a/android/test_config.go b/android/test_config.go
index 28d9ec4..a15343a 100644
--- a/android/test_config.go
+++ b/android/test_config.go
@@ -35,15 +35,16 @@
 	envCopy["PATH"] = os.Getenv("PATH")
 
 	config := &config{
-		productVariables: productVariables{
+		productVariables: ProductVariables{
 			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 b570b23..adcc15a 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -15,7 +15,7 @@
 package android
 
 func init() {
-	RegisterSingletonType("testsuites", testSuiteFilesFactory)
+	RegisterParallelSingletonType("testsuites", testSuiteFilesFactory)
 }
 
 func testSuiteFilesFactory() Singleton {
@@ -24,6 +24,7 @@
 
 type testSuiteFiles struct {
 	robolectric WritablePath
+	ravenwood   WritablePath
 }
 
 type TestSuiteModule interface {
@@ -47,12 +48,15 @@
 	})
 
 	t.robolectric = robolectricTestSuite(ctx, files["robolectric-tests"])
-
 	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("ravenwood-tests", t.ravenwood)
 }
 
 func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) WritablePath {
@@ -60,7 +64,7 @@
 	for _, module := range SortedKeys(files) {
 		installedPaths = append(installedPaths, files[module]...)
 	}
-	testCasesDir := pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases", false)
+	testCasesDir := pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases")
 
 	outputFile := PathForOutput(ctx, "packaging", "robolectric-tests.zip")
 	rule := NewRuleBuilder(pctx, ctx)
@@ -68,8 +72,29 @@
 		FlagWithOutput("-o ", outputFile).
 		FlagWithArg("-P ", "host/testcases").
 		FlagWithArg("-C ", testCasesDir.String()).
-		FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths())
+		FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths()).
+		Flag("-sha256")
 	rule.Build("robolectric_tests_zip", "robolectric-tests.zip")
 
 	return outputFile
 }
+
+func ravenwoodTestSuite(ctx SingletonContext, files map[string]InstallPaths) WritablePath {
+	var installedPaths InstallPaths
+	for _, module := range SortedKeys(files) {
+		installedPaths = append(installedPaths, files[module]...)
+	}
+	testCasesDir := pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases")
+
+	outputFile := PathForOutput(ctx, "packaging", "ravenwood-tests.zip")
+	rule := NewRuleBuilder(pctx, ctx)
+	rule.Command().BuiltTool("soong_zip").
+		FlagWithOutput("-o ", outputFile).
+		FlagWithArg("-P ", "host/testcases").
+		FlagWithArg("-C ", testCasesDir.String()).
+		FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths()).
+		Flag("-sha256")
+	rule.Build("ravenwood_tests_zip", "ravenwood-tests.zip")
+
+	return outputFile
+}
diff --git a/android/testing.go b/android/testing.go
index 2a9c658..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.
@@ -495,12 +466,18 @@
 	ctx.RegisterModuleType(name, m)
 }
 
-func (ctx *TestContext) RegisterSingletonType(name string, factory SingletonFactory) {
-	ctx.singletons = append(ctx.singletons, newSingleton(name, factory))
+func (ctx *TestContext) RegisterParallelSingletonModuleType(name string, factory SingletonModuleFactory) {
+	s, m := SingletonModuleFactoryAdaptor(name, factory)
+	ctx.RegisterParallelSingletonType(name, s)
+	ctx.RegisterModuleType(name, m)
 }
 
-func (ctx *TestContext) RegisterPreSingletonType(name string, factory SingletonFactory) {
-	ctx.preSingletons = append(ctx.preSingletons, newPreSingleton(name, factory))
+func (ctx *TestContext) RegisterSingletonType(name string, factory SingletonFactory) {
+	ctx.singletons = append(ctx.singletons, newSingleton(name, factory, false))
+}
+
+func (ctx *TestContext) RegisterParallelSingletonType(name string, factory SingletonFactory) {
+	ctx.singletons = append(ctx.singletons, newSingleton(name, factory, true))
 }
 
 // ModuleVariantForTests selects a specific variant of the module with the given
@@ -748,7 +725,6 @@
 //   - Depfile
 //   - Rspfile
 //   - RspfileContent
-//   - SymlinkOutputs
 //   - CommandDeps
 //   - CommandOrderOnly
 //
@@ -770,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)
@@ -789,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)
 
@@ -1148,6 +1121,7 @@
 	}
 
 	entriesList := p.AndroidMkEntries()
+	aconfigUpdateAndroidMkEntries(ctx, mod.(Module), &entriesList)
 	for i, _ := range entriesList {
 		entriesList[i].fillInEntries(ctx, mod)
 	}
@@ -1163,6 +1137,7 @@
 	}
 	data := p.AndroidMk()
 	data.fillInData(ctx, mod)
+	aconfigUpdateAndroidMkData(ctx, mod.(Module), &data)
 	return data
 }
 
@@ -1305,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 db45637..1548170 100644
--- a/android/updatable_modules.go
+++ b/android/updatable_modules.go
@@ -33,4 +33,4 @@
 // * AOSP            - xx9990000
 // * x-mainline-prod - xx9990000
 // * master          - 990090000
-const DefaultUpdatableModuleVersion = "349990000"
+const DefaultUpdatableModuleVersion = "990090000"
diff --git a/android/util.go b/android/util.go
index 08a3521..363b31c 100644
--- a/android/util.go
+++ b/android/util.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"cmp"
 	"fmt"
 	"path/filepath"
 	"reflect"
@@ -22,15 +23,16 @@
 	"runtime"
 	"sort"
 	"strings"
+	"sync"
 )
 
 // CopyOf returns a new slice that has the same contents as s.
-func CopyOf(s []string) []string {
+func CopyOf[T any](s []T) []T {
 	// If the input is nil, return nil and not an empty list
 	if s == nil {
 		return s
 	}
-	return append([]string{}, s...)
+	return append([]T{}, s...)
 }
 
 // Concat returns a new slice concatenated from the two input slices. It does not change the input
@@ -42,6 +44,16 @@
 	return res
 }
 
+// JoinPathsWithPrefix converts the paths to strings, prefixes them
+// with prefix and then joins them separated by " ".
+func JoinPathsWithPrefix(paths []Path, prefix string) string {
+	strs := make([]string, len(paths))
+	for i := range paths {
+		strs[i] = paths[i].String()
+	}
+	return JoinWithPrefixAndSeparator(strs, prefix, " ")
+}
+
 // JoinWithPrefix prepends the prefix to each string in the list and
 // returns them joined together with " " as separator.
 func JoinWithPrefix(strs []string, prefix string) string {
@@ -51,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()
 }
@@ -73,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
 	}
@@ -127,19 +154,17 @@
 }
 
 // IndexList returns the index of the first occurrence of the given string in the list or -1
-func IndexList(s string, list []string) int {
+func IndexList[T comparable](t T, list []T) int {
 	for i, l := range list {
-		if l == s {
+		if l == t {
 			return i
 		}
 	}
-
 	return -1
 }
 
-// InList checks if the string belongs to the list
-func InList(s string, list []string) bool {
-	return IndexList(s, list) != -1
+func InList[T comparable](t T, list []T) bool {
+	return IndexList(t, list) != -1
 }
 
 func setFromList[T comparable](l []T) map[T]bool {
@@ -278,44 +303,87 @@
 }
 
 // FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of
-// each.  It modifies the slice contents in place, and returns a subslice of the original slice.
+// each.  It does not modify the input slice.
 func FirstUniqueStrings(list []string) []string {
-	// Do not moodify the input in-place, operate on a copy instead.
-	list = CopyOf(list)
-	// 128 was chosen based on BenchmarkFirstUniqueStrings results.
-	if len(list) > 128 {
-		return firstUniqueStringsMap(list)
-	}
-	return firstUniqueStringsList(list)
+	return firstUnique(list)
 }
 
-func firstUniqueStringsList(list []string) []string {
-	k := 0
+// firstUnique returns all unique elements of a slice, keeping the first copy of each.  It
+// does not modify the input slice.
+func firstUnique[T comparable](slice []T) []T {
+	// Do not modify the input in-place, operate on a copy instead.
+	slice = CopyOf(slice)
+	return firstUniqueInPlace(slice)
+}
+
+// firstUniqueInPlace returns all unique elements of a slice, keeping the first copy of
+// each.  It modifies the slice contents in place, and returns a subslice of the original
+// slice.
+func firstUniqueInPlace[T comparable](slice []T) []T {
+	// 128 was chosen based on BenchmarkFirstUniqueStrings results.
+	if len(slice) > 128 {
+		return firstUniqueMap(slice)
+	}
+	return firstUniqueList(slice)
+}
+
+// firstUniqueList is an implementation of firstUnique using an O(N^2) list comparison to look for
+// duplicates.
+func firstUniqueList[T any](in []T) []T {
+	writeIndex := 0
 outer:
-	for i := 0; i < len(list); i++ {
-		for j := 0; j < k; j++ {
-			if list[i] == list[j] {
+	for readIndex := 0; readIndex < len(in); readIndex++ {
+		for compareIndex := 0; compareIndex < writeIndex; compareIndex++ {
+			if interface{}(in[readIndex]) == interface{}(in[compareIndex]) {
+				// The value at readIndex already exists somewhere in the output region
+				// of the slice before writeIndex, skip it.
 				continue outer
 			}
 		}
-		list[k] = list[i]
-		k++
+		if readIndex != writeIndex {
+			in[writeIndex] = in[readIndex]
+		}
+		writeIndex++
 	}
-	return list[:k]
+	return in[0:writeIndex]
 }
 
-func firstUniqueStringsMap(list []string) []string {
-	k := 0
-	seen := make(map[string]bool, len(list))
-	for i := 0; i < len(list); i++ {
-		if seen[list[i]] {
+// firstUniqueMap is an implementation of firstUnique using an O(N) hash set lookup to look for
+// duplicates.
+func firstUniqueMap[T comparable](in []T) []T {
+	writeIndex := 0
+	seen := make(map[T]bool, len(in))
+	for readIndex := 0; readIndex < len(in); readIndex++ {
+		if _, exists := seen[in[readIndex]]; exists {
 			continue
 		}
-		seen[list[i]] = true
-		list[k] = list[i]
-		k++
+		seen[in[readIndex]] = true
+		if readIndex != writeIndex {
+			in[writeIndex] = in[readIndex]
+		}
+		writeIndex++
 	}
-	return list[:k]
+	return in[0:writeIndex]
+}
+
+// ReverseSliceInPlace reverses the elements of a slice in place and returns it.
+func ReverseSliceInPlace[T any](in []T) []T {
+	for i, j := 0, len(in)-1; i < j; i, j = i+1, j-1 {
+		in[i], in[j] = in[j], in[i]
+	}
+	return in
+}
+
+// ReverseSlice returns a copy of a slice in reverse order.
+func ReverseSlice[T any](in []T) []T {
+	if in == nil {
+		return in
+	}
+	out := make([]T, len(in))
+	for i := 0; i < len(in); i++ {
+		out[i] = in[len(in)-1-i]
+	}
+	return out
 }
 
 // LastUniqueStrings returns all unique elements of a slice of strings, keeping the last copy of
@@ -518,3 +586,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 a2ef589..8e73d83 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -15,11 +15,13 @@
 package android
 
 import (
+	"cmp"
 	"fmt"
 	"reflect"
 	"strconv"
 	"strings"
 	"testing"
+	"unsafe"
 )
 
 var firstUniqueStringsTestCases = []struct {
@@ -74,10 +76,10 @@
 
 	for _, testCase := range firstUniqueStringsTestCases {
 		t.Run("list", func(t *testing.T) {
-			f(t, firstUniqueStringsList, testCase.in, testCase.out)
+			f(t, firstUniqueList[string], testCase.in, testCase.out)
 		})
 		t.Run("map", func(t *testing.T) {
-			f(t, firstUniqueStringsMap, testCase.in, testCase.out)
+			f(t, firstUniqueMap[string], testCase.in, testCase.out)
 		})
 	}
 }
@@ -385,7 +387,7 @@
 	emptyList := []string{}
 	copyOfEmptyList := CopyOf(emptyList)
 	AssertBoolEquals(t, "Copy of an empty list should be an empty list and not nil", true, copyOfEmptyList != nil)
-	copyOfNilList := CopyOf(nil)
+	copyOfNilList := CopyOf([]string(nil))
 	AssertBoolEquals(t, "Copy of a nil list should be a nil list and not an empty list", true, copyOfNilList == nil)
 }
 
@@ -604,11 +606,11 @@
 	}{
 		{
 			name: "list",
-			f:    firstUniqueStringsList,
+			f:    firstUniqueList[string],
 		},
 		{
 			name: "map",
-			f:    firstUniqueStringsMap,
+			f:    firstUniqueMap[string],
 		},
 		{
 			name: "optimal",
@@ -649,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)
@@ -754,3 +756,65 @@
 		})
 	}
 }
+
+var reverseTestCases = []struct {
+	name     string
+	in       []string
+	expected []string
+}{
+	{
+		name:     "nil",
+		in:       nil,
+		expected: nil,
+	},
+	{
+		name:     "empty",
+		in:       []string{},
+		expected: []string{},
+	},
+	{
+		name:     "one",
+		in:       []string{"one"},
+		expected: []string{"one"},
+	},
+	{
+		name:     "even",
+		in:       []string{"one", "two"},
+		expected: []string{"two", "one"},
+	},
+	{
+		name:     "odd",
+		in:       []string{"one", "two", "three"},
+		expected: []string{"three", "two", "one"},
+	},
+}
+
+func TestReverseSliceInPlace(t *testing.T) {
+	for _, testCase := range reverseTestCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			slice := CopyOf(testCase.in)
+			slice2 := slice
+			ReverseSliceInPlace(slice)
+			if !reflect.DeepEqual(slice, testCase.expected) {
+				t.Errorf("expected %#v, got %#v", testCase.expected, slice)
+			}
+			if unsafe.SliceData(slice) != unsafe.SliceData(slice2) {
+				t.Errorf("expected slices to share backing array")
+			}
+		})
+	}
+}
+
+func TestReverseSlice(t *testing.T) {
+	for _, testCase := range reverseTestCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			slice := ReverseSlice(testCase.in)
+			if !reflect.DeepEqual(slice, testCase.expected) {
+				t.Errorf("expected %#v, got %#v", testCase.expected, 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 aaf0606..a4917c5 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -20,7 +20,6 @@
 	"runtime"
 	"strings"
 
-	"android/soong/android/soongconfig"
 	"android/soong/bazel"
 
 	"github.com/google/blueprint/proptools"
@@ -74,6 +73,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"`
@@ -109,6 +109,11 @@
 			Cflags []string
 		}
 
+		Build_from_text_stub struct {
+			Static_libs         []string
+			Exclude_static_libs []string
+		}
+
 		// debuggable is true for eng and userdebug builds, and can be used to turn on additional
 		// debugging features that don't significantly impact runtime behavior.  userdebug builds
 		// are used for dogfooding and performance testing, and should be as similar to user builds
@@ -133,6 +138,7 @@
 
 			Srcs         []string
 			Exclude_srcs []string
+			Cmd          *string
 		}
 
 		// eng is true for -eng builds, and can be used to turn on additional heavyweight debugging
@@ -151,10 +157,6 @@
 			}
 		}
 
-		Pdk struct {
-			Enabled *bool `android:"arch_variant"`
-		} `android:"arch_variant"`
-
 		Uml struct {
 			Cppflags []string
 		}
@@ -170,21 +172,24 @@
 			Whole_static_libs []string `android:"arch_variant"`
 		} `android:"arch_variant"`
 
-		Flatten_apex struct {
-			Enabled *bool
-		}
-
 		Native_coverage struct {
 			Src          *string  `android:"arch_variant"`
 			Srcs         []string `android:"arch_variant"`
 			Exclude_srcs []string `android:"arch_variant"`
 		} `android:"arch_variant"`
+
+		// release_aidl_use_unfrozen is "true" when a device can
+		// use the unfrozen versions of AIDL interfaces.
+		Release_aidl_use_unfrozen struct {
+			Cflags []string
+			Cmd    *string
+		}
 	} `android:"arch_variant"`
 }
 
 var defaultProductVariables interface{} = variableProperties{}
 
-type productVariables struct {
+type ProductVariables struct {
 	// Suffix to add to generated Makefiles
 	Make_suffix *string `json:",omitempty"`
 
@@ -219,6 +224,9 @@
 	DeviceCurrentApiLevelForVendorModules *string  `json:",omitempty"`
 	DeviceSystemSdkVersions               []string `json:",omitempty"`
 	DeviceMaxPageSizeSupported            *string  `json:",omitempty"`
+	DeviceNoBionicPageSizeMacro           *bool    `json:",omitempty"`
+
+	VendorApiLevel *string `json:",omitempty"`
 
 	RecoverySnapshotVersion *string `json:",omitempty"`
 
@@ -286,6 +294,7 @@
 	Uml                          *bool    `json:",omitempty"`
 	Arc                          *bool    `json:",omitempty"`
 	MinimizeJavaDebugInfo        *bool    `json:",omitempty"`
+	Build_from_text_stub         *bool    `json:",omitempty"`
 
 	Check_elf_files *bool `json:",omitempty"`
 
@@ -308,6 +317,7 @@
 	MemtagHeapSyncIncludePaths  []string `json:",omitempty"`
 
 	HWASanIncludePaths []string `json:",omitempty"`
+	HWASanExcludePaths []string `json:",omitempty"`
 
 	VendorPath    *string `json:",omitempty"`
 	OdmPath       *string `json:",omitempty"`
@@ -365,17 +375,11 @@
 
 	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"`
@@ -391,7 +395,6 @@
 	Ndk_abis *bool `json:",omitempty"`
 
 	TrimmedApex                  *bool `json:",omitempty"`
-	Flatten_apex                 *bool `json:",omitempty"`
 	ForceApexSymlinkOptimization *bool `json:",omitempty"`
 	CompressedApex               *bool `json:",omitempty"`
 	Aml_abis                     *bool `json:",omitempty"`
@@ -400,9 +403,10 @@
 
 	WithDexpreopt bool `json:",omitempty"`
 
-	ManifestPackageNameOverrides []string `json:",omitempty"`
-	CertificateOverrides         []string `json:",omitempty"`
-	PackageNameOverrides         []string `json:",omitempty"`
+	ManifestPackageNameOverrides   []string `json:",omitempty"`
+	CertificateOverrides           []string `json:",omitempty"`
+	PackageNameOverrides           []string `json:",omitempty"`
+	ConfiguredJarLocationOverrides []string `json:",omitempty"`
 
 	ApexGlobalMinSdkVersionOverride *string `json:",omitempty"`
 
@@ -416,19 +420,13 @@
 	ProductPublicSepolicyDirs  []string `json:",omitempty"`
 	ProductPrivateSepolicyDirs []string `json:",omitempty"`
 
-	ProductVndkVersion *string `json:",omitempty"`
-
 	TargetFSConfigGen []string `json:",omitempty"`
 
-	MissingUsesLibraries []string `json:",omitempty"`
-
 	EnforceProductPartitionInterface *bool `json:",omitempty"`
 
 	EnforceInterPartitionJavaSdkLibrary *bool    `json:",omitempty"`
 	InterPartitionJavaLibraryAllowList  []string `json:",omitempty"`
 
-	InstallExtraFlattenedApexes *bool `json:",omitempty"`
-
 	BoardUsesRecoveryAsBoot *bool `json:",omitempty"`
 
 	BoardKernelBinaries                []string `json:",omitempty"`
@@ -440,15 +438,20 @@
 
 	ShippingApiLevel *string `json:",omitempty"`
 
-	BuildBrokenClangAsFlags            bool     `json:",omitempty"`
-	BuildBrokenClangCFlags             bool     `json:",omitempty"`
-	BuildBrokenClangProperty           bool     `json:",omitempty"`
-	BuildBrokenDepfile                 *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"`
 
 	BuildDebugfsRestrictionsEnabled bool `json:",omitempty"`
 
@@ -456,7 +459,7 @@
 
 	SelinuxIgnoreNeverallows bool `json:",omitempty"`
 
-	SepolicySplit bool `json:",omitempty"`
+	Release_aidl_use_unfrozen *bool `json:",omitempty"`
 
 	SepolicyFreezeTestExtraDirs         []string `json:",omitempty"`
 	SepolicyFreezeTestExtraPrebuiltDirs []string `json:",omitempty"`
@@ -473,6 +476,82 @@
 	ProductManufacturer string   `json:",omitempty"`
 	ProductBrand        string   `json:",omitempty"`
 	BuildVersionTags    []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"`
+
+	// PartitionVarsForBazelMigrationOnlyDoNotUse are extra variables that are used to define the
+	// partition images. They should not be read from soong modules.
+	PartitionVarsForBazelMigrationOnlyDoNotUse PartitionVariables `json:",omitempty"`
+
+	BuildFlags map[string]string `json:",omitempty"`
+
+	BuildFromSourceStub *bool `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 {
@@ -487,8 +566,8 @@
 	return &v
 }
 
-func (v *productVariables) SetDefaultConfig() {
-	*v = productVariables{
+func (v *ProductVariables) SetDefaultConfig() {
+	*v = ProductVariables{
 		BuildNumberFile: stringPtr("build_number.txt"),
 
 		Platform_version_name:                  stringPtr("S"),
@@ -500,19 +579,20 @@
 		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"),
+		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"),
@@ -524,6 +604,7 @@
 		Malloc_pattern_fill_contents: boolPtr(false),
 		Safestack:                    boolPtr(false),
 		TrimmedApex:                  boolPtr(false),
+		Build_from_text_stub:         boolPtr(false),
 
 		BootJars:     ConfiguredJarList{apexes: []string{}, jars: []string{}},
 		ApexBootJars: ConfiguredJarList{apexes: []string{}, jars: []string{}},
@@ -536,129 +617,115 @@
 	}
 }
 
+func (this *ProductVariables) GetBuildFlagBool(flag string) bool {
+	val, ok := this.BuildFlags[flag]
+	if !ok {
+		return false
+	}
+	return val == "true"
+}
+
 // ProductConfigContext requires the access to the Module to get product config properties.
 type ProductConfigContext interface {
 	Module() Module
 }
 
-// ProductConfigProperty contains the information for a single property (may be a struct) paired
-// with the appropriate ProductConfigVariable.
+// 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
+	name string
 
-	// Namespace of the variable, if this is a soong_config_module_type variable
-	// e.g. "acme", "ANDROID", "vendor_name"
-	Namespace string
-
-	// Unique configuration to identify this product config property (i.e. a
-	// primary key), as just using the product variable name is not sufficient.
-	//
-	// For product variables, this is the product variable name + optional
-	// archvariant information. e.g.
-	//
-	// product_variables: {
-	//     foo: {
-	//         cflags: ["-Dfoo"],
-	//     },
-	// },
-	//
-	// FullConfig would be "foo".
-	//
-	// target: {
-	//     android: {
-	//         product_variables: {
-	//             foo: {
-	//                 cflags: ["-Dfoo-android"],
-	//             },
-	//         },
-	//     },
-	// },
-	//
-	// FullConfig would be "foo-android".
-	//
-	// For soong config variables, this is the namespace + product variable name
-	// + value of the variable, if applicable. The value can also be
-	// conditions_default.
-	//
-	// e.g.
-	//
-	// soong_config_variables: {
-	//     feature1: {
-	//         conditions_default: {
-	//             cflags: ["-DDEFAULT1"],
-	//         },
-	//         cflags: ["-DFEATURE1"],
-	//     },
-	// }
-	//
-	// where feature1 is created in the "acme" namespace, so FullConfig would be
-	// "acme__feature1" and "acme__feature1__conditions_default".
-	//
-	// e.g.
-	//
-	// soong_config_variables: {
-	//     board: {
-	//         soc_a: {
-	//             cflags: ["-DSOC_A"],
-	//         },
-	//         soc_b: {
-	//             cflags: ["-DSOC_B"],
-	//         },
-	//         soc_c: {},
-	//         conditions_default: {
-	//             cflags: ["-DSOC_DEFAULT"]
-	//         },
-	//     },
-	// }
-	//
-	// where board is created in the "acme" namespace, so FullConfig would be
-	// "acme__board__soc_a", "acme__board__soc_b", and
-	// "acme__board__conditions_default"
-	FullConfig string
-
-	// keeps track of whether this product variable is nested under an arch variant
-	OuterAxis bazel.ConfigurationAxis
+	arch string
 }
 
-func (p *ProductConfigProperty) AlwaysEmit() bool {
-	return p.Namespace != ""
+func (p ProductConfigProperty) Name() string {
+	return p.name
 }
 
-func (p *ProductConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis {
-	if p.Namespace == "" {
-		return bazel.ProductVariableConfigurationAxis(p.FullConfig, p.OuterAxis)
+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 {
-		// Soong config variables can be uniquely identified by the namespace
-		// (e.g. acme, android) and the product variable name (e.g. board, size)
-		return bazel.ProductVariableConfigurationAxis(p.Namespace+"__"+p.Name, bazel.NoConfigAxis)
+		return strings.ToLower(p.name + "-" + p.arch)
 	}
 }
 
+// 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 *ProductConfigProperty) SelectKey() string {
-	if p.Namespace == "" {
-		return strings.ToLower(p.FullConfig)
-	}
-
-	if p.FullConfig == bazel.ConditionsDefaultConfigKey {
+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
 	}
 
-	value := p.FullConfig
-	if value == p.Name {
-		value = ""
+	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
-	selectKey := strings.ToLower(strings.Join([]string{p.Namespace, p.Name}, "__"))
-	if value != "" {
-		selectKey = strings.ToLower(strings.Join([]string{selectKey, value}, "__"))
-	}
-
-	return selectKey
+	// 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
@@ -674,89 +741,56 @@
 //
 // The value of the map is the interface{} representing the value of the
 // property, like ["-DDEFINES"] for cflags.
-type ProductConfigProperties map[string]map[ProductConfigProperty]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")
-		productVariableValues(
-			productVariablesProperty,
-			moduleBase.variableProperties,
-			"",
-			"",
-			&productConfigProperties,
-			bazel.ConfigurationAxis{},
-		)
-
-		for axis, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
-			for config, props := range configToProps {
-				// GetArchVariantProperties is creating an instance of the requested type
-				// and productVariablesValues expects an interface, so no need to cast
-				productVariableValues(
-					productVariablesProperty,
-					props,
-					"",
-					config,
-					&productConfigProperties,
-					axis)
-			}
-		}
-	}
-
-	if m, ok := module.(Bazelable); ok && m.namespacedVariableProps() != nil {
-		for namespace, namespacedVariableProps := range m.namespacedVariableProps() {
-			for _, namespacedVariableProp := range namespacedVariableProps {
-				productVariableValues(
-					soongconfig.SoongConfigProperty,
-					namespacedVariableProp,
-					namespace,
-					"",
-					&productConfigProperties,
-					bazel.NoConfigAxis)
-			}
-		}
-	}
-
-	return productConfigProperties
-}
+type ProductConfigProperties map[string]map[ProductConfigOrSoongConfigProperty]interface{}
 
 func (p *ProductConfigProperties) AddProductConfigProperty(
-	propertyName, namespace, productVariableName, config string, property interface{}, outerAxis bazel.ConfigurationAxis) {
-	if (*p)[propertyName] == nil {
-		(*p)[propertyName] = make(map[ProductConfigProperty]interface{})
-	}
+	propertyName, productVariableName, arch string, propertyValue interface{}) {
 
 	productConfigProp := ProductConfigProperty{
-		Namespace:  namespace,           // e.g. acme, android
-		Name:       productVariableName, // e.g. size, feature1, feature2, FEATURE3, board
-		FullConfig: config,              // e.g. size, feature1-x86, size__conditions_default
-		OuterAxis:  outerAxis,
+		name: productVariableName, // e.g. size, feature1, feature2, FEATURE3, board
+		arch: arch,                // e.g. "", x86, arm64
 	}
 
-	if existing, ok := (*p)[propertyName][productConfigProp]; ok && namespace != "" {
-		switch dst := existing.(type) {
-		case []string:
-			if src, ok := property.([]string); ok {
-				dst = append(dst, src...)
-				(*p)[propertyName][productConfigProp] = dst
-			}
-		default:
-			panic(fmt.Errorf("TODO: handle merging value %s", existing))
-		}
-	} else {
-		(*p)[propertyName][productConfigProp] = property
-	}
+	p.AddEitherProperty(propertyName, productConfigProp, propertyValue)
 }
 
-var (
-	conditionsDefaultField string = proptools.FieldNameForProperty(bazel.ConditionsDefaultConfigKey)
-)
+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
+	}
+}
 
 // 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
@@ -787,10 +821,7 @@
 	return v, true
 }
 
-func (productConfigProperties *ProductConfigProperties) AddProductConfigProperties(namespace, suffix string, variableValues reflect.Value, outerAxis bazel.ConfigurationAxis) {
-	// variableValues can either be a product_variables or
-	// soong_config_variables struct.
-	//
+func (productConfigProperties *ProductConfigProperties) AddProductConfigProperties(variableValues reflect.Value, arch string) {
 	// Example of product_variables:
 	//
 	// product_variables: {
@@ -803,35 +834,7 @@
 	//         ],
 	//     },
 	// },
-	//
-	// Example of soong_config_variables:
-	//
-	// soong_config_variables: {
-	//      feature1: {
-	//        	conditions_default: {
-	//               ...
-	//          },
-	//          cflags: ...
-	//      },
-	//      feature2: {
-	//          cflags: ...
-	//        	conditions_default: {
-	//               ...
-	//          },
-	//      },
-	//      board: {
-	//         soc_a: {
-	//             ...
-	//         },
-	//         soc_a: {
-	//             ...
-	//         },
-	//         soc_c: {},
-	//         conditions_default: {
-	//              ...
-	//         },
-	//      },
-	// }
+
 	for i := 0; i < variableValues.NumField(); i++ {
 		// e.g. Platform_sdk_version, Unbundled_build, Malloc_not_svelte, etc.
 		productVariableName := variableValues.Type().Field(i).Name
@@ -843,25 +846,81 @@
 			continue
 		}
 
-		// Unlike product variables, config variables require a few more
-		// indirections to extract the struct from the reflect.Value.
-		if v, ok := maybeExtractConfigVarProp(variableValue); ok {
-			variableValue = v
-		}
-
 		for j := 0; j < variableValue.NumField(); j++ {
 			property := variableValue.Field(j)
 			// e.g. Asflags, Cflags, Enabled, etc.
 			propertyName := variableValue.Type().Field(j).Name
-			// config can also be "conditions_default".
-			config := proptools.PropertyNameForField(propertyName)
+			if property.Kind() != reflect.Interface {
+				productConfigProperties.AddProductConfigProperty(propertyName, productVariableName, arch, property.Interface())
+			}
+		}
+	}
+
+}
+
+func (productConfigProperties *ProductConfigProperties) AddSoongConfigProperties(namespace string, soongConfigVariablesStruct reflect.Value) error {
+	//
+	// 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 property.IsZero() {
+			if propertyOrStruct.IsZero() {
 				continue
 			}
 
-			if v, ok := maybeExtractConfigVarProp(property); ok {
+			if v, ok := maybeExtractConfigVarProp(propertyOrStruct); ok {
 				// The field is a struct, which is used by:
 				// 1) soong_config_string_variables
 				//
@@ -879,6 +938,9 @@
 				//     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++ {
@@ -888,47 +950,60 @@
 					if field.Field(k).IsZero() && namespace == "" {
 						continue
 					}
-					actualPropertyName := field.Type().Field(k).Name
 
-					productConfigProperties.AddProductConfigProperty(
-						actualPropertyName,  // e.g. cflags, static_libs
-						namespace,           // e.g. acme, android
-						productVariableName, // e.g. size, feature1, FEATURE2, board
-						config,
-						field.Field(k).Interface(), // e.g. ["-DDEFAULT"], ["foo", "bar"],
-						outerAxis,
-					)
+					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" {
+						return fmt.Errorf("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 property.Kind() != reflect.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 regular product variable,
-				// or a bool/value config variable.
-				config := productVariableName + suffix
-				productConfigProperties.AddProductConfigProperty(
-					propertyName,
-					namespace,
-					productVariableName,
-					config,
-					property.Interface(),
-					outerAxis,
-				)
+				// 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" {
+					return fmt.Errorf("Arch/Multilib are not currently supported in soong config variable structs")
+				} else {
+					productConfigProperties.AddSoongConfigProperty(propertyOrValueName, namespace, variableName, "", "", propertyOrStruct.Interface())
+				}
 			}
 		}
 	}
+	return nil
 }
 
-// productVariableValues uses reflection to convert a property struct for
-// product_variables and soong_config_variables to structs that can be generated
-// as select statements.
-func productVariableValues(
-	fieldName string, variableProps interface{}, namespace, suffix string, productConfigProperties *ProductConfigProperties, outerAxis bazel.ConfigurationAxis) {
-	if suffix != "" {
-		suffix = "-" + suffix
-	}
+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
 
-	// variableValues represent the product_variables or soong_config_variables struct.
-	variableValues := reflect.ValueOf(variableProps).Elem().FieldByName(fieldName)
-	productConfigProperties.AddProductConfigProperties(namespace, suffix, variableValues, outerAxis)
+			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)
+			}
+		}
+	}
 }
 
 func VariableMutator(mctx BottomUpMutatorContext) {
diff --git a/android_sdk/sdk_repo_host.go b/android_sdk/sdk_repo_host.go
index 61058df..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.1")
+		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")
 			}
@@ -242,7 +243,7 @@
 			fmt.Fprintln(w, ".PHONY:", name, "sdk_repo", "sdk-repo-"+name)
 			fmt.Fprintln(w, "sdk_repo", "sdk-repo-"+name+":", strings.Join(s.FilesToInstall().Strings(), " "))
 
-			fmt.Fprintf(w, "$(call dist-for-goals,sdk_repo sdk-repo-%s,%s:%s-$(FILE_NAME_TAG).zip)\n\n", s.BaseModuleName(), s.outputFile.String(), s.outputBaseName)
+			fmt.Fprintf(w, "$(call dist-for-goals,sdk_repo sdk-repo-%s,%s:%s-FILE_NAME_TAG_PLACEHOLDER.zip)\n\n", s.BaseModuleName(), s.outputFile.String(), s.outputBaseName)
 		},
 	}
 }
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..460f1ff 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -823,6 +823,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 +1470,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 +1481,7 @@
 	product_specific: true,
 
 	sdk_version: "current",
+	target_sdk_version: "target_version",
 	theme: "FooTheme",
 
 }
@@ -1705,9 +1727,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/apex/Android.bp b/apex/Android.bp
index 61d7fb2..27017ae 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,10 +27,8 @@
         "apex_sdk_member.go",
         "apex_singleton.go",
         "builder.go",
-        "bp2build.go",
         "deapexer.go",
         "key.go",
-        "metadata.go",
         "prebuilt.go",
         "testing.go",
         "vndk.go",
@@ -39,7 +38,6 @@
         "bootclasspath_fragment_test.go",
         "classpath_element_test.go",
         "dexpreopt_bootjars_test.go",
-        "metadata_test.go",
         "platform_bootclasspath_test.go",
         "systemserver_classpath_fragment_test.go",
         "vndk_test.go",
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 684833d..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,15 +85,6 @@
 	// conflicts between two apexes with the same apexName.
 
 	moduleNames := []string{}
-	apexType := a.properties.ApexType
-	// To avoid creating duplicate build rules, run this function only when primaryApexType is true
-	// to install symbol files in $(PRODUCT_OUT}/apex.
-	// And if apexType is flattened, run this function to install files in $(PRODUCT_OUT}/system/apex.
-	if !a.primaryApexType && apexType != flattenedApex {
-		return moduleNames
-	}
-
-	seenDataOutPaths := make(map[string]bool)
 
 	for _, fi := range a.filesInfo {
 		linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform()
@@ -131,69 +122,27 @@
 		}
 		// /apex/<apexBundleName>/{lib|framework|...}
 		pathForSymbol := filepath.Join("$(PRODUCT_OUT)", "apex", apexBundleName, fi.installDir)
-		var modulePath string
-		if apexType == flattenedApex {
-			// /system/apex/<apexBundleName>/{lib|framework|...}
-			modulePath = filepath.Join(a.installDir.String(), apexBundleName, fi.installDir)
-			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", modulePath)
-			if a.primaryApexType {
-				fmt.Fprintln(w, "LOCAL_SOONG_SYMBOL_PATH :=", pathForSymbol)
-			}
-			android.AndroidMkEmitAssignList(w, "LOCAL_MODULE_SYMLINKS", fi.symlinks)
-			newDataPaths := []android.DataPath{}
-			for _, path := range fi.dataPaths {
-				dataOutPath := modulePath + ":" + path.SrcPath.Rel()
-				if ok := seenDataOutPaths[dataOutPath]; !ok {
-					newDataPaths = append(newDataPaths, path)
-					seenDataOutPaths[dataOutPath] = true
-				}
-			}
-			android.AndroidMkEmitAssignList(w, "LOCAL_TEST_DATA", android.AndroidMkDataPaths(newDataPaths))
-		} else {
-			modulePath = pathForSymbol
-			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", modulePath)
-
-			// 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,
-			// we will have duplicated notice entries.
-			fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
+		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,
+		// we will have duplicated notice entries.
+		fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
 		fmt.Fprintln(w, "LOCAL_SOONG_INSTALLED_MODULE :=", filepath.Join(modulePath, fi.stem()))
 		fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", fi.builtFile.String()+":"+filepath.Join(modulePath, fi.stem()))
 		fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
 		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())
@@ -237,56 +186,27 @@
 			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")
 		default:
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.stem())
-			if fi.builtFile == a.manifestPbOut && apexType == flattenedApex {
-				if a.primaryApexType {
-					// To install companion files (init_rc, vintf_fragments)
-					// Copy some common properties of apexBundle to apex_manifest
-					commonProperties := []string{
-						"LOCAL_FULL_INIT_RC", "LOCAL_FULL_VINTF_FRAGMENTS",
-					}
-					for _, name := range commonProperties {
-						if value, ok := apexAndroidMkData.Entries.EntryMap[name]; ok {
-							android.AndroidMkEmitAssignList(w, name, value)
-						}
-					}
-
-					// Make apex_manifest.pb module for this APEX to override all other
-					// modules in the APEXes being overridden by this APEX
-					var patterns []string
-					for _, o := range a.overridableProperties.Overrides {
-						patterns = append(patterns, "%."+o+a.suffix)
-					}
-					android.AndroidMkEmitAssignList(w, "LOCAL_OVERRIDES_MODULES", patterns)
-				}
-
-				// File_contexts of flattened APEXes should be merged into file_contexts.bin
-				fmt.Fprintln(w, "LOCAL_FILE_CONTEXTS :=", a.fileContexts)
-			}
 			fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
 		}
 
 		// 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)
 		}
@@ -313,80 +233,71 @@
 
 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)
 			}
 
-			if apexType == flattenedApex {
-				// Only image APEXes can be flattened.
-				fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)  # apex.apexBundle.flat")
-				fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
-				fmt.Fprintln(w, "LOCAL_MODULE :=", name+a.suffix)
-				data.Entries.WriteLicenseVariables(w)
-				a.writeRequiredModules(w, moduleNames)
-				fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
-
-			} else {
-				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_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()
-				if a.isCompressed {
-					stemSuffix = imageCapexSuffix
-				}
-				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+stemSuffix)
-				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
-				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())
-				}
-
-				// Because apex writes .mk with Custom(), we need to write manually some common properties
-				// which are available via data.Entries
-				commonProperties := []string{
-					"LOCAL_FULL_INIT_RC", "LOCAL_FULL_VINTF_FRAGMENTS",
-					"LOCAL_PROPRIETARY_MODULE", "LOCAL_VENDOR_MODULE", "LOCAL_ODM_MODULE", "LOCAL_PRODUCT_MODULE", "LOCAL_SYSTEM_EXT_MODULE",
-					"LOCAL_MODULE_OWNER",
-				}
-				for _, name := range commonProperties {
-					if value, ok := data.Entries.EntryMap[name]; ok {
-						android.AndroidMkEmitAssignList(w, name, value)
-					}
-				}
-
-				android.AndroidMkEmitAssignList(w, "LOCAL_OVERRIDES_MODULES", a.overridableProperties.Overrides)
-				a.writeRequiredModules(w, moduleNames)
-
-				fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
-
-				if apexType == imageApex {
-					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 {
-					goal := "checkbuild"
-					distFile := name + "-installed-files.txt"
-					fmt.Fprintln(w, ".PHONY:", goal)
-					fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
-						goal, a.installedFilesFile.String(), distFile)
-					fmt.Fprintf(w, "$(call declare-0p-target,%s)\n", a.installedFilesFile.String())
-				}
-				for _, dist := range data.Entries.GetDistForGoals(a) {
-					fmt.Fprintf(w, dist)
-				}
-
-				distCoverageFiles(w, "ndk_apis_usedby_apex", a.nativeApisUsedByModuleFile.String())
-				distCoverageFiles(w, "ndk_apis_backedby_apex", a.nativeApisBackedByModuleFile.String())
-				distCoverageFiles(w, "java_apis_used_by_apex", a.javaApisUsedByModuleFile.String())
+			fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)  # apex.apexBundle")
+			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
+			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 := imageApexSuffix
+			if a.isCompressed {
+				stemSuffix = imageCapexSuffix
 			}
+			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+stemSuffix)
+			fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
+			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
+			commonProperties := []string{
+				"LOCAL_FULL_INIT_RC", "LOCAL_FULL_VINTF_FRAGMENTS",
+				"LOCAL_PROPRIETARY_MODULE", "LOCAL_VENDOR_MODULE", "LOCAL_ODM_MODULE", "LOCAL_PRODUCT_MODULE", "LOCAL_SYSTEM_EXT_MODULE",
+				"LOCAL_MODULE_OWNER",
+			}
+			for _, name := range commonProperties {
+				if value, ok := data.Entries.EntryMap[name]; ok {
+					android.AndroidMkEmitAssignList(w, name, value)
+				}
+			}
+
+			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)")
+			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 {
+				goal := "checkbuild"
+				distFile := name + "-installed-files.txt"
+				fmt.Fprintln(w, ".PHONY:", goal)
+				fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
+					goal, a.installedFilesFile.String(), distFile)
+				fmt.Fprintf(w, "$(call declare-0p-target,%s)\n", a.installedFilesFile.String())
+			}
+			for _, dist := range data.Entries.GetDistForGoals(a) {
+				fmt.Fprintf(w, dist)
+			}
+
+			distCoverageFiles(w, "ndk_apis_usedby_apex", a.nativeApisUsedByModuleFile.String())
+			distCoverageFiles(w, "ndk_apis_backedby_apex", a.nativeApisBackedByModuleFile.String())
+			distCoverageFiles(w, "java_apis_used_by_apex", a.javaApisUsedByModuleFile.String())
 		}}
 }
 
diff --git a/apex/apex.go b/apex/apex.go
index 1f2da5f..276ac80 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"
 )
@@ -79,7 +75,6 @@
 	ctx.BottomUp("mark_platform_availability", markPlatformAvailability).Parallel()
 	ctx.BottomUp("apex", apexMutator).Parallel()
 	ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).Parallel()
-	ctx.BottomUp("apex_flattened", apexFlattenedMutator).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,13 +208,8 @@
 
 	HideFromMake bool `blueprint:"mutated"`
 
-	// Internal package method for this APEX. When payload_type is image, this can be either
-	// imageApex or flattenedApex depending on Config.FlattenApex(). When payload_type is zip,
-	// this becomes zipApex.
-	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.
+	// If not specified, this defaults to Soong module name. This must be the name of a Soong module.
 	Apex_available_name *string
 
 	// Variant version of the mainline module. Must be an integer between 0-9
@@ -248,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
 
@@ -265,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
@@ -275,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...)
@@ -282,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 {
@@ -398,7 +393,6 @@
 	android.ModuleBase
 	android.DefaultableModuleBase
 	android.OverridableModuleBase
-	android.BazelModuleBase
 	multitree.ExportableModuleBase
 
 	// Properties
@@ -411,7 +405,7 @@
 	///////////////////////////////////////////////////////////////////////////////////////////
 	// Inputs
 
-	// Keys for apex_paylaod.img
+	// Keys for apex_payload.img
 	publicKeyFile  android.Path
 	privateKeyFile android.Path
 
@@ -423,13 +417,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 ".flattened", ".apex", ".zipapex", or ""
-	suffix string
-
 	// File system type of apex_payload.img
 	payloadFsType fsType
 
@@ -476,6 +463,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
 
@@ -497,8 +487,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.
@@ -508,12 +500,10 @@
 	app apexFileClass = iota
 	appSet
 	etc
-	goBinary
 	javaSharedLib
 	nativeExecutable
 	nativeSharedLib
 	nativeTest
-	pyBinary
 	shBinary
 )
 
@@ -522,12 +512,10 @@
 		"app":              app,
 		"appSet":           appSet,
 		"etc":              etc,
-		"goBinary":         goBinary,
 		"javaSharedLib":    javaSharedLib,
 		"nativeExecutable": nativeExecutable,
 		"nativeSharedLib":  nativeSharedLib,
 		"nativeTest":       nativeTest,
-		"pyBinary":         pyBinary,
 		"shBinary":         shBinary,
 	}
 )
@@ -535,8 +523,7 @@
 // apexFile represents a file in an APEX bundle. This is created during the first half of
 // GenerateAndroidBuildActions by traversing the dependencies of the APEX. Then in the second half
 // of the function, this is used to create commands that copies the files into a staging directory,
-// where they are packaged into the APEX file. This struct is also used for creating Make modules
-// for each of the files in case when the APEX is flattened.
+// where they are packaged into the APEX file.
 type apexFile struct {
 	// buildFile is put in the installDir inside the APEX.
 	builtFile  android.Path
@@ -566,10 +553,6 @@
 
 	multilib string
 
-	isBazelPrebuilt     bool
-	unstrippedBuiltFile android.Path
-	arch                string
-
 	// TODO(jiyong): remove this
 	module android.Module
 }
@@ -719,11 +702,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
@@ -740,24 +722,17 @@
 		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) {
@@ -765,25 +740,28 @@
 		return cc.VendorVariationPrefix, a.vndkVersion(deviceConfig)
 	}
 
-	var prefix string
-	var vndkVersion string
+	prefix := android.CoreVariation
+	vndkVersion := ""
 	if deviceConfig.VndkVersion() != "" {
 		if a.SocSpecific() || a.DeviceSpecific() {
 			prefix = cc.VendorVariationPrefix
 			vndkVersion = deviceConfig.VndkVersion()
 		} else if a.ProductSpecific() {
 			prefix = cc.ProductVariationPrefix
-			vndkVersion = deviceConfig.ProductVndkVersion()
+			vndkVersion = deviceConfig.PlatformVndkVersion()
+		}
+	} else {
+		if a.SocSpecific() || a.DeviceSpecific() {
+			prefix = cc.VendorVariation
+		} else if a.ProductSpecific() {
+			prefix = cc.ProductVariation
 		}
 	}
 	if vndkVersion == "current" {
 		vndkVersion = deviceConfig.PlatformVndkVersion()
 	}
-	if vndkVersion != "" {
-		return prefix, vndkVersion
-	}
 
-	return android.CoreVariation, "" // The usual case
+	return prefix, vndkVersion
 }
 
 // getImageVariation returns the image variant name for this apexBundle. In most cases, it's simply
@@ -810,12 +788,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
@@ -955,13 +927,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)
 
@@ -996,7 +962,7 @@
 	// the non-system APEXes because the VNDK libraries won't be included (and duped) in the
 	// APEX, but shared across APEXes via the VNDK APEX.
 	useVndk := a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && mctx.Config().EnforceProductPartitionInterface())
-	excludeVndkLibs := useVndk && proptools.Bool(a.properties.Use_vndk_as_stable)
+	excludeVndkLibs := useVndk && a.useVndkAsStable(mctx)
 	if proptools.Bool(a.properties.Use_vndk_as_stable) {
 		if !useVndk {
 			mctx.PropertyErrorf("use_vndk_as_stable", "not supported for system/system_ext APEXes")
@@ -1035,6 +1001,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
@@ -1056,7 +1029,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,
 	})
 
@@ -1071,6 +1044,10 @@
 
 	apexVariationName := mctx.ModuleName() // could be com.android.foo
 	a.properties.ApexVariationName = apexVariationName
+	testApexes := []string{}
+	if a.testApex {
+		testApexes = []string{apexVariationName}
+	}
 	apexInfo := android.ApexInfo{
 		ApexVariationName: apexVariationName,
 		MinSdkVersion:     minSdkVersion,
@@ -1079,6 +1056,7 @@
 		InApexVariants:    []string{apexVariationName},
 		InApexModules:     []string{a.Name()}, // could be com.mycompany.android.foo
 		ApexContents:      []*android.ApexContents{apexContents},
+		TestApexes:        testApexes,
 	}
 	mctx.WalkDeps(func(child, parent android.Module) bool {
 		if !continueApexDepsWalk(child, parent) {
@@ -1089,7 +1067,7 @@
 	})
 
 	if a.dynamic_common_lib_apex() {
-		mctx.SetProvider(DCLAInfoProvider, DCLAInfo{
+		android.SetProvider(mctx, DCLAInfoProvider, DCLAInfo{
 			ProvidedLibs: a.properties.Native_shared_libs,
 		})
 	}
@@ -1168,15 +1146,42 @@
 // 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.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
@@ -1232,10 +1237,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,
 		})
 	}
@@ -1247,8 +1252,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
 	}
 
@@ -1351,116 +1356,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.
-	zipApex
-
-	// flattendApex is a packaging method where contents are not included in the APEX file, but
-	// installed to /apex/<apexname> directory on the device. This packaging method is used for
-	// old devices where the filesystem-based APEX file can't be supported.
-	flattenedApex
-)
-
 const (
 	// File extensions of an APEX for different packaging methods
 	imageApexSuffix  = ".apex"
 	imageCapexSuffix = ".capex"
-	zipApexSuffix    = ".zipapex"
-	flattenedSuffix  = ".flattened"
 
 	// variant names each of which is for a packaging method
-	imageApexType     = "image"
-	zipApexType       = "zip"
-	flattenedApexType = "flattened"
+	imageApexType = "image"
 
 	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))
-	}
-}
-
-// apexFlattenedMutator creates one or more variations each of which is for a packaging method.
-// TODO(jiyong): give a better name to this mutator
-func apexFlattenedMutator(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":
-			// This is the normal case. Note that both image and flattend APEXes are
-			// created. The image type is installed to the system partition, while the
-			// flattened APEX is (optionally) installed to the system_ext partition.
-			// This is mostly for GSI which has to support wide range of devices. If GSI
-			// is installed on a newer (APEX-capable) device, the image APEX in the
-			// system will be used. However, if the same GSI is installed on an old
-			// device which can't support image APEX, the flattened APEX in the
-			// system_ext partion (which still is part of GSI) is used instead.
-			variants = append(variants, imageApexType, flattenedApexType)
-		case "zip":
-			variants = append(variants, zipApexType)
-		case "both":
-			variants = append(variants, imageApexType, zipApexType, flattenedApexType)
-		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
-			case flattenedApexType:
-				modules[i].(*apexBundle).properties.ApexType = flattenedApex
-				// See the comment above for why system_ext.
-				if !mctx.Config().FlattenApex() && ab.Platform() {
-					modules[i].(*apexBundle).MakeAsSystemExt()
-				}
-			}
-		}
-	} else if _, ok := mctx.Module().(*OverrideApex); ok {
-		// payload_type is forcibly overridden to "image"
-		// TODO(jiyong): is this the right decision?
-		mctx.CreateVariations(imageApexType, flattenedApexType)
-	}
-}
-
 var _ android.DepIsInSameApex = (*apexBundle)(nil)
 
 // Implements android.DepInInSameApex
@@ -1492,9 +1400,6 @@
 var _ multitree.Exportable = (*apexBundle)(nil)
 
 func (a *apexBundle) Exportable() bool {
-	if a.properties.ApexType == flattenedApex {
-		return false
-	}
 	return true
 }
 
@@ -1507,8 +1412,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
@@ -1596,7 +1501,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{}
@@ -1619,13 +1524,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)
 }
@@ -1633,7 +1534,7 @@
 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") {
+	if sanitizerName == "hwaddress" && strings.HasPrefix(a.Name(), "com.android.runtime") {
 		imageVariation := a.getImageVariation(ctx)
 		for _, target := range ctx.MultiTargets() {
 			if target.Arch.ArchType.Multilib == "lib64" {
@@ -1707,6 +1608,7 @@
 	if rustm.Target().NativeBridge == android.NativeBridgeEnabled {
 		dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath)
 	}
+	dirInApex = filepath.Join(dirInApex, rustm.RelativeInstallPath())
 	fileToCopy := android.OutputFileForModule(ctx, rustm, "")
 	androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName
 	af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, rustm)
@@ -1726,27 +1628,12 @@
 	if rustm.Target().NativeBridge == android.NativeBridgeEnabled {
 		dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath)
 	}
+	dirInApex = filepath.Join(dirInApex, rustm.RelativeInstallPath())
 	fileToCopy := android.OutputFileForModule(ctx, rustm, "")
 	androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName
 	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 {
@@ -1775,7 +1662,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
@@ -1789,7 +1676,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.
@@ -1932,7 +1819,7 @@
 			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
@@ -1962,135 +1849,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 {
-	if _, ok := ctx.Module().(android.OverridableModule); ok {
-		return android.MaybeBp2buildLabelOfOverridingModule(ctx)
-	}
-	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()
@@ -2116,12 +1876,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
 	}
 }
@@ -2139,39 +1894,7 @@
 	}
 }
 
-func (a *apexBundle) setApexTypeAndSuffix(ctx android.ModuleContext) {
-	// Set suffix and primaryApexType depending on the ApexType
-	buildFlattenedAsDefault := ctx.Config().FlattenApex()
-	switch a.properties.ApexType {
-	case imageApex:
-		if buildFlattenedAsDefault {
-			a.suffix = imageApexSuffix
-		} else {
-			a.suffix = ""
-			a.primaryApexType = true
-
-			if ctx.Config().InstallExtraFlattenedApexes() {
-				a.makeModulesToInstall = append(a.makeModulesToInstall, a.Name()+flattenedSuffix)
-			}
-		}
-	case zipApex:
-		if proptools.String(a.properties.Payload_type) == "zip" {
-			a.suffix = ""
-			a.primaryApexType = true
-		} else {
-			a.suffix = zipApexSuffix
-		}
-	case flattenedApex:
-		if buildFlattenedAsDefault {
-			a.suffix = ""
-			a.primaryApexType = true
-		} else {
-			a.suffix = flattenedSuffix
-		}
-	}
-}
-
-func (a apexBundle) isCompressable() bool {
+func (a *apexBundle) isCompressable() bool {
 	return proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex
 }
 
@@ -2200,11 +1923,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
@@ -2247,11 +1982,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
@@ -2263,29 +2006,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",
@@ -2325,6 +2059,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))
@@ -2333,6 +2068,7 @@
 			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)...)
@@ -2438,20 +2174,19 @@
 	// tags used below are private (e.g. `cc.sharedDepTag`).
 	if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
 		if ch, ok := child.(*cc.Module); ok {
-			if ch.UseVndk() && proptools.Bool(a.properties.Use_vndk_as_stable) && ch.IsVndk() {
+			if ch.UseVndk() && a.useVndkAsStable(ctx) && ch.IsVndk() {
 				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.
@@ -2572,20 +2307,19 @@
 	return false
 }
 
+func addAconfigFiles(vctx *visitorContext, ctx android.ModuleContext, module blueprint.Module) {
+	dep, _ := android.OtherModuleProvider(ctx, module, android.AconfigTransitiveDeclarationsInfoProvider)
+	if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil {
+		vctx.aconfigFiles = append(vctx.aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...)
+	}
+}
+
 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
@@ -2605,69 +2339,100 @@
 	}
 	////////////////////////////////////////////////////////////////////////////////////////////
 	// 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)
 	if a.privateKeyFile == nil {
-		ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.overridableProperties.Key))
-		return
+		if ctx.Config().AllowMissingDependencies() {
+			// TODO(b/266099037): a better approach for slim manifests.
+			ctx.AddMissingDependencies([]string{String(a.overridableProperties.Key)})
+			// Create placeholder paths for later stages that expect to see those paths,
+			// though they won't be used.
+			var unusedPath = android.PathForModuleOut(ctx, "nonexistentprivatekey")
+			ctx.Build(pctx, android.BuildParams{
+				Rule:   android.ErrorRule,
+				Output: unusedPath,
+				Args: map[string]string{
+					"error": "Private key not available",
+				},
+			})
+			a.privateKeyFile = unusedPath
+		} else {
+			ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.overridableProperties.Key))
+			return
+		}
 	}
 
+	if a.publicKeyFile == nil {
+		if ctx.Config().AllowMissingDependencies() {
+			// TODO(b/266099037): a better approach for slim manifests.
+			ctx.AddMissingDependencies([]string{String(a.overridableProperties.Key)})
+			// Create placeholder paths for later stages that expect to see those paths,
+			// though they won't be used.
+			var unusedPath = android.PathForModuleOut(ctx, "nonexistentpublickey")
+			ctx.Build(pctx, android.BuildParams{
+				Rule:   android.ErrorRule,
+				Output: unusedPath,
+				Args: map[string]string{
+					"error": "Public key not available",
+				},
+			})
+			a.publicKeyFile = unusedPath
+		} else {
+			ctx.PropertyErrorf("key", "public_key for %q could not be found", String(a.overridableProperties.Key))
+			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.
 	a.buildManifest(ctx, vctx.provideNativeLibs, vctx.requireNativeLibs)
-	if a.properties.ApexType == flattenedApex {
-		a.buildFlattenedApex(ctx)
-	} else {
-		a.buildUnflattenedApex(ctx)
-	}
+	a.buildApex(ctx)
 	a.buildApexDependencyInfo(ctx)
 	a.buildLintReports(ctx)
 
-	// Append meta-files to the filesInfo list so that they are reflected in Android.mk as well.
-	if a.installable() {
-		// For flattened APEX, make sure that APEX manifest and apex_pubkey are also copied
-		// along with other ordinary files. (Note that this is done by apexer for
-		// non-flattened APEXes)
-		a.filesInfo = append(a.filesInfo, newApexFile(ctx, a.manifestPbOut, "apex_manifest.pb", ".", etc, nil))
+	// Set a provider for dexpreopt of bootjars
+	a.provideApexExportsInfo(ctx)
+}
 
-		// Place the public key as apex_pubkey. This is also done by apexer for
-		// non-flattened APEXes case.
-		// TODO(jiyong): Why do we need this CP rule?
-		copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   android.Cp,
-			Input:  a.publicKeyFile,
-			Output: copiedPubkey,
-		})
-		a.filesInfo = append(a.filesInfo, newApexFile(ctx, copiedPubkey, "apex_pubkey", ".", etc, nil))
-	}
+// 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.
@@ -2716,7 +2481,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
 	}
@@ -2728,7 +2493,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.
@@ -2755,10 +2520,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
 }
@@ -2786,6 +2550,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.
@@ -2806,7 +2573,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) {
@@ -2822,104 +2592,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
 //
@@ -2973,11 +2648,11 @@
 // 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 {
@@ -3038,7 +2713,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())
 			}
@@ -3068,7 +2743,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
 	}
 
@@ -3126,11 +2801,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
@@ -3164,7 +2834,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 (
@@ -3229,213 +2898,8 @@
 	//
 	// Module separator
 	//
-	m["com.android.appsearch"] = []string{
-		"icing-java-proto-lite",
-		"libprotobuf-java-lite",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.btservices"] = []string{
-		// empty
-	}
-	//
-	// Module separator
-	//
-	m["com.android.cellbroadcast"] = []string{"CellBroadcastApp", "CellBroadcastServiceModule"}
-	//
-	// Module separator
-	//
-	m["com.android.extservices"] = []string{
-		"error_prone_annotations",
-		"ExtServices-core",
-		"ExtServices",
-		"libtextclassifier-java",
-		"libz_current",
-		"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",
-		"libbuildversion",
-		"libmath",
-		"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{
-		"bionic_libc_platform_headers",
-		"libarm-optimized-routines-math",
-		"libc_aeabi",
-		"libc_bionic",
-		"libc_bionic_ndk",
-		"libc_bootstrap",
-		"libc_common",
-		"libc_common_shared",
-		"libc_common_static",
-		"libc_dns",
-		"libc_dynamic_dispatch",
-		"libc_fortify",
-		"libc_freebsd",
-		"libc_freebsd_large_stack",
-		"libc_gdtoa",
-		"libc_init_dynamic",
-		"libc_init_static",
-		"libc_jemalloc_wrapper",
-		"libc_netbsd",
-		"libc_nomalloc",
-		"libc_nopthread",
-		"libc_openbsd",
-		"libc_openbsd_large_stack",
-		"libc_openbsd_ndk",
-		"libc_pthread",
-		"libc_static_dispatch",
-		"libc_syscalls",
-		"libc_tzcode",
-		"libc_unwind_static",
-		"libdebuggerd",
-		"libdebuggerd_common_headers",
-		"libdebuggerd_handler_core",
-		"libdebuggerd_handler_fallback",
-		"libdl_static",
-		"libjemalloc5",
-		"liblinker_main",
-		"liblinker_malloc",
-		"liblz4",
-		"liblzma",
-		"libprocinfo",
-		"libpropertyinfoparser",
-		"libscudo",
-		"libstdc++",
-		"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",
-		"android.hidl.base-V1.0-java",
-		"libcgrouprc",
-		"libcgrouprc_format",
-		"libtetherutilsjni",
-		"libvndksupport",
-		"net-utils-framework-common",
-		"netd_aidl_interface-V3-java",
-		"netlink-client",
-		"networkstack-aidl-interfaces-java",
-		"tethering-aidl-interfaces-java",
-		"TetheringApiCurrentLib",
-	}
-	//
-	// 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",
-		"android.hidl.base-V1.0-java",
-		"android.hidl.manager-V1.0-java",
-		"android.hidl.manager-V1.1-java",
-		"android.hidl.manager-V1.2-java",
-		"bouncycastle-unbundled",
-		"dnsresolver_aidl_interface-V2-java",
-		"error_prone_annotations",
-		"framework-wifi-pre-jarjar",
-		"framework-wifi-util-lib",
-		"ipmemorystore-aidl-interfaces-V3-java",
-		"ipmemorystore-aidl-interfaces-java",
-		"ksoap2",
-		"libnanohttpd",
-		"libwifi-jni",
-		"net-utils-services-common",
-		"netd_aidl_interface-V2-java",
-		"netd_aidl_interface-unstable-java",
-		"netd_event_listener_interface-java",
-		"netlink-client",
-		"networkstack-client",
-		"services.net",
-		"wifi-lite-protos",
-		"wifi-nano-protos",
-		"wifi-service-pre-jarjar",
-		"wifi-service-resources",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.os.statsd"] = []string{
-		"libstatssocket",
-	}
-	//
-	// Module separator
-	//
-	m[android.AvailableToAnyApex] = []string{
-		// TODO(b/156996905) Set apex_available/min_sdk_version for androidx/extras support libraries
-		"androidx",
-		"androidx-constraintlayout_constraintlayout",
-		"androidx-constraintlayout_constraintlayout-nodeps",
-		"androidx-constraintlayout_constraintlayout-solver",
-		"androidx-constraintlayout_constraintlayout-solver-nodeps",
-		"com.google.android.material_material",
-		"com.google.android.material_material-nodeps",
-
-		"libclang_rt",
-		"libprofile-clang-extras",
-		"libprofile-clang-extras_ndk",
-		"libprofile-extras",
-		"libprofile-extras_ndk",
-		"libunwind",
 	}
 	return m
 }
@@ -3516,297 +2980,15 @@
 	}
 }
 
-// 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
-}
-
-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,
-	}
-
-	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)
-	}
-
-	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
 }
+
+func (a *apexBundle) useVndkAsStable(ctx android.BaseModuleContext) bool {
+	// VNDK cannot be linked if it is deprecated
+	if ctx.Config().IsVndkDeprecated() {
+		return false
+	}
+
+	return proptools.Bool(a.properties.Use_vndk_as_stable)
+}
diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go
index 1581949..25c0cc4 100644
--- a/apex/apex_singleton.go
+++ b/apex/apex_singleton.go
@@ -23,7 +23,11 @@
 )
 
 func init() {
-	android.RegisterSingletonType("apex_depsinfo_singleton", apexDepsInfoSingletonFactory)
+	registerApexDepsInfoComponents(android.InitRegistrationContext)
+}
+
+func registerApexDepsInfoComponents(ctx android.RegistrationContext) {
+	ctx.RegisterParallelSingletonType("apex_depsinfo_singleton", apexDepsInfoSingletonFactory)
 }
 
 type apexDepsInfoSingleton struct {
@@ -79,7 +83,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)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 38d9106..229175f 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,
 
@@ -390,7 +393,7 @@
 			name: "foo.rust",
 			srcs: ["foo.rs"],
 			rlibs: ["libfoo.rlib.rust"],
-			dylibs: ["libfoo.dylib.rust"],
+			rustlibs: ["libfoo.dylib.rust"],
 			apex_available: ["myapex"],
 		}
 
@@ -518,10 +521,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 +536,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 +598,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 +683,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 +710,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 +781,7 @@
 		},
 	}
 	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) {
@@ -786,18 +791,16 @@
 }
 
 func TestFileContexts(t *testing.T) {
-	for _, useFileContextsAsIs := range []bool{true, false} {
+	for _, vendor := range []bool{true, false} {
 		prop := ""
-		if useFileContextsAsIs {
-			prop = "use_file_contexts_as_is: true,\n"
+		if vendor {
+			prop = "vendor: true,\n"
 		}
 		ctx := testApex(t, `
 			apex {
 				name: "myapex",
 				key: "myapex.key",
-				file_contexts: "file_contexts",
 				updatable: false,
-				vendor: true,
 				`+prop+`
 			}
 
@@ -806,73 +809,21 @@
 				public_key: "testkey.avbpubkey",
 				private_key: "testkey.pem",
 			}
-		`, withFiles(map[string][]byte{
-			"file_contexts": nil,
-		}))
+		`)
 
-		rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("file_contexts")
-		forceLabellingCommand := "apex_manifest\\\\.pb u:object_r:system_file:s0"
-		if useFileContextsAsIs {
-			android.AssertStringDoesNotContain(t, "should force-label",
-				rule.RuleParams.Command, forceLabellingCommand)
+		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,
+				"apex_manifest\\\\.pb u:object_r:vendor_apex_metadata_file:s0")
 		} else {
-			android.AssertStringDoesContain(t, "shouldn't force-label",
-				rule.RuleParams.Command, forceLabellingCommand)
+			android.AssertStringDoesContain(t, "should force-label as system_file",
+				rule.RuleParams.Command,
+				"apex_manifest\\\\.pb u:object_r:system_file:s0")
 		}
 	}
 }
 
-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 {
@@ -949,7 +900,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
@@ -990,7 +941,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",
@@ -1002,14 +953,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 {
@@ -1066,7 +1043,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
@@ -1078,7 +1055,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")
 }
@@ -1144,7 +1121,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
@@ -1175,7 +1152,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",
@@ -1311,7 +1288,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
@@ -1335,10 +1312,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)")
 }
 
@@ -1368,6 +1347,8 @@
 		cc_library {
 			name: "mylib",
 			srcs: ["mylib.cpp"],
+			static_libs: ["libstatic"],
+			shared_libs: ["libshared"],
 			runtime_libs: ["libfoo", "libbar"],
 			system_shared_libs: [],
 			stl: "none",
@@ -1392,9 +1373,42 @@
 			apex_available: [ "myapex" ],
 		}
 
+		cc_library {
+			name: "libstatic",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex" ],
+			runtime_libs: ["libstatic_to_runtime"],
+		}
+
+		cc_library {
+			name: "libshared",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex" ],
+			runtime_libs: ["libshared_to_runtime"],
+		}
+
+		cc_library {
+			name: "libstatic_to_runtime",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex" ],
+		}
+
+		cc_library {
+			name: "libshared_to_runtime",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex" ],
+		}
 	`)
 
-	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
@@ -1405,11 +1419,14 @@
 
 	// Ensure that runtime_libs dep in included
 	ensureContains(t, copyCmds, "image.apex/lib64/libbar.so")
+	ensureContains(t, copyCmds, "image.apex/lib64/libshared.so")
+	ensureContains(t, copyCmds, "image.apex/lib64/libshared_to_runtime.so")
 
-	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+	ensureNotContains(t, copyCmds, "image.apex/lib64/libstatic_to_runtime.so")
+
+	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
 	ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
 	ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.so")
-
 }
 
 var prepareForTestOfRuntimeApexWithHwasan = android.GroupFixturePreparers(
@@ -1461,10 +1478,14 @@
 			sanitize: {
 				never: true,
 			},
+			apex_available: [
+				"//apex_available:anyapex",
+				"//apex_available:platform",
+			],
 		}	`)
 	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",
 	})
@@ -1509,11 +1530,15 @@
 			sanitize: {
 				never: true,
 			},
+			apex_available: [
+				"//apex_available:anyapex",
+				"//apex_available:platform",
+			],
 		}
 		`)
 	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",
 	})
@@ -1594,12 +1619,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")
 
@@ -1659,7 +1684,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.
@@ -1981,6 +2006,94 @@
 	android.AssertStringDoesContain(t, "cflags", cflags, "-target aarch64-linux-android29")
 }
 
+func TestTrackAllowedDeps(t *testing.T) {
+	ctx := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			updatable: true,
+			native_shared_libs: [
+				"mylib",
+				"yourlib",
+			],
+			min_sdk_version: "29",
+		}
+
+		apex {
+			name: "myapex2",
+			key: "myapex.key",
+			updatable: false,
+			native_shared_libs: ["yourlib"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			shared_libs: ["libbar"],
+			min_sdk_version: "29",
+			apex_available: ["myapex"],
+		}
+
+		cc_library {
+			name: "libbar",
+			stubs: { versions: ["29", "30"] },
+		}
+
+		cc_library {
+			name: "yourlib",
+			srcs: ["mylib.cpp"],
+			min_sdk_version: "29",
+			apex_available: ["myapex", "myapex2", "//apex_available:platform"],
+		}
+	`, withFiles(android.MockFS{
+		"packages/modules/common/build/allowed_deps.txt": nil,
+	}))
+
+	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/depsinfo/flatlist.txt")
+	android.AssertStringListDoesNotContain(t, "non-updatable myapex2 should not generate depsinfo file", inputs,
+		"out/soong/.intermediates/myapex2/android_common_myapex2/depsinfo/flatlist.txt")
+
+	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",
+		flatlist, "mylib:(minSdkVersion:29)")
+	android.AssertStringListContains(t, "track platform-available lib",
+		flatlist, "yourlib(minSdkVersion:29)")
+}
+
+func TestTrackAllowedDeps_SkipWithoutAllowedDepsTxt(t *testing.T) {
+	ctx := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			updatable: true,
+			min_sdk_version: "29",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+	`)
+	depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton")
+	if nil != depsinfo.MaybeRule("generateApexDepsInfoFilesRule").Output {
+		t.Error("apex_depsinfo_singleton shouldn't run when allowed_deps.txt doesn't exist")
+	}
+}
+
 func TestPlatformUsesLatestStubsFromApexes(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
@@ -2664,7 +2777,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
-			binaries: ["mybin"],
+			binaries: ["mybin", "mybin.rust"],
 			prebuilts: ["myetc"],
 			compile_multilib: "both",
 			updatable: false,
@@ -2699,9 +2812,16 @@
 			stl: "none",
 			apex_available: [ "myapex" ],
 		}
+
+		rust_binary {
+			name: "mybin.rust",
+			srcs: ["foo.rs"],
+			relative_install_path: "rust_subdir",
+			apex_available: [ "myapex" ],
+		}
 	`)
 
-	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
@@ -2717,6 +2837,7 @@
 	ensureContains(t, cmd, "/bin ")
 	ensureContains(t, cmd, "/bin/foo ")
 	ensureContains(t, cmd, "/bin/foo/bar ")
+	ensureContains(t, cmd, "/bin/rust_subdir ")
 }
 
 func TestFilesInSubDirWhenNativeBridgeEnabled(t *testing.T) {
@@ -2765,7 +2886,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",
@@ -2805,14 +2926,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_"
@@ -2822,7 +2943,7 @@
 	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")
 }
@@ -2899,7 +3020,11 @@
 			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"
 
@@ -2961,10 +3086,10 @@
 				ensureListContains(t, libs, lib)
 			}
 			// Check apex contents
-			ensureExactContents(t, ctx, tc.apexName, "android_common_"+tc.apexName+"_image", tc.contents)
+			ensureExactContents(t, ctx, tc.apexName, "android_common_"+tc.apexName, tc.contents)
 
 			// Check "requireNativeLibs"
-			apexManifestRule := ctx.ModuleForTests(tc.apexName, "android_common_"+tc.apexName+"_image").Rule("apexManifestRule")
+			apexManifestRule := ctx.ModuleForTests(tc.apexName, "android_common_"+tc.apexName).Rule("apexManifestRule")
 			requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
 			if tc.requireVndkNamespace {
 				ensureListContains(t, requireNativeLibs, ":vndk")
@@ -2997,10 +3122,7 @@
 			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"])
@@ -3040,7 +3162,7 @@
 					`+tc.additionalProp+`
 				}
 			`)
-			ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+			ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 				"etc/firmware/myfirmware.bin",
 			})
 		})
@@ -3069,14 +3191,14 @@
 		}
 	`)
 
-	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_"
 	var builder strings.Builder
 	data.Custom(&builder, name, prefix, "", data)
 	androidMk := builder.String()
-	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := libc++.vendor.myapex:64 mylib.vendor.myapex:64 apex_manifest.pb.myapex apex_pubkey.myapex libc.vendor libm.vendor libdl.vendor\n")
+	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := libc++.vendor.myapex:64 mylib.vendor.myapex:64 libc.vendor libm.vendor libdl.vendor\n")
 }
 
 func TestAndroidMkWritesCommonProperties(t *testing.T) {
@@ -3098,7 +3220,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_"
@@ -3132,10 +3254,7 @@
 			stubs: {
 				versions: ["1", "2", "3"],
 			},
-			apex_available: [
-				"//apex_available:platform",
-				"myapex",
-			],
+			apex_available: ["myapex"],
 		}
 
 		cc_binary {
@@ -3204,7 +3323,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")
@@ -3224,7 +3343,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)
@@ -3247,7 +3366,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)
@@ -3270,7 +3389,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)
@@ -3294,7 +3413,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)
@@ -3313,7 +3432,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)
@@ -3337,7 +3456,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)
@@ -3518,10 +3637,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, "&&") {
@@ -3610,7 +3725,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())
@@ -3731,8 +3846,9 @@
 			}
 		`+vndkLibrariesTxtFiles("current"), android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 				variables.DeviceVndkVersion = proptools.StringPtr(tc.vndkVersion)
+				variables.KeepVndk = proptools.BoolPtr(true)
 			}))
-			ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", tc.expectedFiles)
+			ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", tc.expectedFiles)
 		})
 	}
 }
@@ -3787,7 +3903,7 @@
 			"libvndk.so":     nil,
 			"libvndk.arm.so": nil,
 		}))
-	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []string{
 		"lib/libvndk.so",
 		"lib/libvndk.arm.so",
 		"lib64/libvndk.so",
@@ -3800,13 +3916,24 @@
 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 += `
@@ -3883,7 +4010,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/*",
@@ -3912,7 +4039,7 @@
 		}`+vndkLibrariesTxtFiles("28", "current"))
 
 	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)
 	}
@@ -3953,7 +4080,7 @@
 		`+vndkLibrariesTxtFiles("current"),
 		withNativeBridgeEnabled)
 
-	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []string{
 		"lib/libvndk.so",
 		"lib64/libvndk.so",
 		"lib/libc++.so",
@@ -4056,7 +4183,7 @@
 		}),
 	)
 
-	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/*",
 	})
@@ -4093,10 +4220,10 @@
 		"libz.map.txt": nil,
 	}))
 
-	apexManifestRule := ctx.ModuleForTests("com.android.vndk.current", "android_common_image").Rule("apexManifestRule")
+	apexManifestRule := ctx.ModuleForTests("com.android.vndk.current", "android_common").Rule("apexManifestRule")
 	provideNativeLibs := names(apexManifestRule.Args["provideNativeLibs"])
 	ensureListEmpty(t, provideNativeLibs)
-	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []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",
 		"*/*",
@@ -4252,7 +4379,7 @@
 		}))
 
 	// Should embed the prebuilt VNDK libraries in the apex
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"bin/foo",
 		"prebuilts/vndk/libc++.so:lib64/libc++.so",
 		"prebuilts/vndk/libvndk.so:lib64/libvndk.so",
@@ -4266,7 +4393,7 @@
 	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")
+	manifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
 	requireNativeLibs := names(manifestRule.Args["requireNativeLibs"])
 	ensureListContains(t, requireNativeLibs, "libllndk.so")
 }
@@ -4303,7 +4430,7 @@
 		apex {
 			name: "myapex_selfcontained",
 			key: "myapex.key",
-			native_shared_libs: ["lib_dep", "libfoo"],
+			native_shared_libs: ["lib_dep_on_bar", "libbar"],
 			compile_multilib: "both",
 			file_contexts: ":myapex-file_contexts",
 			updatable: false,
@@ -4337,6 +4464,18 @@
 		}
 
 		cc_library {
+			name: "lib_dep_on_bar",
+			srcs: ["mylib.cpp"],
+			shared_libs: ["libbar"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [
+				"myapex_selfcontained",
+			],
+		}
+
+
+		cc_library {
 			name: "libfoo",
 			srcs: ["mytest.cpp"],
 			stubs: {
@@ -4346,36 +4485,49 @@
 			stl: "none",
 			apex_available: [
 				"myapex_provider",
+			],
+		}
+
+		cc_library {
+			name: "libbar",
+			srcs: ["mytest.cpp"],
+			stubs: {
+				versions: ["1"],
+			},
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [
 				"myapex_selfcontained",
 			],
 		}
+
 	`)
 
 	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, "libfoo.so")
+	ensureListContains(t, provideNativeLibs, "libbar.so")
 	ensureListEmpty(t, requireNativeLibs)
 }
 
@@ -4408,7 +4560,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")
 }
@@ -4471,7 +4623,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 {
@@ -4510,7 +4662,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"]
 
@@ -4564,7 +4716,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"]
 
@@ -4585,6 +4737,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 {
@@ -4654,7 +4872,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
@@ -4738,7 +4956,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
@@ -4774,7 +4992,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")
@@ -4782,17 +5000,17 @@
 
 func TestApexInVariousPartition(t *testing.T) {
 	testcases := []struct {
-		propName, parition, flattenedPartition string
+		propName, partition string
 	}{
-		{"", "system", "system_ext"},
-		{"product_specific: true", "product", "product"},
-		{"soc_specific: true", "vendor", "vendor"},
-		{"proprietary: true", "vendor", "vendor"},
-		{"vendor: true", "vendor", "vendor"},
-		{"system_ext_specific: true", "system_ext", "system_ext"},
+		{"", "system"},
+		{"product_specific: true", "product"},
+		{"soc_specific: true", "vendor"},
+		{"proprietary: true", "vendor"},
+		{"vendor: true", "vendor"},
+		{"system_ext_specific: true", "system_ext"},
 	}
 	for _, tc := range testcases {
-		t.Run(tc.propName+":"+tc.parition, func(t *testing.T) {
+		t.Run(tc.propName+":"+tc.partition, func(t *testing.T) {
 			ctx := testApex(t, `
 				apex {
 					name: "myapex",
@@ -4808,19 +5026,12 @@
 				}
 			`)
 
-			apex := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
-			expected := "out/soong/target/product/test_device/" + tc.parition + "/apex"
+			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 {
 				t.Errorf("wrong install path. expected %q. actual %q", expected, actual)
 			}
-
-			flattened := ctx.ModuleForTests("myapex", "android_common_myapex_flattened").Module().(*apexBundle)
-			expected = "out/soong/target/product/test_device/" + tc.flattenedPartition + "/apex"
-			actual = flattened.installDir.RelativeToTop().String()
-			if actual != expected {
-				t.Errorf("wrong install path. expected %q. actual %q", expected, actual)
-			}
 		})
 	}
 }
@@ -4839,7 +5050,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")
 }
@@ -4897,7 +5108,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")
 }
@@ -4925,7 +5136,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")
 }
@@ -5144,6 +5355,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) {
@@ -5153,10 +5371,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))
 	}
 
@@ -5210,8 +5428,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")
@@ -5348,7 +5566,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() {
@@ -5434,14 +5652,15 @@
 	`
 
 		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, ``)
 		checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
 			my-bootclasspath-fragment/index.csv
 			out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
+			out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv
 		`)
 	})
 
@@ -5511,20 +5730,21 @@
 	`
 
 		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, ``)
 		checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
 			my-bootclasspath-fragment/index.csv
 			out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
+			out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv
 		`)
 
 		myApex := ctx.ModuleForTests("myapex", "android_common_myapex").Module()
 
 		overrideNames := []string{
-			"",
+			"myapex",
 			"myjavalib.myapex",
 			"libfoo.myapex",
 			"libbar.myapex",
@@ -5613,85 +5833,11 @@
 
 	t.Run("prebuilt library preferred with source", func(t *testing.T) {
 		bp := `
-		prebuilt_apex {
-			name: "myapex",
-			arch: {
-				arm64: {
-					src: "myapex-arm64.apex",
-				},
-				arm: {
-					src: "myapex-arm.apex",
-				},
-			},
-			exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
-		}
-
-		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",
-				signature_patterns: "my-bootclasspath-fragment/signature-patterns.csv",
-				filtered_stub_flags: "my-bootclasspath-fragment/filtered-stub-flags.csv",
-				filtered_flags: "my-bootclasspath-fragment/filtered-flags.csv",
-			},
-		}
-
-		java_import {
-			name: "libfoo",
-			prefer: true,
-			jars: ["libfoo.jar"],
-			apex_available: ["myapex"],
-			permitted_packages: ["foo"],
-		}
-
-		java_library {
-			name: "libfoo",
-			srcs: ["foo/bar/MyClass.java"],
-			apex_available: ["myapex"],
-		}
-
-		java_sdk_library_import {
-			name: "libbar",
-			prefer: true,
-			public: {
-				jars: ["libbar.jar"],
-			},
-			apex_available: ["myapex"],
-			shared_library: false,
-			permitted_packages: ["bar"],
-		}
-
-		java_sdk_library {
-			name: "libbar",
-			srcs: ["foo/bar/MyClass.java"],
-			unsafe_ignore_missing_latest_api: true,
-			apex_available: ["myapex"],
-		}
-	`
-
-		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")
-
-		// Verify the correct module jars contribute to the hiddenapi index file.
-		checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
-		checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
-			my-bootclasspath-fragment/index.csv
-			out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
-		`)
-	})
-
-	t.Run("prebuilt with source apex preferred", func(t *testing.T) {
-		bp := `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
-			java_libs: ["libfoo", "libbar"],
 			updatable: false,
+			bootclasspath_fragments: ["my-bootclasspath-fragment"],
 		}
 
 		apex_key {
@@ -5700,6 +5846,115 @@
 			private_key: "testkey.pem",
 		}
 
+		bootclasspath_fragment {
+			name: "my-bootclasspath-fragment",
+			contents: ["libfoo", "libbar"],
+			apex_available: ["myapex"],
+			hidden_api: {
+				split_packages: ["*"],
+			},
+		}
+
+		prebuilt_apex {
+			name: "myapex",
+			arch: {
+				arm64: {
+					src: "myapex-arm64.apex",
+				},
+				arm: {
+					src: "myapex-arm.apex",
+				},
+			},
+			exported_bootclasspath_fragments: ["my-bootclasspath-fragment"],
+		}
+
+		prebuilt_bootclasspath_fragment {
+			name: "my-bootclasspath-fragment",
+			prefer: true,
+			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",
+				signature_patterns: "my-bootclasspath-fragment/signature-patterns.csv",
+				filtered_stub_flags: "my-bootclasspath-fragment/filtered-stub-flags.csv",
+				filtered_flags: "my-bootclasspath-fragment/filtered-flags.csv",
+			},
+		}
+
+		java_import {
+			name: "libfoo",
+			prefer: true,
+			jars: ["libfoo.jar"],
+			apex_available: ["myapex"],
+			permitted_packages: ["foo"],
+		}
+
+		java_library {
+			name: "libfoo",
+			srcs: ["foo/bar/MyClass.java"],
+			apex_available: ["myapex"],
+			installable: true,
+		}
+
+		java_sdk_library_import {
+			name: "libbar",
+			prefer: true,
+			public: {
+				jars: ["libbar.jar"],
+			},
+			apex_available: ["myapex"],
+			shared_library: false,
+			permitted_packages: ["bar"],
+		}
+
+		java_sdk_library {
+			name: "libbar",
+			srcs: ["foo/bar/MyClass.java"],
+			unsafe_ignore_missing_latest_api: true,
+			apex_available: ["myapex"],
+			compile_dex: true,
+		}
+	`
+
+		ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
+		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, ``)
+		checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
+			my-bootclasspath-fragment/index.csv
+			out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
+			out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv
+		`)
+	})
+
+	t.Run("prebuilt with source apex preferred", func(t *testing.T) {
+		bp := `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			updatable: false,
+			bootclasspath_fragments: ["my-bootclasspath-fragment"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		bootclasspath_fragment {
+			name: "my-bootclasspath-fragment",
+			contents: ["libfoo", "libbar"],
+			apex_available: ["myapex"],
+			hidden_api: {
+				split_packages: ["*"],
+			},
+		}
+
 		prebuilt_apex {
 			name: "myapex",
 			arch: {
@@ -5738,6 +5993,7 @@
 			srcs: ["foo/bar/MyClass.java"],
 			apex_available: ["myapex"],
 			permitted_packages: ["foo"],
+			installable: true,
 		}
 
 		java_sdk_library_import {
@@ -5755,18 +6011,20 @@
 			unsafe_ignore_missing_latest_api: true,
 			apex_available: ["myapex"],
 			permitted_packages: ["bar"],
+			compile_dex: true,
 		}
 	`
 
 		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, ``)
 		checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
-			my-bootclasspath-fragment/index.csv
 			out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
+			out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/modular-hiddenapi/index.csv
+			out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv
 		`)
 	})
 
@@ -5776,7 +6034,7 @@
 			name: "myapex",
 			enabled: false,
 			key: "myapex.key",
-			java_libs: ["libfoo", "libbar"],
+			bootclasspath_fragments: ["my-bootclasspath-fragment"],
 		}
 
 		apex_key {
@@ -5785,6 +6043,16 @@
 			private_key: "testkey.pem",
 		}
 
+		bootclasspath_fragment {
+			name: "my-bootclasspath-fragment",
+			enabled: false,
+			contents: ["libfoo", "libbar"],
+			apex_available: ["myapex"],
+			hidden_api: {
+				split_packages: ["*"],
+			},
+		}
+
 		prebuilt_apex {
 			name: "myapex",
 			arch: {
@@ -5814,7 +6082,6 @@
 
 		java_import {
 			name: "libfoo",
-			prefer: true,
 			jars: ["libfoo.jar"],
 			apex_available: ["myapex"],
 			permitted_packages: ["foo"],
@@ -5822,13 +6089,14 @@
 
 		java_library {
 			name: "libfoo",
+			enabled: false,
 			srcs: ["foo/bar/MyClass.java"],
 			apex_available: ["myapex"],
+			installable: true,
 		}
 
 		java_sdk_library_import {
 			name: "libbar",
-			prefer: true,
 			public: {
 				jars: ["libbar.jar"],
 			},
@@ -5839,84 +6107,104 @@
 
 		java_sdk_library {
 			name: "libbar",
+			enabled: false,
 			srcs: ["foo/bar/MyClass.java"],
 			unsafe_ignore_missing_latest_api: true,
 			apex_available: ["myapex"],
+			compile_dex: true,
 		}
 	`
 
 		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, ``)
 		checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
 			my-bootclasspath-fragment/index.csv
 			out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
+			out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_apex10000/modular-hiddenapi/index.csv
 		`)
 	})
-}
 
-func TestPrebuiltSkipsSymbols(t *testing.T) {
-	testCases := []struct {
-		name               string
-		usePrebuilt        bool
-		installSymbolFiles bool
-	}{
-		{
-			name:               "Source module build rule doesn't install symbol files",
-			usePrebuilt:        true,
-			installSymbolFiles: false,
-		},
-		{
-			name:               "Source module is installed with symbols",
-			usePrebuilt:        false,
-			installSymbolFiles: true,
-		},
-	}
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			preferProperty := "prefer: false"
-			if tc.usePrebuilt {
-				preferProperty = "prefer: true"
-			}
-			ctx := testApex(t, `
-				// Source module
-				apex {
-					name: "myapex",
-					binaries: ["foo"],
-					key: "myapex.key",
-					updatable: false,
-				}
+	t.Run("Co-existing unflagged apexes should create a duplicate deapexer error in hiddenapi processing", 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",
-				}
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
 
-				apex_set {
-					name: "myapex",
-					set: "myapex.apks",
-					`+preferProperty+`
-				}
+		// 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,
+		}
 
-				cc_binary {
-					name: "foo",
-					srcs: ["mylib.cpp"],
-					system_shared_libs: [],
-					stl: "none",
-					apex_available: [ "myapex" ],
-				}
-			`)
-			// Symbol files are installed by installing entries under ${OUT}/apex/{apex name}
-			android.AssertStringListContainsEquals(t, "Installs",
-				ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().FilesToInstall().Strings(),
-				filepath.Join(ctx.Config().SoongOutDir(), "target/product/test_device/apex/myapex/bin/foo"),
-				tc.installSymbolFiles)
-		})
-	}
+		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 installable prebuilt APEXes provide ambiguous deapexers: prebuilt_myapex.v1 and prebuilt_myapex.v2", preparer, fragment)
+	})
+
 }
 
 func TestApexWithTests(t *testing.T) {
@@ -5991,7 +6279,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.
@@ -6008,7 +6296,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_"
@@ -6019,42 +6307,7 @@
 	ensureContains(t, androidMk, "LOCAL_MODULE := mytest1.myapex\n")
 	ensureContains(t, androidMk, "LOCAL_MODULE := mytest2.myapex\n")
 	ensureContains(t, androidMk, "LOCAL_MODULE := mytest3.myapex\n")
-	ensureContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.myapex\n")
-	ensureContains(t, androidMk, "LOCAL_MODULE := apex_pubkey.myapex\n")
 	ensureContains(t, androidMk, "LOCAL_MODULE := myapex\n")
-
-	flatBundle := ctx.ModuleForTests("myapex", "android_common_myapex_flattened").Module().(*apexBundle)
-	data = android.AndroidMkDataForTest(t, ctx, flatBundle)
-	data.Custom(&builder, name, prefix, "", data)
-	flatAndroidMk := builder.String()
-	ensureContainsOnce(t, flatAndroidMk, "LOCAL_TEST_DATA := :baz :bar/baz\n")
-	ensureContainsOnce(t, flatAndroidMk, "LOCAL_TEST_DATA := :testdata/baz\n")
-}
-
-func TestInstallExtraFlattenedApexes(t *testing.T) {
-	ctx := testApex(t, `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			updatable: false,
-		}
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-	`,
-		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-			variables.InstallExtraFlattenedApexes = proptools.BoolPtr(true)
-		}),
-	)
-	ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
-	ensureListContains(t, ab.makeModulesToInstall, "myapex.flattened")
-	mk := android.AndroidMkDataForTest(t, ctx, ab)
-	var builder strings.Builder
-	mk.Custom(&builder, ab.Name(), "TARGET_", "", mk)
-	androidMk := builder.String()
-	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := apex_manifest.pb.myapex apex_pubkey.myapex myapex.flattened\n")
 }
 
 func TestErrorsIfDepsAreNotEnabled(t *testing.T) {
@@ -6126,7 +6379,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")
@@ -6190,7 +6443,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"]
 
@@ -6296,7 +6549,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"]
 
@@ -6341,7 +6594,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",
 	})
 }
@@ -6371,7 +6624,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"]
 
@@ -6496,6 +6749,72 @@
 	}`)
 }
 
+func TestApexAvailable_IndirectStaticDep(t *testing.T) {
+	testApex(t, `
+	apex {
+		name: "myapex",
+		key: "myapex.key",
+		native_shared_libs: ["libfoo"],
+		updatable: false,
+	}
+
+	apex_key {
+		name: "myapex.key",
+		public_key: "testkey.avbpubkey",
+		private_key: "testkey.pem",
+	}
+
+	cc_library {
+		name: "libfoo",
+		stl: "none",
+		static_libs: ["libbar"],
+		system_shared_libs: [],
+		apex_available: ["myapex"],
+	}
+
+	cc_library {
+		name: "libbar",
+		stl: "none",
+		shared_libs: ["libbaz"],
+		system_shared_libs: [],
+		apex_available: ["myapex"],
+	}
+
+	cc_library {
+		name: "libbaz",
+		stl: "none",
+		system_shared_libs: [],
+	}`)
+
+	testApexError(t, `requires "libbar" that doesn't list the APEX under 'apex_available'.`, `
+	apex {
+		name: "myapex",
+		key: "myapex.key",
+		native_shared_libs: ["libfoo"],
+		updatable: false,
+	}
+
+	apex_key {
+		name: "myapex.key",
+		public_key: "testkey.avbpubkey",
+		private_key: "testkey.pem",
+	}
+
+	cc_library {
+		name: "libfoo",
+		stl: "none",
+		static_libs: ["libbar"],
+		system_shared_libs: [],
+		apex_available: ["myapex"],
+	}
+
+	cc_library {
+		name: "libbar",
+		stl: "none",
+		system_shared_libs: [],
+	}`)
+}
+
 func TestApexAvailable_InvalidApexName(t *testing.T) {
 	testApexError(t, "\"otherapex\" is not a valid module name", `
 	apex {
@@ -6622,22 +6941,32 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
+		override_apex {
+			name: "myoverrideapex",
+			base: "bar",
+		}
 	`)
 
-	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"]
 	if barActualDefaultVersion != barExpectedDefaultVersion {
 		t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion)
 	}
+
+	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)
+	}
 }
 
 func TestApexAvailable_ApexAvailableName(t *testing.T) {
@@ -6993,8 +7322,8 @@
 		}
 	`, 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())
 	}
@@ -7002,7 +7331,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"]
 
@@ -7038,13 +7367,11 @@
 	androidMk := builder.String()
 	ensureContains(t, androidMk, "LOCAL_MODULE := override_app.override_myapex")
 	ensureContains(t, androidMk, "LOCAL_MODULE := overrideBpf.o.override_myapex")
-	ensureContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.override_myapex")
 	ensureContains(t, androidMk, "LOCAL_MODULE_STEM := override_myapex.apex")
 	ensureContains(t, androidMk, "LOCAL_OVERRIDES_MODULES := unknownapex myapex")
 	ensureNotContains(t, androidMk, "LOCAL_MODULE := app.myapex")
 	ensureNotContains(t, androidMk, "LOCAL_MODULE := bpf.myapex")
 	ensureNotContains(t, androidMk, "LOCAL_MODULE := override_app.myapex")
-	ensureNotContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.myapex")
 	ensureNotContains(t, androidMk, "LOCAL_MODULE_STEM := myapex.apex")
 }
 
@@ -7094,7 +7421,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
@@ -7153,7 +7480,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
@@ -7191,7 +7518,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")
@@ -7255,7 +7582,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",
 	})
@@ -7304,7 +7631,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",
@@ -7356,7 +7683,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",
 	})
@@ -7445,7 +7772,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",
@@ -7525,7 +7852,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",
 	})
@@ -7567,6 +7894,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 {
@@ -7620,14 +7983,14 @@
 		}
 	`)
 
-	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_"
 	var builder strings.Builder
 	data.Custom(&builder, name, prefix, "", data)
 	androidMk := builder.String()
-	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := mylib.myapex:64 apex_manifest.pb.myapex apex_pubkey.myapex a b\n")
+	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := mylib.myapex:64 a b\n")
 	ensureContains(t, androidMk, "LOCAL_HOST_REQUIRED_MODULES := c d\n")
 	ensureContains(t, androidMk, "LOCAL_TARGET_REQUIRED_MODULES := e f\n")
 }
@@ -7759,13 +8122,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")
@@ -7773,13 +8136,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
@@ -7825,7 +8188,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)
@@ -7835,7 +8198,7 @@
 	ensureNotContains(t, androidMk, "LOCAL_MODULE := prebuilt_myotherlib.myapex\n")
 	ensureNotContains(t, androidMk, "LOCAL_MODULE := myotherlib.myapex\n")
 	// `myapex` should have `myotherlib` in its required line, not `prebuilt_myotherlib`
-	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := mylib.myapex:64 myotherlib:64 apex_manifest.pb.myapex apex_pubkey.myapex\n")
+	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := mylib.myapex:64 myotherlib:64\n")
 }
 
 func TestApexWithJniLibs(t *testing.T) {
@@ -7910,10 +8273,10 @@
 
 	`)
 
-	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 mylib3.so")
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"bin/mybin",
 		"lib64/mylib.so",
 		"lib64/mylib2.so",
@@ -7975,8 +8338,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"}]}`)
@@ -8001,9 +8364,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)
@@ -8035,9 +8398,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())
@@ -8062,135 +8425,15 @@
 		}
 	`)
 
-	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())
 }
 
-func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, preparer android.FixturePreparer, fragments ...java.ApexVariantReference) {
-	t.Helper()
-
-	bp := `
-		java_library {
-			name: "some-updatable-apex-lib",
-			srcs: ["a.java"],
-			sdk_version: "current",
-			apex_available: [
-				"some-updatable-apex",
-			],
-			permitted_packages: ["some.updatable.apex.lib"],
-			min_sdk_version: "33",
-		}
-
-		java_library {
-			name: "some-non-updatable-apex-lib",
-			srcs: ["a.java"],
-			apex_available: [
-				"some-non-updatable-apex",
-			],
-			compile_dex: true,
-			permitted_packages: ["some.non.updatable.apex.lib"],
-		}
-
-		bootclasspath_fragment {
-			name: "some-non-updatable-fragment",
-			contents: ["some-non-updatable-apex-lib"],
-			apex_available: [
-				"some-non-updatable-apex",
-			],
-			hidden_api: {
-				split_packages: ["*"],
-			},
-		}
-
-		java_library {
-			name: "some-platform-lib",
-			srcs: ["a.java"],
-			sdk_version: "current",
-			installable: true,
-		}
-
-		java_library {
-			name: "some-art-lib",
-			srcs: ["a.java"],
-			sdk_version: "current",
-			apex_available: [
-				"com.android.art.debug",
-			],
-			hostdex: true,
-			compile_dex: true,
-			min_sdk_version: "33",
-		}
-
-		apex {
-			name: "some-updatable-apex",
-			key: "some-updatable-apex.key",
-			java_libs: ["some-updatable-apex-lib"],
-			updatable: true,
-			min_sdk_version: "33",
-		}
-
-		apex {
-			name: "some-non-updatable-apex",
-			key: "some-non-updatable-apex.key",
-			bootclasspath_fragments: ["some-non-updatable-fragment"],
-			updatable: false,
-		}
-
-		apex_key {
-			name: "some-updatable-apex.key",
-		}
-
-		apex_key {
-			name: "some-non-updatable-apex.key",
-		}
-
-		apex {
-			name: "com.android.art.debug",
-			key: "com.android.art.debug.key",
-			bootclasspath_fragments: ["art-bootclasspath-fragment"],
-			updatable: true,
-			min_sdk_version: "33",
-		}
-
-		bootclasspath_fragment {
-			name: "art-bootclasspath-fragment",
-			image_name: "art",
-			contents: ["some-art-lib"],
-			apex_available: [
-				"com.android.art.debug",
-			],
-			hidden_api: {
-				split_packages: ["*"],
-			},
-		}
-
-		apex_key {
-			name: "com.android.art.debug.key",
-		}
-
-		filegroup {
-			name: "some-updatable-apex-file_contexts",
-			srcs: [
-				"system/sepolicy/apex/some-updatable-apex-file_contexts",
-			],
-		}
-
-		filegroup {
-			name: "some-non-updatable-apex-file_contexts",
-			srcs: [
-				"system/sepolicy/apex/some-non-updatable-apex-file_contexts",
-			],
-		}
-	`
-
-	testDexpreoptWithApexes(t, bp, errmsg, preparer, fragments...)
-}
-
 func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, preparer android.FixturePreparer, fragments ...java.ApexVariantReference) *android.TestContext {
 	t.Helper()
 
@@ -8214,7 +8457,7 @@
 	result := android.GroupFixturePreparers(
 		cc.PrepareForTestWithCcDefaultModules,
 		java.PrepareForTestWithHiddenApiBuildComponents,
-		java.PrepareForTestWithJavaDefaultModules,
+		java.PrepareForTestWithDexpreopt,
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		PrepareForTestWithApexBuildComponents,
 		preparer,
@@ -8229,12 +8472,16 @@
 					platform_bootclasspath {
 						name: "platform-bootclasspath",
 						fragments: [
+							{apex: "com.android.art", module: "art-bootclasspath-fragment"},
   						%s
 						],
 					}
 				`, insert))
 			}
 		}),
+		// Dexpreopt for boot jars requires the ART boot image profile.
+		java.PrepareApexBootJarModule("com.android.art", "core-oj"),
+		dexpreopt.FixtureSetArtBootJars("com.android.art:core-oj"),
 		dexpreopt.FixtureSetBootImageProfiles("art/build/boot/boot-image-profile.txt"),
 	).
 		ExtendWithErrorHandler(errorHandler).
@@ -8246,30 +8493,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
 		}
 	`
@@ -8279,7 +8535,7 @@
 			java_import {
 				name: "libfoo",
 				jars: ["libfoo.jar"],
-				apex_available: ["com.android.myapex"],
+				apex_available: ["com.android.art"],
 			}
 		`)
 	})
@@ -8291,7 +8547,8 @@
 				public: {
 					jars: ["libbar.jar"],
 				},
-				apex_available: ["com.android.myapex"],
+				shared_library: false,
+				apex_available: ["com.android.art"],
 			}
 		`)
 	})
@@ -8306,7 +8563,8 @@
 				public: {
 					jars: ["libbar.jar"],
 				},
-				apex_available: ["com.android.myapex"],
+				shared_library: false,
+				apex_available: ["com.android.art"],
 			}
 		`)
 	})
@@ -8318,6 +8576,8 @@
 		PrepareForTestWithApexBuildComponents,
 	)
 
+	errCtx := moduleErrorfTestCtx{}
+
 	bpBase := `
 		apex_set {
 			name: "com.android.myapex",
@@ -8366,8 +8626,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) {
@@ -8389,8 +8649,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) {
@@ -8541,126 +8801,6 @@
 	)
 }
 
-func TestNoUpdatableJarsInBootImage(t *testing.T) {
-	// Set the BootJars in dexpreopt.GlobalConfig and productVariables to the same value. This can
-	// result in an invalid configuration as it does not set the ArtApexJars and allows art apex
-	// modules to be included in the BootJars.
-	prepareSetBootJars := func(bootJars ...string) android.FixturePreparer {
-		return android.GroupFixturePreparers(
-			dexpreopt.FixtureSetBootJars(bootJars...),
-			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-				variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
-			}),
-		)
-	}
-
-	// Set the ArtApexJars and BootJars in dexpreopt.GlobalConfig and productVariables all to the
-	// same value. This can result in an invalid configuration as it allows non art apex jars to be
-	// specified in the ArtApexJars configuration.
-	prepareSetArtJars := func(bootJars ...string) android.FixturePreparer {
-		return android.GroupFixturePreparers(
-			dexpreopt.FixtureSetArtBootJars(bootJars...),
-			dexpreopt.FixtureSetBootJars(bootJars...),
-			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-				variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
-			}),
-		)
-	}
-
-	t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) {
-		preparer := android.GroupFixturePreparers(
-			java.FixtureConfigureBootJars("com.android.art.debug:some-art-lib"),
-			java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
-		)
-		fragments := []java.ApexVariantReference{
-			{
-				Apex:   proptools.StringPtr("com.android.art.debug"),
-				Module: proptools.StringPtr("art-bootclasspath-fragment"),
-			},
-			{
-				Apex:   proptools.StringPtr("some-non-updatable-apex"),
-				Module: proptools.StringPtr("some-non-updatable-fragment"),
-			},
-		}
-		testNoUpdatableJarsInBootImage(t, "", preparer, fragments...)
-	})
-
-	t.Run("updatable jar from ART apex in the platform bootclasspath => error", func(t *testing.T) {
-		err := `module "some-art-lib" from updatable apexes \["com.android.art.debug"\] is not allowed in the platform bootclasspath`
-		// Update the dexpreopt BootJars directly.
-		preparer := android.GroupFixturePreparers(
-			prepareSetBootJars("com.android.art.debug:some-art-lib"),
-			java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
-		)
-		testNoUpdatableJarsInBootImage(t, err, preparer)
-	})
-
-	t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
-		err := `ArtApexJars expects this to be in apex "some-updatable-apex" but this is only in apexes.*"com.android.art.debug"`
-		// Update the dexpreopt ArtApexJars directly.
-		preparer := prepareSetArtJars("some-updatable-apex:some-updatable-apex-lib")
-		testNoUpdatableJarsInBootImage(t, err, preparer)
-	})
-
-	t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
-		err := `ArtApexJars expects this to be in apex "some-non-updatable-apex" but this is only in apexes.*"com.android.art.debug"`
-		// Update the dexpreopt ArtApexJars directly.
-		preparer := prepareSetArtJars("some-non-updatable-apex:some-non-updatable-apex-lib")
-		testNoUpdatableJarsInBootImage(t, err, preparer)
-	})
-
-	t.Run("updatable jar from some other apex in the platform bootclasspath => error", func(t *testing.T) {
-		err := `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the platform bootclasspath`
-		preparer := android.GroupFixturePreparers(
-			java.FixtureConfigureBootJars("some-updatable-apex:some-updatable-apex-lib"),
-			java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
-		)
-		testNoUpdatableJarsInBootImage(t, err, preparer)
-	})
-
-	t.Run("non-updatable jar from some other apex in the platform bootclasspath => ok", func(t *testing.T) {
-		preparer := java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib")
-		fragment := java.ApexVariantReference{
-			Apex:   proptools.StringPtr("some-non-updatable-apex"),
-			Module: proptools.StringPtr("some-non-updatable-fragment"),
-		}
-		testNoUpdatableJarsInBootImage(t, "", preparer, fragment)
-	})
-
-	t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) {
-		err := `"platform-bootclasspath" depends on undefined module "nonexistent"`
-		preparer := java.FixtureConfigureBootJars("platform:nonexistent")
-		testNoUpdatableJarsInBootImage(t, err, preparer)
-	})
-
-	t.Run("nonexistent jar in the platform bootclasspath => error", func(t *testing.T) {
-		err := `"platform-bootclasspath" depends on undefined module "nonexistent"`
-		preparer := java.FixtureConfigureBootJars("platform:nonexistent")
-		testNoUpdatableJarsInBootImage(t, err, preparer)
-	})
-
-	t.Run("platform jar in the ART boot image => error", func(t *testing.T) {
-		err := `ArtApexJars is invalid as it requests a platform variant of "some-platform-lib"`
-		// Update the dexpreopt ArtApexJars directly.
-		preparer := prepareSetArtJars("platform:some-platform-lib")
-		testNoUpdatableJarsInBootImage(t, err, preparer)
-	})
-
-	t.Run("platform jar in the platform bootclasspath => ok", func(t *testing.T) {
-		preparer := android.GroupFixturePreparers(
-			java.FixtureConfigureBootJars("platform:some-platform-lib"),
-			java.FixtureConfigureApexBootJars("some-non-updatable-apex:some-non-updatable-apex-lib"),
-		)
-		fragments := []java.ApexVariantReference{
-			{
-				Apex:   proptools.StringPtr("some-non-updatable-apex"),
-				Module: proptools.StringPtr("some-non-updatable-fragment"),
-			},
-		}
-		testNoUpdatableJarsInBootImage(t, "", preparer, fragments...)
-	})
-}
-
 func TestDexpreoptAccessDexFilesFromPrebuiltApex(t *testing.T) {
 	preparer := java.FixtureConfigureApexBootJars("myapex:libfoo")
 	t.Run("prebuilt no source", func(t *testing.T) {
@@ -9013,14 +9153,14 @@
 		apex {
 			name: "com.android.art",
 			key: "myapex.key",
-			native_shared_libs: ["mylib"],
+			native_shared_libs: ["libnativebridge"],
 			updatable: false,
 		}
 
 		apex {
 			name: "com.android.art.debug",
 			key: "myapex.key",
-			native_shared_libs: ["mylib", "mytestlib"],
+			native_shared_libs: ["libnativebridge", "libnativebrdige_test"],
 			updatable: false,
 		}
 
@@ -9031,8 +9171,8 @@
 		}
 
 		cc_library {
-			name: "mylib",
-			srcs: ["mylib.cpp"],
+			name: "libnativebridge",
+			srcs: ["libnativebridge.cpp"],
 			system_shared_libs: [],
 			stl: "none",
 			stubs: {
@@ -9042,10 +9182,10 @@
 		}
 
 		cc_library {
-			name: "mytestlib",
+			name: "libnativebrdige_test",
 			srcs: ["mylib.cpp"],
 			system_shared_libs: [],
-			shared_libs: ["mylib"],
+			shared_libs: ["libnativebridge"],
 			stl: "none",
 			apex_available: ["com.android.art.debug"],
 			test_for: ["com.android.art"],
@@ -9082,7 +9222,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")
@@ -9123,7 +9263,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")
@@ -9183,9 +9323,9 @@
 		}
 	`)
 
-	apexKeysText := ctx.SingletonForTests("apex_keys_text")
-	content := apexKeysText.MaybeDescription("apexkeys.txt").BuildParams.Args["content"]
-	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_ext" sign_tool="sign_myapex"`)
+	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"`)
 }
 
 func TestApexKeysTxtOverrides(t *testing.T) {
@@ -9224,10 +9364,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) {
@@ -9275,12 +9417,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)
 	}
@@ -9341,14 +9483,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
@@ -9400,7 +9542,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)
@@ -9408,7 +9550,7 @@
 
 	// The make level dependency needs to be on otherlib - prebuilt_otherlib isn't
 	// a thing there.
-	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := libc++:64 mylib.myapex:64 apex_manifest.pb.myapex apex_pubkey.myapex otherlib\n")
+	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := libc++:64 mylib.myapex:64 otherlib\n")
 }
 
 func TestExcludeDependency(t *testing.T) {
@@ -9457,7 +9599,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")
 }
 
@@ -9622,28 +9764,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 {
@@ -9797,12 +9917,12 @@
 		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)
 	androidMk := builder.String()
-	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := foo.myapex apex_manifest.pb.myapex apex_pubkey.myapex foo-dexpreopt-arm64-apex@myapex@javalib@foo.jar@classes.odex foo-dexpreopt-arm64-apex@myapex@javalib@foo.jar@classes.vdex\n")
+	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := foo.myapex foo-dexpreopt-arm64-apex@myapex@javalib@foo.jar@classes.odex foo-dexpreopt-arm64-apex@myapex@javalib@foo.jar@classes.vdex\n")
 }
 
 func TestAndroidMk_DexpreoptBuiltInstalledForApex_Prebuilt(t *testing.T) {
@@ -9873,12 +9993,12 @@
 		}
 	`)
 
-	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)
 	androidMk := builder.String()
-	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := foo.myapex apex_manifest.pb.myapex apex_pubkey.myapex otherapex")
+	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := foo.myapex otherapex")
 }
 
 func TestAndroidMk_RequiredDeps(t *testing.T) {
@@ -9896,21 +10016,13 @@
 		}
 	`)
 
-	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
 	data.Custom(&builder, bundle.BaseModuleName(), "TARGET_", "", data)
 	androidMk := builder.String()
-	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := apex_manifest.pb.myapex apex_pubkey.myapex foo\n")
-
-	flattenedBundle := ctx.ModuleForTests("myapex", "android_common_myapex_flattened").Module().(*apexBundle)
-	flattenedBundle.makeModulesToInstall = append(flattenedBundle.makeModulesToInstall, "foo")
-	flattenedData := android.AndroidMkDataForTest(t, ctx, flattenedBundle)
-	var flattenedBuilder strings.Builder
-	flattenedData.Custom(&flattenedBuilder, flattenedBundle.BaseModuleName(), "TARGET_", "", flattenedData)
-	flattenedAndroidMk := flattenedBuilder.String()
-	ensureContains(t, flattenedAndroidMk, "LOCAL_REQUIRED_MODULES := apex_manifest.pb.myapex.flattened apex_pubkey.myapex.flattened foo\n")
+	ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := foo\n")
 }
 
 func TestApexOutputFileProducer(t *testing.T) {
@@ -9922,12 +10034,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) {
@@ -10161,188 +10273,196 @@
 	}
 }
 
-// TODO(b/193460475): Re-enable this test
-//func TestApexStrictUpdtabilityLint(t *testing.T) {
-//	bpTemplate := `
-//		apex {
-//			name: "myapex",
-//			key: "myapex.key",
-//			java_libs: ["myjavalib"],
-//			updatable: %v,
-//			min_sdk_version: "29",
-//		}
-//		apex_key {
-//			name: "myapex.key",
-//		}
-//		java_library {
-//			name: "myjavalib",
-//			srcs: ["MyClass.java"],
-//			apex_available: [ "myapex" ],
-//			lint: {
-//				strict_updatability_linting: %v,
-//			},
-//			sdk_version: "current",
-//			min_sdk_version: "29",
-//		}
-//		`
-//	fs := android.MockFS{
-//		"lint-baseline.xml": nil,
-//	}
-//
-//	testCases := []struct {
-//		testCaseName              string
-//		apexUpdatable             bool
-//		javaStrictUpdtabilityLint bool
-//		lintFileExists            bool
-//		disallowedFlagExpected    bool
-//	}{
-//		{
-//			testCaseName:              "lint-baseline.xml does not exist, no disallowed flag necessary in lint cmd",
-//			apexUpdatable:             true,
-//			javaStrictUpdtabilityLint: true,
-//			lintFileExists:            false,
-//			disallowedFlagExpected:    false,
-//		},
-//		{
-//			testCaseName:              "non-updatable apex respects strict_updatability of javalib",
-//			apexUpdatable:             false,
-//			javaStrictUpdtabilityLint: false,
-//			lintFileExists:            true,
-//			disallowedFlagExpected:    false,
-//		},
-//		{
-//			testCaseName:              "non-updatable apex respects strict updatability of javalib",
-//			apexUpdatable:             false,
-//			javaStrictUpdtabilityLint: true,
-//			lintFileExists:            true,
-//			disallowedFlagExpected:    true,
-//		},
-//		{
-//			testCaseName:              "updatable apex sets strict updatability of javalib to true",
-//			apexUpdatable:             true,
-//			javaStrictUpdtabilityLint: false, // will be set to true by mutator
-//			lintFileExists:            true,
-//			disallowedFlagExpected:    true,
-//		},
-//	}
-//
-//	for _, testCase := range testCases {
-//		bp := fmt.Sprintf(bpTemplate, testCase.apexUpdatable, testCase.javaStrictUpdtabilityLint)
-//		fixtures := []android.FixturePreparer{}
-//		if testCase.lintFileExists {
-//			fixtures = append(fixtures, fs.AddToFixture())
-//		}
-//
-//		result := testApex(t, bp, fixtures...)
-//		myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
-//		sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
-//		disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi")
-//
-//		if disallowedFlagActual != testCase.disallowedFlagExpected {
-//			t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
-//		}
-//	}
-//}
-//
-//func TestUpdatabilityLintSkipLibcore(t *testing.T) {
-//	bp := `
-//		apex {
-//			name: "myapex",
-//			key: "myapex.key",
-//			java_libs: ["myjavalib"],
-//			updatable: true,
-//			min_sdk_version: "29",
-//		}
-//		apex_key {
-//			name: "myapex.key",
-//		}
-//		java_library {
-//			name: "myjavalib",
-//			srcs: ["MyClass.java"],
-//			apex_available: [ "myapex" ],
-//			sdk_version: "current",
-//			min_sdk_version: "29",
-//		}
-//		`
-//
-//	testCases := []struct {
-//		testCaseName           string
-//		moduleDirectory        string
-//		disallowedFlagExpected bool
-//	}{
-//		{
-//			testCaseName:           "lintable module defined outside libcore",
-//			moduleDirectory:        "",
-//			disallowedFlagExpected: true,
-//		},
-//		{
-//			testCaseName:           "lintable module defined in libcore root directory",
-//			moduleDirectory:        "libcore/",
-//			disallowedFlagExpected: false,
-//		},
-//		{
-//			testCaseName:           "lintable module defined in libcore child directory",
-//			moduleDirectory:        "libcore/childdir/",
-//			disallowedFlagExpected: true,
-//		},
-//	}
-//
-//	for _, testCase := range testCases {
-//		lintFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"lint-baseline.xml", "")
-//		bpFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"Android.bp", bp)
-//		result := testApex(t, "", lintFileCreator, bpFileCreator)
-//		myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
-//		sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
-//		cmdFlags := fmt.Sprintf("--baseline %vlint-baseline.xml --disallowed_issues NewApi", testCase.moduleDirectory)
-//		disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, cmdFlags)
-//
-//		if disallowedFlagActual != testCase.disallowedFlagExpected {
-//			t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
-//		}
-//	}
-//}
-//
-//// checks transtive deps of an apex coming from bootclasspath_fragment
-//func TestApexStrictUpdtabilityLintBcpFragmentDeps(t *testing.T) {
-//	bp := `
-//		apex {
-//			name: "myapex",
-//			key: "myapex.key",
-//			bootclasspath_fragments: ["mybootclasspathfragment"],
-//			updatable: true,
-//			min_sdk_version: "29",
-//		}
-//		apex_key {
-//			name: "myapex.key",
-//		}
-//		bootclasspath_fragment {
-//			name: "mybootclasspathfragment",
-//			contents: ["myjavalib"],
-//			apex_available: ["myapex"],
-//			hidden_api: {
-//				split_packages: ["*"],
-//			},
-//		}
-//		java_library {
-//			name: "myjavalib",
-//			srcs: ["MyClass.java"],
-//			apex_available: [ "myapex" ],
-//			sdk_version: "current",
-//			min_sdk_version: "29",
-//			compile_dex: true,
-//		}
-//		`
-//	fs := android.MockFS{
-//		"lint-baseline.xml": nil,
-//	}
-//
-//	result := testApex(t, bp, dexpreopt.FixtureSetApexBootJars("myapex:myjavalib"), fs.AddToFixture())
-//	myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
-//	sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
-//	if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") {
-//		t.Errorf("Strict updabality lint missing in myjavalib coming from bootclasspath_fragment mybootclasspath-fragment\nActual lint cmd: %v", *sboxProto.Commands[0].Command)
-//	}
-//}
+func TestApexStrictUpdtabilityLint(t *testing.T) {
+	bpTemplate := `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			java_libs: ["myjavalib"],
+			updatable: %v,
+			min_sdk_version: "29",
+		}
+		apex_key {
+			name: "myapex.key",
+		}
+		java_library {
+			name: "myjavalib",
+			srcs: ["MyClass.java"],
+			apex_available: [ "myapex" ],
+			lint: {
+				strict_updatability_linting: %v,
+				%s
+			},
+			sdk_version: "current",
+			min_sdk_version: "29",
+		}
+		`
+	fs := android.MockFS{
+		"lint-baseline.xml": nil,
+	}
+
+	testCases := []struct {
+		testCaseName              string
+		apexUpdatable             bool
+		javaStrictUpdtabilityLint bool
+		lintFileExists            bool
+		disallowedFlagExpected    bool
+	}{
+		{
+			testCaseName:              "lint-baseline.xml does not exist, no disallowed flag necessary in lint cmd",
+			apexUpdatable:             true,
+			javaStrictUpdtabilityLint: true,
+			lintFileExists:            false,
+			disallowedFlagExpected:    false,
+		},
+		{
+			testCaseName:              "non-updatable apex respects strict_updatability of javalib",
+			apexUpdatable:             false,
+			javaStrictUpdtabilityLint: false,
+			lintFileExists:            true,
+			disallowedFlagExpected:    false,
+		},
+		{
+			testCaseName:              "non-updatable apex respects strict updatability of javalib",
+			apexUpdatable:             false,
+			javaStrictUpdtabilityLint: true,
+			lintFileExists:            true,
+			disallowedFlagExpected:    true,
+		},
+		{
+			testCaseName:              "updatable apex sets strict updatability of javalib to true",
+			apexUpdatable:             true,
+			javaStrictUpdtabilityLint: false, // will be set to true by mutator
+			lintFileExists:            true,
+			disallowedFlagExpected:    true,
+		},
+	}
+
+	for _, testCase := range testCases {
+		fixtures := []android.FixturePreparer{}
+		baselineProperty := ""
+		if testCase.lintFileExists {
+			fixtures = append(fixtures, fs.AddToFixture())
+			baselineProperty = "baseline_filename: \"lint-baseline.xml\""
+		}
+		bp := fmt.Sprintf(bpTemplate, testCase.apexUpdatable, testCase.javaStrictUpdtabilityLint, baselineProperty)
+
+		result := testApex(t, bp, fixtures...)
+		myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
+		sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto"))
+		disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi")
+
+		if disallowedFlagActual != testCase.disallowedFlagExpected {
+			t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
+		}
+	}
+}
+
+func TestUpdatabilityLintSkipLibcore(t *testing.T) {
+	bp := `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			java_libs: ["myjavalib"],
+			updatable: true,
+			min_sdk_version: "29",
+		}
+		apex_key {
+			name: "myapex.key",
+		}
+		java_library {
+			name: "myjavalib",
+			srcs: ["MyClass.java"],
+			apex_available: [ "myapex" ],
+			sdk_version: "current",
+			min_sdk_version: "29",
+			lint: {
+				baseline_filename: "lint-baseline.xml",
+			}
+		}
+		`
+
+	testCases := []struct {
+		testCaseName           string
+		moduleDirectory        string
+		disallowedFlagExpected bool
+	}{
+		{
+			testCaseName:           "lintable module defined outside libcore",
+			moduleDirectory:        "",
+			disallowedFlagExpected: true,
+		},
+		{
+			testCaseName:           "lintable module defined in libcore root directory",
+			moduleDirectory:        "libcore/",
+			disallowedFlagExpected: false,
+		},
+		{
+			testCaseName:           "lintable module defined in libcore child directory",
+			moduleDirectory:        "libcore/childdir/",
+			disallowedFlagExpected: true,
+		},
+	}
+
+	for _, testCase := range testCases {
+		lintFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"lint-baseline.xml", "")
+		bpFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"Android.bp", bp)
+		result := testApex(t, "", lintFileCreator, bpFileCreator)
+		myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
+		sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto"))
+		cmdFlags := fmt.Sprintf("--baseline %vlint-baseline.xml --disallowed_issues NewApi", testCase.moduleDirectory)
+		disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, cmdFlags)
+
+		if disallowedFlagActual != testCase.disallowedFlagExpected {
+			t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
+		}
+	}
+}
+
+// checks transtive deps of an apex coming from bootclasspath_fragment
+func TestApexStrictUpdtabilityLintBcpFragmentDeps(t *testing.T) {
+	bp := `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			bootclasspath_fragments: ["mybootclasspathfragment"],
+			updatable: true,
+			min_sdk_version: "29",
+		}
+		apex_key {
+			name: "myapex.key",
+		}
+		bootclasspath_fragment {
+			name: "mybootclasspathfragment",
+			contents: ["myjavalib"],
+			apex_available: ["myapex"],
+			hidden_api: {
+				split_packages: ["*"],
+			},
+		}
+		java_library {
+			name: "myjavalib",
+			srcs: ["MyClass.java"],
+			apex_available: [ "myapex" ],
+			sdk_version: "current",
+			min_sdk_version: "29",
+			compile_dex: true,
+			lint: {
+				baseline_filename: "lint-baseline.xml",
+			}
+		}
+		`
+	fs := android.MockFS{
+		"lint-baseline.xml": nil,
+	}
+
+	result := testApex(t, bp, dexpreopt.FixtureSetApexBootJars("myapex:myjavalib"), fs.AddToFixture())
+	myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
+	sboxProto := android.RuleBuilderSboxProtoForTests(t, result, myjavalib.Output("lint.sbox.textproto"))
+	if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") {
+		t.Errorf("Strict updabality lint missing in myjavalib coming from bootclasspath_fragment mybootclasspath-fragment\nActual lint cmd: %v", *sboxProto.Commands[0].Command)
+	}
+}
 
 // updatable apexes should propagate updatable=true to its apps
 func TestUpdatableApexEnforcesAppUpdatability(t *testing.T) {
@@ -10652,6 +10772,8 @@
 			src: "libc.so",
 			min_sdk_version: "29",
 			recovery_available: true,
+			vendor_available: true,
+			product_available: true,
 		}
 		api_imports {
 			name: "api_imports",
@@ -10662,14 +10784,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")
@@ -10689,7 +10811,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
 
@@ -10710,7 +10832,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
 
@@ -10718,6 +10840,80 @@
 	ensureContains(t, cmd, `( echo '/ 1000 1000 0755'; echo '/apex_manifest.json 1000 1000 0644'; echo '/apex_manifest.pb 1000 1000 0644'; cat my_config ) >`)
 }
 
+func TestStubLibrariesMultipleApexViolation(t *testing.T) {
+	testCases := []struct {
+		desc          string
+		hasStubs      bool
+		apexAvailable string
+		expectedError string
+	}{
+		{
+			desc:          "non-stub library can have multiple apex_available",
+			hasStubs:      false,
+			apexAvailable: `["myapex", "otherapex"]`,
+		},
+		{
+			desc:          "stub library should not be available to anyapex",
+			hasStubs:      true,
+			apexAvailable: `["//apex_available:anyapex"]`,
+			expectedError: "Stub libraries should have a single apex_available.*anyapex",
+		},
+		{
+			desc:          "stub library should not be available to multiple apexes",
+			hasStubs:      true,
+			apexAvailable: `["myapex", "otherapex"]`,
+			expectedError: "Stub libraries should have a single apex_available.*myapex.*otherapex",
+		},
+		{
+			desc:          "stub library can be available to a core apex and a test apex",
+			hasStubs:      true,
+			apexAvailable: `["myapex", "test_myapex"]`,
+		},
+	}
+	bpTemplate := `
+		cc_library {
+			name: "libfoo",
+			%v
+			apex_available: %v,
+		}
+		apex {
+			name: "myapex",
+			key: "apex.key",
+			updatable: false,
+			native_shared_libs: ["libfoo"],
+		}
+		apex {
+			name: "otherapex",
+			key: "apex.key",
+			updatable: false,
+		}
+		apex_test {
+			name: "test_myapex",
+			key: "apex.key",
+			updatable: false,
+			native_shared_libs: ["libfoo"],
+		}
+		apex_key {
+			name: "apex.key",
+		}
+	`
+	for _, tc := range testCases {
+		stubs := ""
+		if tc.hasStubs {
+			stubs = `stubs: {symbol_file: "libfoo.map.txt"},`
+		}
+		bp := fmt.Sprintf(bpTemplate, stubs, tc.apexAvailable)
+		mockFsFixturePreparer := android.FixtureModifyMockFS(func(fs android.MockFS) {
+			fs["system/sepolicy/apex/test_myapex-file_contexts"] = nil
+		})
+		if tc.expectedError == "" {
+			testApex(t, bp, mockFsFixturePreparer)
+		} else {
+			testApexError(t, tc.expectedError, bp, mockFsFixturePreparer)
+		}
+	}
+}
+
 func TestFileSystemShouldSkipApexLibraries(t *testing.T) {
 	context := android.GroupFixturePreparers(
 		android.PrepareForIntegrationTestWithAndroid,
@@ -10768,3 +10964,889 @@
 		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) != 5 {
+		t.Fatalf("Expected 5 commands, got %d in:\n%s", len(copyCmds), s)
+	}
+
+	ensureMatches(t, copyCmds[4], "^cp -f .*/aconfig_flags.pb .*/image.apex$")
+
+	combineAconfigRule := mod.Rule("All_aconfig_declarations_dump")
+	s = " " + combineAconfigRule.Args["cache_files"]
+	aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:]
+	if len(aconfigArgs) != 2 {
+		t.Fatalf("Expected 2 commands, got %d in:\n%s", len(aconfigArgs), s)
+	}
+	android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb")
+	android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_bar/intermediate.pb")
+
+	buildParams := combineAconfigRule.BuildParams
+	android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb")
+	android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_bar/intermediate.pb")
+	ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb")
+}
+
+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"],
+		}
+	`)
+
+	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
+	s := mod.Rule("apexRule").Args["copy_commands"]
+	copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
+	if len(copyCmds) != 9 {
+		t.Fatalf("Expected 9 commands, got %d in:\n%s", len(copyCmds), s)
+	}
+
+	ensureMatches(t, copyCmds[8], "^cp -f .*/aconfig_flags.pb .*/image.apex$")
+
+	combineAconfigRule := mod.Rule("All_aconfig_declarations_dump")
+	s = " " + combineAconfigRule.Args["cache_files"]
+	aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:]
+	if len(aconfigArgs) != 3 {
+		t.Fatalf("Expected 3 commands, got %d in:\n%s", len(aconfigArgs), s)
+	}
+	android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb")
+	android.EnsureListContainsSuffix(t, aconfigArgs, "my_cc_library_bar/android_arm64_armv8-a_shared_apex10000/myapex/aconfig_merged.pb")
+	android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_baz/intermediate.pb")
+
+	buildParams := combineAconfigRule.BuildParams
+	if len(buildParams.Inputs) != 3 {
+		t.Fatalf("Expected 3 input, got %d", len(buildParams.Inputs))
+	}
+	android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb")
+	android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_cc_library_bar/android_arm64_armv8-a_shared_apex10000/myapex/aconfig_merged.pb")
+	android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_baz/intermediate.pb")
+	ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb")
+}
+
+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_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) != 23 {
+		t.Fatalf("Expected 23 commands, got %d in:\n%s", len(copyCmds), s)
+	}
+
+	ensureMatches(t, copyCmds[22], "^cp -f .*/aconfig_flags.pb .*/image.apex$")
+
+	combineAconfigRule := mod.Rule("All_aconfig_declarations_dump")
+	s = " " + combineAconfigRule.Args["cache_files"]
+	aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:]
+	if len(aconfigArgs) != 2 {
+		t.Fatalf("Expected 2 commands, got %d in:\n%s", len(aconfigArgs), s)
+	}
+	android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb")
+	android.EnsureListContainsSuffix(t, aconfigArgs, "my_rust_binary/android_arm64_armv8-a_apex10000/myapex/aconfig_merged.pb")
+
+	buildParams := combineAconfigRule.BuildParams
+	if len(buildParams.Inputs) != 2 {
+		t.Fatalf("Expected 3 input, got %d", len(buildParams.Inputs))
+	}
+	android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb")
+	android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_rust_binary/android_arm64_armv8-a_apex10000/myapex/aconfig_merged.pb")
+	ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb")
+}
+
+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)
+	}
+}
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 1b52886..778c20a 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -46,78 +46,6 @@
 	dexpreopt.FixtureSetBootImageProfiles("art/build/boot/boot-image-profile.txt"),
 )
 
-func TestBootclasspathFragments(t *testing.T) {
-	result := android.GroupFixturePreparers(
-		prepareForTestWithBootclasspathFragment,
-		// Configure some libraries in the art bootclasspath_fragment and platform_bootclasspath.
-		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo", "platform:bar"),
-		prepareForTestWithArtApex,
-
-		java.PrepareForTestWithJavaSdkLibraryFiles,
-		java.FixtureWithLastReleaseApis("foo"),
-	).RunTestWithBp(t, `
-		java_sdk_library {
-			name: "foo",
-			srcs: ["b.java"],
-		}
-
-		java_library {
-			name: "bar",
-			srcs: ["b.java"],
-			installable: 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: ["*"],
-			},
-		}
-`,
-	)
-
-	// Make sure that the art-bootclasspath-fragment is using the correct configuration.
-	checkBootclasspathFragment(t, result, "art-bootclasspath-fragment", "android_common_apex10000",
-		"com.android.art:baz,com.android.art:quuz")
-}
-
 func TestBootclasspathFragments_FragmentDependency(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForTestWithBootclasspathFragment,
@@ -125,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, `
@@ -224,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)
@@ -237,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)
@@ -248,16 +180,6 @@
 	checkAPIScopeStubs("other", otherInfo, java.CorePlatformHiddenAPIScope)
 }
 
-func checkBootclasspathFragment(t *testing.T, result *android.TestResult, moduleName, variantName string, expectedConfiguredModules string) {
-	t.Helper()
-
-	bootclasspathFragment := result.ModuleForTests(moduleName, variantName).Module().(*java.BootclasspathFragmentModule)
-
-	bootclasspathFragmentInfo := result.ModuleProvider(bootclasspathFragment, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
-	modules := bootclasspathFragmentInfo.Modules()
-	android.AssertStringEquals(t, "invalid modules for "+moduleName, expectedConfiguredModules, modules.String())
-}
-
 func TestBootclasspathFragmentInArtApex(t *testing.T) {
 	commonPreparer := android.GroupFixturePreparers(
 		prepareForTestWithBootclasspathFragment,
@@ -268,10 +190,10 @@
 			name: "com.android.art",
 			key: "com.android.art.key",
 			bootclasspath_fragments: [
-				"mybootclasspathfragment",
+				"art-bootclasspath-fragment",
 			],
 			// bar (like foo) should be transitively included in this apex because it is part of the
-			// mybootclasspathfragment bootclasspath_fragment.
+			// art-bootclasspath-fragment bootclasspath_fragment.
 			updatable: false,
 		}
 
@@ -280,42 +202,6 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
-
-		java_library {
-			name: "foo",
-			srcs: ["b.java"],
-			installable: true,
-			apex_available: [
-				"com.android.art",
-			],
-		}
-
-		java_library {
-			name: "bar",
-			srcs: ["b.java"],
-			installable: true,
-			apex_available: [
-				"com.android.art",
-			],
-		}
-
-		java_import {
-			name: "foo",
-			jars: ["foo.jar"],
-			apex_available: [
-				"com.android.art",
-			],
-			compile_dex: true,
-		}
-
-		java_import {
-			name: "bar",
-			jars: ["bar.jar"],
-			apex_available: [
-				"com.android.art",
-			],
-			compile_dex: true,
-		}
 	`),
 	)
 
@@ -330,7 +216,7 @@
 	addSource := func(contents ...string) android.FixturePreparer {
 		text := fmt.Sprintf(`
 			bootclasspath_fragment {
-				name: "mybootclasspathfragment",
+				name: "art-bootclasspath-fragment",
 				image_name: "art",
 				%s
 				apex_available: [
@@ -342,6 +228,19 @@
 			}
 		`, contentsInsert(contents))
 
+		for _, content := range contents {
+			text += fmt.Sprintf(`
+				java_library {
+					name: "%[1]s",
+					srcs: ["%[1]s.java"],
+					installable: true,
+					apex_available: [
+						"com.android.art",
+					],
+				}
+			`, content)
+		}
+
 		return android.FixtureAddTextFile("art/build/boot/Android.bp", text)
 	}
 
@@ -357,11 +256,11 @@
 						src: "com.android.art-arm.apex",
 					},
 				},
-				exported_bootclasspath_fragments: ["mybootclasspathfragment"],
+				exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
 			}
 
 			prebuilt_bootclasspath_fragment {
-				name: "mybootclasspathfragment",
+				name: "art-bootclasspath-fragment",
 				image_name: "art",
 				%s
 				prefer: %t,
@@ -369,14 +268,29 @@
 					"com.android.art",
 				],
 				hidden_api: {
-					annotation_flags: "mybootclasspathfragment/annotation-flags.csv",
-					metadata: "mybootclasspathfragment/metadata.csv",
-					index: "mybootclasspathfragment/index.csv",
-					stub_flags: "mybootclasspathfragment/stub-flags.csv",
-					all_flags: "mybootclasspathfragment/all-flags.csv",
+					annotation_flags: "hiddenapi/annotation-flags.csv",
+					metadata: "hiddenapi/metadata.csv",
+					index: "hiddenapi/index.csv",
+					stub_flags: "hiddenapi/stub-flags.csv",
+					all_flags: "hiddenapi/all-flags.csv",
 				},
 			}
 		`, contentsInsert(contents), prefer)
+
+		for _, content := range contents {
+			text += fmt.Sprintf(`
+				java_import {
+					name: "%[1]s",
+					prefer: %[2]t,
+					jars: ["%[1]s.jar"],
+					apex_available: [
+						"com.android.art",
+					],
+					compile_dex: true,
+				}
+			`, content, prefer)
+		}
+
 		return android.FixtureAddTextFile("prebuilts/module_sdk/art/Android.bp", text)
 	}
 
@@ -387,25 +301,27 @@
 			// Configure some libraries in the art bootclasspath_fragment that match the source
 			// bootclasspath_fragment's contents property.
 			java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
+			dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:foo", "com.android.art:bar"),
 			addSource("foo", "bar"),
 			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`,
-			`mybootclasspathfragment`,
+			`dex2oatd`,
 		})
 
 		// Make sure that the source bootclasspath_fragment copies its dex files to the predefined
 		// locations for the art image.
-		module := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000")
+		module := result.ModuleForTests("dex_bootjars", "android_common")
 		checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
 	})
 
@@ -421,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",
@@ -440,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)
@@ -454,6 +370,7 @@
 			// Configure some libraries in the art bootclasspath_fragment that match the source
 			// bootclasspath_fragment's contents property.
 			java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
+			dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:foo", "com.android.art:bar"),
 			addSource("foo", "bar"),
 
 			// Make sure that a preferred prebuilt with consistent contents doesn't affect the apex.
@@ -462,21 +379,22 @@
 			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`,
-			`mybootclasspathfragment`,
+			`dex2oatd`,
 			`prebuilt_com.android.art`,
 		})
 
 		// Make sure that the prebuilt bootclasspath_fragment copies its dex files to the predefined
 		// locations for the art image.
-		module := result.ModuleForTests("prebuilt_mybootclasspathfragment", "android_common_com.android.art")
+		module := result.ModuleForTests("dex_bootjars", "android_common")
 		checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
 	})
 
@@ -552,6 +470,7 @@
 
 		// Configure some libraries in the art bootclasspath_fragment.
 		java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
+		dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:foo", "com.android.art:bar"),
 		java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"),
 	)
 
@@ -566,7 +485,7 @@
 					src: "com.android.art-arm.apex",
 				},
 			},
-			exported_bootclasspath_fragments: ["mybootclasspathfragment"],
+			exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
 		}
 
 		java_import {
@@ -586,7 +505,7 @@
 		}
 
 		prebuilt_bootclasspath_fragment {
-			name: "mybootclasspathfragment",
+			name: "art-bootclasspath-fragment",
 			image_name: "art",
 			// Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
 			contents: ["foo", "bar"],
@@ -594,11 +513,11 @@
 				"com.android.art",
 			],
 			hidden_api: {
-				annotation_flags: "mybootclasspathfragment/annotation-flags.csv",
-				metadata: "mybootclasspathfragment/metadata.csv",
-				index: "mybootclasspathfragment/index.csv",
-				stub_flags: "mybootclasspathfragment/stub-flags.csv",
-				all_flags: "mybootclasspathfragment/all-flags.csv",
+				annotation_flags: "hiddenapi/annotation-flags.csv",
+				metadata: "hiddenapi/metadata.csv",
+				index: "hiddenapi/index.csv",
+				stub_flags: "hiddenapi/stub-flags.csv",
+				all_flags: "hiddenapi/all-flags.csv",
 			},
 		}
 
@@ -608,7 +527,7 @@
 			apex_name: "com.android.art",
 			%s
 			src: "com.mycompany.android.art.apex",
-			exported_bootclasspath_fragments: ["mybootclasspathfragment"],
+			exported_bootclasspath_fragments: ["art-bootclasspath-fragment"],
 		}
 	`
 
@@ -616,24 +535,26 @@
 		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`,
-			`prebuilt_mybootclasspathfragment`,
+			`dex2oatd`,
+			`prebuilt_art-bootclasspath-fragment`,
+			`prebuilt_com.android.art.apex.selector`,
+			`prebuilt_com.android.art.deapexer`,
 		})
 
-		java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_com.android.art", []string{
-			`com.android.art.deapexer`,
+		java.CheckModuleDependencies(t, result.TestContext, "art-bootclasspath-fragment", "android_common_com.android.art", []string{
 			`dex2oatd`,
 			`prebuilt_bar`,
+			`prebuilt_com.android.art.deapexer`,
 			`prebuilt_foo`,
 		})
 
-		module := result.ModuleForTests("mybootclasspathfragment", "android_common_com.android.art")
+		module := result.ModuleForTests("dex_bootjars", "android_common")
 		checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
 	})
 
 	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, ""))
 	})
 }
@@ -722,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",
@@ -730,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")
@@ -752,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)
 	}
 
@@ -762,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
@@ -781,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",
@@ -892,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")
@@ -919,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,
@@ -930,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"),
@@ -1087,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 2a0f6e9..0000000
--- a/apex/bp2build_test.go
+++ /dev/null
@@ -1,461 +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/bazel/cquery"
-	"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) {
-	bp := `
-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",
-	bazel_module: { label: "//:foo" },
-}
-override_apex {
-	name: "override_foo",
-	key: "override_foo_key",
-	package_name: "override_pkg_name",
-	base: "foo",
-	bazel_module: { label: "//:override_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",
-						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
-					},
-					"//:override_foo": 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
-					},
-				},
-			}
-		}),
-	).RunTestWithBp(t, bp)
-
-	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.String(); w != g {
-		t.Errorf("Expected public container key %q, got %q", w, g)
-	}
-
-	if w, g := "out/bazel/execroot/__main__/override_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__/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 f49bed9..3078863 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,12 @@
 	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")
 }
 
 var (
@@ -179,19 +187,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`,
@@ -231,10 +226,28 @@
 
 	apexSepolicyTestsRule = pctx.StaticRule("apexSepolicyTestsRule", blueprint.RuleParams{
 		Command: `${deapexer} --debugfs_path ${debugfs_static} list -Z ${in} > ${out}.fc` +
-			`&& ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`,
+			` && ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`,
 		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
@@ -330,14 +343,16 @@
 // buildFileContexts create build rules to append an entry for apex_manifest.pb to the file_contexts
 // file for this APEX which is either from /systme/sepolicy/apex/<apexname>-file_contexts or from
 // the file_contexts property of this APEX. This is to make sure that the manifest file is correctly
-// labeled as system_file.
+// labeled as system_file or vendor_apex_metadata_file.
 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 +368,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,38 +377,23 @@
 	output := android.PathForModuleOut(ctx, "file_contexts")
 	rule := android.NewRuleBuilder(pctx, ctx)
 
-	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 / as system_file so that apexd can read them
-			rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
-			rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
-		}
-	case flattenedApex:
-		// For flattened apexes, install path should be prepended.
-		// File_contexts file should be emiited to make via LOCAL_FILE_CONTEXTS
-		// so that it can be merged into file_contexts.bin
-		apexPath := android.InstallPathToOnDevicePath(ctx, a.installDir.Join(ctx, a.Name()))
-		apexPath = strings.ReplaceAll(apexPath, ".", `\\.`)
-		// remove old file
-		rule.Command().Text("rm").FlagWithOutput("-f ", output)
-		// copy file_contexts
-		rule.Command().Text("awk").Text(`'/object_r/{printf("` + apexPath + `%s\n", $0)}'`).Input(fileContexts).Text(">").Output(output)
-		// new line
-		rule.Command().Text("echo").Text(">>").Output(output)
-		if !useFileContextsAsIs {
-			// force-label /apex_manifest.pb and / as system_file so that apexd can read them
-			rule.Command().Text("echo").Flag(apexPath + `/apex_manifest\\.pb u:object_r:system_file:s0`).Text(">>").Output(output)
-			rule.Command().Text("echo").Flag(apexPath + "/ u:object_r:system_file:s0").Text(">>").Output(output)
-		}
-	default:
-		panic(fmt.Errorf("unsupported type %v", a.properties.ApexType))
+	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 file.
+		labelForRoot = "u:object_r:vendor_file:s0"
+		labelForManifest = "u:object_r:vendor_apex_metadata_file:s0"
+	}
+	// 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")
@@ -472,10 +472,25 @@
 	})
 }
 
-// buildUnflattendApex creates build rules to build an APEX using apexer.
-func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
-	apexType := a.properties.ApexType
-	suffix := apexType.suffix()
+func isVintfFragment(fi apexFile) bool {
+	isVintfFragment, _ := path.Match("etc/vintf/*.xml", 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) {
+	suffix := imageApexSuffix
 	apexName := a.BaseModuleName()
 
 	////////////////////////////////////////////////////////////////////////////////////////////
@@ -484,10 +499,6 @@
 	imageDir := android.PathForModuleOut(ctx, "image"+suffix)
 
 	installSymbolFiles := (!ctx.Config().KatiEnabled() || a.ExportedToMake()) && a.installable()
-	// We can't install symbol files when prebuilt is used.
-	if a.IsReplacedByPrebuilt() {
-		installSymbolFiles = false
-	}
 
 	// set of dependency module:location mappings
 	installMapSet := make(map[string]bool)
@@ -514,7 +525,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 {
@@ -532,7 +551,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.
@@ -550,13 +568,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)
@@ -564,6 +577,7 @@
 
 		installMapSet[installMapPath.String()+":"+fi.installDir+"/"+fi.builtFile.Base()] = true
 	}
+
 	implicitInputs = append(implicitInputs, a.manifestPbOut)
 
 	if len(installMapSet) > 0 {
@@ -618,263 +632,265 @@
 	outHostBinDir := ctx.Config().HostToolPath(ctx, "").String()
 	prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
 
-	if apexType == imageApex {
+	defaultReadOnlyFiles := []string{"apex_manifest.json", "apex_manifest.pb"}
+	if len(a.aconfigFiles) > 0 {
+		apexAconfigFile := android.PathForModuleOut(ctx, "aconfig_flags.pb")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        aconfig.AllDeclarationsRule,
+			Inputs:      a.aconfigFiles,
+			Output:      apexAconfigFile,
+			Description: "combine_aconfig_declarations",
+			Args: map[string]string{
+				"cache_files": android.JoinPathsWithPrefix(a.aconfigFiles, "--cache "),
+			},
+		})
 
-		////////////////////////////////////////////////////////////////////////////////////
-		// 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)
+		copyCommands = append(copyCommands, "cp -f "+apexAconfigFile.String()+" "+imageDir.String())
+		implicitInputs = append(implicitInputs, apexAconfigFile)
+		defaultReadOnlyFiles = append(defaultReadOnlyFiles, apexAconfigFile.Base())
+	}
 
-		////////////////////////////////////////////////////////////////////////////////////
-		// Step 3: Prepare option flags for apexer and invoke it to create an unsigned APEX.
-		// TODO(jiyong): use the RuleBuilder
-		optFlags := []string{}
+	////////////////////////////////////////////////////////////////////////////////////
+	// 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)
 
-		fileContexts := a.buildFileContexts(ctx)
-		implicitInputs = append(implicitInputs, fileContexts)
+	////////////////////////////////////////////////////////////////////////////////////
+	// Step 3: Prepare option flags for apexer and invoke it to create an unsigned APEX.
+	// TODO(jiyong): use the RuleBuilder
+	optFlags := []string{}
 
-		implicitInputs = append(implicitInputs, a.privateKeyFile, a.publicKeyFile)
-		optFlags = append(optFlags, "--pubkey "+a.publicKeyFile.String())
+	fileContexts := a.buildFileContexts(ctx)
+	implicitInputs = append(implicitInputs, fileContexts)
 
-		manifestPackageName := a.getOverrideManifestPackageName(ctx)
-		if manifestPackageName != "" {
-			optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
+	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)
 		}
 
-		if a.properties.AndroidManifest != nil {
-			androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
+		implicitInputs = append(implicitInputs, androidManifestFile)
+		optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
+	} else if a.testApex {
+		optFlags = append(optFlags, "--test_only")
+	}
 
-			if a.testApex {
-				androidManifestFile = markManifestTestOnly(ctx, androidManifestFile)
-			}
+	// Determine target/min sdk version from the context
+	// TODO(jiyong): make this as a function
+	moduleMinSdkVersion := a.minSdkVersion(ctx)
+	minSdkVersion := moduleMinSdkVersion.String()
 
-			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())
+	// 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) {
-			targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
+			minSdkVersion = 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)
+	}
+	// 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 a.overridableProperties.Logging_parent != "" {
-			optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent)
-		}
+	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)
 
-		// 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()))
+	if a.overridableProperties.Logging_parent != "" {
+		optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent)
+	}
 
-		// 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
-
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        apexProtoConvertRule,
-			Input:       unsignedOutputFile,
-			Output:      apexProtoFile,
-			Description: "apex proto convert",
+	// 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()))
 
-		implicitInputs = append(implicitInputs, unsignedOutputFile)
+	// 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")
+	}
 
-		// Run coverage analysis
-		apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.txt")
+	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:        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")
-		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
-
-		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(),
-			},
-		})
-	} else { // zipApex
-		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)
@@ -892,9 +908,15 @@
 		args["outCommaList"] = signedOutputFile.String()
 	}
 	var validations android.Paths
-	if suffix == imageApexSuffix {
+	validations = append(validations, runApexLinkerconfigValidation(ctx, unsignedOutputFile.OutputPath, imageDir.OutputPath))
+	// TODO(b/279688635) deapexer supports [ext4]
+	if 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",
@@ -953,53 +975,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)
-}
 
-// buildFlattenedApex creates rules for a flattened APEX. Flattened APEX actually doesn't have a
-// single output file. It is a phony target for all the files under /system/apex/<name> directory.
-// This function creates the installation rules for the files.
-func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
-	bundleName := a.Name()
-	installedSymlinks := append(android.InstallPaths(nil), a.compatSymlinks...)
-	if a.installable() {
-		for _, fi := range a.filesInfo {
-			dir := filepath.Join("apex", bundleName, fi.installDir)
-			installDir := android.PathForModuleInstall(ctx, dir)
-			if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
-				pathOnDevice := filepath.Join("/", fi.partition, fi.path())
-				installedSymlinks = append(installedSymlinks,
-					ctx.InstallAbsoluteSymlink(installDir, fi.stem(), pathOnDevice))
-			} else {
-				if fi.class == appSet {
-					as := fi.module.(*java.AndroidAppSet)
-					ctx.InstallFileWithExtraFilesZip(installDir, as.BaseModuleName()+".apk",
-						as.OutputFile(), as.PackedAdditionalOutputs())
-				} else {
-					target := ctx.InstallFile(installDir, fi.stem(), fi.builtFile)
-					for _, sym := range fi.symlinks {
-						installedSymlinks = append(installedSymlinks,
-							ctx.InstallSymlink(installDir, sym, target))
-					}
-				}
-			}
-		}
-
-		// Create install rules for the files added in GenerateAndroidBuildActions after
-		// buildFlattenedApex is called.  Add the links to system libs (if any) as dependencies
-		// of the apex_manifest.pb file since it is always present.
-		dir := filepath.Join("apex", bundleName)
-		installDir := android.PathForModuleInstall(ctx, dir)
-		ctx.InstallFile(installDir, "apex_manifest.pb", a.manifestPbOut, installedSymlinks.Paths()...)
-		ctx.InstallFile(installDir, "apex_pubkey", a.publicKeyFile)
-	}
-
-	a.fileContexts = a.buildFileContexts(ctx)
-
-	a.outputFile = android.PathForModuleInstall(ctx, "apex", bundleName)
+	a.apexKeysPath = writeApexKeys(ctx, a)
 }
 
 // getCertificateAndPrivateKey retrieves the cert and the private key that will be used to sign
@@ -1043,21 +1024,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() {
@@ -1132,8 +1104,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)
@@ -1142,7 +1114,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))
@@ -1197,6 +1170,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}
@@ -1210,3 +1196,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 fed9cd1..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)
@@ -140,7 +146,6 @@
 			Tool(android.PathForSource(ctx, "build/soong/scripts/unpack-prebuilt-apex.sh")).
 			BuiltTool("deapexer").
 			BuiltTool("debugfs").
-			BuiltTool("blkid").
 			BuiltTool("fsck.erofs").
 			Input(p.inputApex).
 			Text(deapexerOutput.String())
diff --git a/apex/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go
index bba8bb6..d9ab8fa 100644
--- a/apex/dexpreopt_bootjars_test.go
+++ b/apex/dexpreopt_bootjars_test.go
@@ -138,8 +138,8 @@
 		prepareForTestWithArtApex,
 	).RunTestWithBp(t, fmt.Sprintf(bp, preferPrebuilt))
 
-	platformBootclasspath := result.ModuleForTests("platform-bootclasspath", "android_common")
-	rule := platformBootclasspath.Output(ruleFile)
+	dexBootJars := result.ModuleForTests("dex_bootjars", "android_common")
+	rule := dexBootJars.Output(ruleFile)
 
 	inputs := rule.Implicits.Strings()
 	sort.Strings(inputs)
@@ -155,15 +155,15 @@
 }
 
 func TestDexpreoptBootJarsWithSourceArtApex(t *testing.T) {
-	ruleFile := "boot.art"
+	ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art"
 
 	expectedInputs := []string{
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/core-oj.jar",
 		"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/dexpreopt_arm64/dex_artjars/boot.prof",
-		"out/soong/dexpreopt_arm64/dex_bootjars/boot.prof",
+		"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",
 	}
 
 	expectedOutputs := []string{
@@ -192,15 +192,15 @@
 // The only difference is that the ART profile should be deapexed from the prebuilt APEX. Other
 // inputs and outputs should be the same as above.
 func TestDexpreoptBootJarsWithPrebuiltArtApex(t *testing.T) {
-	ruleFile := "boot.art"
+	ruleFile := "out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art"
 
 	expectedInputs := []string{
 		"out/soong/dexpreopt_arm64/dex_bootjars_input/core-oj.jar",
 		"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/dexpreopt_arm64/dex_bootjars/boot.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",
 	}
 
 	expectedOutputs := []string{
@@ -252,3 +252,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 0a7e80f..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.RegisterSingletonType("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/metadata.go b/apex/metadata.go
deleted file mode 100644
index b1dff3e..0000000
--- a/apex/metadata.go
+++ /dev/null
@@ -1,99 +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.
- */
-
-package apex
-
-import (
-	"encoding/json"
-
-	"github.com/google/blueprint"
-
-	"android/soong/android"
-)
-
-var (
-	mtctx = android.NewPackageContext("android/soong/multitree_apex")
-)
-
-func init() {
-	RegisterModulesSingleton(android.InitRegistrationContext)
-}
-
-func RegisterModulesSingleton(ctx android.RegistrationContext) {
-	ctx.RegisterSingletonType("apex_multitree_singleton", multitreeAnalysisSingletonFactory)
-}
-
-var PrepareForTestWithApexMultitreeSingleton = android.FixtureRegisterWithContext(RegisterModulesSingleton)
-
-func multitreeAnalysisSingletonFactory() android.Singleton {
-	return &multitreeAnalysisSingleton{}
-}
-
-type multitreeAnalysisSingleton struct {
-	multitreeApexMetadataPath android.OutputPath
-}
-
-type ApexMultitreeMetadataEntry struct {
-	// The name of the apex.
-	Name string
-
-	// TODO: Add other properties as needed.
-}
-
-type ApexMultitreeMetadata struct {
-	// Information about the installable apexes.
-	Apexes map[string]ApexMultitreeMetadataEntry
-}
-
-func (p *multitreeAnalysisSingleton) GenerateBuildActions(context android.SingletonContext) {
-	data := ApexMultitreeMetadata{
-		Apexes: make(map[string]ApexMultitreeMetadataEntry, 0),
-	}
-	context.VisitAllModules(func(module android.Module) {
-		// If this module is not being installed, ignore it.
-		if !module.Enabled() || module.IsSkipInstall() {
-			return
-		}
-		// Actual apexes provide ApexBundleInfoProvider.
-		if _, ok := context.ModuleProvider(module, ApexBundleInfoProvider).(ApexBundleInfo); !ok {
-			return
-		}
-		bundle, ok := module.(*apexBundle)
-		if ok && !bundle.testApex && !bundle.vndkApex && bundle.primaryApexType {
-			name := module.Name()
-			entry := ApexMultitreeMetadataEntry{
-				Name: name,
-			}
-			data.Apexes[name] = entry
-		}
-	})
-	p.multitreeApexMetadataPath = android.PathForOutput(context, "multitree_apex_metadata.json")
-
-	jsonStr, err := json.Marshal(data)
-	if err != nil {
-		context.Errorf(err.Error())
-	}
-	android.WriteFileRule(context, p.multitreeApexMetadataPath, string(jsonStr))
-	// This seems cleaner, but doesn't emit the phony rule in testing.
-	// context.Phony("multitree_apex_metadata", p.multitreeApexMetadataPath)
-
-	context.Build(mtctx, android.BuildParams{
-		Rule:        blueprint.Phony,
-		Description: "phony rule for multitree_apex_metadata",
-		Inputs:      []android.Path{p.multitreeApexMetadataPath},
-		Output:      android.PathForPhony(context, "multitree_apex_metadata"),
-	})
-}
diff --git a/apex/metadata_test.go b/apex/metadata_test.go
deleted file mode 100644
index fed5bea..0000000
--- a/apex/metadata_test.go
+++ /dev/null
@@ -1,103 +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.
- */
-
-package apex
-
-import (
-	"strings"
-	"testing"
-
-	"android/soong/android"
-	"android/soong/java"
-)
-
-func TestModulesSingleton(t *testing.T) {
-	result := android.GroupFixturePreparers(
-		PrepareForTestWithApexMultitreeSingleton,
-		java.PrepareForTestWithJavaDefaultModules,
-		PrepareForTestWithApexBuildComponents,
-		java.FixtureConfigureApexBootJars("myapex:foo"),
-		java.PrepareForTestWithJavaSdkLibraryFiles,
-	).RunTestWithBp(t, `
-		prebuilt_apex {
-			name: "myapex",
-			src: "myapex.apex",
-			exported_bootclasspath_fragments: ["mybootclasspath-fragment"],
-		}
-
-		// A prebuilt java_sdk_library_import that is not preferred by default but will be preferred
-		// because AlwaysUsePrebuiltSdks() is true.
-		java_sdk_library_import {
-			name: "foo",
-			prefer: false,
-			shared_library: false,
-			permitted_packages: ["foo"],
-			public: {
-				jars: ["sdk_library/public/foo-stubs.jar"],
-				stub_srcs: ["sdk_library/public/foo_stub_sources"],
-				current_api: "sdk_library/public/foo.txt",
-				removed_api: "sdk_library/public/foo-removed.txt",
-				sdk_version: "current",
-			},
-			apex_available: ["myapex"],
-		}
-
-		prebuilt_bootclasspath_fragment {
-			name: "mybootclasspath-fragment",
-			apex_available: [
-				"myapex",
-			],
-			contents: [
-				"foo",
-			],
-			hidden_api: {
-				stub_flags: "prebuilt-stub-flags.csv",
-				annotation_flags: "prebuilt-annotation-flags.csv",
-				metadata: "prebuilt-metadata.csv",
-				index: "prebuilt-index.csv",
-				all_flags: "prebuilt-all-flags.csv",
-			},
-		}
-
-		platform_bootclasspath {
-			name: "myplatform-bootclasspath",
-			fragments: [
-				{
-					apex: "myapex",
-					module:"mybootclasspath-fragment",
-				},
-			],
-		}
-`,
-	)
-
-	outputs := result.SingletonForTests("apex_multitree_singleton").AllOutputs()
-	for _, output := range outputs {
-		testingBuildParam := result.SingletonForTests("apex_multitree_singleton").Output(output)
-		switch {
-		case strings.Contains(output, "soong/multitree_apex_metadata.json"):
-			android.AssertStringEquals(t, "Invalid build rule", "android/soong/android.writeFile", testingBuildParam.Rule.String())
-			android.AssertIntEquals(t, "Invalid input", len(testingBuildParam.Inputs), 0)
-			android.AssertStringDoesContain(t, "Invalid output path", output, "soong/multitree_apex_metadata.json")
-
-		case strings.HasSuffix(output, "multitree_apex_metadata"):
-			android.AssertStringEquals(t, "Invalid build rule", "<builtin>:phony", testingBuildParam.Rule.String())
-			android.AssertStringEquals(t, "Invalid input", testingBuildParam.Inputs[0].String(), "out/soong/multitree_apex_metadata.json")
-			android.AssertStringEquals(t, "Invalid output path", output, "multitree_apex_metadata")
-			android.AssertIntEquals(t, "Invalid args", len(testingBuildParam.Args), 0)
-		}
-	}
-}
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 05bb136..2bd3159 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -152,10 +152,10 @@
 	).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)}
@@ -234,7 +234,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 +252,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 +387,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 +427,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 +545,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 0d83830..399d9b9 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.
@@ -121,7 +132,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 {
@@ -133,9 +148,7 @@
 }
 
 func (p *prebuiltCommon) checkForceDisable(ctx android.ModuleContext) bool {
-	// If the device is configured to use flattened APEX, force disable the prebuilt because
-	// the prebuilt is a non-flattened one.
-	forceDisable := ctx.Config().FlattenApex()
+	forceDisable := false
 
 	// Force disable the prebuilts when we are doing unbundled build. We do unbundled build
 	// to build the prebuilts themselves.
@@ -169,50 +182,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) {
@@ -231,20 +240,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.
@@ -425,7 +442,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,
 	})
 
@@ -434,7 +451,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,
 	}
@@ -481,6 +498,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 {
@@ -609,6 +629,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)
@@ -622,9 +643,14 @@
 		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
@@ -637,7 +663,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.
@@ -737,13 +764,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)
@@ -753,13 +778,49 @@
 	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())
+	}
+}
+
 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")
@@ -779,20 +840,28 @@
 		return
 	}
 
+	// dexpreopt any system server jars if present
+	p.dexpreoptSystemServerJars(ctx)
+
+	// provide info used for generating the boot image
+	p.provideApexExportsInfo(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 {
@@ -878,12 +947,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)
@@ -958,13 +1022,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)
@@ -981,6 +1043,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)
@@ -999,6 +1062,12 @@
 		return
 	}
 
+	// dexpreopt any system server jars if present
+	a.dexpreoptSystemServerJars(ctx)
+
+	// provide info used for generating the boot image
+	a.provideApexExportsInfo(ctx)
+
 	// Save the files that need to be made available to Make.
 	a.initApexFilesForAndroidMk(ctx)
 
@@ -1008,10 +1077,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/testing.go b/apex/testing.go
index 69bd73e..3b200f0 100644
--- a/apex/testing.go
+++ b/apex/testing.go
@@ -19,6 +19,7 @@
 var PrepareForTestWithApexBuildComponents = android.GroupFixturePreparers(
 	android.FixtureRegisterWithContext(registerApexBuildComponents),
 	android.FixtureRegisterWithContext(registerApexKeyBuildComponents),
+	android.FixtureRegisterWithContext(registerApexDepsInfoComponents),
 	// Additional files needed in tests that disallow non-existent source files.
 	// This includes files that are needed by all, or at least most, instances of an apex module type.
 	android.MockFS{
diff --git a/apex/vndk.go b/apex/vndk.go
index 095e89d..377c1c0 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -65,20 +65,27 @@
 		}
 
 		vndkVersion := ab.vndkVersion(mctx.DeviceConfig())
-		apiLevel, err := android.ApiLevelFromUser(mctx, vndkVersion)
-		if err != nil {
-			mctx.PropertyErrorf("vndk_version", "%s", err.Error())
-			return
-		}
+		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)) &&
+				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()
+			}
+			if proptools.String(ab.vndkProperties.Vndk_version) != "" &&
+				mctx.DeviceConfig().PlatformVndkVersion() != "" &&
+				apiLevel.GreaterThanOrEqualTo(android.ApiLevelOrPanic(mctx, mctx.DeviceConfig().PlatformVndkVersion())) {
+				ab.Disable()
+			}
 		}
 	}
 }
@@ -90,6 +97,11 @@
 		if vndkVersion == "" {
 			vndkVersion = mctx.DeviceConfig().PlatformVndkVersion()
 		}
+
+		if vndkVersion == "" {
+			return
+		}
+
 		if vndkVersion == mctx.DeviceConfig().PlatformVndkVersion() {
 			vndkVersion = "current"
 		} else {
@@ -103,19 +115,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
index 21526c3..e2aee96 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -51,10 +51,11 @@
 	`+vndkLibrariesTxtFiles("current"),
 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 			variables.DeviceVndkVersion = proptools.StringPtr("")
+			variables.KeepVndk = proptools.BoolPtr(true)
 		}),
 	)
 	// VNDK-Lite contains only core variants of VNDK-Sp libraries
-	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []string{
 		"lib/libvndksp.so",
 		"lib/libc++.so",
 		"lib64/libvndksp.so",
@@ -109,19 +110,14 @@
 		}
 
 		// VNDK APEX doesn't create apex variant
-		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
+		files := getFiles(t, ctx, "com.android.vndk.current", "android_common")
 		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")
-			}),
-		)
+		ctx := testApex(t, bp)
 
-		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
+		files := getFiles(t, ctx, "com.android.vndk.current", "android_common")
 		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
 	})
 
@@ -133,10 +129,10 @@
 			}),
 		)
 
-		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
+		files := getFiles(t, ctx, "com.android.vndk.current", "android_common")
 		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")
+		files = getFiles(t, ctx, "com.android.vndk.current", "android_common_cov")
 		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 4d39e8f..35942bc 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -17,6 +17,8 @@
 import (
 	"crypto/sha256"
 	"encoding/base64"
+	"encoding/json"
+	"errors"
 	"fmt"
 	"path/filepath"
 	"reflect"
@@ -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 {
@@ -116,6 +74,14 @@
 	InputDepsetHashes []string
 	InputPaths        []string
 	FileContents      string
+	// If ShouldRunInSbox is true, Soong will use sbox to created an isolated environment
+	// and run the mixed build action there
+	ShouldRunInSbox bool
+	// A list of files to add as implicit deps to the outputs of this BuildStatement.
+	// 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
@@ -169,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
 	}
 
@@ -347,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 {
@@ -453,8 +441,27 @@
 	return hashes, nil
 }
 
+// escapes the args received from aquery and creates a command string
+func commandString(actionEntry *analysis_v2_proto.Action) string {
+	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, " ")
+}
+
 func (a *aqueryArtifactHandler) normalActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
-	command := strings.Join(proptools.ShellEscapeListIncludingSpaces(actionEntry.Arguments), " ")
+	command := commandString(actionEntry)
 	inputDepsetHashes, err := a.depsetContentHashes(actionEntry.InputDepSetIds)
 	if err != nil {
 		return nil, err
@@ -472,6 +479,12 @@
 		Env:               actionEntry.EnvironmentVariables,
 		Mnemonic:          actionEntry.Mnemonic,
 	}
+	if buildStatement.Mnemonic == "GoToolchainBinaryBuild" {
+		// Unlike b's execution root, mixed build execution root contains a symlink to prebuilts/go
+		// This causes issues for `GOCACHE=$(mktemp -d) go build ...`
+		// To prevent this, sandbox this action in mixed builds as well
+		buildStatement.ShouldRunInSbox = true
+	}
 	return buildStatement, nil
 }
 
@@ -523,6 +536,7 @@
 		Mnemonic:          actionEntry.Mnemonic,
 		InputDepsetHashes: depsetHashes,
 		FileContents:      actionEntry.FileContents,
+		IsExecutable:      actionEntry.IsExecutable,
 	}, nil
 }
 
@@ -548,6 +562,72 @@
 	}, nil
 }
 
+type bazelSandwichJson struct {
+	Target         string   `json:"target"`
+	DependOnTarget *bool    `json:"depend_on_target,omitempty"`
+	ImplicitDeps   []string `json:"implicit_deps"`
+}
+
+func (a *aqueryArtifactHandler) unresolvedSymlinkActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
+	outputPaths, depfile, err := a.getOutputPaths(actionEntry)
+	if err != nil {
+		return nil, err
+	}
+	if len(actionEntry.InputDepSetIds) != 0 || len(outputPaths) != 1 {
+		return nil, fmt.Errorf("expected 0 inputs and 1 output to symlink action, got: input %q, output %q", actionEntry.InputDepSetIds, outputPaths)
+	}
+	target := actionEntry.UnresolvedSymlinkTarget
+	if target == "" {
+		return nil, fmt.Errorf("expected an unresolved_symlink_target, but didn't get one")
+	}
+	if filepath.Clean(target) != target {
+		return nil, fmt.Errorf("expected %q, got %q", filepath.Clean(target), target)
+	}
+	if strings.HasPrefix(target, "/") {
+		return nil, fmt.Errorf("no absolute symlinks allowed: %s", target)
+	}
+
+	out := outputPaths[0]
+	outDir := filepath.Dir(out)
+	var implicitDeps []string
+	if strings.HasPrefix(target, "bazel_sandwich:") {
+		j := bazelSandwichJson{}
+		err := json.Unmarshal([]byte(target[len("bazel_sandwich:"):]), &j)
+		if err != nil {
+			return nil, err
+		}
+		if proptools.BoolDefault(j.DependOnTarget, true) {
+			implicitDeps = append(implicitDeps, j.Target)
+		}
+		implicitDeps = append(implicitDeps, j.ImplicitDeps...)
+		dotDotsToReachCwd := ""
+		if outDir != "." {
+			dotDotsToReachCwd = strings.Repeat("../", strings.Count(outDir, "/")+1)
+		}
+		target = proptools.ShellEscapeIncludingSpaces(j.Target)
+		target = "{DOTDOTS_TO_OUTPUT_ROOT}" + dotDotsToReachCwd + target
+	} else {
+		target = proptools.ShellEscapeIncludingSpaces(target)
+	}
+
+	outDir = proptools.ShellEscapeIncludingSpaces(outDir)
+	out = proptools.ShellEscapeIncludingSpaces(out)
+	// Use absolute paths, because some soong actions don't play well with relative paths (for example, `cp -d`).
+	command := fmt.Sprintf("mkdir -p %[1]s && rm -f %[2]s && ln -sf %[3]s %[2]s", outDir, out, target)
+	symlinkPaths := outputPaths[:]
+
+	buildStatement := &BuildStatement{
+		Command:      command,
+		Depfile:      depfile,
+		OutputPaths:  outputPaths,
+		Env:          actionEntry.EnvironmentVariables,
+		Mnemonic:     actionEntry.Mnemonic,
+		SymlinkPaths: symlinkPaths,
+		ImplicitDeps: implicitDeps,
+	}
+	return buildStatement, nil
+}
+
 func (a *aqueryArtifactHandler) symlinkActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
 	outputPaths, depfile, err := a.getOutputPaths(actionEntry)
 	if err != nil {
@@ -653,14 +733,16 @@
 		if len(actionEntry.Arguments) < 1 {
 			return a.templateExpandActionBuildStatement(actionEntry)
 		}
-	case "FileWrite", "SourceSymlinkManifest":
+	case "FileWrite", "SourceSymlinkManifest", "RepoMappingManifest":
 		return a.fileWriteActionBuildStatement(actionEntry)
 	case "SymlinkTree":
 		return a.symlinkTreeActionBuildStatement(actionEntry)
+	case "UnresolvedSymlink":
+		return a.unresolvedSymlinkActionBuildStatement(actionEntry)
 	}
 
 	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 19a584f..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) {
@@ -357,9 +361,11 @@
 	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 	if expected := 1; len(actual) != expected {
 		t.Fatalf("Expected %d build statements, got %d", expected, len(actual))
+		return
 	}
 
 	bs := actual[0]
@@ -381,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],
@@ -405,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) {
@@ -544,6 +550,7 @@
 	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 	assertBuildStatements(t, []*BuildStatement{
 		&BuildStatement{
@@ -556,7 +563,7 @@
 	}, actual)
 }
 
-func TestBazelOutRemovalFromInputDepsets(t *testing.T) {
+func TestBazelToolsRemovalFromInputDepsets(t *testing.T) {
 	const inputString = `{
  "artifacts": [
    { "id": 1, "path_fragment_id": 10 },
@@ -634,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 },
@@ -756,9 +811,11 @@
 	actualBuildStatements, actualDepsets, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 	if expected := 2; len(actualBuildStatements) != expected {
 		t.Fatalf("Expected %d build statements, got %d %#v", expected, len(actualBuildStatements), actualBuildStatements)
+		return
 	}
 
 	expectedDepsetFiles := [][]string{
@@ -859,6 +916,7 @@
 
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 
 	expectedBuildStatements := []*BuildStatement{
@@ -907,6 +965,7 @@
 	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 
 	expectedBuildStatements := []*BuildStatement{
@@ -932,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],
@@ -951,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) {
@@ -982,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) {
@@ -1017,6 +1076,7 @@
 	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 
 	expectedBuildStatements := []*BuildStatement{
@@ -1058,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) {
@@ -1088,6 +1148,7 @@
 	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 	assertBuildStatements(t, []*BuildStatement{
 		&BuildStatement{
@@ -1126,6 +1187,7 @@
 	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 	assertBuildStatements(t, []*BuildStatement{
 		&BuildStatement{
@@ -1136,6 +1198,126 @@
 	}, actual)
 }
 
+func TestUnresolvedSymlink(t *testing.T) {
+	const inputString = `
+{
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "UnresolvedSymlink",
+   "configuration_id": 1,
+   "output_ids": [1],
+   "primary_output_id": 1,
+   "execution_platform": "//build/bazel/platforms:linux_x86_64",
+   "unresolved_symlink_target": "symlink/target"
+ }],
+ "path_fragments": [
+   { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+	if err != nil {
+		t.Errorf("Unexpected error %q", err)
+		return
+	}
+	assertBuildStatements(t, []*BuildStatement{{
+		Command:      "mkdir -p path/to && rm -f path/to/symlink && ln -sf symlink/target path/to/symlink",
+		OutputPaths:  []string{"path/to/symlink"},
+		Mnemonic:     "UnresolvedSymlink",
+		SymlinkPaths: []string{"path/to/symlink"},
+	}}, actual)
+}
+
+func TestUnresolvedSymlinkBazelSandwich(t *testing.T) {
+	const inputString = `
+{
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "UnresolvedSymlink",
+   "configuration_id": 1,
+   "output_ids": [1],
+   "primary_output_id": 1,
+   "execution_platform": "//build/bazel/platforms:linux_x86_64",
+   "unresolved_symlink_target": "bazel_sandwich:{\"target\":\"target/product/emulator_x86_64/system\"}"
+ }],
+ "path_fragments": [
+   { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+	if err != nil {
+		t.Errorf("Unexpected error %q", err)
+		return
+	}
+	assertBuildStatements(t, []*BuildStatement{{
+		Command:      "mkdir -p path/to && rm -f path/to/symlink && ln -sf {DOTDOTS_TO_OUTPUT_ROOT}../../target/product/emulator_x86_64/system path/to/symlink",
+		OutputPaths:  []string{"path/to/symlink"},
+		Mnemonic:     "UnresolvedSymlink",
+		SymlinkPaths: []string{"path/to/symlink"},
+		ImplicitDeps: []string{"target/product/emulator_x86_64/system"},
+	}}, actual)
+}
+
+func TestUnresolvedSymlinkBazelSandwichWithAlternativeDeps(t *testing.T) {
+	const inputString = `
+{
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "UnresolvedSymlink",
+   "configuration_id": 1,
+   "output_ids": [1],
+   "primary_output_id": 1,
+   "execution_platform": "//build/bazel/platforms:linux_x86_64",
+   "unresolved_symlink_target": "bazel_sandwich:{\"depend_on_target\":false,\"implicit_deps\":[\"target/product/emulator_x86_64/obj/PACKAGING/systemimage_intermediates/staging_dir.stamp\"],\"target\":\"target/product/emulator_x86_64/system\"}"
+ }],
+ "path_fragments": [
+   { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+	if err != nil {
+		t.Errorf("Unexpected error %q", err)
+		return
+	}
+	assertBuildStatements(t, []*BuildStatement{{
+		Command:      "mkdir -p path/to && rm -f path/to/symlink && ln -sf {DOTDOTS_TO_OUTPUT_ROOT}../../target/product/emulator_x86_64/system path/to/symlink",
+		OutputPaths:  []string{"path/to/symlink"},
+		Mnemonic:     "UnresolvedSymlink",
+		SymlinkPaths: []string{"path/to/symlink"},
+		// Note that the target of the symlink, target/product/emulator_x86_64/system, is not listed here
+		ImplicitDeps: []string{"target/product/emulator_x86_64/obj/PACKAGING/systemimage_intermediates/staging_dir.stamp"},
+	}}, actual)
+}
+
 func assertError(t *testing.T, err error, expected string) {
 	t.Helper()
 	if err == nil {
@@ -1201,6 +1383,9 @@
 	if !reflect.DeepEqual(sortedStrings(first.SymlinkPaths), sortedStrings(second.SymlinkPaths)) {
 		return "SymlinkPaths"
 	}
+	if !reflect.DeepEqual(sortedStrings(first.ImplicitDeps), sortedStrings(second.ImplicitDeps)) {
+		return "ImplicitDeps"
+	}
 	if first.Depfile != second.Depfile {
 		return "Depfile"
 	}
diff --git a/bazel/bazel_proxy.go b/bazel/bazel_proxy.go
index d7f5e64..229818d 100644
--- a/bazel/bazel_proxy.go
+++ b/bazel/bazel_proxy.go
@@ -26,10 +26,11 @@
 	"time"
 )
 
-// Logs fatal events of ProxyServer.
+// Logs events of ProxyServer.
 type ServerLogger interface {
 	Fatal(v ...interface{})
 	Fatalf(format string, v ...interface{})
+	Println(v ...interface{})
 }
 
 // CmdRequest is a request to the Bazel Proxy server.
@@ -71,9 +72,10 @@
 // The ProxyServer will only live as long as soong_ui does; the
 // underlying Bazel server will live past the duration of the build.
 type ProxyServer struct {
-	logger       ServerLogger
-	outDir       string
-	workspaceDir string
+	logger          ServerLogger
+	outDir          string
+	workspaceDir    string
+	bazeliskVersion string
 	// The server goroutine will listen on this channel and stop handling requests
 	// once it is written to.
 	done chan struct{}
@@ -119,13 +121,36 @@
 }
 
 // NewProxyServer is a constructor for a ProxyServer.
-func NewProxyServer(logger ServerLogger, outDir string, workspaceDir string) *ProxyServer {
-	return &ProxyServer{
-		logger:       logger,
-		outDir:       outDir,
-		workspaceDir: workspaceDir,
-		done:         make(chan struct{}),
+func NewProxyServer(logger ServerLogger, outDir string, workspaceDir string, bazeliskVersion string) *ProxyServer {
+	if len(bazeliskVersion) > 0 {
+		logger.Println("** Using Bazelisk for this build, due to env var USE_BAZEL_VERSION=" + bazeliskVersion + " **")
 	}
+
+	return &ProxyServer{
+		logger:          logger,
+		outDir:          outDir,
+		workspaceDir:    workspaceDir,
+		done:            make(chan struct{}),
+		bazeliskVersion: bazeliskVersion,
+	}
+}
+
+func ExecBazel(bazelPath string, workspaceDir string, request CmdRequest) (stdout []byte, stderr []byte, cmdErr error) {
+	bazelCmd := exec.Command(bazelPath, request.Argv...)
+	bazelCmd.Dir = workspaceDir
+	bazelCmd.Env = request.Env
+
+	stderrBuffer := &bytes.Buffer{}
+	bazelCmd.Stderr = stderrBuffer
+
+	if output, err := bazelCmd.Output(); err != nil {
+		cmdErr = fmt.Errorf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
+			err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderrBuffer)
+	} else {
+		stdout = output
+	}
+	stderr = stderrBuffer.Bytes()
+	return
 }
 
 func (b *ProxyServer) handleRequest(conn net.Conn) error {
@@ -137,23 +162,16 @@
 		return fmt.Errorf("Error decoding request: %s", err)
 	}
 
-	bazelCmd := exec.Command("./build/bazel/bin/bazel", req.Argv...)
-	bazelCmd.Dir = b.workspaceDir
-	bazelCmd.Env = req.Env
-
-	stderr := &bytes.Buffer{}
-	bazelCmd.Stderr = stderr
-	var stdout string
-	var bazelErrString string
-
-	if output, err := bazelCmd.Output(); err != nil {
-		bazelErrString = fmt.Sprintf("bazel command failed: %s\n---command---\n%s\n---env---\n%s\n---stderr---\n%s---",
-			err, bazelCmd, strings.Join(bazelCmd.Env, "\n"), stderr)
-	} else {
-		stdout = string(output)
+	if len(b.bazeliskVersion) > 0 {
+		req.Env = append(req.Env, "USE_BAZEL_VERSION="+b.bazeliskVersion)
+	}
+	stdout, stderr, cmdErr := ExecBazel("./build/bazel/bin/bazel", b.workspaceDir, req)
+	errorString := ""
+	if cmdErr != nil {
+		errorString = cmdErr.Error()
 	}
 
-	resp := CmdResponse{stdout, string(stderr.Bytes()), bazelErrString}
+	resp := CmdResponse{string(stdout), string(stderr), errorString}
 	enc := gob.NewEncoder(conn)
 	if err := enc.Encode(&resp); err != nil {
 		return fmt.Errorf("Error encoding response: %s", err)
diff --git a/bazel/configurability.go b/bazel/configurability.go
index 4680256..2c9a536 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -31,15 +31,15 @@
 
 	// OsType names in arch.go
 	OsAndroid     = "android"
-	osDarwin      = "darwin"
-	osLinux       = "linux_glibc"
+	OsDarwin      = "darwin"
+	OsLinux       = "linux_glibc"
 	osLinuxMusl   = "linux_musl"
 	osLinuxBionic = "linux_bionic"
-	osWindows     = "windows"
+	OsWindows     = "windows"
 
 	// Targets in arch.go
 	osArchAndroidArm        = "android_arm"
-	osArchAndroidArm64      = "android_arm64"
+	OsArchAndroidArm64      = "android_arm64"
 	osArchAndroidRiscv64    = "android_riscv64"
 	osArchAndroidX86        = "android_x86"
 	osArchAndroidX86_64     = "android_x86_64"
@@ -67,13 +67,18 @@
 
 	ConditionsDefaultSelectKey = "//conditions:default"
 
-	productVariableBazelPackage = "//build/bazel/product_variables"
+	productVariableBazelPackage = "//build/bazel/product_config/config_settings"
 
-	AndroidAndInApex  = "android-in_apex"
-	AndroidAndNonApex = "android-non_apex"
+	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 {
@@ -128,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
@@ -155,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.
 	}
 
@@ -192,22 +197,23 @@
 	// in a cyclic dependency.
 	osToArchMap = map[string][]string{
 		OsAndroid:     {archArm, archArm64, archRiscv64, archX86, archX86_64},
-		osLinux:       {archX86, archX86_64},
+		OsLinux:       {archX86, archX86_64},
 		osLinuxMusl:   {archX86, archX86_64},
-		osDarwin:      {archArm64, archX86_64},
+		OsDarwin:      {archArm64, archX86_64},
 		osLinuxBionic: {archArm64, archX86_64},
 		// TODO(cparsons): According to arch.go, this should contain archArm, archArm64, as well.
-		osWindows: {archX86, archX86_64},
+		OsWindows: {archX86, archX86_64},
 	}
 
 	osAndInApexMap = map[string]string{
 		AndroidAndInApex:           "//build/bazel/rules/apex:android-in_apex",
-		AndroidAndNonApex:          "//build/bazel/rules/apex:android-non_apex",
-		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",
+		AndroidPlatform:            "//build/bazel/rules/apex:system",
+		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,
 	}
 
@@ -216,6 +222,17 @@
 		NonApex:                    "//build/bazel/rules/apex:non_apex",
 		ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
 	}
+
+	errorProneMap = map[string]string{
+		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
@@ -229,6 +246,9 @@
 	productVariables
 	osAndInApex
 	inApex
+	errorProneDisabled
+	// TODO: b/294868620 - Remove when completing the bug
+	sanitizersEnabled
 )
 
 func osArchString(os string, arch string) string {
@@ -237,13 +257,16 @@
 
 func (ct configurationType) String() string {
 	return map[configurationType]string{
-		noConfig:         "no_config",
-		arch:             "arch",
-		os:               "os",
-		osArch:           "arch_os",
-		productVariables: "product_variables",
-		osAndInApex:      "os_in_apex",
-		inApex:           "in_apex",
+		noConfig:           "no_config",
+		arch:               "arch",
+		os:                 "os",
+		osArch:             "arch_os",
+		productVariables:   "product_variables",
+		osAndInApex:        "os_in_apex",
+		inApex:             "in_apex",
+		errorProneDisabled: "errorprone_disabled",
+		// TODO: b/294868620 - Remove when completing the bug
+		sanitizersEnabled: "sanitizers_enabled",
 	}[ct]
 }
 
@@ -268,13 +291,21 @@
 	case productVariables:
 		// do nothing
 	case osAndInApex:
-		if _, ok := osAndInApexMap[config]; !ok {
-			panic(fmt.Errorf("Unknown os+in_apex config: %s", config))
-		}
+		// do nothing
+		// this axis can contain additional per-apex keys
 	case inApex:
 		if _, ok := inApexMap[config]; !ok {
 			panic(fmt.Errorf("Unknown in_apex config: %s", config))
 		}
+	case errorProneDisabled:
+		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))
 	}
@@ -293,15 +324,22 @@
 	case osArch:
 		return platformOsArchMap[config]
 	case productVariables:
-		if strings.HasSuffix(config, ConditionsDefaultConfigKey) {
-			// e.g. "acme__feature1__conditions_default" or "android__board__conditions_default"
+		if config == ConditionsDefaultConfigKey {
 			return ConditionsDefaultSelectKey
 		}
 		return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
 	case osAndInApex:
-		return osAndInApexMap[config]
+		if ret, exists := osAndInApexMap[config]; exists {
+			return ret
+		}
+		return config
 	case inApex:
 		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))
 	}
@@ -320,14 +358,19 @@
 	OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex}
 	// An axis for in_apex-specific configurations
 	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
-func ProductVariableConfigurationAxis(variable string, outerAxis ConfigurationAxis) ConfigurationAxis {
+func ProductVariableConfigurationAxis(archVariant bool, variable string) ConfigurationAxis {
 	return ConfigurationAxis{
 		configurationType: productVariables,
 		subType:           variable,
-		outerAxisType:     outerAxis.configurationType,
+		archVariant:       archVariant,
 	}
 }
 
@@ -338,8 +381,8 @@
 	// some configuration types (e.g. productVariables) have multiple independent axes, subType helps
 	// distinguish between them without needing to list all 17 product variables.
 	subType string
-	// used to keep track of which product variables are arch variant
-	outerAxisType configurationType
+
+	archVariant bool
 }
 
 func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool {
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index 6a3b3c8..791c6bc 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -8,10 +8,10 @@
 
 var (
 	GetOutputFiles      = &getOutputFilesRequestType{}
-	GetPythonBinary     = &getPythonBinaryRequestType{}
 	GetCcInfo           = &getCcInfoType{}
 	GetApexInfo         = &getApexInfoType{}
 	GetCcUnstrippedInfo = &getCcUnstrippedInfoType{}
+	GetPrebuiltFileInfo = &getPrebuiltFileInfo{}
 )
 
 type CcAndroidMkInfo struct {
@@ -45,8 +45,6 @@
 
 type getOutputFilesRequestType struct{}
 
-type getPythonBinaryRequestType struct{}
-
 // Name returns a string name for this request type. Such request type names must be unique,
 // and must only consist of alphanumeric characters.
 func (g getOutputFilesRequestType) Name() string {
@@ -72,31 +70,6 @@
 	return splitOrEmpty(rawString, ", ")
 }
 
-// Name returns a string name for this request type. Such request type names must be unique,
-// and must only consist of alphanumeric characters.
-func (g getPythonBinaryRequestType) Name() string {
-	return "getPythonBinary"
-}
-
-// 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.
-func (g getPythonBinaryRequestType) StarlarkFunctionBody() string {
-	return "return providers(target)['FilesToRunProvider'].executable.path"
-}
-
-// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
-// The given rawString must correspond to the string output which was created by evaluating the
-// Starlark given in StarlarkFunctionBody.
-func (g getPythonBinaryRequestType) ParseResult(rawString string) string {
-	return rawString
-}
-
 type getCcInfoType struct{}
 
 // Name returns a string name for this request type. Such request type names must be unique,
@@ -403,3 +376,51 @@
 	}
 	return nil
 }
+
+type getPrebuiltFileInfo struct{}
+
+// Name returns a string name for this request type. Such request type names must be unique,
+// and must only consist of alphanumeric characters.
+func (g getPrebuiltFileInfo) Name() string {
+	return "getPrebuiltFileInfo"
+}
+
+// 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.
+func (g getPrebuiltFileInfo) StarlarkFunctionBody() string {
+	return `
+p = providers(target)
+prebuilt_file_info = p.get("//build/bazel/rules:prebuilt_file.bzl%PrebuiltFileInfo")
+if not prebuilt_file_info:
+  fail("%s did not provide PrebuiltFileInfo" % id_string)
+
+return json.encode({
+	"Src": prebuilt_file_info.src.path,
+	"Dir": prebuilt_file_info.dir,
+	"Filename": prebuilt_file_info.filename,
+	"Installable": prebuilt_file_info.installable,
+})`
+}
+
+type PrebuiltFileInfo struct {
+	// TODO: b/207489266 - Fully support all properties in prebuilt_file
+	Src         string
+	Dir         string
+	Filename    string
+	Installable bool
+}
+
+// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
+// The given rawString must correspond to the string output which was created by evaluating the
+// Starlark given in StarlarkFunctionBody.
+func (g getPrebuiltFileInfo) ParseResult(rawString string) (PrebuiltFileInfo, error) {
+	var info PrebuiltFileInfo
+	err := parseJson(rawString, &info)
+	return info, err
+}
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index 7003ce1..e772bb7 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -40,34 +40,6 @@
 	}
 }
 
-func TestGetPythonBinaryParseResults(t *testing.T) {
-	t.Parallel()
-	testCases := []struct {
-		description    string
-		input          string
-		expectedOutput string
-	}{
-		{
-			description:    "no result",
-			input:          "",
-			expectedOutput: "",
-		},
-		{
-			description:    "one result",
-			input:          "test",
-			expectedOutput: "test",
-		},
-	}
-	for _, tc := range testCases {
-		t.Run(tc.description, func(t *testing.T) {
-			actualOutput := GetPythonBinary.ParseResult(tc.input)
-			if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
-				t.Errorf("expected %#v != actual %#v", tc.expectedOutput, actualOutput)
-			}
-		})
-	}
-}
-
 func TestGetCcInfoParseResults(t *testing.T) {
 	t.Parallel()
 	testCases := []struct {
diff --git a/bazel/properties.go b/bazel/properties.go
index 40d0ba3..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
 }
@@ -288,6 +281,41 @@
 	return result
 }
 
+// FirstUniqueBazelLabelListAttribute takes a LabelListAttribute and makes the LabelList for
+// each axis/configuration by keeping the first instance of a Label and omitting all subsequent
+// repetitions.
+func FirstUniqueBazelLabelListAttribute(attr LabelListAttribute) LabelListAttribute {
+	var result LabelListAttribute
+	result.Value = FirstUniqueBazelLabelList(attr.Value)
+	if attr.HasConfigurableValues() {
+		result.ConfigurableValues = make(configurableLabelLists)
+	}
+	for axis, configToLabels := range attr.ConfigurableValues {
+		for c, l := range configToLabels {
+			result.SetSelectValue(axis, c, FirstUniqueBazelLabelList(l))
+		}
+	}
+
+	return result
+}
+
+// SubtractBazelLabelListAttribute subtract needle from haystack for LabelList in each
+// axis/configuration.
+func SubtractBazelLabelListAttribute(haystack LabelListAttribute, needle LabelListAttribute) LabelListAttribute {
+	var result LabelListAttribute
+	result.Value = SubtractBazelLabelList(haystack.Value, needle.Value)
+	if haystack.HasConfigurableValues() {
+		result.ConfigurableValues = make(configurableLabelLists)
+	}
+	for axis, configToLabels := range haystack.ConfigurableValues {
+		for haystackConfig, haystackLabels := range configToLabels {
+			result.SetSelectValue(axis, haystackConfig, SubtractBazelLabelList(haystackLabels, needle.SelectValue(axis, haystackConfig)))
+		}
+	}
+
+	return result
+}
+
 type Attribute interface {
 	HasConfigurableValues() bool
 }
@@ -334,7 +362,7 @@
 			if containsArch {
 				allProductVariablesAreArchVariant := true
 				for k := range la.ConfigurableValues {
-					if k.configurationType == productVariables && k.outerAxisType != arch {
+					if k.configurationType == productVariables && !k.archVariant {
 						allProductVariablesAreArchVariant = false
 					}
 				}
@@ -398,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)
 		}
@@ -414,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))
@@ -484,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)
 		}
@@ -631,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 {
@@ -766,7 +794,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		lla.Value = list
-	case arch, os, osArch, productVariables, osAndInApex, inApex:
+	case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled, sanitizersEnabled:
 		if lla.ConfigurableValues == nil {
 			lla.ConfigurableValues = make(configurableLabelLists)
 		}
@@ -782,7 +810,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return lla.Value
-	case arch, os, osArch, productVariables, osAndInApex, inApex:
+	case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled, sanitizersEnabled:
 		return lla.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -1140,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)
 		}
@@ -1156,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 {
@@ -1346,7 +1374,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		sla.Value = list
-	case arch, os, osArch, productVariables, osAndInApex:
+	case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled, sanitizersEnabled:
 		if sla.ConfigurableValues == nil {
 			sla.ConfigurableValues = make(configurableStringLists)
 		}
@@ -1362,7 +1390,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return sla.Value
-	case arch, os, osArch, productVariables, osAndInApex:
+	case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled, sanitizersEnabled:
 		return sla.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -1424,3 +1452,16 @@
 	sub := productVariableSubstitutionPattern.ReplaceAllString(s, "$("+productVariable+")")
 	return sub, s != sub
 }
+
+// StringMapAttribute is a map of strings.
+// The use case for this is storing the flag_values in a config_setting object.
+// Bazel rules do not support map attributes, and this should NOT be used in Bazel rules.
+type StringMapAttribute map[string]string
+
+// ConfigSettingAttributes stores the keys of a config_setting object.
+type ConfigSettingAttributes struct {
+	// Each key in Flag_values is a label to a custom string_setting
+	Flag_values StringMapAttribute
+	// Each element in Constraint_values is a label to a constraint_value
+	Constraint_values LabelListAttribute
+}
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
index cf03eb5..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"},
@@ -125,6 +129,63 @@
 		}
 	}
 }
+
+func TestSubtractBazelLabelListAttribute(t *testing.T) {
+	testCases := []struct {
+		haystack LabelListAttribute
+		needle   LabelListAttribute
+		expected LabelListAttribute
+	}{
+		{
+			haystack: LabelListAttribute{
+				Value: makeLabelList(
+					[]string{"a", "b", "a", "c"},
+					[]string{"x", "x", "y", "z"},
+				),
+				ConfigurableValues: configurableLabelLists{
+					ArchConfigurationAxis: labelListSelectValues{
+						"arm": makeLabelList([]string{"arm_1", "arm_2"}, []string{}),
+						"x86": makeLabelList([]string{"x86_3", "x86_4", "x86_5"}, []string{"x86_5"}),
+					},
+				},
+			},
+			needle: LabelListAttribute{
+				Value: makeLabelList(
+					[]string{"d", "a"},
+					[]string{"x", "y2", "z2"},
+				),
+				ConfigurableValues: configurableLabelLists{
+					ArchConfigurationAxis: labelListSelectValues{
+						"arm": makeLabelList([]string{"arm_1", "arm_3"}, []string{}),
+						"x86": makeLabelList([]string{"x86_3", "x86_4"}, []string{"x86_6"}),
+					},
+				},
+			},
+			expected: LabelListAttribute{
+				Value: makeLabelList(
+					[]string{"b", "c"},
+					[]string{"x", "x", "y", "z"},
+				),
+				ConfigurableValues: configurableLabelLists{
+					ArchConfigurationAxis: labelListSelectValues{
+						"arm": makeLabelList([]string{"arm_2"}, []string{}),
+						"x86": makeLabelList([]string{"x86_5"}, []string{"x86_5"}),
+					},
+				},
+				ForceSpecifyEmptyList: false,
+				EmitEmptyList:         false,
+				Prepend:               false,
+			},
+		},
+	}
+	for _, tc := range testCases {
+		got := SubtractBazelLabelListAttribute(tc.haystack, tc.needle)
+		if !reflect.DeepEqual(tc.expected, got) {
+			t.Fatalf("Expected\n%v, but got\n%v", tc.expected, got)
+		}
+	}
+}
+
 func TestFirstUniqueBazelLabelList(t *testing.T) {
 	testCases := []struct {
 		originalLabelList       LabelList
@@ -137,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"},
@@ -150,6 +214,7 @@
 					{Label: "a"},
 					{Label: "b"},
 					{Label: "c"},
+					{Label: "//foo:bar", OriginalModuleName: "bar"},
 				},
 				Excludes: []Label{
 					{Label: "x"},
@@ -167,6 +232,46 @@
 	}
 }
 
+func TestFirstUniqueBazelLabelListAttribute(t *testing.T) {
+	testCases := []struct {
+		originalLabelList       LabelListAttribute
+		expectedUniqueLabelList LabelListAttribute
+	}{
+		{
+			originalLabelList: LabelListAttribute{
+				Value: makeLabelList(
+					[]string{"a", "b", "a", "c"},
+					[]string{"x", "x", "y", "z"},
+				),
+				ConfigurableValues: configurableLabelLists{
+					ArchConfigurationAxis: labelListSelectValues{
+						"arm": makeLabelList([]string{"1", "2", "1"}, []string{}),
+						"x86": makeLabelList([]string{"3", "4", "4"}, []string{"5", "5"}),
+					},
+				},
+			},
+			expectedUniqueLabelList: LabelListAttribute{
+				Value: makeLabelList(
+					[]string{"a", "b", "c"},
+					[]string{"x", "y", "z"},
+				),
+				ConfigurableValues: configurableLabelLists{
+					ArchConfigurationAxis: labelListSelectValues{
+						"arm": makeLabelList([]string{"1", "2"}, []string{}),
+						"x86": makeLabelList([]string{"3", "4"}, []string{"5"}),
+					},
+				},
+			},
+		},
+	}
+	for _, tc := range testCases {
+		actualUniqueLabelList := FirstUniqueBazelLabelListAttribute(tc.originalLabelList)
+		if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
+			t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
+		}
+	}
+}
+
 func TestUniqueSortedBazelLabelList(t *testing.T) {
 	testCases := []struct {
 		originalLabelList       LabelList
@@ -248,13 +353,13 @@
 			OsArchConfigurationAxis: labelListSelectValues{
 				"linux_x86": makeLabelList([]string{"linux_x86_include"}, []string{}),
 			},
-			ProductVariableConfigurationAxis("product_with_defaults", NoConfigAxis): labelListSelectValues{
+			ProductVariableConfigurationAxis(false, "product_with_defaults"): labelListSelectValues{
 				"a":                        makeLabelList([]string{}, []string{"not_in_value"}),
 				"b":                        makeLabelList([]string{"b_val"}, []string{}),
 				"c":                        makeLabelList([]string{"c_val"}, []string{}),
 				ConditionsDefaultConfigKey: makeLabelList([]string{"c_val", "default", "default2", "all_exclude"}, []string{}),
 			},
-			ProductVariableConfigurationAxis("product_only_with_excludes", NoConfigAxis): labelListSelectValues{
+			ProductVariableConfigurationAxis(false, "product_only_with_excludes"): labelListSelectValues{
 				"a": makeLabelList([]string{}, []string{"product_config_exclude"}),
 			},
 		},
@@ -282,13 +387,13 @@
 			"linux_x86":                makeLabels("linux_x86_include"),
 			ConditionsDefaultConfigKey: nilLabels,
 		},
-		ProductVariableConfigurationAxis("product_with_defaults", NoConfigAxis): {
+		ProductVariableConfigurationAxis(false, "product_with_defaults"): {
 			"a":                        nilLabels,
 			"b":                        makeLabels("b_val"),
 			"c":                        makeLabels("c_val"),
 			ConditionsDefaultConfigKey: makeLabels("c_val", "default", "default2"),
 		},
-		ProductVariableConfigurationAxis("product_only_with_excludes", NoConfigAxis): {
+		ProductVariableConfigurationAxis(false, "product_only_with_excludes"): {
 			"a":                        nilLabels,
 			ConditionsDefaultConfigKey: makeLabels("product_config_exclude"),
 		},
@@ -679,7 +784,7 @@
 			OsArchConfigurationAxis: stringListSelectValues{
 				"linux_x86": {"linux_x86_include"},
 			},
-			ProductVariableConfigurationAxis("a", NoConfigAxis): stringListSelectValues{
+			ProductVariableConfigurationAxis(false, "a"): stringListSelectValues{
 				"a": []string{"not_in_value"},
 			},
 		},
@@ -704,7 +809,7 @@
 			"linux": []string{"linux_include"},
 		},
 		OsArchConfigurationAxis: stringListSelectValues{},
-		ProductVariableConfigurationAxis("a", NoConfigAxis): stringListSelectValues{
+		ProductVariableConfigurationAxis(false, "a"): stringListSelectValues{
 			"a": []string{"not_in_value"},
 		},
 	}
diff --git a/bloaty/bloaty.go b/bloaty/bloaty.go
index 50f241f..43fb71d 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.
@@ -51,8 +51,8 @@
 	pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS)
 	pctx.SourcePathVariable("bloaty", "prebuilts/build-tools/${hostPrebuiltTag}/bin/bloaty")
 	pctx.HostBinToolVariable("bloatyMerger", "bloaty_merger")
-	android.RegisterSingletonType("file_metrics", fileSizesSingleton)
-	fileSizeMeasurerKey = blueprint.NewProvider(measuredFiles{})
+	android.RegisterParallelSingletonType("file_metrics", fileSizesSingleton)
+	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,10 @@
 func (singleton *sizesSingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	var deps android.Paths
 	ctx.VisitAllModules(func(m android.Module) {
-		if !ctx.ModuleHasProvider(m, fileSizeMeasurerKey) {
+		filePaths, ok := android.SingletonModuleProvider(ctx, m, fileSizeMeasurerKey)
+		if !ok {
 			return
 		}
-		filePaths := ctx.ModuleProvider(m, fileSizeMeasurerKey).(measuredFiles)
 		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 9ec3a40..ba12682 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -7,19 +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",
@@ -31,56 +28,14 @@
         "soong-genrule",
         "soong-linkerconfig",
         "soong-python",
+        "soong-rust",
         "soong-sh",
         "soong-shared",
         "soong-starlark-format",
         "soong-ui-metrics",
     ],
     testSrcs: [
-        "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",
-        "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",
-        "ndk_headers_conversion_test.go",
-        "package_conversion_test.go",
-        "performance_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 928a1f2..0000000
--- a/bp2build/android_app_conversion_test.go
+++ /dev/null
@@ -1,398 +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",
-}
-`,
-		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 TestAndroidAppMinSdkProvided(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",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("android_binary", "foo", AttrNameToString{
-				"manifest":       `"AndroidManifest.xml"`,
-				"resource_files": `[]`,
-				"manifest_values": `{
-        "minSdkVersion": "24",
-    }`,
-				"sdk_version": `"current"`,
-			}),
-		}})
-}
-
-func TestAndroidAppMinSdkDefaultToSdkVersion(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",
-    }`,
-				"sdk_version": `"30"`,
-			}),
-		}})
-}
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
deleted file mode 100644
index 1cc3f22..0000000
--- a/bp2build/apex_conversion_test.go
+++ /dev/null
@@ -1,1590 +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",
-	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",
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
-				"android_manifest": `"ApogeeAndroidManifest.xml"`,
-				"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"`,
-			}),
-		}})
-}
-
-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"`,
-				"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_variables: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_variables: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 d1dfb9d..0000000
--- a/bp2build/bp2build.go
+++ /dev/null
@@ -1,142 +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"
-)
-
-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 {
-	// 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)
-	}
-	bp2buildFiles := CreateBazelFiles(ctx.Config(), nil, res.buildFileToTargets, ctx.mode)
-	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)
-
-	injectionFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics)
-	if err != nil {
-		fmt.Printf("%s\n", err.Error())
-		os.Exit(1)
-	}
-	writeFiles(ctx, android.PathForOutput(ctx, bazel.SoongInjectionDirName), injectionFiles)
-	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, error) {
-	var ret []BazelFile
-
-	productConfigFiles, err := CreateProductConfigFiles(ctx)
-	if err != nil {
-		return nil, err
-	}
-	ret = append(ret, productConfigFiles...)
-	injectionFiles, err := soongInjectionFiles(ctx.Config(), metrics)
-	if err != nil {
-		return nil, err
-	}
-	ret = append(ret, injectionFiles...)
-	return ret, 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 3abef9d..0000000
--- a/bp2build/bp2build_product_config.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package bp2build
-
-import (
-	"fmt"
-	"os"
-	"path/filepath"
-	"strings"
-)
-
-func CreateProductConfigFiles(
-	ctx *CodegenContext) ([]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)
-	}
-	bytes, err := os.ReadFile(productVariablesFileName)
-	if err != nil {
-		return 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)
-
-	result := []BazelFile{
-		newFile(
-			currentProductFolder,
-			"soong.variables.bzl",
-			`variables = json.decode("""`+strings.ReplaceAll(string(bytes), "\\", "\\\\")+`""")`),
-		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__",
-])
-`)),
-		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_FOLDER}:{PRODUCT}-{VARIANT}"
-]
-`)),
-		newFile(
-			"product_config_platforms",
-			"common.bazelrc",
-			productReplacer.Replace(`
-build --platforms @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
-
-build:android --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}
-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
-`)),
-		newFile(
-			"product_config_platforms",
-			"platform_mappings",
-			productReplacer.Replace(`
-flags:
-  --cpu=k8
-    @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}
-`)),
-	}
-
-	return result, nil
-}
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 b7678a4..bd56768 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -36,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
@@ -92,45 +98,77 @@
 // statements (use LoadStatements for that), since the targets are usually not
 // adjacent to the load statements at the top of the BUILD file.
 func (targets BazelTargets) String() string {
-	var res string
+	var res strings.Builder
 	for i, target := range targets {
 		if target.ruleClass != "package" {
-			res += target.content
+			res.WriteString(target.content)
 		}
 		if i != len(targets)-1 {
-			res += "\n\n"
+			res.WriteString("\n\n")
 		}
 	}
-	return res
+	return res.String()
 }
 
 // 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 {
@@ -160,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
@@ -189,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)
 	}
@@ -220,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,
@@ -243,8 +266,8 @@
 }
 
 type conversionResults struct {
-	buildFileToTargets map[string]BazelTargets
-	metrics            CodegenMetrics
+	buildFileToTargets    map[string]BazelTargets
+	moduleNameToPartition map[string]string
 }
 
 func (r conversionResults) BuildDirToTargets() map[string]BazelTargets {
@@ -252,82 +275,23 @@
 }
 
 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
 
 	bpCtx := ctx.Context()
 	bpCtx.VisitAllModules(func(m blueprint.Module) {
 		dir := bpCtx.ModuleDir(m)
-		moduleType := bpCtx.ModuleType(m)
 		dirs[dir] = true
 
 		var targets []BazelTarget
 
 		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.AddConvertedModule(m, moduleType, dir, Handcrafted)
-			} else if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() {
-				// Handle modules converted to generated targets.
-
-				// Log the module.
-				metrics.AddConvertedModule(aModule, moduleType, dir, Generated)
-
-				// 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
-					}
-				}
-				var targetErrs []error
-				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 {
-				metrics.AddUnconvertedModule(moduleType)
-				return
-			}
 		case QueryView:
 			// Blocklist certain module types from being generated.
 			if canonicalizeModuleType(bpCtx.ModuleType(m)) == "package" {
@@ -340,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
@@ -374,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) {
@@ -541,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
@@ -600,6 +505,11 @@
 		// TODO(b/164227191): implement pretty print for interfaces.
 		// Interfaces are used for for arch, multilib and target properties.
 		return "", nil
+	case reflect.Map:
+		if v, ok := propertyValue.Interface().(bazel.StringMapAttribute); ok {
+			return starlark_fmt.PrintStringStringDict(v, indent), nil
+		}
+		return "", fmt.Errorf("bp2build expects map of type map[string]string for field: %s", propertyValue)
 	default:
 		return "", fmt.Errorf(
 			"unexpected kind for property struct field: %s", propertyValue.Kind())
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
deleted file mode 100644
index 73ee26b..0000000
--- a/bp2build/build_conversion_test.go
+++ /dev/null
@@ -1,1900 +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/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": `["//build/bazel/product_variables:unbundled_build"]`,
-				}),
-			},
-		},
-		{
-			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",
-	})
-}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
deleted file mode 100644
index a8e557d..0000000
--- a/bp2build/bzl_conversion_test.go
+++ /dev/null
@@ -1,232 +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(),
-        "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(),
-    },
-)
-
-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(),
-        "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(),
-    },
-)
-
-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(),
-        "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_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(android.NullConfig("out", "out/soong"), 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 0315732..0000000
--- a/bp2build/cc_binary_conversion_test.go
+++ /dev/null
@@ -1,998 +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)",
-    ]`,
-			},
-			},
-		},
-	})
-}
-
-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",
-    ]`,
-				"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",
-            "-arm_isa_thumb",
-        ],
-        "//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 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",
-    ]`,
-			}},
-		},
-	})
-}
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
deleted file mode 100644
index 86aa4aa..0000000
--- a/bp2build/cc_library_conversion_test.go
+++ /dev/null
@@ -1,4483 +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`,
-			"implementation_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"]`,
-		}),
-	},
-	)
-}
-
-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"]`,
-		}),
-	},
-	)
-}
-
-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{}),
-			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)",
-    ]`,
-			}),
-		},
-	})
-}
-
-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_variables: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_variables: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_variables: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_variables: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_bp2build_converted", AttrNameToString{
-				"srcs": `["a_fg.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_bp2build_converted", AttrNameToString{
-				"srcs": `["a_fg.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:android-in_apex": ["@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:android-in_apex": [
-            "@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",
-            "-arm_isa_thumb",
-        ],
-        "//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 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 },
-}
-cc_library {
-	name: "bazlib",
-	stubs: { symbol_file: "bar.map.txt", versions: ["28", "29", "current"] },
-	bazel_module: { bp2build_available: false },
-}
-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": `select({
-        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"],
-        "//conditions:default": [":barlib"],
-    })`,
-				"dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:bazlib"],
-        "//conditions:default": [":bazlib"],
-    })`,
-				"local_includes": `["."]`,
-				"tags":           `["apex_available=apex_available:platform"]`,
-			}),
-			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"implementation_dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:barlib"],
-        "//conditions:default": [":barlib"],
-    })`,
-				"dynamic_deps": `select({
-        "//build/bazel/rules/apex:android-in_apex": ["@api_surfaces//module-libapi/current:bazlib"],
-        "//conditions:default": [":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 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_variables:eng": [
-            "-UDEBUG_ONLY_CODE",
-            "-DDEBUG_ONLY_CODE=1",
-        ],
-        "//conditions:default": [],
-    })`,
-			"srcs": `["a.cpp"]`,
-		}),
-	},
-	)
-}
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 9ba9337..0000000
--- a/bp2build/cc_library_shared_conversion_test.go
+++ /dev/null
@@ -1,1315 +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)",
-    ]`,
-			}),
-		},
-	})
-}
-
-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)",
-    ]`,
-			}),
-		},
-	})
-}
-
-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",
-				"implementation_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:android-in_apex": ["@api_surfaces//module-libapi/current:a"],
-        "//conditions:default": [":a"],
-    })`,
-				"tags": `["apex_available=apex_b"]`,
-			}),
-		},
-	})
-}
-
-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:android-in_apex": ["@api_surfaces//module-libapi/current:a"],
-        "//conditions:default": [":a"],
-    })`,
-				"tags": `[
-        "apex_available=//apex_available:platform",
-        "apex_available=apex_b",
-    ]`,
-			}),
-		},
-	})
-}
-
-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:android-in_apex": ["@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)"]`,
-			}),
-		},
-	})
-}
-
-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 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 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"`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
deleted file mode 100644
index cd4cf51..0000000
--- a/bp2build/cc_library_static_conversion_test.go
+++ /dev/null
@@ -1,2034 +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",
-    ]`,
-			}),
-		},
-	})
-}
-
-// 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_variables:binder32bit": ["-Wbinder32bit"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_variables: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_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_variables:malloc_not_svelte-android": ["-Wandroid_malloc_not_svelte"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_variables:malloc_not_svelte-arm": ["-Wlib32_malloc_not_svelte"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_variables:malloc_not_svelte-arm64": ["-Warm64_malloc_not_svelte"],
-        "//conditions:default": [],
-    }) + select({
-        "//build/bazel/product_variables: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_variables: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 },
-}
-
-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:android-in_apex": ["@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{
-				"implementation_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 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": `["."]`,
-			}),
-		},
-	})
-}
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
deleted file mode 100644
index eab84e1..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_variables: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 20adddb..0000000
--- a/bp2build/cc_test_conversion_test.go
+++ /dev/null
@@ -1,262 +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"],
-        },
-    },
-    data: [":data_mod", "file.txt"],
-    data_bins: [":cc_bin"],
-    data_libs: [":cc_lib"],
-    cflags: ["-Wall"],
-}
-` + simpleModuleDoNotConvertBp2build("cc_library", "foolib") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "hostlib") +
-			simpleModuleDoNotConvertBp2build("genrule", "data_mod") +
-			simpleModuleDoNotConvertBp2build("cc_binary", "cc_bin") +
-			simpleModuleDoNotConvertBp2build("cc_test_library", "cc_lib"),
-		targets: []testBazelTarget{
-			{"cc_test", "mytest", AttrNameToString{
-				"copts": `["-Wall"]`,
-				"data": `[
-        ":data_mod",
-        "file.txt",
-        ":cc_bin",
-        ":cc_lib",
-    ]`,
-				"deps": `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": [],
-    })`,
-				"gtest":          "True",
-				"isolated":       "True",
-				"local_includes": `["."]`,
-				"dynamic_deps": `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",
-				"isolated":       "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"] },
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_test", "mytest", AttrNameToString{
-				"tags":           `["no-remote"]`,
-				"local_includes": `["."]`,
-				"srcs":           `["test.cpp"]`,
-				"gtest":          "True",
-				"isolated":       "True",
-			},
-			},
-		},
-	})
-}
-
-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",
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_test", "mytest", AttrNameToString{
-				"gtest":                  "True",
-				"isolated":               "True",
-				"local_includes":         `["."]`,
-				"srcs":                   `["test.cpp"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-				"test_config":            `"test_config.xml"`,
-			},
-			},
-		},
-	})
-}
-
-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"],
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_test", "mytest", AttrNameToString{
-				"gtest":                  "True",
-				"isolated":               "True",
-				"local_includes":         `["."]`,
-				"srcs":                   `["test.cpp"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-				"test_config":            `"AndroidTest.xml"`,
-			},
-			},
-		},
-	})
-}
-
-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,
-}
-`,
-		targets: []testBazelTarget{
-			{"cc_test", "mytest", AttrNameToString{
-				"auto_generate_test_config": "True",
-				"gtest":                     "True",
-				"isolated":                  "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"`,
-			},
-			},
-		},
-	})
-}
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/configurability.go b/bp2build/configurability.go
index 8e17103..3d9f0a2 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -279,6 +279,10 @@
 	}
 
 	if len(selects) == 0 {
+		// If there is a default value, and there are no selects for this axis, print that without any selects.
+		if val, exists := selectMap[bazel.ConditionsDefaultSelectKey]; exists {
+			return prettyPrint(val, indent, emitZeroValues)
+		}
 		// No conditions (or all values are empty lists), so no need for a map.
 		return "", nil
 	}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 608fcd8..9f1aa09 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -1,20 +1,10 @@
 package bp2build
 
 import (
-	"android/soong/starlark_fmt"
-	"encoding/json"
-	"fmt"
 	"reflect"
-	"strconv"
 	"strings"
 
 	"android/soong/android"
-	"android/soong/cc"
-	cc_config "android/soong/cc/config"
-	java_config "android/soong/java/config"
-
-	"android/soong/apex"
-
 	"github.com/google/blueprint/proptools"
 )
 
@@ -24,91 +14,7 @@
 	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()))
-
-	apiLevelsContent, err := json.Marshal(android.GetApiLevelsMap(cfg))
-	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", "api_levels.bzl", android.StarlarkApiLevelConfigs(cfg)))
-	files = append(files, newFile("api_levels", "platform_versions.bzl", platformVersionContents(cfg)))
-
-	files = append(files, newFile("allowlists", GeneratedBuildFileName, ""))
-	files = append(files, newFile("allowlists", "env.bzl", android.EnvironmentVarsFile(cfg)))
-	// 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(
-	cfg android.Config,
-	ruleShims map[string]RuleShim,
-	buildToTargets map[string]BazelTargets,
-	mode CodegenMode) []BazelFile {
-
+func CreateBazelFiles(ruleShims map[string]RuleShim, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
 	var files []BazelFile
 
 	if mode == QueryView {
@@ -141,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 != "" {
@@ -177,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 2f5dc3c..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 {
@@ -27,8 +25,7 @@
 }
 
 func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) {
-	files := CreateBazelFiles(android.NullConfig("out", "out/soong"),
-		map[string]RuleShim{}, map[string]BazelTargets{}, QueryView)
+	files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, QueryView)
 	expectedFilePaths := []bazelFilepath{
 		{
 			dir:      "",
@@ -81,117 +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: "api_levels.bzl",
-		},
-		{
-			dir:      "api_levels",
-			basename: "platform_versions.bzl",
-		},
-		{
-			dir:      "allowlists",
-			basename: GeneratedBuildFileName,
-		},
-		{
-			dir:      "allowlists",
-			basename: "env.bzl",
-		},
-		{
-			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 7ce559d..0000000
--- a/bp2build/filegroup_conversion_test.go
+++ /dev/null
@@ -1,172 +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_bp2build_converted", AttrNameToString{
-				"srcs":                `["proto/foo.proto"]`,
-				"strip_import_prefix": `"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",
-    ]`}),
-		}})
-}
diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go
deleted file mode 100644
index 3490881..0000000
--- a/bp2build/genrule_conversion_test.go
+++ /dev/null
@@ -1,693 +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"
-	"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),
-	}
-}
-
-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"],
-    tool_files: [":foo.tool"],
-    cmd: "$(locations :foo.tool) -s $(out) $(location :other.tool)",
-    bazel_module: { bp2build_available: true },
-}`
-
-	for _, tc := range testCases {
-		moduleAttrs := AttrNameToString{
-			"cmd":   `"$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)"`,
-			"outs":  `["foo.out"]`,
-			"srcs":  `["//other:other.tool"]`,
-			"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,
-			})
-	})
-}
diff --git a/bp2build/gensrcs_conversion_test.go b/bp2build/gensrcs_conversion_test.go
deleted file mode 100644
index 4845973..0000000
--- a/bp2build/gensrcs_conversion_test.go
+++ /dev/null
@@ -1,80 +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)",
-                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)"`,
-			},
-		},
-		{
-			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/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
deleted file mode 100644
index c821f59..0000000
--- a/bp2build/java_binary_host_conversion_test.go
+++ /dev/null
@@ -1,333 +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"]`,
-				"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{
-			"test.mf":   "Main-Class: com.android.test.MainClass",
-			"res/a.res": "",
-			"res/b.res": "",
-		},
-		Blueprint: `java_binary_host {
-    name: "java-binary-host",
-    manifest: "test.mf",
-    srcs: ["a.java", "b.kt"],
-    java_resources: ["res/a.res", "res/b.res"],
-}
-`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("kt_jvm_library", "java-binary-host_lib", AttrNameToString{
-				"srcs": `[
-        "a.java",
-        "b.kt",
-    ]`,
-				"resources": `[
-        "res/a.res",
-        "res/b.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 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 24b763b..0000000
--- a/bp2build/java_library_conversion_test.go
+++ /dev/null
@@ -1,824 +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 TestJavaLibraryErrorproneJavacflagsEnabledManually(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    srcs: ["a.java"],
-    javacflags: ["-Xsuper-fast"],
-    errorprone: {
-        enabled: true,
-        javacflags: ["-Xep:SpeedLimit:OFF"],
-    },
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"javacopts": `[
-        "-Xsuper-fast",
-        "-Xep:SpeedLimit:OFF",
-    ]`,
-				"srcs": `["a.java"]`,
-			}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-		},
-	})
-}
-
-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 TestJavaLibraryErrorproneJavacflagsErrorproneDisabledManually(t *testing.T) {
-	runJavaLibraryTestCase(t, Bp2buildTestCase{
-		Blueprint: `java_library {
-    name: "java-lib-1",
-    srcs: ["a.java"],
-    javacflags: ["-Xsuper-fast"],
-    errorprone: {
-		enabled: false,
-        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 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{
-		Filesystem: map[string]string{
-			"res/a.res":      "",
-			"res/b.res":      "",
-			"res/dir1/b.res": "",
-		},
-		Blueprint: `java_library {
-    name: "java-lib-1",
-	java_resources: ["res/a.res", "res/b.res"],
-}`,
-		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"resources": `[
-        "res/a.res",
-        "res/b.res",
-    ]`,
-			}),
-			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"),
-		},
-	})
-}
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/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 a020650..0000000
--- a/bp2build/metrics.go
+++ /dev/null
@@ -1,207 +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),
-		},
-		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) AddUnconvertedModule(moduleType string) {
-	metrics.serialized.UnconvertedModuleCount += 1
-	metrics.serialized.TotalModuleTypeCount[moduleType] += 1
-}
-
-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, conversionType ConversionType) {
-	//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
-
-	if conversionType == Handcrafted {
-		metrics.serialized.HandCraftedModuleCount += 1
-	} else if conversionType == Generated {
-		metrics.serialized.GeneratedModuleCount += 1
-	}
-}
diff --git a/bp2build/ndk_headers_conversion_test.go b/bp2build/ndk_headers_conversion_test.go
deleted file mode 100644
index 9d0f1f2..0000000
--- a/bp2build/ndk_headers_conversion_test.go
+++ /dev/null
@@ -1,164 +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 TestNdkHeaderFilepaths(t *testing.T) {
-	bpTemplate := `
-	ndk_headers {
-		name: "foo",
-		srcs: %v,
-		exclude_srcs: %v,
-	}
-	`
-	testCases := []struct {
-		desc         string
-		srcs         string
-		excludeSrcs  string
-		expectedHdrs string
-	}{
-		{
-			desc:         "Single header file",
-			srcs:         `["foo.h"]`,
-			excludeSrcs:  `[]`,
-			expectedHdrs: `["foo.h"]`,
-		},
-		{
-			desc:        "Multiple header files",
-			srcs:        `["foo.h", "foo_other.h"]`,
-			excludeSrcs: `[]`,
-			expectedHdrs: `[
-        "foo.h",
-        "foo_other.h",
-    ]`,
-		},
-		{
-			desc:         "Multiple header files with excludes",
-			srcs:         `["foo.h", "foo_other.h"]`,
-			excludeSrcs:  `["foo_other.h"]`,
-			expectedHdrs: `["foo.h"]`,
-		},
-		{
-			desc:        "Multiple header files via Soong-supported globs",
-			srcs:        `["*.h"]`,
-			excludeSrcs: `[]`,
-			expectedHdrs: `[
-        "foo.h",
-        "foo_other.h",
-    ]`,
-		},
-	}
-	for _, testCase := range testCases {
-		fs := map[string]string{
-			"foo.h":       "",
-			"foo_other.h": "",
-		}
-		expectedApiContributionTargetName := "foo.contribution"
-		expectedBazelTarget := MakeBazelTargetNoRestrictions(
-			"cc_api_headers",
-			expectedApiContributionTargetName,
-			AttrNameToString{
-				"hdrs": testCase.expectedHdrs,
-			},
-		)
-		RunApiBp2BuildTestCase(t, cc.RegisterNdkModuleTypes, Bp2buildTestCase{
-			Description:          testCase.desc,
-			Blueprint:            fmt.Sprintf(bpTemplate, testCase.srcs, testCase.excludeSrcs),
-			ExpectedBazelTargets: []string{expectedBazelTarget},
-			Filesystem:           fs,
-		})
-	}
-}
-
-func TestNdkHeaderIncludeDir(t *testing.T) {
-	bpTemplate := `
-	ndk_headers {
-		name: "foo",
-		from: %v,
-		to: "this/value/is/ignored",
-	}
-	`
-	testCases := []struct {
-		desc               string
-		from               string
-		expectedIncludeDir string
-	}{
-		{
-			desc:               "Empty `from` value",
-			from:               `""`,
-			expectedIncludeDir: `""`,
-		},
-		{
-			desc:               "Non-Empty `from` value",
-			from:               `"include"`,
-			expectedIncludeDir: `"include"`,
-		},
-	}
-	for _, testCase := range testCases {
-		expectedApiContributionTargetName := "foo.contribution"
-		expectedBazelTarget := MakeBazelTargetNoRestrictions(
-			"cc_api_headers",
-			expectedApiContributionTargetName,
-			AttrNameToString{
-				"include_dir": testCase.expectedIncludeDir,
-			},
-		)
-		RunApiBp2BuildTestCase(t, cc.RegisterNdkModuleTypes, Bp2buildTestCase{
-			Description:          testCase.desc,
-			Blueprint:            fmt.Sprintf(bpTemplate, testCase.from),
-			ExpectedBazelTargets: []string{expectedBazelTarget},
-		})
-	}
-}
-
-func TestVersionedNdkHeaderFilepaths(t *testing.T) {
-	bp := `
-	versioned_ndk_headers {
-		name: "common_libc",
-		from: "include"
-	}
-	`
-	fs := map[string]string{
-		"include/math.h":    "",
-		"include/stdio.h":   "",
-		"include/arm/arm.h": "",
-		"include/x86/x86.h": "",
-	}
-	expectedApiContributionTargetName := "common_libc.contribution"
-	expectedBazelTarget := MakeBazelTargetNoRestrictions(
-		"cc_api_headers",
-		expectedApiContributionTargetName,
-		AttrNameToString{
-			"include_dir": `"include"`,
-			"hdrs": `[
-        "include/math.h",
-        "include/stdio.h",
-        "include/arm/arm.h",
-        "include/x86/x86.h",
-    ]`,
-		},
-	)
-	RunApiBp2BuildTestCase(t, cc.RegisterNdkModuleTypes, Bp2buildTestCase{
-		Blueprint:            bp,
-		Filesystem:           fs,
-		ExpectedBazelTargets: []string{expectedBazelTarget},
-	})
-}
diff --git a/bp2build/ndk_library_conversion_test.go b/bp2build/ndk_library_conversion_test.go
deleted file mode 100644
index 819ab25..0000000
--- a/bp2build/ndk_library_conversion_test.go
+++ /dev/null
@@ -1,77 +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 TestNdkLibraryContributionSymbolFile(t *testing.T) {
-	bp := `
-	ndk_library {
-		name: "libfoo",
-		symbol_file: "libfoo.map.txt",
-	}
-	`
-	expectedBazelTarget := MakeBazelTargetNoRestrictions(
-		"cc_api_contribution",
-		"libfoo.ndk.contribution",
-		AttrNameToString{
-			"api":                    `"libfoo.map.txt"`,
-			"api_surfaces":           `["publicapi"]`,
-			"library_name":           `"libfoo"`,
-			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-		},
-	)
-	RunApiBp2BuildTestCase(t, cc.RegisterNdkModuleTypes, Bp2buildTestCase{
-		Blueprint:            bp,
-		ExpectedBazelTargets: []string{expectedBazelTarget},
-	})
-}
-
-func TestNdkLibraryContributionHeaders(t *testing.T) {
-	bp := `
-	ndk_library {
-		name: "libfoo",
-		symbol_file: "libfoo.map.txt",
-		export_header_libs: ["libfoo_headers"],
-	}
-	`
-	fs := map[string]string{
-		"header_directory/Android.bp": `
-		ndk_headers {
-			name: "libfoo_headers",
-		}
-		`,
-	}
-	expectedBazelTarget := MakeBazelTargetNoRestrictions(
-		"cc_api_contribution",
-		"libfoo.ndk.contribution",
-		AttrNameToString{
-			"api":                    `"libfoo.map.txt"`,
-			"api_surfaces":           `["publicapi"]`,
-			"library_name":           `"libfoo"`,
-			"hdrs":                   `["//header_directory:libfoo_headers.contribution"]`,
-			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-		},
-	)
-	RunApiBp2BuildTestCase(t, cc.RegisterNdkModuleTypes, Bp2buildTestCase{
-		Blueprint:            bp,
-		Filesystem:           fs,
-		ExpectedBazelTargets: []string{expectedBazelTarget},
-	})
-}
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/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go
deleted file mode 100644
index aa0a5b7..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_variables: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_variables: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 ba42f34..0000000
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ /dev/null
@@ -1,1253 +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_variables: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_variables: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_variables:acme__board__soc_a": ["-DSOC_A"],
-        "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
-        "//build/bazel/product_variables:acme__board__soc_c": [],
-        "//conditions:default": ["-DSOC_DEFAULT"],
-    }),
-    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_variables:acme__board__soc_a": ["-DSOC_A"],
-        "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
-        "//build/bazel/product_variables:acme__board__soc_c": [],
-        "//conditions:default": ["-DSOC_DEFAULT"],
-    }) + select({
-        "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
-        "//conditions:default": ["-DDEFAULT1"],
-    }) + select({
-        "//build/bazel/product_variables: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_variables:acme__board__soc_a": ["-DSOC_A"],
-        "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
-        "//build/bazel/product_variables:acme__board__soc_c": [],
-        "//conditions:default": ["-DSOC_DEFAULT"],
-    }),
-    implementation_deps = select({
-        "//build/bazel/product_variables:acme__board__soc_a": ["//foo/bar:soc_a_dep"],
-        "//build/bazel/product_variables:acme__board__soc_b": ["//foo/bar:soc_b_dep"],
-        "//build/bazel/product_variables: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_variables: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_variables:acme__feature": ["-asflag_bar"],
-        "//conditions:default": ["-asflag_default_bar"],
-    }),
-    copts = select({
-        "//build/bazel/product_variables: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_variables:acme__feature": ["-asflag_bar"],
-        "//conditions:default": ["-asflag_default_bar"],
-    }),
-    copts = select({
-        "//build/bazel/product_variables: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_variables:vendor_bar__feature": ["-DVENDOR_BAR_FEATURE"],
-        "//conditions:default": ["-DVENDOR_BAR_DEFAULT"],
-    }) + select({
-        "//build/bazel/product_variables:vendor_foo__feature": ["-DVENDOR_FOO_FEATURE"],
-        "//conditions:default": ["-DVENDOR_FOO_DEFAULT"],
-    }) + select({
-        "//build/bazel/product_variables: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_variables: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_variables: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_variables: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_variables: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_variables: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_variables: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_variables: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_variables: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_variables:android__alphabet__a": [],
-        "//build/bazel/product_variables:android__alphabet__b": [],
-        "//conditions:default": ["//foo/bar:lib_default_bp2build_cc_library_static"],
-    }),
-    dynamic_deps = select({
-        "//build/bazel/product_variables:android__alphabet__a": ["//foo/bar:lib_a"],
-        "//build/bazel/product_variables: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 = ["//build/bazel/product_variables:alphabet_module__special_build"] + 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": [],
-    }),
-)`}})
-}
-
-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,
-}`
-
-	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 = ["//build/bazel/product_variables:alphabet_module__special_build"],
-)`}})
-}
-
-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"],
-)`}})
-}
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 6e919db..0000000
--- a/bp2build/testing.go
+++ /dev/null
@@ -1,663 +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
-	Blueprint                  string
-	ExpectedBazelTargets       []string
-	Filesystem                 map[string]string
-	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)
-		}),
-		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
-	}
-
-	codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
-	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
-}
-
-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) 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()}, attrs)
-}
-
-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 710d9cd..e1b512f 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,8 +150,6 @@
 		// 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",
-		// TODO(b/296014682): Remove after the bpf_headers is moved to Connectivity
-		"-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",
@@ -208,7 +203,7 @@
 		}
 
 	}
-	ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
+	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
 }
 
 func (bpf *bpf) AndroidMk() android.AndroidMkData {
@@ -232,52 +227,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) {
@@ -301,39 +269,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/build_kzip.bash b/build_kzip.bash
index eeef7d4..4c42048 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -35,8 +35,16 @@
 # sufficiently many files were generated.
 declare -r out="${OUT_DIR:-out}"
 
-# Build extraction files for C++ and Java. Build `merge_zips` which we use later.
-build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k merge_zips xref_cxx xref_java xref_rust
+# Build extraction files and `merge_zips` which we use later.
+kzip_targets=(
+  merge_zips
+  xref_cxx
+  xref_java
+  # TODO: b/286390153 - reenable rust
+  # xref_rust
+)
+
+build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k --skip-soong-tests --ninja_weight_source=not_used "${kzip_targets[@]}"
 
 # Build extraction file for Go the files in build/{blueprint,soong} directories.
 declare -r abspath_out=$(realpath "${out}")
@@ -63,10 +71,9 @@
 set +e
 
 declare -r kzip_count=$(find "$out" -name '*.kzip' | wc -l)
-(($kzip_count>100000)) || { printf "Too few kzip files were generated: %d\n" $kzip_count; exit 1; }
+(($kzip_count>100000)) || { >&2 printf "ERROR: Too few kzip files were generated: %d\n" $kzip_count; exit 1; }
 
 # Pack
-# TODO(asmundak): this should be done by soong.
 declare -r allkzip="$KZIP_NAME.kzip"
 "$out/host/linux-x86/bin/merge_zips" "$DIST_DIR/$allkzip" @<(find "$out" -name '*.kzip')
 
diff --git a/cc/Android.bp b/cc/Android.bp
index b12bdce..9e4b763 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -9,9 +9,9 @@
         "blueprint",
         "blueprint-pathtools",
         "soong",
+        "soong-aconfig",
         "soong-aidl-library",
         "soong-android",
-        "soong-bazel",
         "soong-cc-config",
         "soong-etc",
         "soong-fuzz",
@@ -26,18 +26,18 @@
         "fdo_profile.go",
         "androidmk.go",
         "api_level.go",
-        "bp2build.go",
         "builder.go",
         "cc.go",
         "ccdeps.go",
         "check.go",
         "coverage.go",
         "gen.go",
+        "generated_cc_library.go",
         "image.go",
         "linkable.go",
         "lto.go",
         "makevars.go",
-        "pgo.go",
+        "orderfile.go",
         "prebuilt.go",
         "proto.go",
         "rs.go",
@@ -48,7 +48,6 @@
         "snapshot_utils.go",
         "stl.go",
         "strip.go",
-        "sysprop.go",
         "tidy.go",
         "util.go",
         "vendor_snapshot.go",
@@ -104,6 +103,7 @@
         "lto_test.go",
         "ndk_test.go",
         "object_test.go",
+        "orderfile_test.go",
         "prebuilt_test.go",
         "proto_test.go",
         "sanitize_test.go",
diff --git a/cc/afdo.go b/cc/afdo.go
index 137ea97..79fbae1 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -24,17 +24,8 @@
 	"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")
-
-const afdoCFlagsFormat = "-fprofile-sample-use=%s"
+// This flag needs to be in both CFlags and LdFlags to ensure correct symbol ordering
+const afdoFlagsFormat = "-fprofile-sample-use=%s -fprofile-sample-accurate"
 
 func recordMissingAfdoProfileFile(ctx android.BaseModuleContext, missing string) {
 	getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
@@ -63,6 +54,13 @@
 	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
 func (afdo *afdo) afdoEnabled() bool {
@@ -83,10 +81,14 @@
 		// 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 {
 		// The flags are prepended to allow overriding.
-		profileUseFlag := fmt.Sprintf(afdoCFlagsFormat, *path)
+		profileUseFlag := fmt.Sprintf(afdoFlagsFormat, *path)
 		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...)
 
@@ -130,9 +132,12 @@
 		return
 	}
 
+	if !c.afdo.afdoEnabled() {
+		return
+	}
+
 	ctx.VisitDirectDepsWithTag(FdoProfileTag, func(m android.Module) {
-		if ctx.OtherModuleHasProvider(m, FdoProfileProvider) {
-			info := ctx.OtherModuleProvider(m, FdoProfileProvider).(FdoProfileInfo)
+		if info, ok := android.OtherModuleProvider(ctx, m, FdoProfileProvider); ok {
 			c.afdo.Properties.FdoProfilePath = proptools.StringPtr(info.Path.String())
 		}
 	})
diff --git a/cc/androidmk.go b/cc/androidmk.go
index ce35b5c..c39668c 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -50,6 +50,7 @@
 	InVendorRamdisk() bool
 	InRecovery() bool
 	NotInPlatform() bool
+	InVendorOrProduct() bool
 }
 
 type subAndroidMkProvider interface {
@@ -82,8 +83,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,20 +102,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() {
+				if c.InVendorOrProduct() {
 					entries.SetBool("LOCAL_USE_VNDK", true)
 					if c.IsVndk() && !c.static() {
 						entries.SetString("LOCAL_SOONG_VNDK_VERSION", c.VndkVersion())
@@ -133,6 +126,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 +169,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 +295,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 +364,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 +391,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...)
 		}
 	})
@@ -530,9 +486,9 @@
 
 	entries.SubName = ""
 
-	if c.isSanitizerEnabled(cfi) {
+	if c.IsSanitizerEnabled(cfi) {
 		entries.SubName += ".cfi"
-	} else if c.isSanitizerEnabled(Hwasan) {
+	} else if c.IsSanitizerEnabled(Hwasan) {
 		entries.SubName += ".hwasan"
 	}
 
diff --git a/cc/api_level.go b/cc/api_level.go
index a5571f3..69a0d3a 100644
--- a/cc/api_level.go
+++ b/cc/api_level.go
@@ -31,7 +31,11 @@
 	case android.Arm64, android.X86_64:
 		return android.FirstLp64Version
 	case android.Riscv64:
-		return android.FutureApiLevel
+		apiLevel, err := android.ApiLevelFromUser(ctx, "VanillaIceCream")
+		if err != nil {
+			panic(err)
+		}
+		return apiLevel
 	default:
 		panic(fmt.Errorf("Unknown arch %q", arch))
 	}
diff --git a/cc/binary.go b/cc/binary.go
index 98b9923..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,
@@ -512,7 +509,7 @@
 		}
 		binary.baseInstaller.subDir = "bootstrap"
 	}
-	binary.baseInstaller.installExecutable(ctx, file)
+	binary.baseInstaller.install(ctx, file)
 
 	var preferredArchSymlinkPath android.OptionalPath
 	for _, symlink := range 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,144 +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)
-	}
-
-	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 5e1c2d3..0000000
--- a/cc/bp2build.go
+++ /dev/null
@@ -1,1584 +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"
-
-	"android/soong/android"
-	"android/soong/bazel"
-	"android/soong/cc/config"
-
-	"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"
-
-	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
-
-	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)
-			}
-		}
-	}
-}
-
-// 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"}},
-		// 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"}},
-	}
-
-	return bazel.PartitionLabelListAttribute(ctx, &srcs, 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))
-		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)
-
-	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
-
-	// Lex sources and options
-	lSrcs   bazel.LabelListAttribute
-	llSrcs  bazel.LabelListAttribute
-	lexopts bazel.StringListAttribute
-
-	// Sysprop sources
-	syspropSrcs 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
-
-	stubsSymbolFile *string
-	stubsVersions   bazel.StringListAttribute
-
-	features bazel.StringListAttribute
-
-	suffix bazel.StringAttribute
-
-	fdoProfile bazel.LabelAttribute
-}
-
-type filterOutFn func(string) bool
-
-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.
-	if srcsList, ok := parseSrcs(ctx, props); 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", "-arm_isa_thumb"})
-	} 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))
-	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 bazel.LabelListAttribute) {
-	ca.srcs.ResolveExcludes()
-	partitionedSrcs := groupSrcsByExtension(ctx, ca.srcs)
-
-	ca.protoSrcs = partitionedSrcs[protoSrcPartition]
-	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(implementationHdrs)
-		partitionedSrcs[p] = lla
-	}
-
-	ca.srcs = partitionedSrcs[cppSrcPartition]
-	ca.cSrcs = partitionedSrcs[cSrcPartition]
-	ca.asSrcs = partitionedSrcs[asSrcPartition]
-	ca.asmSrcs = partitionedSrcs[asmSrcPartition]
-	ca.lSrcs = partitionedSrcs[lSrcPartition]
-	ca.llSrcs = partitionedSrcs[llSrcPartition]
-	ca.syspropSrcs = partitionedSrcs[syspropSrcPartition]
-
-	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.
-	generatedSrcsLabelList := android.BazelLabelForModuleDepsExcludes(ctx, props.Generated_sources, 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
-}
-
-// includesFromLabelList extracts relative/absolute includes from a bazel.LabelList>
-func includesFromLabelList(labelList bazel.LabelList) (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)
-		}
-	}
-	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{})
-
-	var implementationHdrs bazel.LabelListAttribute
-
-	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
-
-	// 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)
-				}
-				(&compilerAttrs).bp2buildForAxisAndConfig(ctx, axis, cfg, baseCompilerProps)
-				aidlLibs.Append(android.BazelLabelForModuleDeps(ctx, baseCompilerProps.Aidl.Libs))
-			}
-
-			var exportHdrs []string
-
-			if baseLinkerProps, ok := archVariantLinkerProps[axis][cfg].(*BaseLinkerProperties); ok {
-				exportHdrs = baseLinkerProps.Export_generated_headers
-
-				(&linkerAttrs).bp2buildForAxisAndConfig(ctx, module, axis, cfg, baseLinkerProps)
-			}
-			headers := maybePartitionExportedAndImplementationsDeps(ctx, !module.Binary(), allHdrs, exportHdrs, android.BazelLabelForModuleDeps)
-			implementationHdrs.SetSelectValue(axis, cfg, headers.implementation)
-			compilerAttrs.hdrs.SetSelectValue(axis, cfg, headers.export)
-
-			exportIncludes, exportAbsoluteIncludes := includesFromLabelList(headers.export)
-			compilerAttrs.includes.Includes.SetSelectValue(axis, cfg, exportIncludes)
-			compilerAttrs.includes.AbsoluteIncludes.SetSelectValue(axis, cfg, exportAbsoluteIncludes)
-
-			includes, absoluteIncludes := includesFromLabelList(headers.implementation)
-			currAbsoluteIncludes := compilerAttrs.absoluteIncludes.SelectValue(axis, cfg)
-			currAbsoluteIncludes = android.FirstUniqueStrings(append(currAbsoluteIncludes, absoluteIncludes...))
-
-			compilerAttrs.absoluteIncludes.SetSelectValue(axis, cfg, currAbsoluteIncludes)
-
-			currIncludes := compilerAttrs.localIncludes.SelectValue(axis, cfg)
-			currIncludes = android.FirstUniqueStrings(append(currIncludes, includes...))
-
-			compilerAttrs.localIncludes.SetSelectValue(axis, cfg, currIncludes)
-
-			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 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)
-	(&linkerAttrs).finalize(ctx)
-
-	(&compilerAttrs.srcs).Add(bp2BuildYasm(ctx, module, compilerAttrs))
-
-	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)
-			}
-		}
-	}
-
-	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
-
-	features := compilerAttrs.features.Clone().Append(linkerAttrs.features).Append(bp2buildSanitizerFeatures(ctx, module))
-	features = features.Append(bp2buildLtoFeatures(ctx, module))
-	features.DeduplicateAxesFromBase()
-
-	addMuslSystemDynamicDeps(ctx, linkerAttrs)
-
-	return baseAttributes{
-		compilerAttrs,
-		linkerAttrs,
-		*features,
-		protoDep.protoDep,
-		aidlDep,
-		nativeCoverage,
-	}
-}
-
-// 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
-	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 {
-				if isBinary {
-					wholeStaticLibs = append(wholeStaticLibs, versionLib)
-				} else {
-					la.implementationWholeArchiveDeps.SetSelectValue(axis, config, bazelLabelForWholeDepsExcludes(ctx, []string{versionLib}, props.Exclude_static_libs))
-				}
-			}
-		}
-	}
-
-	// 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))
-
-	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)
-		setStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1)
-	}
-
-	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))
-	}
-
-	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)
-	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
-}
-
-func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
-	config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int) {
-
-	depsWithStubs := []bazel.Label{}
-	for _, l := range dynamicLibs.Includes {
-		dep, _ := ctx.ModuleFromName(l.OriginalModuleName)
-		if d, ok := dep.(*Module); ok && d.HasStubsVariants() {
-			depApexAvailable := d.ApexAvailable()
-			if !availableToSameApexes(apexAvailable, depApexAvailable) {
-				depsWithStubs = append(depsWithStubs, l)
-			}
-		}
-	}
-	if len(depsWithStubs) > 0 {
-		implDynamicDeps := bazel.SubtractBazelLabelList(dynamicLibs, bazel.MakeLabelList(depsWithStubs))
-		dynamicDeps.SetSelectValue(axis, config, implDynamicDeps)
-
-		stubLibLabels := []bazel.Label{}
-		for _, l := range depsWithStubs {
-			stubLabelInApiSurfaces := bazel.Label{
-				Label: apiSurfaceModuleLibCurrentPackage + strings.TrimPrefix(l.OriginalModuleName, ":"),
-			}
-			stubLibLabels = append(stubLibLabels, stubLabelInApiSurfaces)
-		}
-		inApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex)
-		nonApexSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex)
-		defaultSelectValue := dynamicDeps.SelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey)
-		if axis == bazel.NoConfigAxis {
-			(&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
-			(&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
-			(&defaultSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
-			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
-			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
-			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.FirstUniqueBazelLabelList(defaultSelectValue))
-		} else if config == bazel.OsAndroid {
-			(&inApexSelectValue).Append(bazel.MakeLabelList(stubLibLabels))
-			(&nonApexSelectValue).Append(bazel.MakeLabelList(depsWithStubs))
-			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.FirstUniqueBazelLabelList(inApexSelectValue))
-			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, bazel.FirstUniqueBazelLabelList(nonApexSelectValue))
-		}
-	}
-}
-
-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.ProductConfigProperty]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)
-		la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndNonApex, 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)
-		}
-		la.implementationDynamicDeps.Exclude(bazel.OsAndInApexAxis, bazel.AndroidAndInApex, bazel.MakeLabelList(stubsToRemove))
-	}
-
-	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 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
-	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 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)
-			}
-			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
-}
diff --git a/cc/builder.go b/cc/builder.go
index fef00d4..e4d5be2 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -125,6 +125,14 @@
 		},
 		"objcopyCmd", "prefix")
 
+	// Rule to run objcopy --remove-section=.llvm_addrsig on a partially linked object
+	noAddrSig = pctx.AndroidStaticRule("noAddrSig",
+		blueprint.RuleParams{
+			Command:     "rm -f ${out} && $objcopyCmd --remove-section=.llvm_addrsig ${in} ${out}",
+			CommandDeps: []string{"$objcopyCmd"},
+		},
+		"objcopyCmd")
+
 	_ = pctx.SourcePathVariable("stripPath", "build/soong/scripts/strip.sh")
 	_ = pctx.SourcePathVariable("xzCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/xz")
 	_ = pctx.SourcePathVariable("createMiniDebugInfo", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/create_minidebuginfo")
@@ -526,7 +534,7 @@
 		toolingCppflags += " ${config.NoOverride64GlobalCflags}"
 	}
 
-	modulePath := android.PathForModuleSrc(ctx).String()
+	modulePath := ctx.ModuleDir()
 	if android.IsThirdPartyPath(modulePath) {
 		cflags += " ${config.NoOverrideExternalGlobalCflags}"
 		toolingCflags += " ${config.NoOverrideExternalGlobalCflags}"
@@ -673,16 +681,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
@@ -867,7 +870,8 @@
 // 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 {
+	excludedSymbolVersions, excludedSymbolTags []string,
+	api string) android.OptionalPath {
 
 	outputFile := android.PathForModuleOut(ctx, baseName+".lsdump")
 
@@ -884,6 +888,11 @@
 	for _, tag := range excludedSymbolTags {
 		symbolFilterStr += " --exclude-symbol-tag " + tag
 	}
+	apiLevelsJson := android.GetApiLevelsJson(ctx)
+	implicits = append(implicits, apiLevelsJson)
+	symbolFilterStr += " --api-map " + apiLevelsJson.String()
+	symbolFilterStr += " --api " + api
+
 	rule := sAbiLink
 	args := map[string]string{
 		"symbolFilter":        symbolFilterStr,
@@ -1008,6 +1017,21 @@
 	})
 }
 
+// Generate a rule for running objcopy --remove-section=.llvm_addrsig on a partially linked object
+func transformObjectNoAddrSig(ctx android.ModuleContext, inputFile android.Path, outputFile android.WritablePath) {
+	objcopyCmd := "${config.ClangBin}/llvm-objcopy"
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        noAddrSig,
+		Description: "remove addrsig " + outputFile.Base(),
+		Output:      outputFile,
+		Input:       inputFile,
+		Args: map[string]string{
+			"objcopyCmd": objcopyCmd,
+		},
+	})
+}
+
 // Registers a build statement to invoke `strip` (to discard symbols and data from object files).
 func transformStrip(ctx android.ModuleContext, inputFile android.Path,
 	outputFile android.WritablePath, flags StripFlags) {
@@ -1028,6 +1052,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 c40c5a6..449d38f 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -25,12 +25,12 @@
 	"strings"
 
 	"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"
@@ -41,6 +41,7 @@
 func init() {
 	RegisterCCBuildComponents(android.InitRegistrationContext)
 
+	pctx.Import("android/soong/android")
 	pctx.Import("android/soong/cc/config")
 }
 
@@ -67,13 +68,14 @@
 
 		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.TopDown("lto_deps", ltoDepsMutator)
-		ctx.BottomUp("lto", ltoMutator).Parallel()
+		ctx.Transition("orderfile", &orderfileTransitionMutator{})
+
+		ctx.Transition("lto", &ltoTransitionMutator{})
 
 		ctx.BottomUp("check_linktype", checkLinkTypeMutator).Parallel()
 		ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
@@ -84,7 +86,7 @@
 		ctx.TopDown("sabi_deps", sabiDepsMutator)
 	})
 
-	ctx.RegisterSingletonType("kythe_extract_all", kytheExtractAllFactory)
+	ctx.RegisterParallelSingletonType("kythe_extract_all", kytheExtractAllFactory)
 }
 
 // Deps is a struct containing module names of dependencies, separated by the kind of dependency.
@@ -135,6 +137,8 @@
 
 	// 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
 }
 
 // PathDeps is a struct containing file paths to dependencies of a module.
@@ -151,7 +155,7 @@
 	StaticLibs, LateStaticLibs, WholeStaticLibs android.Paths
 
 	// Transitive static library dependencies of static libraries for use in ordering.
-	TranstiveStaticLibrariesForOrdering *android.DepSet
+	TranstiveStaticLibrariesForOrdering *android.DepSet[android.Path]
 
 	// Paths to .o files
 	Objs Objects
@@ -295,8 +299,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.
@@ -519,12 +523,14 @@
 	inRamdisk() bool
 	inVendorRamdisk() bool
 	inRecovery() bool
+	InVendorOrProduct() bool
 	selectedStl() string
 	baseModuleName() string
 	getVndkExtendsModuleName() string
 	isAfdoCompile() bool
-	isPgoCompile() bool
+	isOrderfileCompile() bool
 	isCfi() bool
+	isFuzzer() bool
 	isNDKStubLibrary() bool
 	useClangLld(actx ModuleContext) bool
 	isForPlatform() bool
@@ -537,6 +543,7 @@
 	isPreventInstall() bool
 	isCfiAssemblySupportEnabled() bool
 	getSharedFlags() *SharedFlags
+	notInPlatform() bool
 }
 
 type SharedFlags struct {
@@ -566,6 +573,24 @@
 	props() []interface{}
 }
 
+// Information returned from Generator about the source code it's generating
+type GeneratedSource struct {
+	IncludeDirs    android.Paths
+	Sources        android.Paths
+	Headers        android.Paths
+	ReexportedDirs android.Paths
+}
+
+// generator allows injection of generated code
+type Generator interface {
+	GeneratorProps() []interface{}
+	GeneratorInit(ctx BaseModuleContext)
+	GeneratorDeps(ctx DepsContext, deps Deps) Deps
+	GeneratorFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags
+	GeneratorSources(ctx ModuleContext) GeneratedSource
+	GeneratorBuildActions(ctx ModuleContext, flags Flags, deps PathDeps)
+}
+
 // compiler is the interface for a compiler helper object. Different module decorators may implement
 // this helper differently.
 type compiler interface {
@@ -592,12 +617,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.
@@ -701,6 +729,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
@@ -800,19 +830,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",
@@ -830,15 +847,12 @@
 type Module struct {
 	fuzz.FuzzModule
 
-	android.BazelModuleBase
-
 	VendorProperties VendorProperties
 	Properties       BaseProperties
 
 	// initialize before calling Init
 	hod        android.HostOrDeviceSupported
 	multilib   android.Multilib
-	bazelable  bool
 	testModule bool
 
 	// Allowable SdkMemberTypes of this module type.
@@ -849,21 +863,21 @@
 	// 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.
-	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
 
@@ -894,6 +908,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{}) {
@@ -1078,6 +1095,24 @@
 	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()))
+}
+
+func (c *Module) RustLibraryInterface() bool {
+	return false
+}
+
 func (c *Module) IsFuzzModule() bool {
 	if _, ok := c.compiler.(*fuzzBinary); ok {
 		return true
@@ -1096,7 +1131,7 @@
 	panic(fmt.Errorf("FuzzPackagedModule called on non-fuzz module: %q", c.BaseModuleName()))
 }
 
-func (c *Module) FuzzSharedLibraries() android.Paths {
+func (c *Module) FuzzSharedLibraries() android.RuleBuilderInstalls {
 	if fuzzer, ok := c.compiler.(*fuzzBinary); ok {
 		return fuzzer.sharedLibraries
 	}
@@ -1191,6 +1226,9 @@
 
 func (c *Module) Init() android.Module {
 	c.AddProperties(&c.Properties, &c.VendorProperties)
+	for _, generator := range c.generators {
+		c.AddProperties(generator.GeneratorProps()...)
+	}
 	if c.compiler != nil {
 		c.AddProperties(c.compiler.compilerProps()...)
 	}
@@ -1224,17 +1262,14 @@
 	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()...)
 	}
 
 	android.InitAndroidArchModule(c, c.hod, c.multilib)
-	if c.bazelable {
-		android.InitBazelModule(c)
-	}
 	android.InitApexModule(c)
 	android.InitDefaultableModule(c)
 
@@ -1249,7 +1284,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 {
@@ -1353,16 +1388,23 @@
 	return false
 }
 
-func (c *Module) isPgoCompile() bool {
-	if pgo := c.pgo; pgo != nil {
-		return pgo.Properties.PgoCompile
+func (c *Module) isOrderfileCompile() bool {
+	if orderfile := c.orderfile; orderfile != nil {
+		return orderfile.Properties.OrderfileLoad
 	}
 	return false
 }
 
 func (c *Module) isCfi() bool {
 	if sanitize := c.sanitize; sanitize != nil {
-		return Bool(sanitize.Properties.Sanitize.Cfi)
+		return Bool(sanitize.Properties.SanitizeMutated.Cfi)
+	}
+	return false
+}
+
+func (c *Module) isFuzzer() bool {
+	if sanitize := c.sanitize; sanitize != nil {
+		return Bool(sanitize.Properties.SanitizeMutated.Fuzzer)
 	}
 	return false
 }
@@ -1483,8 +1525,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
 	}
@@ -1566,9 +1606,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
@@ -1586,6 +1627,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
@@ -1626,6 +1678,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)
 }
@@ -1654,14 +1710,18 @@
 	return ctx.mod.isAfdoCompile()
 }
 
-func (ctx *moduleContextImpl) isPgoCompile() bool {
-	return ctx.mod.isPgoCompile()
+func (ctx *moduleContextImpl) isOrderfileCompile() bool {
+	return ctx.mod.isOrderfileCompile()
 }
 
 func (ctx *moduleContextImpl) isCfi() bool {
 	return ctx.mod.isCfi()
 }
 
+func (ctx *moduleContextImpl) isFuzzer() bool {
+	return ctx.mod.isFuzzer()
+}
+
 func (ctx *moduleContextImpl) isNDKStubLibrary() bool {
 	return ctx.mod.isNDKStubLibrary()
 }
@@ -1694,7 +1754,7 @@
 }
 
 func (ctx *moduleContextImpl) baseModuleName() string {
-	return ctx.mod.ModuleBase.BaseModuleName()
+	return ctx.mod.BaseModuleName()
 }
 
 func (ctx *moduleContextImpl) getVndkExtendsModuleName() string {
@@ -1702,11 +1762,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 {
@@ -1742,6 +1804,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,
@@ -1762,7 +1828,7 @@
 	module.vndkdep = &vndkdep{}
 	module.lto = &lto{}
 	module.afdo = &afdo{}
-	module.pgo = &pgo{}
+	module.orderfile = &orderfile{}
 	return module
 }
 
@@ -1821,8 +1887,7 @@
 			// 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
@@ -1846,7 +1911,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.
@@ -1877,103 +1942,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))
-}
-
-var (
-	mixedBuildSupportedCcTest = []string{
-		"adbd_test",
-		"adb_crypto_test",
-		"adb_pairing_auth_test",
-		"adb_pairing_connection_test",
-		"adb_tls_connection_test",
-	}
-)
-
-// IsMixedBuildSupported returns true if the module should be analyzed by Bazel
-// in any of the --bazel-mode(s). This filters at the module level and takes
-// precedence over the allowlists in allowlists/allowlists.go.
-func (c *Module) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
-	_, isForTesting := ctx.Config().BazelContext.(android.MockBazelContext)
-	if c.testBinary() && !android.InList(c.Name(), mixedBuildSupportedCcTest) && !isForTesting {
-		// Per-module rollout of mixed-builds for cc_test modules.
-		return false
-	}
-
-	// TODO(b/261058727): Remove this (enable mixed builds for modules with UBSan)
-	// Currently we can only support ubsan when minimum runtime is used.
-	return c.bazelHandler != nil && (!isUbsanEnabled(c) || c.MinimalRuntimeNeeded())
-}
-
-func isUbsanEnabled(c *Module) bool {
-	if c.sanitize == nil {
-		return false
-	}
-	sanitizeProps := &c.sanitize.Properties.SanitizeMutated
-	return Bool(sanitizeProps.Integer_overflow) || len(sanitizeProps.Misc_undefined) > 0
-}
-
-func GetApexConfigKey(ctx android.BaseModuleContext) *android.ApexConfigKey {
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
-	if !apexInfo.IsForPlatform() {
-		if !ctx.Config().BazelContext.IsModuleDclaAllowed(ctx.Module().Name()) {
-			return nil
-		}
-		apexKey := android.ApexConfigKey{
-			WithinApex:     true,
-			ApexSdkVersion: findApexSdkVersion(ctx, apexInfo).String(),
-		}
-		return &apexKey
-	}
-
-	return nil
-}
-
-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,
@@ -1985,6 +1953,61 @@
 	return ctx
 }
 
+// TODO (b/277651159): Remove this allowlist
+var (
+	skipStubLibraryMultipleApexViolation = map[string]bool{
+		"libclang_rt.asan":   true,
+		"libclang_rt.hwasan": true,
+		// runtime apex
+		"libc":          true,
+		"libc_hwasan":   true,
+		"libdl_android": true,
+		"libm":          true,
+		"libdl":         true,
+		"libz":          true,
+		// art apex
+		"libandroidio":    true,
+		"libdexfile":      true,
+		"libnativebridge": true,
+		"libnativehelper": true,
+		"libnativeloader": true,
+		"libsigchain":     true,
+	}
+)
+
+// Returns true if a stub library could be installed in multiple apexes
+func (c *Module) stubLibraryMultipleApexViolation(ctx android.ModuleContext) bool {
+	// If this is not an apex variant, no check necessary
+	if !c.InAnyApex() {
+		return false
+	}
+	// If this is not a stub library, no check necessary
+	if !c.HasStubsVariants() {
+		return false
+	}
+	// Skip the allowlist
+	// Use BaseModuleName so that this matches prebuilts.
+	if _, exists := skipStubLibraryMultipleApexViolation[c.BaseModuleName()]; exists {
+		return false
+	}
+
+	_, aaWithoutTestApexes, _ := android.ListSetDifference(c.ApexAvailable(), c.TestApexes())
+	// Stub libraries should not have more than one apex_available
+	if len(aaWithoutTestApexes) > 1 {
+		return true
+	}
+	// Stub libraries should not use the wildcard
+	if aaWithoutTestApexes[0] == android.AvailableToAnyApex {
+		return true
+	}
+	// Default: no violation
+	return false
+}
+
+func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	android.CollectDependencyAconfigFiles(ctx, &d.mergedAconfigFiles)
+}
+
 func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
 	// Handle the case of a test module split by `test_per_src` mutator.
 	//
@@ -1997,7 +2020,7 @@
 	}
 
 	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
 	}
@@ -2011,6 +2034,29 @@
 		return
 	}
 
+	for _, generator := range c.generators {
+		gen := generator.GeneratorSources(ctx)
+		deps.IncludeDirs = append(deps.IncludeDirs, gen.IncludeDirs...)
+		deps.ReexportedDirs = append(deps.ReexportedDirs, gen.ReexportedDirs...)
+		deps.GeneratedDeps = append(deps.GeneratedDeps, gen.Headers...)
+		deps.ReexportedGeneratedHeaders = append(deps.ReexportedGeneratedHeaders, gen.Headers...)
+		deps.ReexportedDeps = append(deps.ReexportedDeps, gen.Headers...)
+		if len(deps.Objs.objFiles) == 0 {
+			// If we are reusuing object files (which happens when we're a shared library and we're
+			// reusing our static variant's object files), then skip adding the actual source files,
+			// because we already have the object for it.
+			deps.GeneratedSources = append(deps.GeneratedSources, gen.Sources...)
+		}
+	}
+
+	if ctx.Failed() {
+		return
+	}
+
+	if c.stubLibraryMultipleApexViolation(actx) {
+		actx.PropertyErrorf("apex_available",
+			"Stub libraries should have a single apex_available (test apexes excluded). Got %v", c.ApexAvailable())
+	}
 	if c.Properties.Clang != nil && *c.Properties.Clang == false {
 		ctx.PropertyErrorf("clang", "false (GCC) is no longer supported")
 	} else if c.Properties.Clang != nil && !ctx.DeviceConfig().BuildBrokenClangProperty() {
@@ -2021,6 +2067,9 @@
 		Toolchain: c.toolchain(ctx),
 		EmitXrefs: ctx.Config().EmitXrefRules(),
 	}
+	for _, generator := range c.generators {
+		flags = generator.GeneratorFlags(ctx, flags, deps)
+	}
 	if c.compiler != nil {
 		flags = c.compiler.compilerFlags(ctx, flags, deps)
 	}
@@ -2045,8 +2094,8 @@
 	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)
 	}
 	for _, feature := range c.features {
 		flags = feature.flags(ctx, flags)
@@ -2078,6 +2127,10 @@
 
 	flags.AssemblerWithCpp = inList("-xassembler-with-cpp", flags.Local.AsFlags)
 
+	for _, generator := range c.generators {
+		generator.GeneratorBuildActions(ctx, flags, deps)
+	}
+
 	var objs Objects
 	if c.compiler != nil {
 		objs = c.compiler.compile(ctx, flags, deps)
@@ -2107,11 +2160,46 @@
 		}
 	}
 	if c.testModule {
-		ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+		android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 	}
-	ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: deps.GeneratedSources.Strings()})
+	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() {
@@ -2123,16 +2211,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
@@ -2155,12 +2242,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)
@@ -2169,6 +2250,9 @@
 }
 
 func (c *Module) begin(ctx BaseModuleContext) {
+	for _, generator := range c.generators {
+		generator.GeneratorInit(ctx)
+	}
 	if c.compiler != nil {
 		c.compiler.compilerInit(ctx)
 	}
@@ -2184,11 +2268,14 @@
 	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.pgo != nil {
-		c.pgo.begin(ctx)
+	if c.orderfile != nil {
+		c.orderfile.begin(ctx)
 	}
 	if ctx.useSdk() && c.IsSdkVariant() {
 		version, err := nativeApiLevelFromUser(ctx, ctx.sdkVersion())
@@ -2204,6 +2291,9 @@
 func (c *Module) deps(ctx DepsContext) Deps {
 	deps := Deps{}
 
+	for _, generator := range c.generators {
+		deps = generator.GeneratorDeps(ctx, deps)
+	}
 	if c.compiler != nil {
 		deps = c.compiler.compilerDeps(ctx, deps)
 	}
@@ -2340,9 +2430,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)
 			}
 		}
 	}
@@ -2357,16 +2447,16 @@
 		// 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() {
+		if c.InVendor() && c.VndkVersion() == actx.DeviceConfig().VndkVersion() && actx.OtherModuleExists("vendor_snapshot") {
 			snapshotModule = actx.AddVariationDependencies(nil, nil, "vendor_snapshot")
-		} else if recoverySnapshotVersion := actx.DeviceConfig().RecoverySnapshotVersion(); recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" && c.InRecovery() {
+		} else if recoverySnapshotVersion := actx.DeviceConfig().RecoverySnapshotVersion(); recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" && c.InRecovery() && actx.OtherModuleExists("recovery_snapshot") {
 			snapshotModule = actx.AddVariationDependencies(nil, nil, "recovery_snapshot")
 		}
 		if len(snapshotModule) > 0 && snapshotModule[0] != nil {
-			snapshot := actx.OtherModuleProvider(snapshotModule[0], SnapshotInfoProvider).(SnapshotInfo)
+			snapshot, _ := android.OtherModuleProvider(actx, snapshotModule[0], SnapshotInfoProvider)
 			*snapshotInfo = &snapshot
 			// republish the snapshot for use in later mutators on this module
-			actx.SetProvider(SnapshotInfoProvider, snapshot)
+			android.SetProvider(actx, SnapshotInfoProvider, snapshot)
 		}
 	}
 	if *snapshotInfo == nil {
@@ -2586,6 +2676,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) {
@@ -2812,20 +2905,20 @@
 			ctx.ModuleErrorf("links %q built against newer API version %q",
 				ctx.OtherModuleName(to.Module()), "current")
 		} else {
-			fromApi, err := strconv.Atoi(from.SdkVersion())
+			fromApi, err := android.ApiLevelFromUserWithConfig(ctx.Config(), from.SdkVersion())
 			if err != nil {
 				ctx.PropertyErrorf("sdk_version",
-					"Invalid sdk_version value (must be int or current): %q",
+					"Invalid sdk_version value (must be int, preview or current): %q",
 					from.SdkVersion())
 			}
-			toApi, err := strconv.Atoi(to.SdkVersion())
+			toApi, err := android.ApiLevelFromUserWithConfig(ctx.Config(), to.SdkVersion())
 			if err != nil {
 				ctx.PropertyErrorf("sdk_version",
-					"Invalid sdk_version value (must be int or current): %q",
+					"Invalid sdk_version value (must be int, preview or current): %q",
 					to.SdkVersion())
 			}
 
-			if toApi > fromApi {
+			if toApi.GreaterThan(fromApi) {
 				ctx.ModuleErrorf("links %q built against newer API version %q",
 					ctx.OtherModuleName(to.Module()), to.SdkVersion())
 			}
@@ -2951,7 +3044,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{}
@@ -2961,7 +3054,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
 		}
 	})
@@ -3012,12 +3105,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,
 				)
 			}
 		}
@@ -3082,10 +3173,10 @@
 			// 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
@@ -3102,8 +3193,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
@@ -3112,7 +3206,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 {
@@ -3121,7 +3215,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 {
@@ -3158,7 +3252,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 {
@@ -3173,7 +3268,6 @@
 					break
 				}
 
-				staticLibraryInfo := ctx.OtherModuleProvider(dep, StaticLibraryInfoProvider).(StaticLibraryInfo)
 				linkFile = android.OptionalPathForPath(staticLibraryInfo.StaticLibrary)
 				if libDepTag.wholeStatic {
 					ptr = &depPaths.WholeStaticLibs
@@ -3283,7 +3377,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)
@@ -3359,20 +3453,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
@@ -3402,7 +3496,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
@@ -3448,9 +3542,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.
@@ -3468,8 +3562,8 @@
 // to match the topological order of the dependency tree, including any static analogues of
 // direct shared libraries.  It returns the ordered static dependencies, and an android.DepSet
 // of the transitive dependencies.
-func orderStaticModuleDeps(staticDeps []StaticLibraryInfo, sharedDeps []SharedLibraryInfo) (ordered android.Paths, transitive *android.DepSet) {
-	transitiveStaticLibsBuilder := android.NewDepSetBuilder(android.TOPOLOGICAL)
+func orderStaticModuleDeps(staticDeps []StaticLibraryInfo, sharedDeps []SharedLibraryInfo) (ordered android.Paths, transitive *android.DepSet[android.Path]) {
+	transitiveStaticLibsBuilder := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL)
 	var staticPaths android.Paths
 	for _, staticDep := range staticDeps {
 		staticPaths = append(staticPaths, staticDep.StaticLibrary)
@@ -3524,7 +3618,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()
@@ -3601,6 +3695,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)
 	}
@@ -3696,7 +3795,7 @@
 }
 
 func GetMakeLinkType(actx android.ModuleContext, c LinkableInterface) string {
-	if c.UseVndk() {
+	if c.InVendorOrProduct() {
 		if c.IsLlndk() {
 			if !c.IsLlndkPublic() {
 				return "native:vndk_private"
@@ -3940,6 +4039,7 @@
 	headerLibrary
 	testBin // testBinary already declared
 	ndkLibrary
+	ndkPrebuiltStl
 )
 
 func (c *Module) typ() moduleType {
@@ -3956,8 +4056,8 @@
 		// TODO(b/244431896) properly convert cc_test_library to its own macro. This
 		// will let them add implicit compile deps on gtest, for example.
 		//
-		// For now, treat them as regular shared libraries.
-		return sharedLibrary
+		// For now, treat them as regular libraries.
+		return fullLibrary
 	} else if c.CcLibrary() {
 		static := false
 		shared := false
@@ -3978,78 +4078,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)
-		}
-	}
-}
-
-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)
-	case ndkLibrary:
-		ndkLibraryBp2build(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
@@ -4091,7 +4133,7 @@
 		&VndkProperties{},
 		&LTOProperties{},
 		&AfdoProperties{},
-		&PgoProperties{},
+		&OrderfileProperties{},
 		&android.ProtoProperties{},
 		// RustBindgenProperties is included here so that cc_defaults can be used for rust_bindgen modules.
 		&RustBindgenClangProperties{},
@@ -4141,6 +4183,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 d6b969a..6cc500b 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -26,7 +26,8 @@
 
 	"android/soong/aidl_library"
 	"android/soong/android"
-	"android/soong/bazel/cquery"
+
+	"github.com/google/blueprint"
 )
 
 func init() {
@@ -40,33 +41,30 @@
 var prepareForCcTest = android.GroupFixturePreparers(
 	PrepareForTestWithCcIncludeVndk,
 	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+		variables.VendorApiLevel = StringPtr("202404")
 		variables.DeviceVndkVersion = StringPtr("current")
-		variables.ProductVndkVersion = StringPtr("current")
+		variables.KeepVndk = BoolPtr(true)
 		variables.Platform_vndk_version = StringPtr("29")
 	}),
 )
 
-var ccLibInApex = "cc_lib_in_apex"
+// TODO(b/316829758) Update prepareForCcTest with this configuration and remove prepareForCcTestWithoutVndk
+var prepareForCcTestWithoutVndk = android.GroupFixturePreparers(
+	PrepareForIntegrationTestWithCc,
+	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+		variables.VendorApiLevel = StringPtr("202404")
+	}),
+)
+
 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) {
-				mixedBuildMod.QueueBazelCall(ctx)
-			}
-		}
-	}
-}
-
 func testApexMutator(mctx android.BottomUpMutatorContext) {
 	modules := mctx.CreateVariations(apexVariationName)
 	apexInfo := android.ApexInfo{
@@ -104,33 +102,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.
@@ -167,7 +138,6 @@
 	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
@@ -235,13 +205,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()
@@ -370,9 +340,9 @@
 	}
 }
 
-func checkWriteFileOutput(t *testing.T, params android.TestingBuildParams, expected []string) {
+func checkWriteFileOutput(t *testing.T, ctx *android.TestContext, 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)
 }
@@ -380,7 +350,7 @@
 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)
+	checkWriteFileOutput(t, ctx, vndkSnapshot.Output(output), expected)
 }
 
 func checkVndkLibrariesOutput(t *testing.T, ctx *android.TestContext, module string, expected []string) {
@@ -523,7 +493,6 @@
 
 	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)
@@ -654,6 +623,7 @@
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
+	config.TestProductVariables.KeepVndk = BoolPtr(true)
 	ctx := testCcWithConfig(t, config)
 
 	module := ctx.ModuleForTests("llndk.libraries.txt", "android_common")
@@ -706,6 +676,7 @@
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
+	config.TestProductVariables.KeepVndk = BoolPtr(true)
 
 	setVndkMustUseVendorVariantListForTest(config, []string{"libvndk"})
 
@@ -748,7 +719,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
 	}
 
@@ -805,7 +776,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,63 +859,6 @@
 	}
 }
 
-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.
@@ -1110,6 +1024,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1131,6 +1046,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1152,6 +1068,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1174,6 +1091,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1389,6 +1307,7 @@
 		cc_library {
 			name: "libanothervndksp",
 			vendor_available: true,
+			product_available: true,
 		}
 	`)
 }
@@ -1466,7 +1385,6 @@
 	`
 	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)
@@ -1481,70 +1399,6 @@
 	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.
@@ -1919,7 +1773,6 @@
 	`
 	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)
@@ -2277,11 +2130,13 @@
 	ensureStringContains(t, vendor_cflags, "-D__ANDROID_VNDK__")
 	ensureStringContains(t, vendor_cflags, "-D__ANDROID_VENDOR__")
 	ensureStringNotContains(t, vendor_cflags, "-D__ANDROID_PRODUCT__")
+	ensureStringContains(t, vendor_cflags, "-D__ANDROID_VENDOR_API__=202404")
 
 	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__")
+	ensureStringNotContains(t, product_cflags, "-D__ANDROID_VENDOR_API__=202404")
 }
 
 func TestEnforceProductVndkVersionErrors(t *testing.T) {
@@ -2700,8 +2555,8 @@
 
 	variant := "android_arm64_armv8-a_static"
 	moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
-	actual := 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 +2591,8 @@
 
 	variant := "android_arm64_armv8-a_static"
 	moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
-	actual := 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,6 +2651,7 @@
 		name: "libexternal_headers",
 		export_include_dirs: ["include"],
 		vendor_available: true,
+		product_available: true,
 	}
 	cc_library_headers {
 		name: "libexternal_llndk_headers",
@@ -2837,7 +2693,7 @@
 	checkExportedIncludeDirs := func(module, variant 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)
 	}
@@ -3033,24 +2889,6 @@
 	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,253 +2928,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,
-		}
-		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": 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
@@ -3491,7 +3082,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()
@@ -3574,9 +3165,6 @@
 }
 
 func TestStubsForLibraryInMultipleApexes(t *testing.T) {
-	// TODO(b/275313114): Test exposes non-determinism which should be corrected and the test
-	// reenabled.
-	t.Skip()
 	t.Parallel()
 	ctx := testCc(t, `
 		cc_library_shared {
@@ -3681,133 +3269,6 @@
 	}
 }
 
-func TestMixedBuildUsesStubs(t *testing.T) {
-	// TODO(b/275313114): Test exposes non-determinism which should be corrected and the test
-	// reenabled.
-	t.Skip()
-	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 }{
@@ -4181,9 +3642,6 @@
 			shared: {
 				srcs: ["baz.c"],
 			},
-			bazel_module: {
-				bp2build_available: true,
-			},
 		}
 
 		cc_library_static {
@@ -4467,7 +3925,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"
@@ -4502,7 +3960,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) {
@@ -4553,7 +4011,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) {
@@ -4667,7 +4125,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,8 +4440,8 @@
 	cppOnly := []string{"-fPIC", "${config.CommonGlobalCppflags}", "${config.DeviceGlobalCppflags}", "${config.ArmCppflags}"}
 
 	cflags := []string{"-Werror", "-std=candcpp"}
-	cstd := []string{"-std=gnu11", "-std=conly"}
-	cppstd := []string{"-std=gnu++17", "-std=cpp", "-fno-rtti"}
+	cstd := []string{"-std=gnu17", "-std=conly"}
+	cppstd := []string{"-std=gnu++20", "-std=cpp", "-fno-rtti"}
 
 	lastIncludes := []string{
 		"out/soong/ndk/sysroot/usr/include",
@@ -5313,55 +4771,116 @@
 	}
 }
 
-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",
+		cc_library {
+			name: "test_lib",
+			srcs: ["test_lib.cpp"],
+			dist: {
+				targets: [ "dist_target" ],
+				tag: "stripped_all",
+			}
+		}
+ `
+	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("Expected cc_library to produce output files, error: %s", err)
+		return
+	}
+	if !strings.HasSuffix(outputFile.Strings()[0], "/stripped_all/test_lib.so") {
+		t.Errorf("Unexpected output file: %s", outputFile.Strings()[0])
+		return
+	}
+}
+
+// TODO(b/316829758) Remove this test and do not set VNDK version from other tests
+func TestImageVariantsWithoutVndk(t *testing.T) {
+	t.Parallel()
+
+	bp := `
+	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 := prepareForCcTestWithoutVndk.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
 	}
 
-	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),
+	testDepWithVariant := func(imageVariant string) {
+		imageVariantStr := ""
+		if imageVariant != "core" {
+			imageVariantStr = "_" + imageVariant
+		}
+		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 TestVendorSdkVersionWithoutVndk(t *testing.T) {
+	t.Parallel()
+
+	bp := `
+		cc_library {
+			name: "libfoo",
+			srcs: ["libfoo.cc"],
+			vendor_available: true,
+		}
+
+		cc_library {
+			name: "libbar",
+			srcs: ["libbar.cc"],
+			vendor_available: true,
+			min_sdk_version: "29",
+		}
+	`
+
+	ctx := prepareForCcTestWithoutVndk.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)
+	}
+
+	testSdkVersionFlag("libfoo", "10000")
+	testSdkVersionFlag("libbar", "29")
+
+	ctx = android.GroupFixturePreparers(
+		prepareForCcTestWithoutVndk,
+		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)
-	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("")
-	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())
+	testSdkVersionFlag("libfoo", "30")
+	testSdkVersionFlag("libbar", "29")
 }
diff --git a/cc/ccdeps.go b/cc/ccdeps.go
index 75e1faf..d30abba 100644
--- a/cc/ccdeps.go
+++ b/cc/ccdeps.go
@@ -30,7 +30,7 @@
 // The info file is generated in $OUT/module_bp_cc_depend.json.
 
 func init() {
-	android.RegisterSingletonType("ccdeps_generator", ccDepsGeneratorSingleton)
+	android.RegisterParallelSingletonType("ccdeps_generator", ccDepsGeneratorSingleton)
 }
 
 func ccDepsGeneratorSingleton() android.Singleton {
diff --git a/cc/cmakelists.go b/cc/cmakelists.go
index ad130ba..0f3f02d 100644
--- a/cc/cmakelists.go
+++ b/cc/cmakelists.go
@@ -29,7 +29,7 @@
 // structure (see variable CLionOutputProjectsDirectory for root).
 
 func init() {
-	android.RegisterSingletonType("cmakelists_generator", cMakeListsGeneratorSingleton)
+	android.RegisterParallelSingletonType("cmakelists_generator", cMakeListsGeneratorSingleton)
 }
 
 func cMakeListsGeneratorSingleton() android.Singleton {
diff --git a/cc/compdb.go b/cc/compdb.go
index ea12443..617be1a 100644
--- a/cc/compdb.go
+++ b/cc/compdb.go
@@ -32,7 +32,7 @@
 // make SOONG_GEN_COMPDB=1 nothing to get all targets.
 
 func init() {
-	android.RegisterSingletonType("compdb_generator", compDBGeneratorSingleton)
+	android.RegisterParallelSingletonType("compdb_generator", compDBGeneratorSingleton)
 }
 
 func compDBGeneratorSingleton() android.Singleton {
diff --git a/cc/compiler.go b/cc/compiler.go
index 16f4a6e..c57b72c 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -189,13 +189,13 @@
 			// build the recovery variant of the C/C++ module.
 			Exclude_generated_sources []string
 		}
-		Vendor_ramdisk struct {
+		Ramdisk, Vendor_ramdisk struct {
 			// list of source files that should not be used to
-			// build the vendor ramdisk variant of the C/C++ module.
+			// build the ramdisk variants of the C/C++ module.
 			Exclude_srcs []string `android:"path"`
 
-			// List of additional cflags that should be used to build the vendor ramdisk
-			// variant of the C/C++ module.
+			// List of additional cflags that should be used to build the ramdisk
+			// variants of the C/C++ module.
 			Cflags []string
 		}
 		Platform struct {
@@ -339,7 +339,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...)
@@ -351,6 +351,7 @@
 	CheckBadCompilerFlags(ctx, "vendor.cflags", compiler.Properties.Target.Vendor.Cflags)
 	CheckBadCompilerFlags(ctx, "product.cflags", compiler.Properties.Target.Product.Cflags)
 	CheckBadCompilerFlags(ctx, "recovery.cflags", compiler.Properties.Target.Recovery.Cflags)
+	CheckBadCompilerFlags(ctx, "ramdisk.cflags", compiler.Properties.Target.Ramdisk.Cflags)
 	CheckBadCompilerFlags(ctx, "vendor_ramdisk.cflags", compiler.Properties.Target.Vendor_ramdisk.Cflags)
 	CheckBadCompilerFlags(ctx, "platform.cflags", compiler.Properties.Target.Platform.Cflags)
 
@@ -384,7 +385,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())
@@ -401,10 +402,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__")
 		}
@@ -469,7 +479,7 @@
 			target += strconv.Itoa(android.FutureApiLevelInt)
 		} else {
 			apiLevel := nativeApiLevelOrPanic(ctx, version)
-			target += apiLevel.String()
+			target += strconv.Itoa(apiLevel.FinalOrFutureInt())
 		}
 	}
 
@@ -536,6 +546,9 @@
 	if ctx.inVendorRamdisk() {
 		flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Vendor_ramdisk.Cflags)...)
 	}
+	if ctx.inRamdisk() {
+		flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Ramdisk.Cflags)...)
+	}
 	if !ctx.useSdk() {
 		flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Platform.Cflags)...)
 	}
@@ -707,7 +720,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 ca2e05f..82beb29 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -100,7 +100,15 @@
 		return strings.Join(flags, " ")
 	})
 
-	exportedVars.ExportStringListStaticVariable("Arm64Cflags", arm64Cflags)
+	exportedVars.ExportStringList("Arm64Cflags", arm64Cflags)
+	pctx.VariableFunc("Arm64Cflags", func(ctx android.PackageVarContext) string {
+		flags := arm64Cflags
+		if ctx.Config().NoBionicPageSizeMacro() {
+			flags = append(flags, "-D__BIONIC_NO_PAGE_SIZE_MACRO")
+		}
+		return strings.Join(flags, " ")
+	})
+
 	exportedVars.ExportStringListStaticVariable("Arm64Cppflags", arm64Cppflags)
 
 	exportedVars.ExportVariableReferenceDict("Arm64ArchVariantCflags", arm64ArchVariantCflagsVar)
diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go
index 9f5124b..335ad56 100644
--- a/cc/config/arm64_linux_host.go
+++ b/cc/config/arm64_linux_host.go
@@ -46,6 +46,10 @@
 		"-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
@@ -60,6 +64,7 @@
 func init() {
 	exportedVars.ExportStringListStaticVariable("LinuxBionicArm64Cflags", linuxCrossCflags)
 	exportedVars.ExportStringListStaticVariable("LinuxBionicArm64Ldflags", linuxCrossLdflags)
+	exportedVars.ExportStringListStaticVariable("LinuxBionicArm64Lldflags", 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 dec2b45..603bc6d 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -28,13 +28,20 @@
 
 	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
@@ -43,9 +50,7 @@
 
 	armNoFixCortexA8LdFlags = []string{"-Wl,--no-fix-cortex-a8"}
 
-	armArmCflags = []string{
-		"-fstrict-aliasing",
-	}
+	armArmCflags = []string{}
 
 	armThumbCflags = []string{
 		"-mthumb",
@@ -185,12 +190,7 @@
 	exportedVars.ExportString("ArmClangTriple", clangTriple)
 
 	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("ArmLldflags", armLldflags)
 
 	exportedVars.ExportStringListStaticVariable("ArmFixCortexA8LdFlags", armFixCortexA8LdFlags)
 	exportedVars.ExportStringListStaticVariable("ArmNoFixCortexA8LdFlags", armNoFixCortexA8LdFlags)
diff --git a/cc/config/arm_linux_host.go b/cc/config/arm_linux_host.go
index 525fb5d..e21c60d 100644
--- a/cc/config/arm_linux_host.go
+++ b/cc/config/arm_linux_host.go
@@ -27,16 +27,24 @@
 		"-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("LinuxArmLldflags", linuxArmLldflags)
 	exportedVars.ExportStringListStaticVariable("LinuxArm64Ldflags", linuxArm64Ldflags)
-	exportedVars.ExportStringListStaticVariable("LinuxArm64Lldflags", linuxArm64Ldflags)
+	exportedVars.ExportStringListStaticVariable("LinuxArm64Lldflags", linuxArm64Lldflags)
 
 	exportedVars.ExportStringListStaticVariable("LinuxArmYasmFlags", []string{"-f elf32 -m arm"})
 	exportedVars.ExportStringListStaticVariable("LinuxArm64YasmFlags", []string{"-f elf64 -m aarch64"})
diff --git a/cc/config/darwin_host.go b/cc/config/darwin_host.go
index 2cabdc8..b789590 100644
--- a/cc/config/darwin_host.go
+++ b/cc/config/darwin_host.go
@@ -79,7 +79,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 a0fe4b7..5fed7f1 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -16,6 +16,7 @@
 
 import (
 	"runtime"
+	"slices"
 	"strings"
 
 	"android/soong/android"
@@ -29,88 +30,121 @@
 	// 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",
-		"-g",
-		"-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",
 	}
 
 	commonGlobalConlyflags = []string{}
@@ -122,6 +156,7 @@
 		"-fdebug-default-version=4",
 	}
 
+	// Compilation flags for device code; not applied to host code.
 	deviceGlobalCflags = []string{
 		"-ffunction-sections",
 		"-fdata-sections",
@@ -147,12 +182,14 @@
 	commonGlobalLldflags = []string{
 		"-fuse-ld=lld",
 		"-Wl,--icf=safe",
+		"-Wl,--no-demangle",
 	}
 
 	deviceGlobalCppflags = []string{
 		"-fvisibility-inlines-hidden",
 	}
 
+	// Linking flags for device code; not applied to host binaries.
 	deviceGlobalLdflags = []string{
 		"-Wl,-z,noexecstack",
 		"-Wl,-z,relro",
@@ -168,7 +205,9 @@
 		"-Wl,--exclude-libs,libunwind.a",
 	}
 
-	deviceGlobalLldflags = append(deviceGlobalLdflags, commonGlobalLldflags...)
+	deviceGlobalLldflags = append(append(deviceGlobalLdflags, commonGlobalLldflags...),
+		"-Wl,--compress-debug-sections=zstd",
+	)
 
 	hostGlobalCflags = []string{}
 
@@ -179,8 +218,6 @@
 	hostGlobalLldflags = commonGlobalLldflags
 
 	commonGlobalCppflags = []string{
-		"-Wsign-promo",
-
 		// -Wimplicit-fallthrough is not enabled by -Wall.
 		"-Wimplicit-fallthrough",
 
@@ -191,6 +228,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",
@@ -208,6 +255,7 @@
 		"-Werror=fortify-source",
 
 		"-Werror=address-of-temporary",
+		"-Werror=incompatible-function-pointer-types",
 		"-Werror=null-dereference",
 		"-Werror=return-type",
 
@@ -215,8 +263,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.
@@ -226,7 +272,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
@@ -240,26 +287,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",
@@ -287,25 +328,54 @@
 
 		// 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-but-set-variable",
+		"-Wno-unused-but-set-parameter",
+		"-Wno-unqualified-std-cast-call",
+		"-Wno-array-parameter",
+		"-Wno-gnu-offsetof-extensions",
 	}
 
 	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               = "gnu11"
-	CppStdVersion             = "gnu++17"
-	ExperimentalCStdVersion   = "gnu17"
-	ExperimentalCppStdVersion = "gnu++2a"
+	CStdVersion               = "gnu17"
+	CppStdVersion             = "gnu++20"
+	ExperimentalCStdVersion   = "gnu2x"
+	ExperimentalCppStdVersion = "gnu++2b"
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r487747c"
+	ClangDefaultVersion      = "clang-r498229b"
 	ClangDefaultShortVersion = "17"
 
 	// Directories with warnings from Android.bp files.
@@ -320,12 +390,6 @@
 	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)
 }
@@ -348,20 +412,20 @@
 	exportedVars.ExportStringList("CommonGlobalCflags", commonGlobalCflags)
 
 	pctx.VariableFunc("CommonGlobalCflags", func(ctx android.PackageVarContext) string {
-		flags := commonGlobalCflags
+		flags := slices.Clone(commonGlobalCflags)
 
 		// http://b/131390872
 		// Automatically initialize any uninitialized stack variables.
 		// Prefer zero-init if multiple options are set.
 		if ctx.Config().IsEnvTrue("AUTO_ZERO_INITIALIZE") {
-			flags = append(flags, "-ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang -Wno-unused-command-line-argument")
+			flags = append(flags, "-ftrivial-auto-var-init=zero")
 		} else if ctx.Config().IsEnvTrue("AUTO_PATTERN_INITIALIZE") {
 			flags = append(flags, "-ftrivial-auto-var-init=pattern")
 		} else if ctx.Config().IsEnvTrue("AUTO_UNINITIALIZE") {
 			flags = append(flags, "-ftrivial-auto-var-init=uninitialized")
 		} else {
 			// Default to zero initialization.
-			flags = append(flags, "-ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang -Wno-unused-command-line-argument")
+			flags = append(flags, "-ftrivial-auto-var-init=zero")
 		}
 
 		// Workaround for ccache with clang.
@@ -374,6 +438,21 @@
 			flags = append(flags, "-Wno-error=unknown-warning-option")
 		}
 
+		switch ctx.Config().Getenv("CLANG_DEFAULT_DEBUG_LEVEL") {
+		case "debug_level_0":
+			flags = append(flags, "-g0")
+		case "debug_level_1":
+			flags = append(flags, "-g1")
+		case "debug_level_2":
+			flags = append(flags, "-g2")
+		case "debug_level_3":
+			flags = append(flags, "-g3")
+		case "debug_level_g":
+			flags = append(flags, "-g")
+		default:
+			flags = append(flags, "-g")
+		}
+
 		return strings.Join(flags, " ")
 	})
 
@@ -391,6 +470,7 @@
 		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, " ")
 	})
@@ -427,14 +507,19 @@
 	exportedVars.ExportStringList("CommonGlobalIncludes", commonGlobalIncludes)
 	pctx.PrefixedExistentPathsForSourcesVariable("CommonGlobalIncludes", "-I", commonGlobalIncludes)
 
+	exportedVars.ExportStringStaticVariable("CLANG_DEFAULT_VERSION", ClangDefaultVersion)
+	exportedVars.ExportStringStaticVariable("CLANG_DEFAULT_SHORT_VERSION", ClangDefaultShortVersion)
+
 	pctx.StaticVariableWithEnvOverride("ClangBase", "LLVM_PREBUILTS_BASE", ClangDefaultBase)
-	exportedVars.ExportStringStaticVariableWithEnvOverride("ClangVersion", "LLVM_PREBUILTS_VERSION", ClangDefaultVersion)
+	pctx.StaticVariableWithEnvOverride("ClangVersion", "LLVM_PREBUILTS_VERSION", ClangDefaultVersion)
 	pctx.StaticVariable("ClangPath", "${ClangBase}/${HostPrebuiltTag}/${ClangVersion}")
 	pctx.StaticVariable("ClangBin", "${ClangPath}/bin")
 
-	exportedVars.ExportStringStaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion)
+	pctx.StaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion)
 	pctx.StaticVariable("ClangAsanLibDir", "${ClangBase}/linux-x86/${ClangVersion}/lib/clang/${ClangShortVersion}/lib/linux")
 
+	exportedVars.ExportStringListStaticVariable("WarningAllowedProjects", 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.
 	pctx.SourcePathVariable("RSClangBase", "prebuilts/clang/host")
@@ -443,11 +528,12 @@
 	pctx.StaticVariable("RSLLVMPrebuiltsPath", "${RSClangBase}/${HostPrebuiltTag}/${RSClangVersion}/bin")
 	pctx.StaticVariable("RSIncludePath", "${RSLLVMPrebuiltsPath}/../lib64/clang/${RSReleaseVersion}/include")
 
-	pctx.PrefixedExistentPathsForSourcesVariable("RsGlobalIncludes", "-I",
-		[]string{
-			"external/clang/lib/Headers",
-			"frameworks/rs/script_api/include",
-		})
+	rsGlobalIncludes := []string{
+		"external/clang/lib/Headers",
+		"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 != "" {
diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go
index a63d5c2..deb922b 100644
--- a/cc/config/riscv64_device.go
+++ b/cc/config/riscv64_device.go
@@ -25,21 +25,31 @@
 	riscv64Cflags = []string{
 		// Help catch common 32/64-bit errors.
 		"-Werror=implicit-function-declaration",
-		"-fno-emulated-tls",
-		// A temporary fix for SExtWRemoval miscompilation bug.
-		"-mllvm",
-		"-riscv-disable-sextw-removal=true",
+		"-march=rv64gcv_zba_zbb_zbs",
+		// Equivalent to "-munaligned-access", but our clang doesn't have that yet.
+		"-Xclang -target-feature -Xclang +unaligned-scalar-mem",
+		"-Xclang -target-feature -Xclang +unaligned-vector-mem",
+		// Until https://gitlab.com/qemu-project/qemu/-/issues/1976 is fixed...
+		"-mno-implicit-float",
+		// (https://github.com/google/android-riscv64/issues/124)
+		"-mllvm -jump-is-expensive=false",
 	}
 
 	riscv64ArchVariantCflags = map[string][]string{}
 
 	riscv64Ldflags = []string{
 		"-Wl,--hash-style=gnu",
+		"-march=rv64gcv_zba_zbb_zbs",
+		// Equivalent to "-munaligned-access", but our clang doesn't have that yet.
+		"-Xclang -target-feature -Xclang +unaligned-scalar-mem",
+		"-Xclang -target-feature -Xclang +unaligned-vector-mem",
+		// We should change the default for this in clang, but for now...
+		// (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{}
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index d55a13d..b40557a 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -16,7 +16,6 @@
 
 import (
 	"android/soong/android"
-	"regexp"
 	"strings"
 )
 
@@ -42,6 +41,8 @@
 		"-bugprone-unchecked-optional-access",
 		// http://b/265438407
 		"-misc-use-anonymous-namespace",
+		// http://b/285005947
+		"-performance-avoid-endl",
 	}
 
 	// Some clang-tidy checks are included in some tidy_checks_as_errors lists,
@@ -56,6 +57,14 @@
 		"-bugprone-signed-char-misuse",
 		// http://b/241819232
 		"-misc-const-correctness",
+		// http://b/285356805
+		"-bugprone-unsafe-functions",
+		"-cert-msc24-c",
+		"-cert-msc33-c",
+		// http://b/285356799
+		"-modernize-type-traits",
+		// http://b/285361108
+		"-readability-avoid-unconditional-preprocessor-if",
 	}
 
 	extraArgFlags = []string{
@@ -271,11 +280,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 6a10e14..62f75d1 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -20,6 +20,12 @@
 	"android/soong/android"
 )
 
+func init() {
+	exportedVars.ExportStringListStaticVariable("DarwinAvailableLibraries", darwinAvailableLibraries)
+	exportedVars.ExportStringListStaticVariable("LinuxAvailableLibraries", linuxAvailableLibraries)
+	exportedVars.ExportStringListStaticVariable("WindowsAvailableLibraries", windowsAvailableLibraries)
+}
+
 type toolchainFactory func(arch android.Arch) Toolchain
 
 var toolchainFactories = make(map[android.OsType]map[android.ArchType]toolchainFactory)
@@ -255,5 +261,3 @@
 func LibFuzzerRuntimeInterceptors(t Toolchain) string {
 	return LibclangRuntimeLibrary(t, "fuzzer_interceptors")
 }
-
-var inList = android.InList
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index 9f093bb..b97d511 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -33,6 +33,8 @@
 		"-Wl,--hash-style=gnu",
 	}
 
+	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",
 		},
@@ -94,10 +101,23 @@
 	exportedVars.ExportStringListStaticVariable("X86_64ToolchainLdflags", []string{"-m64"})
 
 	exportedVars.ExportStringListStaticVariable("X86_64Ldflags", x86_64Ldflags)
-	exportedVars.ExportStringListStaticVariable("X86_64Lldflags", x86_64Ldflags)
+	exportedVars.ExportStringList("X86_64Lldflags", X86_64Lldflags)
+	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, " ")
+	})
 
 	// Clang cflags
-	exportedVars.ExportStringListStaticVariable("X86_64Cflags", x86_64Cflags)
+	exportedVars.ExportStringList("X86_64Cflags", x86_64Cflags)
+	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")
+		}
+		return strings.Join(flags, " ")
+	})
+
 	exportedVars.ExportStringListStaticVariable("X86_64Cppflags", x86_64Cppflags)
 
 	// Yasm flags
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index c826d3c..2faa670 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -56,6 +56,11 @@
 		"goldmont-plus": []string{
 			"-march=goldmont-plus",
 		},
+		"goldmont-without-sha-xsaves": []string{
+			"-march=goldmont",
+			"-mno-sha",
+			"-mno-xsaves",
+		},
 		"haswell": []string{
 			"-march=core-avx2",
 		},
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index e006471..f80be99 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -53,6 +53,10 @@
 		"--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
@@ -71,7 +75,7 @@
 func init() {
 	exportedVars.ExportStringListStaticVariable("LinuxBionicCflags", linuxBionicCflags)
 	exportedVars.ExportStringListStaticVariable("LinuxBionicLdflags", linuxBionicLdflags)
-	exportedVars.ExportStringListStaticVariable("LinuxBionicLldflags", linuxBionicLdflags)
+	exportedVars.ExportStringListStaticVariable("LinuxBionicLldflags", linuxBionicLldflags)
 
 	// Use the device gcc toolchain for now
 	exportedVars.ExportStringStaticVariable("LinuxBionicGccVersion", x86_64GccVersion)
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index 93aa82e..f95da0b 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -59,6 +59,10 @@
 		"--gcc-toolchain=${LinuxGccRoot}",
 	}
 
+	linuxLldflags = append(linuxLdflags,
+		"-Wl,--compress-debug-sections=zstd",
+	)
+
 	linuxGlibcLdflags = []string{
 		"--sysroot ${LinuxGccRoot}/sysroot",
 	}
@@ -138,7 +142,7 @@
 
 	exportedVars.ExportStringListStaticVariable("LinuxCflags", linuxCflags)
 	exportedVars.ExportStringListStaticVariable("LinuxLdflags", linuxLdflags)
-	exportedVars.ExportStringListStaticVariable("LinuxLldflags", linuxLdflags)
+	exportedVars.ExportStringListStaticVariable("LinuxLldflags", linuxLldflags)
 	exportedVars.ExportStringListStaticVariable("LinuxGlibcCflags", linuxGlibcCflags)
 	exportedVars.ExportStringListStaticVariable("LinuxGlibcLdflags", linuxGlibcLdflags)
 	exportedVars.ExportStringListStaticVariable("LinuxGlibcLldflags", linuxGlibcLdflags)
diff --git a/cc/coverage.go b/cc/coverage.go
index c0f6973..43f5e07 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 {
@@ -48,6 +71,7 @@
 func getGcovProfileLibraryName(ctx ModuleContextIntf) string {
 	// This function should only ever be called for a cc.Module, so the
 	// following statement should always succeed.
+	// LINT.IfChange
 	if ctx.useSdk() {
 		return "libprofile-extras_ndk"
 	} else {
@@ -63,6 +87,7 @@
 	} else {
 		return "libprofile-clang-extras"
 	}
+	// LINT.ThenChange(library.go)
 }
 
 func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
@@ -100,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...)
 			}
 		}
 	}
@@ -221,7 +246,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
@@ -233,43 +258,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..0893da5 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,7 +43,7 @@
 }
 
 // FdoProfileProvider is used to provide path to an fdo profile
-var FdoProfileProvider = blueprint.NewMutatorProvider(FdoProfileInfo{}, "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
@@ -63,7 +62,7 @@
 func (fp *fdoProfile) fdoProfileMutator(ctx android.BottomUpMutatorContext) {
 	if fp.properties.Profile != nil {
 		path := android.PathForModuleSrc(ctx, *fp.properties.Profile)
-		ctx.SetProvider(FdoProfileProvider, FdoProfileInfo{
+		android.SetProvider(ctx, FdoProfileProvider, FdoProfileInfo{
 			Path: path,
 		})
 	}
@@ -77,7 +76,7 @@
 	}
 }
 
-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 452cf35..2436f33 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -28,7 +28,8 @@
 
 func init() {
 	android.RegisterModuleType("cc_fuzz", LibFuzzFactory)
-	android.RegisterSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
+	android.RegisterParallelSingletonType("cc_fuzz_packaging", fuzzPackagingFactory)
+	android.RegisterParallelSingletonType("cc_fuzz_presubmit_packaging", fuzzPackagingFactoryPresubmit)
 }
 
 type FuzzProperties struct {
@@ -104,7 +105,8 @@
 	*baseCompiler
 	fuzzPackagedModule  fuzz.FuzzPackagedModule
 	installedSharedDeps []string
-	sharedLibraries     android.Paths
+	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,70 +226,91 @@
 }
 
 func SharedLibraryInstallLocation(
-	libraryPath android.Path, 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", libraryPath.Base())
+		installLocation, fuzzDir, archString, subdir, libraryBase)
 	return installLocation
 }
 
 // Get the device-only shared library symbols install directory.
-func SharedLibrarySymbolsInstallLocation(libraryPath android.Path, fuzzDir string, archString string) string {
-	return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, "/lib/", libraryPath.Base())
+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) {
+	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(), 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, 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)
-
-	fuzzBin.fuzzPackagedModule = PackageFuzzModule(ctx, fuzzBin.fuzzPackagedModule, pctx)
-
-	// Grab the list of required shared libraries.
-	fuzzBin.sharedLibraries, _ = CollectAllSharedDependencies(ctx)
-
-	for _, lib := range fuzzBin.sharedLibraries {
-		fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
-			SharedLibraryInstallLocation(
-				lib, ctx.Host(), installBase, ctx.Arch().ArchType.String()))
-
-		// Also add the dependency on the shared library symbols dir.
-		if !ctx.Host() {
-			fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps,
-				SharedLibrarySymbolsInstallLocation(lib, installBase, ctx.Arch().ArchType.String()))
-		}
-	}
 }
 
 func PackageFuzzModule(ctx android.ModuleContext, fuzzPackagedModule fuzz.FuzzPackagedModule, pctx android.PackageContext) fuzz.FuzzPackagedModule {
 	fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Corpus)
-	builder := android.NewRuleBuilder(pctx, ctx)
-	intermediateDir := android.PathForModuleOut(ctx, "corpus")
-	for _, entry := range fuzzPackagedModule.Corpus {
-		builder.Command().Text("cp").
-			Input(entry).
-			Output(intermediateDir.Join(ctx, entry.Base()))
-	}
-	builder.Build("copy_corpus", "copy corpus")
-	fuzzPackagedModule.CorpusIntermediateDir = intermediateDir
 
 	fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Data)
-	builder = android.NewRuleBuilder(pctx, ctx)
-	intermediateDir = android.PathForModuleOut(ctx, "data")
-	for _, entry := range fuzzPackagedModule.Data {
-		builder.Command().Text("cp").
-			Input(entry).
-			Output(intermediateDir.Join(ctx, entry.Rel()))
-	}
-	builder.Build("copy_data", "copy data")
-	fuzzPackagedModule.DataIntermediateDir = intermediateDir
 
 	if fuzzPackagedModule.FuzzProperties.Dictionary != nil {
 		fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzzPackagedModule.FuzzProperties.Dictionary)
@@ -297,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)
@@ -355,6 +388,7 @@
 	fuzzPackagingArchModules         string
 	fuzzTargetSharedDepsInstallPairs string
 	allFuzzTargetsName               string
+	onlyIncludePresubmits            bool
 }
 
 func fuzzPackagingFactory() android.Singleton {
@@ -363,6 +397,18 @@
 		fuzzPackagingArchModules:         "SOONG_FUZZ_PACKAGING_ARCH_MODULES",
 		fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
 		allFuzzTargetsName:               "ALL_FUZZ_TARGETS",
+		onlyIncludePresubmits:            false,
+	}
+	return fuzzPackager
+}
+
+func fuzzPackagingFactoryPresubmit() android.Singleton {
+
+	fuzzPackager := &ccRustFuzzPackager{
+		fuzzPackagingArchModules:         "SOONG_PRESUBMIT_FUZZ_PACKAGING_ARCH_MODULES",
+		fuzzTargetSharedDepsInstallPairs: "PRESUBMIT_FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
+		allFuzzTargetsName:               "ALL_PRESUBMIT_FUZZ_TARGETS",
+		onlyIncludePresubmits:            true,
 	}
 	return fuzzPackager
 }
@@ -386,21 +432,29 @@
 		if !ok || ccModule.PreventInstall() {
 			return
 		}
-
 		// Discard non-fuzz targets.
 		if ok := fuzz.IsValid(ccModule.FuzzModuleStruct()); !ok {
 			return
 		}
 
 		sharedLibsInstallDirPrefix := "lib"
+		if ccModule.InVendor() {
+			sharedLibsInstallDirPrefix = "lib/vendor"
+		}
+
 		if !ccModule.IsFuzzModule() {
 			return
 		}
 
 		hostOrTargetString := "target"
-		if ccModule.Host() {
+		if ccModule.Target().HostCross {
+			hostOrTargetString = "host_cross"
+		} else if ccModule.Host() {
 			hostOrTargetString = "host"
 		}
+		if s.onlyIncludePresubmits == true {
+			hostOrTargetString = "presubmit-" + hostOrTargetString
+		}
 
 		fpm := fuzz.FuzzPackagedModule{}
 		if ok {
@@ -423,8 +477,16 @@
 		files = append(files, GetSharedLibsToZip(ccModule.FuzzSharedLibraries(), ccModule, &s.FuzzPackager, archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...)
 
 		// The executable.
-		files = append(files, fuzz.FileToZip{android.OutputFileForModule(ctx, ccModule, "unstripped"), ""})
+		files = append(files, fuzz.FileToZip{SourceFilePath: android.OutputFileForModule(ctx, ccModule, "unstripped")})
 
+		if s.onlyIncludePresubmits == true {
+			if fpm.FuzzProperties.Fuzz_config == nil {
+				return
+			}
+			if !BoolDefault(fpm.FuzzProperties.Fuzz_config.Use_for_presubmit, false) {
+				return
+			}
+		}
 		archDirs[archOs], ok = s.BuildZipFile(ctx, module, fpm, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
 		if !ok {
 			return
@@ -454,19 +516,25 @@
 
 // GetSharedLibsToZip finds and marks all the transiently-dependent shared libraries for
 // packaging.
-func GetSharedLibsToZip(sharedLibraries android.Paths, module LinkableInterface, s *fuzz.FuzzPackager, archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip {
+func GetSharedLibsToZip(sharedLibraries android.RuleBuilderInstalls, module LinkableInterface, s *fuzz.FuzzPackager, archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip {
 	var files []fuzz.FileToZip
 
 	fuzzDir := "fuzz"
 
-	for _, library := range sharedLibraries {
-		files = append(files, fuzz.FileToZip{library, destinationPathPrefix})
+	for _, ruleBuilderInstall := range sharedLibraries {
+		library := ruleBuilderInstall.From
+		install := ruleBuilderInstall.To
+		files = append(files, fuzz.FileToZip{
+			SourceFilePath:        library,
+			DestinationPathPrefix: destinationPathPrefix,
+			DestinationPath:       install,
+		})
 
 		// For each architecture-specific shared library dependency, we need to
 		// 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(
-			library, module.Host(), fuzzDir, archString)
+			install, module.Host(), module.InVendor(), fuzzDir, archString)
 		if (*sharedLibraryInstalled)[installDestination] {
 			continue
 		}
@@ -484,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(library, fuzzDir, archString)
+			symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, module.InVendor(), fuzzDir, archString)
 			symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
 			s.SharedLibInstallStrings = append(s.SharedLibInstallStrings,
 				library.String()+":"+symbolsInstallDestination)
@@ -498,12 +566,12 @@
 // VisitDirectDeps is used first to avoid incorrectly using the core libraries (sanitizer
 // runtimes, libc, libdl, etc.) from a dependency. This may cause issues when dependencies
 // have explicit sanitizer tags, as we may get a dependency on an unsanitized libc, etc.
-func CollectAllSharedDependencies(ctx android.ModuleContext) (android.Paths, []android.Module) {
+func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilderInstalls, []android.Module) {
 	seen := make(map[string]bool)
 	recursed := make(map[string]bool)
 	deps := []android.Module{}
 
-	var sharedLibraries android.Paths
+	var sharedLibraries android.RuleBuilderInstalls
 
 	// Enumerate the first level of dependencies, as we discard all non-library
 	// modules in the BFS loop below.
@@ -511,22 +579,47 @@
 		if !IsValidSharedDependency(dep) {
 			return
 		}
+		sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider)
+		if !hasSharedLibraryInfo {
+			return
+		}
 		if seen[ctx.OtherModuleName(dep)] {
 			return
 		}
 		seen[ctx.OtherModuleName(dep)] = true
 		deps = append(deps, dep)
-		sharedLibraries = append(sharedLibraries, android.OutputFileForModule(ctx, dep, "unstripped"))
+
+		installDestination := sharedLibraryInfo.SharedLibrary.Base()
+		ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, dep, "unstripped"), installDestination}
+		sharedLibraries = append(sharedLibraries, ruleBuilderInstall)
 	})
 
 	ctx.WalkDeps(func(child, parent android.Module) bool {
+
+		// If this is a Rust module which is not rust_ffi_shared, we still want to bundle any transitive
+		// shared dependencies (even for rust_ffi_static)
+		if rustmod, ok := child.(LinkableInterface); ok && rustmod.RustLibraryInterface() && !rustmod.Shared() {
+			if recursed[ctx.OtherModuleName(child)] {
+				return false
+			}
+			recursed[ctx.OtherModuleName(child)] = true
+			return true
+		}
+
 		if !IsValidSharedDependency(child) {
 			return false
 		}
+		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)
-			sharedLibraries = append(sharedLibraries, android.OutputFileForModule(ctx, child, "unstripped"))
+
+			installDestination := sharedLibraryInfo.SharedLibrary.Base()
+			ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, child, "unstripped"), installDestination}
+			sharedLibraries = append(sharedLibraries, ruleBuilderInstall)
 		}
 
 		if recursed[ctx.OtherModuleName(child)] {
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
new file mode 100644
index 0000000..b1084e4
--- /dev/null
+++ b/cc/generated_cc_library.go
@@ -0,0 +1,34 @@
+// 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 cc
+
+import (
+	"android/soong/android"
+)
+
+func GeneratedCcLibraryModuleFactory(moduleName string, callbacks Generator) android.Module {
+	module, _ := NewLibrary(android.HostAndDeviceSupported)
+
+	// Can be used as both a static and a shared library.
+	module.sdkMemberTypes = []android.SdkMemberType{
+		sharedLibrarySdkMemberType,
+		staticLibrarySdkMemberType,
+		staticAndSharedLibrarySdkMemberType,
+	}
+
+	module.generators = append(module.generators, callbacks)
+
+	return module.Init()
+}
diff --git a/cc/genrule.go b/cc/genrule.go
index d1c4c2a..0fb3e2d 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -62,7 +62,6 @@
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibBoth)
 
 	android.InitApexModule(module)
-	android.InitBazelModule(module)
 
 	return module
 }
@@ -80,15 +79,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 {
@@ -116,32 +107,32 @@
 }
 
 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)
+	vndkVersion := ctx.DeviceConfig().VndkVersion()
+	vendorVariantRequired := Bool(g.Vendor_available) || Bool(g.Odm_available) || ctx.SocSpecific() || ctx.DeviceSpecific()
+	productVariantRequired := Bool(g.Product_available) || ctx.ProductSpecific()
+
+	if vndkVersion == "" {
+		if vendorVariantRequired {
+			variants = append(variants, VendorVariation)
 		}
-	}
-
-	if ctx.DeviceConfig().ProductVndkVersion() == "" {
-		return variants
-	}
-
-	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)
+		}
+	} else {
+		if vendorVariantRequired {
+			// 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)
+			}
+		}
+		if productVariantRequired {
+			variants = append(variants, ProductVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
 		}
 	}
 
diff --git a/cc/genrule_test.go b/cc/genrule_test.go
index 0d16e62..05c644f 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,26 @@
 		})
 	}
 }
+
+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 := PrepareForTestWithCcIncludeVndk.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)
+	}
+}
diff --git a/cc/image.go b/cc/image.go
index e65a9aa..d02a2f3 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -23,6 +23,8 @@
 
 	"android/soong/android"
 	"android/soong/snapshot"
+
+	"github.com/google/blueprint/proptools"
 )
 
 var _ android.ImageInterface = (*Module)(nil)
@@ -40,27 +42,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 +79,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 +120,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 {
@@ -427,7 +431,6 @@
 
 	platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
 	boardVndkVersion := mctx.DeviceConfig().VndkVersion()
-	productVndkVersion := mctx.DeviceConfig().ProductVndkVersion()
 	recoverySnapshotVersion := mctx.DeviceConfig().RecoverySnapshotVersion()
 	usingRecoverySnapshot := recoverySnapshotVersion != "current" &&
 		recoverySnapshotVersion != ""
@@ -444,42 +447,25 @@
 	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, platformVndkVersion)
+		productVariants = append(productVariants, platformVndkVersion)
 		// 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)
-		}
 	} 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
+		productVariants = append(productVariants, platformVndkVersion)
 	} else if m.IsSnapshotPrebuilt() {
 		// Make vendor variants only for the versions in BOARD_VNDK_VERSION and
 		// PRODUCT_EXTRA_VNDK_VERSIONS.
@@ -507,10 +493,6 @@
 		// 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)
-			}
 		}
 	} else if vendorSpecific && m.SdkVersion() == "" {
 		// This will be available in /vendor (or /odm) only
@@ -538,17 +520,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, platformVndkVersion)
 	}
 
 	if m.RamdiskAvailable() {
@@ -588,11 +563,19 @@
 	}
 
 	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 +626,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 +643,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)
+		}
 	}
 }
 
@@ -678,19 +669,29 @@
 	}
 }
 
+func squashRamdiskSrcs(m *Module) {
+	if lib, ok := m.compiler.(*libraryDecorator); ok {
+		lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs, lib.baseCompiler.Properties.Target.Ramdisk.Exclude_srcs...)
+	}
+}
+
 func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
 	m := module.(*Module)
 	if variant == android.RamdiskVariation {
 		m.MakeAsPlatform()
+		squashRamdiskSrcs(m)
 	} else if variant == android.VendorRamdiskVariation {
 		m.MakeAsPlatform()
 		squashVendorRamdiskSrcs(m)
 	} 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)
+	} else if strings.HasPrefix(variant, VendorVariation) {
+		m.Properties.ImageVariation = VendorVariation
+
+		if strings.HasPrefix(variant, VendorVariationPrefix) {
+			m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix)
+		}
 		squashVendorSrcs(m)
 
 		// Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION.
@@ -700,9 +701,11 @@
 			m.Properties.HideFromMake = true
 			m.HideFromMake()
 		}
-	} else if strings.HasPrefix(variant, ProductVariationPrefix) {
-		m.Properties.ImageVariationPrefix = ProductVariationPrefix
-		m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix)
+	} 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 716a0df..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,11 +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) installExecutable(ctx ModuleContext, file android.Path) {
-	installer.path = ctx.InstallExecutable(installer.installDir(ctx), file.Base(), file)
+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 d5f5b40..4b6ac59 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"io"
+	"log"
 	"path/filepath"
 	"regexp"
 	"strconv"
@@ -24,8 +25,6 @@
 	"sync"
 
 	"android/soong/android"
-	"android/soong/bazel"
-	"android/soong/bazel/cquery"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
@@ -93,6 +92,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 {
@@ -214,424 +220,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)
-	}
-
-	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: baseAttributes.features,
-	}
-
-	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:                          baseAttributes.features,
-		bazelCcHeaderAbiCheckerAttributes: bp2buildParseAbiCheckerProps(ctx, m),
-
-		Fdo_profile: compilerAttrs.fdoProfile,
-	}
-
-	if compilerAttrs.stubsSymbolFile != nil && len(compilerAttrs.stubsVersions.Value) > 0 {
-		sharedTargetAttrs.Stubs_symbol_file = compilerAttrs.stubsSymbolFile
-	}
-
-	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",
-	}
-
-	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
@@ -644,8 +232,6 @@
 		staticLibrarySdkMemberType,
 		staticAndSharedLibrarySdkMemberType,
 	}
-	module.bazelable = true
-	module.bazelHandler = &ccLibraryBazelHandler{module: module}
 	return module.Init()
 }
 
@@ -654,8 +240,6 @@
 	module, library := NewLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyStatic()
 	module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType}
-	module.bazelable = true
-	module.bazelHandler = &ccLibraryBazelHandler{module: module}
 	return module.Init()
 }
 
@@ -664,8 +248,6 @@
 	module, library := NewLibrary(android.HostAndDeviceSupported)
 	library.BuildOnlyShared()
 	module.sdkMemberTypes = []android.SdkMemberType{sharedLibrarySdkMemberType}
-	module.bazelable = true
-	module.bazelHandler = &ccLibraryBazelHandler{module: module}
 	return module.Init()
 }
 
@@ -675,8 +257,6 @@
 	module, library := NewLibrary(android.HostSupported)
 	library.BuildOnlyStatic()
 	module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType}
-	module.bazelable = true
-	module.bazelHandler = &ccLibraryBazelHandler{module: module}
 	return module.Init()
 }
 
@@ -685,8 +265,6 @@
 	module, library := NewLibrary(android.HostSupported)
 	library.BuildOnlyShared()
 	module.sdkMemberTypes = []android.SdkMemberType{sharedLibrarySdkMemberType}
-	module.bazelable = true
-	module.bazelHandler = &ccLibraryBazelHandler{module: module}
 	return module.Init()
 }
 
@@ -765,7 +343,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
@@ -824,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
@@ -849,145 +429,6 @@
 	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.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{}
 
@@ -1002,11 +443,6 @@
 			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
@@ -1436,12 +872,18 @@
 func (library *libraryDecorator) getLibName(ctx BaseModuleContext) string {
 	name := library.getLibNameHelper(ctx.baseModuleName(), ctx.inVendor(), ctx.inProduct())
 
+	// Replace name with VNDK ext as original lib only when VNDK is enabled
 	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.DeviceConfig().VndkVersion() != "" {
+			// 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())
+			})
+		} else {
+			// TODO(b/320208784) : Suggest a solution for former VNDK-ext libraries before VNDK deprecation.
+			log.Printf("VNDK Extension on module %s will not be available once VNDK is deprecated", ctx.baseModuleName())
+		}
 	}
 
 	if ctx.Host() && Bool(library.Properties.Unique_host_soname) {
@@ -1607,6 +1049,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 {
 
@@ -1637,13 +1113,13 @@
 	ctx.CheckbuildFile(outputFile)
 
 	if library.static() {
-		ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+		android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{
 			StaticLibrary:                outputFile,
 			ReuseObjects:                 library.reuseObjects,
 			Objects:                      library.objects,
 			WholeStaticLibsFromPrebuilts: library.wholeStaticLibsFromPrebuilts,
 
-			TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder(android.TOPOLOGICAL).
+			TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).
 				Direct(outputFile).
 				Transitive(deps.TranstiveStaticLibrariesForOrdering).
 				Build(),
@@ -1651,7 +1127,7 @@
 	}
 
 	if library.header() {
-		ctx.SetProvider(HeaderLibraryInfoProvider, HeaderLibraryInfo{})
+		android.SetProvider(ctx, HeaderLibraryInfoProvider, HeaderLibraryInfo{})
 	}
 
 	return outputFile
@@ -1769,6 +1245,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...)
@@ -1788,13 +1275,13 @@
 	library.coverageOutputFile = transformCoverageFilesToZip(ctx, objs, library.getLibName(ctx))
 	library.linkSAbiDumpFiles(ctx, objs, fileName, unstrippedOutputFile)
 
-	var transitiveStaticLibrariesForOrdering *android.DepSet
+	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,
@@ -1811,15 +1298,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(),
 		})
@@ -1830,6 +1317,10 @@
 	return library.unstrippedOutputFile
 }
 
+func (library *libraryDecorator) strippedAllOutputFilePath() android.Path {
+	return library.strippedAllOutputFile
+}
+
 func (library *libraryDecorator) disableStripping() {
 	library.stripper.StripProperties.Strip.None = BoolPtr(true)
 }
@@ -1859,11 +1350,11 @@
 		fileName+".lsdump")
 }
 
-func getRefAbiDumpDir(isNdk, isVndk bool) string {
+func getRefAbiDumpDir(isNdk, isLlndk bool) string {
 	var dirName string
 	if isNdk {
 		dirName = "ndk"
-	} else if isVndk {
+	} else if isLlndk {
 		dirName = "vndk"
 	} else {
 		dirName = "platform"
@@ -1890,11 +1381,8 @@
 	}
 }
 
-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() {
+func currRefAbiDumpVersion(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()
@@ -1936,20 +1424,20 @@
 func (library *libraryDecorator) crossVersionAbiDiff(ctx android.ModuleContext, 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,
 		isLlndkOrNdk, true /* allowExtensions */, sourceVersion, errorMessage)
 }
 
 func (library *libraryDecorator) sameVersionAbiDiff(ctx android.ModuleContext, referenceDump android.Path,
-	baseName string, isLlndkOrNdk, allowExtensions bool) {
+	baseName 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)
+		isLlndkOrNdk, false /* allowExtensions */, "current", errorMessage)
 }
 
 func (library *libraryDecorator) optInAbiDiff(ctx android.ModuleContext, referenceDump android.Path,
@@ -1957,6 +1445,10 @@
 
 	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
+	// Most opt-in libraries do not have dumps for all default architectures.
+	if ctx.Config().HasDeviceProduct() {
+		errorMessage += " -products " + ctx.Config().DeviceProduct()
+	}
 
 	library.sourceAbiDiff(ctx, referenceDump, baseName, nameExt,
 		isLlndkOrNdk, false /* allowExtensions */, "current", errorMessage)
@@ -1974,38 +1466,36 @@
 		}
 		exportedHeaderFlags := strings.Join(SourceAbiFlags, " ")
 		headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx)
+		// The logic must be consistent with classifySourceAbiDump.
+		isNdk := ctx.isNdk(ctx.Config())
+		isLlndk := ctx.isImplementationForLLNDKPublic()
+		currVersion := currRefAbiDumpVersion(ctx)
 		library.sAbiOutputFile = transformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedHeaderFlags,
 			android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)),
 			headerAbiChecker.Exclude_symbol_versions,
-			headerAbiChecker.Exclude_symbol_tags)
+			headerAbiChecker.Exclude_symbol_tags,
+			currVersion)
 
 		addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.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)
+		dumpDir := getRefAbiDumpDir(isNdk, isLlndk)
 		binderBitness := ctx.DeviceConfig().BinderBitness()
-		// If NDK or PLATFORM library, check against previous version ABI.
-		if !isVndk {
-			prevVersionInt := prevRefAbiDumpVersion(ctx, dumpDir)
-			prevVersion := strconv.Itoa(prevVersionInt)
-			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)
-			}
+		// Check against the previous version.
+		prevVersionInt := prevRefAbiDumpVersion(ctx, dumpDir)
+		prevVersion := strconv.Itoa(prevVersionInt)
+		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)
 		}
 		// 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())
+				fileName, isLlndk || isNdk)
 		}
 		// Check against the opt-in reference dumps.
 		for i, optInDumpDir := range headerAbiChecker.Ref_dump_dirs {
@@ -2265,7 +1755,7 @@
 
 			// do not install vndk libs
 			// vndk libs are packaged into VNDK APEX
-			if ctx.isVndk() && !ctx.IsVndkExt() {
+			if ctx.isVndk() && !ctx.IsVndkExt() && !ctx.Config().IsVndkDeprecated() && !ctx.inProduct() {
 				return
 			}
 		} else if library.hasStubsVariants() && !ctx.Host() && ctx.directlyInAnyApex() {
@@ -2289,7 +1779,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())
@@ -2409,7 +1899,7 @@
 		return nil
 	}
 
-	if library.hasLLNDKStubs() && ctx.Module().(*Module).UseVndk() {
+	if library.hasLLNDKStubs() && ctx.Module().(*Module).InVendorOrProduct() {
 		// LLNDK libraries only need a single stubs variant.
 		return []string{android.FutureApiLevel.String()}
 	}
@@ -2683,7 +2173,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)
@@ -2854,237 +2344,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)
-	}
-
-	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)
-		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,
-
-			Features: baseAttributes.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: baseAttributes.features,
-
-			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
-
-	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
-
-	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..aab6664 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()}
 	}
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 9578807..6f22091 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -2,7 +2,6 @@
 
 import (
 	"android/soong/android"
-	"android/soong/bazel/cquery"
 	"android/soong/fuzz"
 	"android/soong/snapshot"
 
@@ -87,8 +86,26 @@
 	// 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
+
+	// IsSnapshotSanitizer returns true if this snapshot module implements SnapshotSanitizer.
+	IsSnapshotSanitizer() bool
+
+	// IsSnapshotSanitizerAvailable returns true if this snapshot module has a sanitizer source available (cfi, hwasan).
+	IsSnapshotSanitizerAvailable(t SanitizerType) bool
+
+	// SetSnapshotSanitizerVariation sets the sanitizer variation type for this snapshot module.
+	SetSnapshotSanitizerVariation(t SanitizerType, enabled bool)
+
+	// IsSnapshotUnsanitizedVariant returns true if this is the unsanitized snapshot module variant.
+	IsSnapshotUnsanitizedVariant() bool
 }
 
 // LinkableInterface is an interface for a type of module that is linkable in a C++ library.
@@ -100,6 +117,9 @@
 	CcLibrary() bool
 	CcLibraryInterface() bool
 
+	// RustLibraryInterface returns true if this is a Rust library module
+	RustLibraryInterface() bool
+
 	// BaseModuleName returns the android.ModuleBase.BaseModuleName() value for this module.
 	BaseModuleName() string
 
@@ -130,7 +150,7 @@
 
 	// FuzzSharedLibraries returns the shared library dependencies for this module.
 	// Expects that IsFuzzModule returns true.
-	FuzzSharedLibraries() android.Paths
+	FuzzSharedLibraries() android.RuleBuilderInstalls
 
 	Device() bool
 	Host() bool
@@ -198,6 +218,7 @@
 	ProductSpecific() bool
 	InProduct() bool
 	SdkAndPlatformVariantVisibleToMake() bool
+	InVendorOrProduct() bool
 
 	// SubName returns the modules SubName, used for image and NDK/SDK variations.
 	SubName() string
@@ -236,6 +257,9 @@
 	// Dylib returns true if this is an dylib module.
 	Dylib() bool
 
+	// RlibStd returns true if this is an rlib which links against an rlib libstd.
+	RlibStd() bool
+
 	// Static returns true if this is a static library module.
 	Static() bool
 
@@ -342,10 +366,10 @@
 	TableOfContents android.OptionalPath
 
 	// should be obtained from static analogue
-	TransitiveStaticLibrariesForOrdering *android.DepSet
+	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
@@ -368,7 +392,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 {
@@ -384,17 +408,17 @@
 	// This isn't the actual transitive DepSet, shared library dependencies have been
 	// converted into static library analogues.  It is only used to order the static
 	// library dependencies that were specified for the current module.
-	TransitiveStaticLibrariesForOrdering *android.DepSet
+	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.
@@ -406,20 +430,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..85c128e 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -214,6 +214,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.
@@ -300,6 +305,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")
@@ -639,6 +648,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/lto.go b/cc/lto.go
index 1afa1dd..b2b4570 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,29 +38,19 @@
 // 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"`
-		Full  *bool `android:"arch_variant"`
 		Thin  *bool `android:"arch_variant"`
 	} `android:"arch_variant"`
 
-	// Dep properties indicate that this module needs to be built with LTO
-	// since it is an object dependency of an LTO module.
-	FullEnabled  bool `blueprint:"mutated"`
-	ThinEnabled  bool `blueprint:"mutated"`
-	NoLtoEnabled bool `blueprint:"mutated"`
-	FullDep      bool `blueprint:"mutated"`
-	ThinDep      bool `blueprint:"mutated"`
-	NoLtoDep     bool `blueprint:"mutated"`
-
-	// Use clang lld instead of gnu ld.
-	Use_clang_lld *bool
+	LtoEnabled bool `blueprint:"mutated"`
+	LtoDefault bool `blueprint:"mutated"`
 
 	// Use -fwhole-program-vtables cflag.
 	Whole_program_vtables *bool
@@ -72,211 +65,192 @@
 }
 
 func (lto *lto) begin(ctx BaseModuleContext) {
+	// First, determine the module independent default LTO mode.
+	ltoDefault := true
 	if ctx.Config().IsEnvTrue("DISABLE_LTO") {
-		lto.Properties.NoLtoEnabled = true
+		ltoDefault = false
+	} else if lto.Never() {
+		ltoDefault = false
+	} else if ctx.Host() {
+		// Performance and binary size are less important for host binaries.
+		ltoDefault = false
+	} else if ctx.Arch().ArchType.Multilib == "lib32" {
+		// LP32 has many subtle issues and less test coverage.
+		ltoDefault = false
 	}
-}
 
-func (lto *lto) useClangLld(ctx BaseModuleContext) bool {
-	if lto.Properties.Use_clang_lld != nil {
-		return Bool(lto.Properties.Use_clang_lld)
+	// Then, determine the actual LTO mode to use. If different from `ltoDefault`, a variant needs
+	// to be created.
+	ltoEnabled := ltoDefault
+	if lto.Never() {
+		ltoEnabled = false
+	} else if lto.ThinLTO() {
+		// Module explicitly requests for LTO.
+		ltoEnabled = true
+	} 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
 	}
-	return true
+
+	lto.Properties.LtoDefault = ltoDefault
+	lto.Properties.LtoEnabled = ltoEnabled
 }
 
 func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
-	// TODO(b/131771163): Disable LTO when using explicit fuzzing configurations.
-	// LTO breaks fuzzer builds.
-	if inList("-fsanitize=fuzzer-no-link", flags.Local.CFlags) {
+	// 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() {
 		return flags
 	}
+	if lto.Properties.LtoEnabled {
+		ltoCFlags := []string{"-flto=thin", "-fsplit-lto-unit"}
+		var ltoLdFlags []string
 
-	// TODO(b/254713216): LTO doesn't work on riscv64 yet.
-	if ctx.Arch().ArchType == android.Riscv64 {
-		return flags
-	}
-
-	if lto.LTO(ctx) {
-		var ltoCFlag string
-		var ltoLdFlag string
-		if lto.ThinLTO() {
-			ltoCFlag = "-flto=thin -fsplit-lto-unit"
-		} else if lto.FullLTO() {
-			ltoCFlag = "-flto"
-		} else {
-			ltoCFlag = "-flto=thin -fsplit-lto-unit"
-			ltoLdFlag = "-Wl,--lto-O0"
+		// The module did not explicitly turn on LTO. Only leverage LTO's
+		// better dead code elimination and CFG simplification, but do
+		// not perform costly optimizations for a balance between compile
+		// time, binary size and performance.
+		// Apply the same for Eng builds as well.
+		if !lto.ThinLTO() || ctx.Config().Eng() {
+			ltoLdFlags = append(ltoLdFlags, "-Wl,--lto-O0")
 		}
 
-		flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlag)
-		flags.Local.AsFlags = append(flags.Local.AsFlags, ltoCFlag)
-		flags.Local.LdFlags = append(flags.Local.LdFlags, ltoCFlag)
-		flags.Local.LdFlags = append(flags.Local.LdFlags, ltoLdFlag)
-
 		if Bool(lto.Properties.Whole_program_vtables) {
-			flags.Local.CFlags = append(flags.Local.CFlags, "-fwhole-program-vtables")
+			ltoCFlags = append(ltoCFlags, "-fwhole-program-vtables")
 		}
 
-		if (lto.DefaultThinLTO(ctx) || lto.ThinLTO()) && ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && lto.useClangLld(ctx) {
+		if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") {
 			// Set appropriate ThinLTO cache policy
 			cacheDirFormat := "-Wl,--thinlto-cache-dir="
 			cacheDir := android.PathForOutput(ctx, "thinlto-cache").String()
-			flags.Local.LdFlags = append(flags.Local.LdFlags, cacheDirFormat+cacheDir)
+			ltoLdFlags = append(ltoLdFlags, cacheDirFormat+cacheDir)
 
 			// Limit the size of the ThinLTO cache to the lesser of 10% of available
 			// disk space and 10GB.
 			cachePolicyFormat := "-Wl,--thinlto-cache-policy="
 			policy := "cache_size=10%:cache_size_bytes=10g"
-			flags.Local.LdFlags = append(flags.Local.LdFlags, cachePolicyFormat+policy)
+			ltoLdFlags = append(ltoLdFlags, cachePolicyFormat+policy)
 		}
 
-		// If the module does not have a profile, be conservative and limit cross TU inline
-		// limit to 5 LLVM IR instructions, to balance binary size increase and performance.
-		if !ctx.isPgoCompile() && !ctx.isAfdoCompile() {
-			flags.Local.LdFlags = append(flags.Local.LdFlags,
-				"-Wl,-plugin-opt,-import-instr-limit=5")
+		// Reduce the inlining threshold for a better balance of binary size and
+		// performance.
+		if !ctx.Darwin() {
+			if ctx.isAfdoCompile() {
+				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...)
+		flags.Local.LdFlags = append(flags.Local.LdFlags, ltoLdFlags...)
 	}
 	return flags
 }
 
-func (lto *lto) LTO(ctx BaseModuleContext) bool {
-	return lto.ThinLTO() || lto.FullLTO() || lto.DefaultThinLTO(ctx)
-}
-
-func (lto *lto) DefaultThinLTO(ctx BaseModuleContext) bool {
-	// LP32 has many subtle issues and less test coverage.
-	lib32 := ctx.Arch().ArchType.Multilib == "lib32"
-	// CFI enables full LTO.
-	cfi := ctx.isCfi()
-	// Performance and binary size are less important for host binaries and tests.
-	host := ctx.Host()
-	test := ctx.testBinary() || ctx.testLibrary()
-	// FIXME: ThinLTO for VNDK produces different output.
-	// b/169217596
-	vndk := ctx.isVndk()
-	return GlobalThinLTO(ctx) && !lto.Never() && !lib32 && !cfi && !host && !test && !vndk
-}
-
-func (lto *lto) FullLTO() bool {
-	return lto != nil && (proptools.Bool(lto.Properties.Lto.Full) || lto.Properties.FullEnabled)
-}
-
 func (lto *lto) ThinLTO() bool {
-	return lto != nil && (proptools.Bool(lto.Properties.Lto.Thin) || lto.Properties.ThinEnabled)
+	return lto != nil && proptools.Bool(lto.Properties.Lto.Thin)
 }
 
 func (lto *lto) Never() bool {
-	return lto != nil && (proptools.Bool(lto.Properties.Lto.Never) || lto.Properties.NoLtoEnabled)
+	return lto != nil && proptools.Bool(lto.Properties.Lto.Never)
 }
 
-func GlobalThinLTO(ctx android.BaseModuleContext) bool {
-	return ctx.Config().IsEnvTrue("GLOBAL_THINLTO")
-}
-
-// Propagate lto requirements down from binaries
-func ltoDepsMutator(mctx android.TopDownMutatorContext) {
-	globalThinLTO := GlobalThinLTO(mctx)
-
-	if m, ok := mctx.Module().(*Module); ok {
-		full := m.lto.FullLTO()
-		thin := m.lto.ThinLTO()
-		never := m.lto.Never()
-		if full && thin {
-			mctx.PropertyErrorf("LTO", "FullLTO and ThinLTO are mutually exclusive")
-		}
-
-		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 full && !dep.lto.FullLTO() {
-					dep.lto.Properties.FullDep = true
-				}
-				if !globalThinLTO && thin && !dep.lto.ThinLTO() {
-					dep.lto.Properties.ThinDep = true
-				}
-				if globalThinLTO && never && !dep.lto.Never() {
-					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.FullDep && !m.lto.FullLTO() {
-			variationNames = append(variationNames, "lto-full")
-		}
-		if !globalThinLTO && m.lto.Properties.ThinDep && !m.lto.ThinLTO() {
-			variationNames = append(variationNames, "lto-thin")
-		}
-		if globalThinLTO && m.lto.Properties.NoLtoDep && !m.lto.Never() {
-			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 ""
 		}
 
-		// Use correct dependencies if LTO property is explicitly set
-		// (mutually exclusive)
-		if m.lto.FullLTO() {
-			mctx.SetDependencyVariation("lto-full")
-		}
-		if !globalThinLTO && m.lto.ThinLTO() {
-			mctx.SetDependencyVariation("lto-thin")
-		}
-		// Never must be the last, it overrides Thin or Full.
-		if globalThinLTO && m.lto.Never() {
-			mctx.SetDependencyVariation("lto-none")
+		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-full" {
-					variation.lto.Properties.FullEnabled = true
-				}
-				if name == "lto-thin" {
-					variation.lto.Properties.ThinEnabled = true
-				}
-				if name == "lto-none" {
-					variation.lto.Properties.NoLtoEnabled = true
-				}
-				variation.Properties.PreventInstall = true
-				variation.Properties.HideFromMake = true
-				variation.lto.Properties.FullDep = false
-				variation.lto.Properties.ThinDep = 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 4220f32..e4b5a3a 100644
--- a/cc/lto_test.go
+++ b/cc/lto_test.go
@@ -23,6 +23,20 @@
 	"github.com/google/blueprint"
 )
 
+var LTOPreparer = android.GroupFixturePreparers(
+	prepareForCcTest,
+)
+
+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()
 	bp := `
@@ -31,9 +45,6 @@
 		srcs: ["src.c"],
 		static_libs: ["foo", "lib_never_lto"],
 		shared_libs: ["bar"],
-		lto: {
-			thin: true,
-		}
 	}
 	cc_library_static {
 		name: "foo",
@@ -57,52 +68,40 @@
 	}
 `
 
-	result := android.GroupFixturePreparers(
-		prepareForCcTest,
-	).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)
 		}
 	}
 }
@@ -137,30 +136,19 @@
 	}
 `
 
-	result := android.GroupFixturePreparers(
-		prepareForCcTest,
-	).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"]
@@ -168,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"]
@@ -197,9 +185,7 @@
 			},
 		},
 	}`
-	result := android.GroupFixturePreparers(
-		prepareForCcTest,
-	).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,9 +213,7 @@
 		},
 	}`
 
-	result := android.GroupFixturePreparers(
-		prepareForCcTest,
-	).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..70fdd57 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -123,6 +123,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, " "))
 
diff --git a/cc/ndk_abi.go b/cc/ndk_abi.go
index 3456c32..86166dc 100644
--- a/cc/ndk_abi.go
+++ b/cc/ndk_abi.go
@@ -19,8 +19,8 @@
 )
 
 func init() {
-	android.RegisterSingletonType("ndk_abi_dump", NdkAbiDumpSingleton)
-	android.RegisterSingletonType("ndk_abi_diff", NdkAbiDiffSingleton)
+	android.RegisterParallelSingletonType("ndk_abi_dump", NdkAbiDumpSingleton)
+	android.RegisterParallelSingletonType("ndk_abi_diff", NdkAbiDiffSingleton)
 }
 
 func getNdkAbiDumpInstallBase(ctx android.PathContext) android.OutputPath {
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 7354be9..567cb7c 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -18,11 +18,8 @@
 	"fmt"
 	"path/filepath"
 
-	"github.com/google/blueprint"
-	"github.com/google/blueprint/proptools"
-
 	"android/soong/android"
-	"android/soong/bazel"
+	"github.com/google/blueprint"
 )
 
 var (
@@ -81,10 +78,10 @@
 
 type headerModule struct {
 	android.ModuleBase
-	android.BazelModuleBase
 
 	properties headerProperties
 
+	srcPaths     android.Paths
 	installPaths android.Paths
 	licensePath  android.Path
 }
@@ -128,8 +125,8 @@
 
 	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)
@@ -147,39 +144,6 @@
 	}
 }
 
-// TODO(b/243196151): Populate `system` and `arch` metadata
-type bazelCcApiHeadersAttributes struct {
-	Hdrs        bazel.LabelListAttribute
-	Include_dir *string
-}
-
-func createCcApiHeadersTarget(ctx android.TopDownMutatorContext, includes []string, excludes []string, include_dir *string) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_api_headers",
-		Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl",
-	}
-	attrs := &bazelCcApiHeadersAttributes{
-		Hdrs: bazel.MakeLabelListAttribute(
-			android.BazelLabelForModuleSrcExcludes(
-				ctx,
-				includes,
-				excludes,
-			),
-		),
-		Include_dir: include_dir,
-	}
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-		Name: android.ApiContributionTargetName(ctx.ModuleName()),
-	}, attrs)
-}
-
-var _ android.ApiProvider = (*headerModule)(nil)
-
-func (h *headerModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
-	// Generate `cc_api_headers` target for Multi-tree API export
-	createCcApiHeadersTarget(ctx, h.properties.Srcs, h.properties.Exclude_srcs, h.properties.From)
-}
-
 // ndk_headers installs the sets of ndk headers defined in the srcs property
 // to the sysroot base + "usr/include" + to directory + directory component.
 // ndk_headers requires the license file to be specified. Example:
@@ -190,7 +154,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)
@@ -218,7 +182,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).
@@ -226,10 +190,10 @@
 // Note that this is really only built to handle bionic/libc/include.
 type versionedHeaderModule struct {
 	android.ModuleBase
-	android.BazelModuleBase
 
 	properties versionedHeaderProperties
 
+	srcPaths     android.Paths
 	installPaths android.Paths
 	licensePath  android.Path
 }
@@ -248,9 +212,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)
@@ -261,20 +225,11 @@
 		ctx.ModuleErrorf("glob %q matched zero files", String(m.properties.From))
 	}
 
-	processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, srcFiles, installPaths)
-}
-
-var _ android.ApiProvider = (*versionedHeaderModule)(nil)
-
-func (h *versionedHeaderModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
-	// Glob all .h files under `From`
-	includePattern := headerGlobPattern(proptools.String(h.properties.From))
-	// Generate `cc_api_headers` target for Multi-tree API export
-	createCcApiHeadersTarget(ctx, []string{includePattern}, []string{}, h.properties.From)
+	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
@@ -299,7 +254,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(),
@@ -312,11 +267,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)
@@ -363,6 +318,7 @@
 
 	properties preprocessedHeadersProperties
 
+	srcPaths     android.Paths
 	installPaths android.Paths
 	licensePath  android.Path
 }
@@ -375,9 +331,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 f8a3559..183e818 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -25,15 +25,13 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/cc/config"
 )
 
 func init() {
 	pctx.HostBinToolVariable("ndkStubGenerator", "ndkstubgen")
-	pctx.HostBinToolVariable("abidiff", "abidiff")
-	pctx.HostBinToolVariable("abitidy", "abitidy")
-	pctx.HostBinToolVariable("abidw", "abidw")
+	pctx.HostBinToolVariable("stg", "stg")
+	pctx.HostBinToolVariable("stgdiff", "stgdiff")
 }
 
 var (
@@ -44,28 +42,26 @@
 			CommandDeps: []string{"$ndkStubGenerator"},
 		}, "arch", "apiLevel", "apiMap", "flags")
 
-	abidw = pctx.AndroidStaticRule("abidw",
+	// $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: "$abidw --type-id-style hash --no-corpus-path " +
-				"--no-show-locs --no-comp-dir-path -w $symbolList " +
-				"$in --out-file $out",
-			CommandDeps: []string{"$abidw"},
-		}, "symbolList")
+			Command:     "$stg -S :$symbolList --file-filter :$headersList --elf $in -o $out",
+			CommandDeps: []string{"$stg"},
+		}, "symbolList", "headersList")
 
-	abitidy = pctx.AndroidStaticRule("abitidy",
-		blueprint.RuleParams{
-			Command:     "$abitidy --all $flags -i $in -o $out",
-			CommandDeps: []string{"$abitidy"},
-		}, "flags")
-
-	abidiff = pctx.AndroidStaticRule("abidiff",
+	stgdiff = pctx.AndroidStaticRule("stgdiff",
 		blueprint.RuleParams{
 			// Need to create *some* output for ninja. We don't want to use tee
 			// 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:     "$abidiff $args $in > $out || (cat $out && false)",
-			CommandDeps: []string{"$abidiff"},
+			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")
 
 	ndkLibrarySuffix = ".ndk"
@@ -107,12 +103,6 @@
 	// https://github.com/android-ndk/ndk/issues/265.
 	Unversioned_until *string
 
-	// If true, does not emit errors when APIs lacking type information are
-	// found. This is false by default and should not be enabled outside bionic,
-	// where it is enabled pending a fix for http://b/190554910 (no debug info
-	// for asm implemented symbols).
-	Allow_untyped_symbols *bool
-
 	// Headers presented by this library to the Public API Surface
 	Export_header_libs []string
 }
@@ -326,7 +316,7 @@
 	apiLevel android.ApiLevel) android.OptionalPath {
 
 	subpath := filepath.Join("prebuilts/abi-dumps/ndk", apiLevel.String(),
-		ctx.Arch().ArchType.String(), this.libraryName(ctx), "abi.xml")
+		ctx.Arch().ArchType.String(), this.libraryName(ctx), "abi.stg")
 	return android.ExistentPathForSource(ctx, subpath)
 }
 
@@ -343,50 +333,32 @@
 		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) {
 	implementationLibrary := this.findImplementationLibrary(ctx)
-	abiRawPath := getNdkAbiDumpInstallBase(ctx).Join(ctx,
-		this.apiLevel.String(), ctx.Arch().ArchType.String(),
-		this.libraryName(ctx), "abi.raw.xml")
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        abidw,
-		Description: fmt.Sprintf("abidw %s", implementationLibrary),
-		Input:       implementationLibrary,
-		Output:      abiRawPath,
-		Implicit:    symbolList,
-		Args: map[string]string{
-			"symbolList": symbolList.String(),
-		},
-	})
-
 	this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx,
 		this.apiLevel.String(), ctx.Arch().ArchType.String(),
-		this.libraryName(ctx), "abi.xml")
-	untypedFlag := "--abort-on-untyped-symbols"
-	if proptools.BoolDefault(this.properties.Allow_untyped_symbols, false) {
-		untypedFlag = ""
-	}
+		this.libraryName(ctx), "abi.stg")
+	headersList := getNdkABIHeadersFile(ctx)
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        abitidy,
-		Description: fmt.Sprintf("abitidy %s", implementationLibrary),
-		Input:       abiRawPath,
-		Output:      this.abiDumpPath,
+		Rule:        stg,
+		Description: fmt.Sprintf("stg %s", implementationLibrary),
+		Input:       implementationLibrary,
+		Implicits: []android.Path{
+			symbolList,
+			headersList,
+		},
+		Output: this.abiDumpPath,
 		Args: map[string]string{
-			"flags": untypedFlag,
+			"symbolList":  symbolList.String(),
+			"headersList": headersList.String(),
 		},
 	})
 }
@@ -405,11 +377,13 @@
 func (this *stubDecorator) diffAbi(ctx ModuleContext) {
 	// Catch any ABI changes compared to the checked-in definition of this API
 	// level.
-	abiDiffPath := android.PathForModuleOut(ctx, "abidiff.timestamp")
+	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{
@@ -421,11 +395,14 @@
 		})
 	} else {
 		ctx.Build(pctx, android.BuildParams{
-			Rule: abidiff,
-			Description: fmt.Sprintf("abidiff %s %s", prebuiltAbiDump,
+			Rule: stgdiff,
+			Description: fmt.Sprintf("Comparing ABI %s %s", prebuiltAbiDump,
 				this.abiDumpPath),
 			Output: abiDiffPath,
 			Inputs: android.Paths{prebuiltAbiDump.Path(), this.abiDumpPath},
+			Args: map[string]string{
+				"args": "--format=small",
+			},
 		})
 	}
 	this.abiDiffPaths = append(this.abiDiffPaths, abiDiffPath)
@@ -433,7 +410,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 "+
@@ -442,23 +419,28 @@
 		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: abidiff,
-				Description: fmt.Sprintf("abidiff %s %s", this.abiDumpPath,
-					nextAbiDump),
+				Rule: stgdiff,
+				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": "--no-added-syms",
+					"args": "--format=small --ignore=interface_addition",
 				},
 			})
 		}
@@ -487,7 +469,7 @@
 	c.versionScriptPath = nativeAbiResult.versionScript
 	if canDumpAbi(ctx.Config()) {
 		c.dumpAbi(ctx, nativeAbiResult.symbolList)
-		if canDiffAbi() {
+		if canDiffAbi(ctx.Config()) {
 			c.diffAbi(ctx)
 		}
 	}
@@ -504,6 +486,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
 }
@@ -580,43 +568,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)
-}
-
-func ndkLibraryBp2build(ctx android.TopDownMutatorContext, m *Module) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_api_contribution",
-		Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl",
-	}
-	stubLibrary := m.compiler.(*stubDecorator)
-	attrs := &bazelCcApiContributionAttributes{
-		Library_name: stubLibrary.implementationModuleName(m.Name()),
-		Api_surfaces: bazel.MakeStringListAttribute(
-			[]string{android.PublicApi.String()}),
-	}
-	if symbolFile := stubLibrary.properties.Symbol_file; symbolFile != nil {
-		apiLabel := android.BazelLabelForModuleSrcSingle(ctx, proptools.String(symbolFile)).Label
-		attrs.Api = *bazel.MakeLabelAttribute(apiLabel)
-	}
-	apiHeaders := apiHeaderLabels(ctx, stubLibrary.properties.Export_header_libs)
-	attrs.Hdrs = bazel.MakeLabelListAttribute(apiHeaders)
-	apiContributionTargetName := android.ApiContributionTargetName(ctx.ModuleName())
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: apiContributionTargetName}, attrs)
-}
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index 1d15cf8..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,
@@ -113,14 +116,14 @@
 	ndk.libraryDecorator.flagExporter.setProvider(ctx)
 
 	if ndk.static() {
-		depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(lib).Build()
-		ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+		depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(lib).Build()
+		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 dffc6c6..483d23b 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -54,19 +54,19 @@
 
 import (
 	"android/soong/android"
+	"strings"
 )
 
 func init() {
 	RegisterNdkModuleTypes(android.InitRegistrationContext)
-	pctx.Import("android/soong/android")
 }
 
 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.RegisterSingletonType("ndk", NdkSingleton)
+	ctx.RegisterParallelSingletonType("ndk", NdkSingleton)
 }
 
 func getNdkInstallBase(ctx android.PathContext) android.InstallPath {
@@ -97,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) {
@@ -114,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)
 		}
@@ -176,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/object.go b/cc/object.go
index 5d61872..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"))
 }
@@ -309,6 +180,8 @@
 			})
 		}
 	} else {
+		outputAddrSig := android.PathForModuleOut(ctx, "addrsig", outputName)
+
 		if String(object.Properties.Prefix_symbols) != "" {
 			input := android.PathForModuleOut(ctx, "unprefixed", outputName)
 			transformBinaryPrefixSymbols(ctx, String(object.Properties.Prefix_symbols), input,
@@ -316,7 +189,12 @@
 			output = input
 		}
 
-		transformObjsToObj(ctx, objs.objFiles, builderFlags, output, flags.LdFlagsDeps)
+		transformObjsToObj(ctx, objs.objFiles, builderFlags, outputAddrSig, flags.LdFlagsDeps)
+
+		// ld -r reorders symbols and invalidates the .llvm_addrsig section, which then causes warnings
+		// if the resulting object is used with ld --icf=safe.  Strip the .llvm_addrsig section to
+		// prevent the warnings.
+		transformObjectNoAddrSig(ctx, outputAddrSig, output)
 	}
 
 	ctx.CheckbuildFile(outputFile)
@@ -341,6 +219,10 @@
 	return nil
 }
 
+func (object *objectLinker) strippedAllOutputFilePath() android.Path {
+	panic("Not implemented.")
+}
+
 func (object *objectLinker) nativeCoverage() bool {
 	return true
 }
@@ -356,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..c0d1331 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
@@ -43,11 +43,17 @@
 		{"android_arm64_armv8-a_sdk_current", "10000"},
 		{"android_vendor.29_arm64_armv8-a", "29"},
 	}
+
+	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 = prepareForCcTestWithoutVndk.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
new file mode 100644
index 0000000..38b8905
--- /dev/null
+++ b/cc/orderfile.go
@@ -0,0 +1,252 @@
+// 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.
+//
+// Note: If you want to know how to use orderfile for your binary or shared
+// library, you can go look at the README in toolchains/pgo-profiles/orderfiles
+
+package cc
+
+import (
+	"fmt"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+// Order files are text files containing symbols representing functions names.
+// Linkers (lld) uses order files to layout functions in a specific order.
+// These binaries with ordered symbols will reduce page faults and improve a program's launch time
+// due to the efficient loading of symbols during a program’s cold-start.
+var (
+	// Add flags to ignore warnings about symbols not be found
+	// or not allowed to be ordered
+	orderfileOtherFlags = []string{
+		"-Wl,--no-warn-symbol-ordering",
+	}
+
+	// Add folder projects for orderfiles
+	globalOrderfileProjects = []string{
+		"toolchain/pgo-profiles/orderfiles",
+		"vendor/google_data/pgo_profile/orderfiles",
+	}
+)
+
+var orderfileProjectsConfigKey = android.NewOnceKey("OrderfileProjects")
+
+const orderfileProfileFlag = "-forder-file-instrumentation"
+const orderfileUseFormat = "-Wl,--symbol-ordering-file=%s"
+
+func getOrderfileProjects(config android.DeviceConfig) []string {
+	return config.OnceStringSlice(orderfileProjectsConfigKey, func() []string {
+		return globalOrderfileProjects
+	})
+}
+
+func recordMissingOrderfile(ctx BaseModuleContext, missing string) {
+	getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
+}
+
+type OrderfileProperties struct {
+	Orderfile struct {
+		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"`
+}
+
+type orderfile struct {
+	Properties OrderfileProperties
+}
+
+func (props *OrderfileProperties) shouldInstrument() bool {
+	return Bool(props.Orderfile.Instrumentation)
+}
+
+// ShouldLoadOrderfile returns true if we need to load the order file rather than
+// profile the binary or shared library
+func (props *OrderfileProperties) shouldLoadOrderfile() bool {
+	return Bool(props.Orderfile.Load_order_file) && props.Orderfile.Order_file_path != nil
+}
+
+// orderfileEnabled returns true for binaries and shared libraries
+// if instrument flag is set to true
+func (orderfile *orderfile) orderfileEnabled() bool {
+	return orderfile != nil && orderfile.Properties.shouldInstrument()
+}
+
+// orderfileLinkEnabled returns true for binaries and shared libraries
+// if you should instrument dependencies
+func (orderfile *orderfile) orderfileLinkEnabled() bool {
+	return orderfile != nil && orderfile.Properties.OrderfileInstrLink
+}
+
+func (orderfile *orderfile) props() []interface{} {
+	return []interface{}{&orderfile.Properties}
+}
+
+// Get the path to the order file by checking it is valid and not empty
+func (props *OrderfileProperties) getOrderfile(ctx BaseModuleContext) android.OptionalPath {
+	orderFile := *props.Orderfile.Order_file_path
+
+	// Test if the order file is present in any of the Orderfile projects
+	for _, profileProject := range getOrderfileProjects(ctx.DeviceConfig()) {
+		path := android.ExistentPathForSource(ctx, profileProject, orderFile)
+		if path.Valid() {
+			return path
+		}
+	}
+
+	// Record that this module's order file is absent
+	missing := *props.Orderfile.Order_file_path + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
+	recordMissingOrderfile(ctx, missing)
+
+	return android.OptionalPath{}
+}
+
+func (props *OrderfileProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
+	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...)
+	return flags
+}
+
+func (props *OrderfileProperties) addLoadFlags(ctx ModuleContext, flags Flags) Flags {
+	orderFile := props.getOrderfile(ctx)
+	orderFilePath := orderFile.Path()
+	loadFlags := props.loadOrderfileFlags(ctx, orderFilePath.String())
+
+	flags.Local.LdFlags = append(flags.Local.LdFlags, loadFlags...)
+
+	// Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
+	// if orderfile gets updated
+	flags.CFlagsDeps = append(flags.CFlagsDeps, orderFilePath)
+	flags.LdFlagsDeps = append(flags.LdFlagsDeps, orderFilePath)
+	return flags
+}
+
+func (orderfile *orderfile) begin(ctx BaseModuleContext) {
+	// Currently, we are not enabling orderfiles for host
+	if ctx.Host() {
+		return
+	}
+
+	// Currently, we are not enabling orderfiles to begin from static libraries
+	if ctx.static() && !ctx.staticBinary() {
+		return
+	}
+
+	if ctx.DeviceConfig().ClangCoverageEnabled() {
+		return
+	}
+
+	// Checking if orderfile is enabled for this module
+	if !orderfile.orderfileEnabled() {
+		return
+	}
+
+	orderfile.Properties.OrderfileLoad = orderfile.Properties.shouldLoadOrderfile()
+	orderfile.Properties.ShouldProfileModule = !orderfile.Properties.shouldLoadOrderfile()
+	orderfile.Properties.OrderfileInstrLink = orderfile.orderfileEnabled() && !orderfile.Properties.shouldLoadOrderfile()
+}
+
+func (orderfile *orderfile) flags(ctx ModuleContext, flags Flags) Flags {
+	props := orderfile.Properties
+	// Add flags to load the orderfile using the path in its Android.bp
+	if orderfile.Properties.OrderfileLoad {
+		flags = props.addLoadFlags(ctx, flags)
+		return flags
+	}
+
+	// Add flags to profile this module
+	if props.ShouldProfileModule {
+		flags = props.addInstrumentationProfileGatherFlags(ctx, flags)
+		return flags
+	}
+
+	return flags
+}
+
+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
+	}
+}
+
+// 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 ""
+		}
+
+		if sourceVariation != "" {
+			return sourceVariation
+		}
+
+		// 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
new file mode 100644
index 0000000..3486f96
--- /dev/null
+++ b/cc/orderfile_test.go
@@ -0,0 +1,470 @@
+// 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 cc
+
+import (
+	"strings"
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestOrderfileProfileSharedLibrary(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_library_shared {
+		name: "libTest",
+		srcs: ["test.c"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: false,
+			order_file_path: "",
+		},
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-forder-file-instrumentation"
+
+	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 enable 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) {
+		t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags)
+	}
+}
+
+func TestOrderfileLoadSharedLibrary(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_library_shared {
+		name: "libTest",
+		srcs: ["test.c"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: true,
+			order_file_path: "libTest.orderfile",
+		},
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+		android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/libTest.orderfile", "TEST"),
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/libTest.orderfile"
+
+	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+
+	// Check ldFlags of orderfile-enabled module
+	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)
+	}
+}
+
+func TestOrderfileProfileBinary(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_binary {
+		name: "test",
+		srcs: ["test.c"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: false,
+			order_file_path: "",
+		},
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-forder-file-instrumentation"
+
+	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 enable 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) {
+		t.Errorf("Expected 'test' to enable orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags)
+	}
+}
+
+func TestOrderfileLoadBinary(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_binary {
+		name: "test",
+		srcs: ["test.c"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: true,
+			order_file_path: "test.orderfile",
+		},
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+		android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/test.orderfile", "TEST"),
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/test.orderfile"
+
+	test := result.ModuleForTests("test", "android_arm64_armv8-a")
+
+	// Check ldFlags of orderfile-enabled module
+	ldFlags := test.Rule("ld").Args["ldFlags"]
+	if !strings.Contains(ldFlags, expectedCFlag) {
+		t.Errorf("Expected 'test' to load orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags)
+	}
+}
+
+// Profile flags should propagate through static libraries
+func TestOrderfileProfilePropagateStaticDeps(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_library_shared {
+		name: "libTest",
+		srcs: ["test.c"],
+		static_libs: ["libFoo"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: false,
+			order_file_path: "",
+		},
+	}
+
+	cc_library_static {
+		name: "libFoo",
+		srcs: ["foo.c"],
+		static_libs: ["libBar"],
+	}
+
+	cc_library_static {
+		name: "libBar",
+		srcs: ["bar.c"],
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-forder-file-instrumentation"
+
+	// Check cFlags 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 enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// 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")
+
+	cFlags = libFooOfVariant.Rule("cc").Args["cFlags"]
+	if !strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libFooOfVariant' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	cFlags = libBarOfVariant.Rule("cc").Args["cFlags"]
+	if !strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libBarOfVariant' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check dependency edge from orderfile-enabled module to orderfile variant static libraries
+	if !hasDirectDep(result, libTest.Module(), libFooOfVariant.Module()) {
+		t.Errorf("libTest missing dependency on orderfile variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFooOfVariant.Module(), libBarOfVariant.Module()) {
+		t.Errorf("libTest missing dependency on orderfile variant of libBar")
+	}
+
+	// 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' to not enable 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' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check no dependency edge from orderfile-enabled module to non-orderfile variant static libraries
+	if hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+		t.Errorf("libTest has dependency on non-orderfile variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+		t.Errorf("libTest has dependency on non-orderfile variant of libBar")
+	}
+}
+
+// Load flags should never propagate
+func TestOrderfileLoadPropagateStaticDeps(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_library_shared {
+		name: "libTest",
+		srcs: ["test.c"],
+		static_libs: ["libFoo"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: true,
+			order_file_path: "test.orderfile",
+		},
+	}
+
+	cc_library_static {
+		name: "libFoo",
+		srcs: ["foo.c"],
+		static_libs: ["libBar"],
+	}
+
+	cc_library_static {
+		name: "libBar",
+		srcs: ["bar.c"],
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+		android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/test.orderfile", "TEST"),
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/test.orderfile"
+
+	// Check ldFlags of orderfile-enabled module
+	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+
+	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)
+	}
+
+	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()) {
+		t.Errorf("libTest missing dependency on non-orderfile variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+		t.Errorf("libTest missing dependency on non-orderfile variant of libBar")
+	}
+
+	// Make sure no orderfile variants are created for static libraries because the flags were not propagated
+	libFooVariants := result.ModuleVariantsForTests("libFoo")
+	for _, v := range libFooVariants {
+		if strings.Contains(v, "orderfile") {
+			t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v)
+		}
+	}
+
+	libBarVariants := result.ModuleVariantsForTests("libBar")
+	for _, v := range libBarVariants {
+		if strings.Contains(v, "orderfile") {
+			t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v)
+		}
+	}
+}
+
+// Profile flags should not propagate through shared libraries
+func TestOrderfileProfilePropagateSharedDeps(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_library_shared {
+		name: "libTest",
+		srcs: ["test.c"],
+		shared_libs: ["libFoo"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: false,
+			order_file_path: "",
+		},
+	}
+
+	cc_library_shared {
+		name: "libFoo",
+		srcs: ["foo.c"],
+		static_libs: ["libBar"],
+	}
+
+	cc_library_static {
+		name: "libBar",
+		srcs: ["bar.c"],
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-forder-file-instrumentation"
+
+	// Check cFlags 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 enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// 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")
+
+	cFlags = libFoo.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libFoo' to not enable 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' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check dependency edge from orderfile-enabled module to non-orderfile variant static libraries
+	if !hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+		t.Errorf("libTest missing dependency on non-orderfile variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+		t.Errorf("libTest missing dependency on non-orderfile variant of libBar")
+	}
+
+	// Make sure no orderfile variants are created for libraries because the flags were not propagated
+	libFooVariants := result.ModuleVariantsForTests("libFoo")
+	for _, v := range libFooVariants {
+		if strings.Contains(v, "orderfile") {
+			t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v)
+		}
+	}
+
+	libBarVariants := result.ModuleVariantsForTests("libBar")
+	for _, v := range libBarVariants {
+		if strings.Contains(v, "orderfile") {
+			t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v)
+		}
+	}
+}
+
+// Profile flags should not work or be propagated if orderfile flags start at a static library
+func TestOrderfileProfileStaticLibrary(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_library_static {
+		name: "libTest",
+		srcs: ["test.c"],
+		static_libs: ["libFoo"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: false,
+			order_file_path: "",
+		},
+	}
+
+	cc_library_static {
+		name: "libFoo",
+		srcs: ["foo.c"],
+		static_libs: ["libBar"],
+	}
+
+	cc_library_static {
+		name: "libBar",
+		srcs: ["bar.c"],
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-forder-file-instrumentation"
+
+	// Check cFlags of module
+	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_static")
+
+	cFlags := libTest.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libTest' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check cFlags of the 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' to not enable 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' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check dependency edge from orderfile-enabled module to non-orderfile variant libraries
+	if !hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+		t.Errorf("libTest missing dependency on non-orderfile variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+		t.Errorf("libTest missing dependency on non-orderfile variant of libBar")
+	}
+
+	// Make sure no orderfile variants are created for static libraries because the flags were not propagated
+	libFooVariants := result.ModuleVariantsForTests("libFoo")
+	for _, v := range libFooVariants {
+		if strings.Contains(v, "orderfile") {
+			t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v)
+		}
+	}
+
+	libBarVariants := result.ModuleVariantsForTests("libBar")
+	for _, v := range libBarVariants {
+		if strings.Contains(v, "orderfile") {
+			t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v)
+		}
+	}
+}
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 44cd0d7..8f4b7df 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 {
@@ -140,8 +139,8 @@
 		}
 
 		if p.static() {
-			depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(in).Build()
-			ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+			depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(in).Build()
+			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,6 @@
 
 func (p *prebuiltLibraryLinker) disablePrebuilt() {
 	p.properties.Srcs = nil
-	p.properties.MixedBuildsDisabled = true
 }
 
 // Implements versionedInterface
@@ -272,8 +270,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 +344,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 +359,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.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 +392,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 +403,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 +496,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 +512,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 +536,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..95fb7ed 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,99 @@
 	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 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])
+	}
 }
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 fbc86e2..b0d759b 100644
--- a/cc/rs.go
+++ b/cc/rs.go
@@ -15,11 +15,11 @@
 package cc
 
 import (
-	"android/soong/android"
 	"path/filepath"
 	"runtime"
 	"strings"
 
+	"android/soong/android"
 	"github.com/google/blueprint"
 )
 
@@ -100,11 +100,12 @@
 func rsFlags(ctx ModuleContext, flags Flags, properties *BaseCompilerProperties) Flags {
 	targetApi := String(properties.Renderscript.Target_api)
 	if targetApi == "" && ctx.useSdk() {
-		switch ctx.sdkVersion() {
-		case "current", "system_current", "test_current":
-			// Nothing
-		default:
-			targetApi = android.GetNumericSdkVersion(ctx.sdkVersion())
+		targetApiLevel := android.ApiLevelOrPanic(ctx, ctx.sdkVersion())
+		if targetApiLevel.IsCurrent() || targetApiLevel.IsPreview() {
+			// If the target level is current or preview, leave the 'target-api' unset.
+			// This signals to llvm-rs-cc that the development API should be used.
+		} else {
+			targetApi = targetApiLevel.String()
 		}
 	}
 
diff --git a/cc/sabi.go b/cc/sabi.go
index 4cd776a..9f5781f 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -105,30 +105,17 @@
 	if headerAbiChecker.explicitlyDisabled() {
 		return ""
 	}
-	// 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() {
+		// Return NDK if the library is both NDK and LLNDK.
+		if m.IsNdk(ctx.Config()) {
+			return "NDK"
 		}
-	}
-	if m.library.hasStubsVariants() && !m.InProduct() && !m.InVendor() {
-		return "PLATFORM"
+		if m.isImplementationForLLNDKPublic() {
+			return "LLNDK"
+		}
+		if m.library.hasStubsVariants() {
+			return "PLATFORM"
+		}
 	}
 	if headerAbiChecker.enabled() {
 		if m.InProduct() {
@@ -194,8 +181,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.
diff --git a/cc/sanitize.go b/cc/sanitize.go
index e28f537..52b5be9 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -38,11 +38,11 @@
 	}
 	asanLdflags = []string{"-Wl,-u,__asan_preinit"}
 
+	// DO NOT ADD MLLVM FLAGS HERE! ADD THEM BELOW TO hwasanCommonFlags.
 	hwasanCflags = []string{
 		"-fno-omit-frame-pointer",
 		"-Wno-frame-larger-than=",
 		"-fsanitize-hwaddress-abi=platform",
-		"-mllvm", "-hwasan-use-after-scope=1",
 	}
 
 	// ThinLTO performs codegen during link time, thus these flags need to
@@ -56,21 +56,22 @@
 		// higher number of "optimized out" stack variables.
 		// b/112437883.
 		"-instcombine-lower-dbg-declare=0",
-		// TODO(b/159343917): HWASan and GlobalISel don't play nicely, and
-		// GlobalISel is the default at -O0 on aarch64.
-		"--aarch64-enable-global-isel-at-O=-1",
-		"-fast-isel=false",
+		"-hwasan-use-after-scope=1",
+		"-dom-tree-reachability-max-bbs-to-explore=128",
 	}
 
+	sanitizeIgnorelistPrefix = "-fsanitize-ignorelist="
+
 	cfiBlocklistPath     = "external/compiler-rt/lib/cfi"
 	cfiBlocklistFilename = "cfi_blocklist.txt"
+	cfiEnableFlag        = "-fsanitize=cfi"
 	cfiCrossDsoFlag      = "-fsanitize-cfi-cross-dso"
 	cfiCflags            = []string{"-flto", cfiCrossDsoFlag,
-		"-fsanitize-ignorelist=" + cfiBlocklistPath + "/" + cfiBlocklistFilename}
+		sanitizeIgnorelistPrefix + cfiBlocklistPath + "/" + cfiBlocklistFilename}
 	// -flto and -fvisibility are required by clang when -fsanitize=cfi is
 	// used, but have no effect on assembly files
 	cfiAsflags = []string{"-flto", "-fvisibility=default"}
-	cfiLdflags = []string{"-flto", cfiCrossDsoFlag, "-fsanitize=cfi",
+	cfiLdflags = []string{"-flto", cfiCrossDsoFlag, cfiEnableFlag,
 		"-Wl,-plugin-opt,O1"}
 	cfiExportsMapPath      = "build/soong/cc/config"
 	cfiExportsMapFilename  = "cfi_exports.map"
@@ -85,7 +86,9 @@
 	memtagStackCommonFlags = []string{"-march=armv8-a+memtag", "-mllvm", "-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"
 )
 
 type SanitizerType int
@@ -406,13 +409,16 @@
 	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 by transitions.
-	exportedVars.ExportStringList("CfiCFlags", cfiCflags[2:])
+	// 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)
@@ -420,6 +426,8 @@
 	exportedVars.ExportString("CfiExportsMapFilename", cfiExportsMapFilename)
 	exportedVars.ExportString("CfiAssemblySupportFlag", cfiAssemblySupportFlag)
 
+	exportedVars.ExportString("NoSanitizeLinkRuntimeFlag", noSanitizeLinkRuntimeFlag)
+
 	android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider)
 	android.RegisterMakeVarsProvider(pctx, hwasanMakeVarsProvider)
 }
@@ -545,7 +553,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 {
@@ -640,10 +650,6 @@
 	if (ctx.Arch().ArchType != android.Arm64 && ctx.Arch().ArchType != android.Riscv64) || !ctx.toolchain().Bionic() {
 		s.Scs = nil
 	}
-	// ...but temporarily globally disabled on riscv64 (http://b/277909695).
-	if ctx.Arch().ArchType == android.Riscv64 {
-		s.Scs = nil
-	}
 
 	// Memtag_heap is only implemented on AArch64.
 	// Memtag ABI is Android specific for now, so disable for host.
@@ -673,18 +679,27 @@
 		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
 		s.Diag.Cfi = nil
 	}
 
+	// TODO(b/280478629): runtimes don't exist for musl arm64 yet.
+	if ctx.toolchain().Musl() && ctx.Arch().ArchType == android.Arm64 {
+		s.Address = nil
+		s.Hwaddress = nil
+		s.Thread = nil
+		s.Scudo = nil
+		s.Fuzzer = nil
+		s.Cfi = nil
+		s.Diag.Cfi = nil
+		s.Misc_undefined = nil
+		s.Undefined = nil
+		s.All_undefined = nil
+		s.Integer_overflow = nil
+	}
+
 	// Also disable CFI for VNDK variants of components
 	if ctx.isVndk() && ctx.useVndk() {
 		s.Cfi = nil
@@ -884,13 +899,8 @@
 
 	if Bool(sanProps.Memtag_stack) {
 		flags.Local.CFlags = append(flags.Local.CFlags, memtagStackCommonFlags...)
-		// TODO(fmayer): remove -Wno-error once https://reviews.llvm.org/D127917 is in Android toolchain.
-		flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-error=frame-larger-than")
 		flags.Local.AsFlags = append(flags.Local.AsFlags, memtagStackCommonFlags...)
 		flags.Local.LdFlags = append(flags.Local.LdFlags, memtagStackCommonFlags...)
-		// This works around LLD complaining about the stack frame size.
-		// TODO(fmayer): remove once https://reviews.llvm.org/D127917 is in Android toolchain.
-		flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--no-fatal-warnings")
 	}
 
 	if (Bool(sanProps.Memtag_heap) || Bool(sanProps.Memtag_stack) || Bool(sanProps.Memtag_globals)) && ctx.binary() {
@@ -915,7 +925,7 @@
 			// Bionic and musl sanitizer runtimes have already been added as dependencies so that
 			// the right variant of the runtime will be used (with the "-android" or "-musl"
 			// suffixes), so don't let clang the runtime library.
-			flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-sanitize-link-runtime")
+			flags.Local.LdFlags = append(flags.Local.LdFlags, noSanitizeLinkRuntimeFlag)
 		} else {
 			// Host sanitizers only link symbols in the final executable, so
 			// there will always be undefined symbols in intermediate libraries.
@@ -970,7 +980,7 @@
 
 	blocklist := android.OptionalPathForModuleSrc(ctx, s.Properties.Sanitize.Blocklist)
 	if blocklist.Valid() {
-		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-ignorelist="+blocklist.String())
+		flags.Local.CFlags = append(flags.Local.CFlags, sanitizeIgnorelistPrefix+blocklist.String())
 		flags.CFlagsDeps = append(flags.CFlagsDeps, blocklist.Path())
 	}
 
@@ -1103,12 +1113,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
 }
 
@@ -1175,7 +1188,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
 			}
 		})
@@ -1229,12 +1242,10 @@
 		}
 	}
 
-	if c, ok := ctx.Module().(*Module); ok {
-		//TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable
-
+	if c, ok := ctx.Module().(LinkableInterface); ok {
 		// Check if it's a snapshot module supporting sanitizer
-		if ss, ok := c.linker.(snapshotSanitizer); ok {
-			if ss.isSanitizerAvailable(s.sanitizer) {
+		if c.IsSnapshotSanitizer() {
+			if c.IsSnapshotSanitizerAvailable(s.sanitizer) {
 				return []string{"", s.sanitizer.variationName()}
 			} else {
 				return []string{""}
@@ -1266,8 +1277,8 @@
 
 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) {
+		if dm, ok := ctx.Module().(LinkableInterface); ok {
+			if dm.IsSnapshotSanitizerAvailable(s.sanitizer) {
 				return incomingVariation
 			}
 		}
@@ -1382,19 +1393,19 @@
 		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() {
+	} else if c, ok := mctx.Module().(LinkableInterface); ok {
+		if c.IsSnapshotSanitizerAvailable(s.sanitizer) {
+			if !c.IsSnapshotUnsanitizedVariant() {
 				// 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)
+			c.SetSnapshotSanitizerVariation(s.sanitizer, sanitizerVariation)
 
 			// Export the static lib name to make
-			if c.static() && c.ExportedToMake() {
+			if c.Static() && c.ExportedToMake() {
 				// use BaseModuleName which is the name for Make.
 				if s.sanitizer == cfi {
 					cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName())
@@ -1406,6 +1417,35 @@
 	}
 }
 
+func (c *Module) IsSnapshotSanitizer() bool {
+	if _, ok := c.linker.(SnapshotSanitizer); ok {
+		return true
+	}
+	return false
+}
+
+func (c *Module) IsSnapshotSanitizerAvailable(t SanitizerType) bool {
+	if ss, ok := c.linker.(SnapshotSanitizer); ok {
+		return ss.IsSanitizerAvailable(t)
+	}
+	return false
+}
+
+func (c *Module) SetSnapshotSanitizerVariation(t SanitizerType, enabled bool) {
+	if ss, ok := c.linker.(SnapshotSanitizer); ok {
+		ss.SetSanitizerVariation(t, enabled)
+	} else {
+		panic(fmt.Errorf("Calling SetSnapshotSanitizerVariation on a non-snapshotLibraryDecorator: %s", c.Name()))
+	}
+}
+
+func (c *Module) IsSnapshotUnsanitizedVariant() bool {
+	if ss, ok := c.linker.(SnapshotSanitizer); ok {
+		return ss.IsUnsanitizedVariant()
+	}
+	return false
+}
+
 func (c *Module) SanitizeNever() bool {
 	return Bool(c.sanitize.Properties.SanitizeMutated.Never)
 }
@@ -1587,7 +1627,7 @@
 
 		addStaticDeps := func(dep string, hideSymbols bool) {
 			// If we're using snapshots, redirect to snapshot whenever possible
-			snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo)
+			snapshot, _ := android.ModuleProvider(mctx, SnapshotInfoProvider)
 			if lib, ok := snapshot.StaticLibs[dep]; ok {
 				dep = lib
 			}
@@ -1636,12 +1676,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 {
@@ -1674,7 +1714,7 @@
 				addStaticDeps(runtimeSharedLibrary, true)
 			} else if !c.static() && !c.Header() {
 				// If we're using snapshots, redirect to snapshot whenever possible
-				snapshot := mctx.Provider(SnapshotInfoProvider).(SnapshotInfo)
+				snapshot, _ := android.ModuleProvider(mctx, SnapshotInfoProvider)
 				if lib, ok := snapshot.SharedLibs[runtimeSharedLibrary]; ok {
 					runtimeSharedLibrary = lib
 				}
@@ -1871,7 +1911,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/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index bb6e257..e769fe9 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -100,6 +100,7 @@
 	snapshotBinarySuffix = "_binary."
 	snapshotObjectSuffix = "_object."
 	SnapshotRlibSuffix   = "_rlib."
+	SnapshotDylibSuffix  = "_dylib."
 )
 
 type SnapshotProperties struct {
@@ -107,6 +108,7 @@
 	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"`
@@ -186,26 +188,28 @@
 	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{
+	android.SetProvider(ctx, 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 map[string]string
+	HeaderLibs, Binaries, Objects, StaticLibs, SharedLibs, Rlibs, Dylibs map[string]string
 }
 
-var SnapshotInfoProvider = blueprint.NewMutatorProvider(SnapshotInfo{}, "deps")
+var SnapshotInfoProvider = blueprint.NewMutatorProvider[SnapshotInfo]("deps")
 
 var _ android.ImageInterface = (*snapshotModule)(nil)
 
@@ -399,11 +403,11 @@
 	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 SnapshotSanitizer interface {
+	IsSanitizerAvailable(t SanitizerType) bool
+	SetSanitizerVariation(t SanitizerType, enabled bool)
+	IsSanitizerEnabled(t SanitizerType) bool
+	IsUnsanitizedVariant() bool
 }
 
 type snapshotLibraryDecorator struct {
@@ -456,9 +460,9 @@
 		return p.libraryDecorator.link(ctx, flags, deps, objs)
 	}
 
-	if p.isSanitizerEnabled(cfi) {
+	if p.IsSanitizerEnabled(cfi) {
 		p.properties = p.sanitizerProperties.Cfi
-	} else if p.isSanitizerEnabled(Hwasan) {
+	} else if p.IsSanitizerEnabled(Hwasan) {
 		p.properties = p.sanitizerProperties.Hwasan
 	}
 
@@ -490,7 +494,7 @@
 		p.tocFile = android.OptionalPathForPath(tocFile)
 		TransformSharedObjectToToc(ctx, in, tocFile)
 
-		ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+		android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
 			SharedLibrary: in,
 			Target:        ctx.Target(),
 
@@ -499,8 +503,8 @@
 	}
 
 	if p.static() {
-		depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(in).Build()
-		ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+		depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(in).Build()
+		android.SetProvider(ctx, StaticLibraryInfoProvider, StaticLibraryInfo{
 			StaticLibrary: in,
 
 			TransitiveStaticLibrariesForOrdering: depSet,
@@ -522,9 +526,9 @@
 	return false
 }
 
-var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil)
+var _ SnapshotSanitizer = (*snapshotLibraryDecorator)(nil)
 
-func (p *snapshotLibraryDecorator) isSanitizerAvailable(t SanitizerType) bool {
+func (p *snapshotLibraryDecorator) IsSanitizerAvailable(t SanitizerType) bool {
 	switch t {
 	case cfi:
 		return p.sanitizerProperties.Cfi.Src != nil
@@ -535,23 +539,23 @@
 	}
 }
 
-func (p *snapshotLibraryDecorator) setSanitizerVariation(t SanitizerType, enabled bool) {
-	if !enabled || p.isSanitizerEnabled(t) {
+func (p *snapshotLibraryDecorator) SetSanitizerVariation(t SanitizerType, enabled bool) {
+	if !enabled || p.IsSanitizerEnabled(t) {
 		return
 	}
-	if !p.isUnsanitizedVariant() {
+	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 {
+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 (p *snapshotLibraryDecorator) IsUnsanitizedVariant() bool {
+	return !p.IsSanitizerEnabled(Asan) &&
+		!p.IsSanitizerEnabled(Hwasan)
 }
 
 func snapshotLibraryFactory(image SnapshotImage, moduleSuffix string) (*Module, *snapshotLibraryDecorator) {
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index cf4617d..1ee120e 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -57,6 +57,14 @@
 	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
diff --git a/cc/stl.go b/cc/stl.go
index f1433ef..63c23d7 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -80,8 +80,7 @@
 			return ""
 		}
 		s = deduplicateStlInput(s)
-		archHasNDKStl := ctx.Arch().ArchType != android.Riscv64
-		if ctx.useSdk() && ctx.Device() && archHasNDKStl {
+		if ctx.useSdk() && ctx.Device() {
 			switch s {
 			case "", "system":
 				return "ndk_system"
@@ -120,11 +119,6 @@
 	}()
 }
 
-func needsLibAndroidSupport(ctx BaseModuleContext) bool {
-	version := nativeApiLevelOrPanic(ctx, ctx.sdkVersion())
-	return version.LessThan(android.FirstNonLibAndroidSupportVersion)
-}
-
 func staticUnwinder(ctx android.BaseModuleContext) string {
 	vndkVersion := ctx.Module().(*Module).VndkVersion()
 
@@ -140,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++":
@@ -178,17 +170,13 @@
 		// 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)
 		} else {
 			deps.StaticLibs = append(deps.StaticLibs, stl.Properties.SelectedStl, "ndk_libc++abi")
 		}
-		if needsLibAndroidSupport(ctx) {
-			// Use LateStaticLibs for ndk_libandroid_support so that its include directories
-			// come after ndk_libc++_static or ndk_libc++_shared.
-			deps.LateStaticLibs = append(deps.LateStaticLibs, "ndk_libandroid_support")
-		}
 		deps.StaticLibs = append(deps.StaticLibs, "ndk_libunwind")
 	default:
 		panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl))
@@ -197,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":
@@ -230,8 +216,7 @@
 	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 f324dcc..47c6cb9 100644
--- a/cc/stub_library.go
+++ b/cc/stub_library.go
@@ -23,11 +23,12 @@
 
 func init() {
 	// Use singleton type to gather all generated soong modules.
-	android.RegisterSingletonType("stublibraries", stubLibrariesSingleton)
+	android.RegisterParallelSingletonType("stublibraries", stubLibrariesSingleton)
 }
 
 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..345e9f9 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
@@ -136,6 +145,8 @@
 
 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('introduced='):
         return True
     if tag.startswith('introduced-'):
@@ -170,6 +181,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)
diff --git a/cc/symbolfile/test_symbolfile.py b/cc/symbolfile/test_symbolfile.py
index 856b9d7..83becc2 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'),
@@ -425,13 +435,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 +449,11 @@
         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)
 
         expected_symbols = [
             Symbol('baz', Tags()),
-            Symbol('qux', Tags.from_strs(['woodly', 'doodly'])),
+            Symbol('qux', Tags.from_strs(['apex', 'llndk'])),
         ]
         self.assertEqual(expected_symbols, version.symbols)
 
@@ -476,7 +486,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 +498,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 +547,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 +564,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'])),
                 ]),
         ]
 
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 4b3db01..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()
 }
 
@@ -164,7 +161,7 @@
 
 // cc_test_host compiles a test host binary.
 func TestHostFactory() android.Module {
-	module := NewTest(android.HostSupported, true)
+	module := NewTest(android.HostSupported)
 	return module.Init()
 }
 
@@ -268,7 +265,7 @@
 	return BoolDefault(test.LinkerProperties.Gtest, true)
 }
 
-func (test *testDecorator) isolated(ctx BaseModuleContext) bool {
+func (test *testDecorator) isolated(ctx android.EarlyModuleContext) bool {
 	return BoolDefault(test.LinkerProperties.Isolated, false)
 }
 
@@ -324,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)
 }
@@ -358,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()...)
 }
@@ -394,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,
@@ -424,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)
 }
 
@@ -436,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"})
@@ -484,9 +523,8 @@
 	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()
@@ -532,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()...)
 }
@@ -548,7 +595,6 @@
 	}
 	module.linker = test
 	module.installer = test
-	module.bazelable = true
 	return module
 }
 
@@ -582,7 +628,7 @@
 type benchmarkDecorator struct {
 	*binaryDecorator
 	Properties BenchmarkProperties
-	data       android.Paths
+	data       []android.DataPath
 	testConfig android.Path
 }
 
@@ -603,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) {
@@ -621,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)
 
@@ -636,116 +708,3 @@
 	module.installer = benchmark
 	return module
 }
-
-type ccTestBazelHandler struct {
-	module *Module
-}
-
-var _ BazelHandler = (*ccTestBazelHandler)(nil)
-
-func (handler *ccTestBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(label, cquery.GetCcUnstrippedInfo, android.GetConfigKey(ctx))
-}
-
-func (handler *ccTestBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
-	bazelCtx := ctx.Config().BazelContext
-	info, err := bazelCtx.GetCcUnstrippedInfo(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
-	Isolated 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)
-
-	for _, propIntf := range m.GetProperties() {
-		if testLinkerProps, ok := propIntf.(*TestLinkerProperties); ok {
-			testBinaryAttrs.Gtest = proptools.BoolDefault(testLinkerProps.Gtest, true)
-			testBinaryAttrs.Isolated = proptools.BoolDefault(testLinkerProps.Isolated, true)
-			break
-		}
-	}
-
-	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, testBinaryAttrs.Isolated),
-				&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)
-}
diff --git a/cc/testing.go b/cc/testing.go
index ced0929..bac41e7 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -35,13 +35,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 {
@@ -82,6 +83,10 @@
 			sanitize: {
 				never: true,
 			},
+			apex_available: [
+				"//apex_available:anyapex",
+				"//apex_available:platform",
+			],
 		}
 
 		cc_prebuilt_library_static {
@@ -419,11 +424,6 @@
 			export_include_dirs: ["ndk_libc++_shared"],
 		}
 
-		ndk_prebuilt_static_stl {
-			name: "ndk_libandroid_support",
-			export_include_dirs: ["ndk_libandroid_support"],
-		}
-
 		cc_library_static {
 			name: "libgoogle-benchmark",
 			sdk_version: "current",
@@ -559,7 +559,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(),
 )
 
@@ -569,16 +569,16 @@
 
 	// Additional files needed in tests that disallow non-existent source.
 	android.MockFS{
-		"defaults/cc/common/libc.map.txt":           nil,
-		"defaults/cc/common/libdl.map.txt":          nil,
-		"defaults/cc/common/libm.map.txt":           nil,
-		"defaults/cc/common/ndk_libandroid_support": nil,
-		"defaults/cc/common/ndk_libc++_shared":      nil,
-		"defaults/cc/common/crtbegin_so.c":          nil,
-		"defaults/cc/common/crtbegin.c":             nil,
-		"defaults/cc/common/crtend_so.c":            nil,
-		"defaults/cc/common/crtend.c":               nil,
-		"defaults/cc/common/crtbrand.c":             nil,
+		"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,
+		"defaults/cc/common/crtbegin.c":        nil,
+		"defaults/cc/common/crtend_so.c":       nil,
+		"defaults/cc/common/crtend.c":          nil,
+		"defaults/cc/common/crtbrand.c":        nil,
 
 		"defaults/cc/common/libclang_rt.ubsan_minimal.android_arm64.a": nil,
 		"defaults/cc/common/libclang_rt.ubsan_minimal.android_arm.a":   nil,
@@ -673,7 +673,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.
@@ -798,7 +798,7 @@
 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)
+	content := android.ContentFromFileRuleForTests(t, ctx, out)
 
 	var flags snapshotJsonFlags
 	if err := json.Unmarshal([]byte(content), &flags); err != nil {
diff --git a/cc/tidy.go b/cc/tidy.go
index bbcaece..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)
@@ -201,7 +200,7 @@
 }
 
 func init() {
-	android.RegisterSingletonType("tidy_phony_targets", TidyPhonySingleton)
+	android.RegisterParallelSingletonType("tidy_phony_targets", TidyPhonySingleton)
 }
 
 // This TidyPhonySingleton generates both tidy-* and obj-* phony targets for C/C++ files.
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 6d8ac43..c93646b 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -28,8 +28,8 @@
 	return android.JoinWithPrefix(dirs.Strings(), "-I")
 }
 
-var indexList = android.IndexList
-var inList = android.InList
+var indexList = android.IndexList[string]
+var inList = android.InList[string]
 var filterList = android.FilterList
 var removeListFromList = android.RemoveListFromList
 var removeFromList = android.RemoveFromList
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index d2531c0..a33ed5f 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -98,6 +98,11 @@
 			if !sanitizable.Shared() && sanitizable.IsSanitizerEnabled(scs) {
 				return false
 			}
+			// cfi and hwasan cannot be enabled at the same time.
+			// Skip variants that have both cfi and hwasan enabled.
+			if sanitizable.IsSanitizerEnabled(cfi) && sanitizable.IsSanitizerEnabled(Hwasan) {
+				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.
@@ -108,10 +113,10 @@
 				return false
 			}
 		}
-		if sanitizable.Static() {
+		if sanitizable.Static() || sanitizable.Rlib() {
 			return sanitizable.OutputFile().Valid() && !isPrivate(image, m)
 		}
-		if sanitizable.Shared() || sanitizable.Rlib() {
+		if sanitizable.Shared() || sanitizable.Dylib() {
 			if !sanitizable.OutputFile().Valid() {
 				return false
 			}
@@ -153,6 +158,8 @@
 	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"`
@@ -268,7 +275,7 @@
 		var propOut string
 
 		if m.IsSnapshotLibrary() {
-			exporterInfo := ctx.ModuleProvider(m.Module(), FlagExporterInfoProvider).(FlagExporterInfo)
+			exporterInfo, _ := android.SingletonModuleProvider(ctx, m.Module(), FlagExporterInfoProvider)
 
 			// library flags
 			prop.ExportedFlags = exporterInfo.Flags
@@ -283,8 +290,17 @@
 			if m.Shared() {
 				prop.SharedLibs = m.SnapshotSharedLibs()
 			}
-			// static libs dependencies are required to collect the NOTICE files.
+
+			// 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()
@@ -299,13 +315,15 @@
 				libType = "shared"
 			} else if m.Rlib() {
 				libType = "rlib"
+			} else if m.Dylib() {
+				libType = "dylib"
 			} else {
 				libType = "header"
 			}
 
 			var stem string
 
-			// install .a or .so
+			// install .a, .rlib, .dylib.so, or .so
 			if libType != "header" {
 				libPath := m.OutputFile().Path()
 				stem = libPath.Base()
@@ -328,6 +346,12 @@
 						}
 					}
 				}
+				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 {
@@ -341,8 +365,12 @@
 			prop.StaticExecutable = m.StaticExecutable()
 			prop.InstallInRoot = m.InstallInRoot()
 			prop.SharedLibs = m.SnapshotSharedLibs()
-			// static libs dependencies are required to collect the NOTICE files.
+			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())
@@ -379,7 +407,7 @@
 
 		moduleDir := ctx.ModuleDir(module)
 		inProprietaryPath := s.Image.IsProprietaryPath(moduleDir, ctx.DeviceConfig())
-		apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+		apexInfo, _ := android.SingletonModuleProvider(ctx, module, android.ApexInfoProvider)
 
 		if s.Image.ExcludeFromSnapshot(m) {
 			if inProprietaryPath {
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index c5431b3..890a533 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -23,13 +23,14 @@
 	"testing"
 )
 
-func checkJsonContents(t *testing.T, ctx android.TestingSingleton, jsonPath string, key string, value string) {
-	jsonOut := ctx.MaybeOutput(jsonPath)
+func checkJsonContents(t *testing.T, ctx *android.TestContext, snapshotSingleton android.TestingSingleton, jsonPath string, key string, value string) {
+	jsonOut := snapshotSingleton.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)) {
+	content := android.ContentFromFileRuleForTests(t, ctx, jsonOut)
+	if !strings.Contains(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"])
 	}
 }
@@ -167,8 +168,8 @@
 			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")
+		checkJsonContents(t, ctx, snapshotSingleton, filepath.Join(staticDir, "libb.a.json"), "MinSdkVersion", "apex_inherit")
+		checkJsonContents(t, ctx, 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" {
diff --git a/cc/vndk.go b/cc/vndk.go
index 9b70004..0e0dba9 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -28,10 +28,12 @@
 	"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 +41,40 @@
 	vndkUsingCoreVariantLibrariesTxt = "vndkcorevariant.libraries.txt"
 )
 
-func VndkLibrariesTxtModules(vndkVersion string) []string {
+func VndkLibrariesTxtModules(vndkVersion string, ctx android.BaseModuleContext) []string {
+	// Return the list of vndk txt files for the vndk apex of the vndkVersion.
 	if vndkVersion == "current" {
-		return []string{
-			llndkLibrariesTxt,
-			vndkCoreLibrariesTxt,
-			vndkSpLibrariesTxt,
-			vndkPrivateLibrariesTxt,
-			vndkProductLibrariesTxt,
+		// We can assume all txt files are snapshotted if we find one of them.
+		currentVndkSnapshotted := ctx.OtherModuleExists(insertVndkVersion(llndkLibrariesTxt, ctx.DeviceConfig().PlatformVndkVersion()))
+		if currentVndkSnapshotted {
+			// If the current VNDK is already snapshotted (which can happen with
+			// the `next` config), use the prebuilt txt files in the snapshot.
+			// This is because the txt files built from source are probably be
+			// for the in-development version.
+			vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
+		} else {
+			// Use the txt files generated from the source
+			return []string{
+				llndkLibrariesTxtForApex,
+				vndkCoreLibrariesTxt,
+				vndkSpLibrariesTxt,
+				vndkPrivateLibrariesTxt,
+				vndkProductLibrariesTxt,
+			}
 		}
 	}
+
 	// 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,11 +369,19 @@
 		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
+		}
+
+		// ignore prebuilt vndk modules that are newer than or equal to the platform vndk version
+		platformVndkApiLevel := android.ApiLevelOrPanic(mctx, mctx.DeviceConfig().PlatformVndkVersion())
+		if platformVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(mctx, p.Version())) {
+			return false
+		}
 	}
 
 	if lib, ok := m.linker.(libraryInterface); ok {
@@ -393,11 +418,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,16 +442,17 @@
 
 func init() {
 	RegisterVndkLibraryTxtTypes(android.InitRegistrationContext)
-	android.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
+	android.RegisterParallelSingletonType("vndk-snapshot", VndkSnapshotSingleton)
 }
 
 func RegisterVndkLibraryTxtTypes(ctx android.RegistrationContext) {
-	ctx.RegisterSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory)
-	ctx.RegisterSingletonModuleType("vndksp_libraries_txt", vndkSPLibrariesTxtFactory)
-	ctx.RegisterSingletonModuleType("vndkcore_libraries_txt", vndkCoreLibrariesTxtFactory)
-	ctx.RegisterSingletonModuleType("vndkprivate_libraries_txt", vndkPrivateLibrariesTxtFactory)
-	ctx.RegisterSingletonModuleType("vndkproduct_libraries_txt", vndkProductLibrariesTxtFactory)
-	ctx.RegisterSingletonModuleType("vndkcorevariant_libraries_txt", vndkUsingCoreVariantLibrariesTxtFactory)
+	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)
+	ctx.RegisterParallelSingletonModuleType("vndkproduct_libraries_txt", vndkProductLibrariesTxtFactory)
+	ctx.RegisterParallelSingletonModuleType("vndkcorevariant_libraries_txt", vndkUsingCoreVariantLibrariesTxtFactory)
 }
 
 type vndkLibrariesTxt struct {
@@ -445,22 +471,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.
@@ -518,12 +553,20 @@
 	return filename
 }
 
+func (txt *vndkLibrariesTxt) DepsMutator(mctx android.BottomUpMutatorContext) {
+	versionedName := insertVndkVersion(txt.Name(), mctx.DeviceConfig().PlatformVndkVersion())
+	if mctx.OtherModuleExists(versionedName) {
+		// If the prebuilt vndk libraries txt files exist, install them instead.
+		txt.HideFromMake()
+		mctx.AddDependency(txt, nil, versionedName)
+	}
+}
+
 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())
+
+	if Bool(txt.properties.Insert_vndk_version) {
+		filename = insertVndkVersion(filename, ctx.DeviceConfig().PlatformVndkVersion())
 	}
 
 	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
@@ -550,6 +593,10 @@
 }
 
 func (txt *vndkLibrariesTxt) MakeVars(ctx android.MakeVarsContext) {
+	if txt.makeVarName == "" {
+		return
+	}
+
 	filter := func(modules []string, prefix string) []string {
 		if prefix == "" {
 			return modules
@@ -725,7 +772,7 @@
 		prop.MinSdkVersion = m.MinSdkVersion()
 
 		if ctx.Config().VndkSnapshotBuildArtifacts() {
-			exportedInfo := ctx.ModuleProvider(m, FlagExporterInfoProvider).(FlagExporterInfo)
+			exportedInfo, _ := android.SingletonModuleProvider(ctx, m, FlagExporterInfoProvider)
 			prop.ExportedFlags = exportedInfo.Flags
 			prop.ExportedDirs = exportedInfo.IncludeDirs.Strings()
 			prop.ExportedSystemDirs = exportedInfo.SystemIncludeDirs.Strings()
@@ -750,7 +797,7 @@
 			return
 		}
 
-		apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+		apexInfo, _ := android.SingletonModuleProvider(ctx, module, android.ApexInfoProvider)
 
 		vndkType, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo)
 		if !ok {
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 37819a4..eb1790f 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -131,6 +131,12 @@
 
 func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
+	platformVndkApiLevel := android.ApiLevelOrPanic(ctx, ctx.DeviceConfig().PlatformVndkVersion())
+	if platformVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(ctx, p.Version())) {
+		// This prebuilt VNDK module is not required for the current build
+		ctx.Module().HideFromMake()
+		return nil
+	}
 
 	if !p.MatchesWithDevice(ctx.DeviceConfig()) {
 		ctx.Module().HideFromMake()
@@ -165,7 +171,7 @@
 			p.androidMkSuffix = ""
 		}
 
-		ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
+		android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
 			SharedLibrary: in,
 			Target:        ctx.Target(),
 
@@ -181,6 +187,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() {
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/cmd/merge_module_info_json/Android.bp b/cmd/merge_module_info_json/Android.bp
new file mode 100644
index 0000000..1ae6a47
--- /dev/null
+++ b/cmd/merge_module_info_json/Android.bp
@@ -0,0 +1,30 @@
+// 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+    name: "merge_module_info_json",
+    srcs: [
+        "merge_module_info_json.go",
+    ],
+    deps: [
+        "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 e3d1179..1aa6f6f 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
@@ -122,7 +124,7 @@
 }
 
 func (be ZipEntryFromBuffer) WriteToZip(dest string, zw *zip.Writer) error {
-	w, err := zw.CreateHeader(be.fh)
+	w, err := zw.CreateHeaderAndroid(be.fh)
 	if err != nil {
 		return err
 	}
@@ -562,6 +564,8 @@
 		}
 	}
 
+	var jarServices jar.Services
+
 	// Finally, add entries from all the input zips.
 	for _, inputZip := range inputZips {
 		_, copyFully := zipsToNotStrip[inputZip.Name()]
@@ -570,6 +574,14 @@
 		}
 
 		for i, entry := range inputZip.Entries() {
+			if emulateJar && jarServices.IsServiceFile(entry) {
+				// If this is a jar, collect service files to combine  instead of adding them to the zip.
+				err := jarServices.AddServiceFile(entry)
+				if err != nil {
+					return err
+				}
+				continue
+			}
 			if copyFully || !out.isEntryExcluded(entry.Name) {
 				if err := out.copyEntry(inputZip, i); err != nil {
 					return err
@@ -585,6 +597,16 @@
 	}
 
 	if emulateJar {
+		// Combine all the service files into a single list of combined service files and add them to the zip.
+		for _, serviceFile := range jarServices.ServiceFiles() {
+			_, err := out.addZipEntry(serviceFile.Name, ZipEntryFromBuffer{
+				fh:      serviceFile.FileHeader,
+				content: serviceFile.Contents,
+			})
+			if err != nil {
+				return err
+			}
+		}
 		return out.writeEntries(out.jarSorted())
 	} else if sortEntries {
 		return out.writeEntries(out.alphanumericSorted())
diff --git a/cmd/merge_zips/merge_zips_test.go b/cmd/merge_zips/merge_zips_test.go
index cb58436..64b08d0 100644
--- a/cmd/merge_zips/merge_zips_test.go
+++ b/cmd/merge_zips/merge_zips_test.go
@@ -17,38 +17,50 @@
 import (
 	"bytes"
 	"fmt"
+	"hash/crc32"
 	"os"
 	"strconv"
 	"strings"
 	"testing"
+	"time"
 
 	"android/soong/jar"
 	"android/soong/third_party/zip"
 )
 
 type testZipEntry struct {
-	name string
-	mode os.FileMode
-	data []byte
+	name      string
+	mode      os.FileMode
+	data      []byte
+	method    uint16
+	timestamp time.Time
 }
 
 var (
-	A     = testZipEntry{"A", 0755, []byte("foo")}
-	a     = testZipEntry{"a", 0755, []byte("foo")}
-	a2    = testZipEntry{"a", 0755, []byte("FOO2")}
-	a3    = testZipEntry{"a", 0755, []byte("Foo3")}
-	bDir  = testZipEntry{"b/", os.ModeDir | 0755, nil}
-	bbDir = testZipEntry{"b/b/", os.ModeDir | 0755, nil}
-	bbb   = testZipEntry{"b/b/b", 0755, nil}
-	ba    = testZipEntry{"b/a", 0755, []byte("foob")}
-	bc    = testZipEntry{"b/c", 0755, []byte("bar")}
-	bd    = testZipEntry{"b/d", 0700, []byte("baz")}
-	be    = testZipEntry{"b/e", 0700, []byte("")}
+	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}
 
-	metainfDir     = testZipEntry{jar.MetaDir, os.ModeDir | 0755, nil}
-	manifestFile   = testZipEntry{jar.ManifestFile, 0755, []byte("manifest")}
-	manifestFile2  = testZipEntry{jar.ManifestFile, 0755, []byte("manifest2")}
-	moduleInfoFile = testZipEntry{jar.ModuleInfoClass, 0755, []byte("module-info")}
+	withTimestamp    = testZipEntry{"timestamped", 0755, nil, zip.Store, jar.DefaultTime.Add(time.Hour)}
+	withoutTimestamp = testZipEntry{"timestamped", 0755, nil, zip.Store, jar.DefaultTime}
+
+	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 {
@@ -236,6 +248,23 @@
 				"in1": true,
 			},
 		},
+		{
+			name: "services",
+			in: [][]testZipEntry{
+				{service1a, service2},
+				{service1b},
+			},
+			jar: true,
+			out: []testZipEntry{service1combined, service2},
+		},
+		{
+			name: "strip timestamps",
+			in: [][]testZipEntry{
+				{withTimestamp},
+				{a},
+			},
+			out: []testZipEntry{withoutTimestamp, a},
+		},
 	}
 
 	for _, test := range testCases {
@@ -256,7 +285,7 @@
 
 			closeErr := writer.Close()
 			if closeErr != nil {
-				t.Fatal(err)
+				t.Fatal(closeErr)
 			}
 
 			if test.err != "" {
@@ -266,12 +295,16 @@
 					t.Fatal("incorrect err, want:", test.err, "got:", err)
 				}
 				return
+			} else if err != nil {
+				t.Fatal("unexpected err: ", err)
 			}
 
 			if !bytes.Equal(want, out.Bytes()) {
 				t.Error("incorrect zip output")
 				t.Errorf("want:\n%s", dumpZip(want))
 				t.Errorf("got:\n%s", dumpZip(out.Bytes()))
+				os.WriteFile("/tmp/got.zip", out.Bytes(), 0755)
+				os.WriteFile("/tmp/want.zip", want, 0755)
 			}
 		})
 	}
@@ -286,8 +319,15 @@
 			Name: e.name,
 		}
 		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 {
+			fh.CompressedSize64 = fh.UncompressedSize64
+		}
 
-		w, err := zw.CreateHeader(&fh)
+		w, err := zw.CreateHeaderAndroid(&fh)
 		if err != nil {
 			panic(err)
 		}
@@ -328,7 +368,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/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 0212075..c3b0381 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -50,7 +50,6 @@
 
 var bazelMode = flag.Bool("bazel-mode", false, "use bazel for analysis of certain modules")
 var bazelModeStaging = flag.Bool("bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules")
-var bazelModeDev = flag.Bool("bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)")
 
 var onlyConfig = flag.Bool("only-config", false, "Only run product config (not Soong or Kati)")
 var onlySoong = flag.Bool("only-soong", false, "Only run product config and Soong (not Kati)")
@@ -229,10 +228,6 @@
 		count++
 		str = "--bazel-mode-staging"
 	}
-	if *bazelModeDev {
-		count++
-		str = "--bazel-mode-dev"
-	}
 
 	if count > 1 {
 		// Can't set more than one
@@ -404,6 +399,9 @@
 	var wg sync.WaitGroup
 	for i := 0; i < jobs; i++ {
 		wg.Add(1)
+		// To smooth out the spikes in memory usage, skew the
+		// initial starting time of the jobs by a small amount.
+		time.Sleep(15 * time.Second)
 		go func() {
 			defer wg.Done()
 			for {
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 ba0648d..6d1caf9 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -556,7 +556,8 @@
     {{- end}}
     {{- end}}
     {{- if .IsApk}}
-    presigned: true
+    preprocessed: true,
+    presigned: true,
     {{- end}}
 
 }
@@ -650,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/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 2c35d76..4727566 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -16,6 +16,7 @@
 
 import (
 	"bytes"
+	"errors"
 	"flag"
 	"fmt"
 	"os"
@@ -25,11 +26,10 @@
 
 	"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"
 	"github.com/google/blueprint/deptools"
 	"github.com/google/blueprint/metrics"
@@ -73,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.BazelForceEnabledModules, "bazel-force-enabled-modules", "", "additional modules to build with Bazel. Comma-delimited")
+	flag.StringVar(&cmdlineArgs.SoongVariables, "soong_variables", "soong.variables", "the file contains all build variables")
 	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.BazelModeDev, "bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)")
-	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")
 	// 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")
@@ -110,29 +103,16 @@
 	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 {
-		return ctx.Config().BazelContext.InvokeBazel(ctx.Config(), ctx)
+func needToWriteNinjaHint(ctx *android.Context) bool {
+	switch ctx.Config().GetenvWithDefault("SOONG_GENERATES_NINJA_HINT", "") {
+	case "always":
+		return true
+	case "depend":
+		if _, err := os.Stat(filepath.Join(ctx.Config().OutDir(), ".ninja_log")); errors.Is(err, os.ErrNotExist) {
+			return true
+		}
 	}
-	ctx.SetBeforePrepareBuildActionsHook(bazelHook)
-	ninjaDeps := bootstrap.RunBlueprint(cmdlineArgs.Args, bootstrap.DoEverything, ctx.Context, ctx.Config())
-	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)
-	return cmdlineArgs.OutFile
+	return false
 }
 
 // Run the code-generation phase to convert BazelTargetModules to BUILD files.
@@ -145,129 +125,48 @@
 	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 := bootstrap.RunBlueprint(cmdlineArgs.Args,
-		bootstrap.StopBeforePrepareBuildActions,
-		ctx.Context,
-		ctx.Config())
-	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, 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)
-	}
-
-	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 {
-	wantModules := make([]string, len(allowlists.HugeModulesMap))
-	i := 0
-	for k := range allowlists.HugeModulesMap {
-		wantModules[i] = k
-		i += 1
-	}
-	outputsMap := ctx.Context.GetOutputsFromModuleNames(wantModules)
-	var outputBuilder strings.Builder
-	for k, v := range allowlists.HugeModulesMap {
-		for _, output := range outputsMap[k] {
-			outputBuilder.WriteString(fmt.Sprintf("%s,%d\n", output, v))
+	ctx.BeginEvent("ninja_hint")
+	defer ctx.EndEvent("ninja_hint")
+	// The current predictor focuses on reducing false negatives.
+	// If there are too many false positives (e.g., most modules are marked as positive),
+	// real long-running jobs cannot run early.
+	// Therefore, the model should be adjusted in this case.
+	// The model should also be adjusted if there are critical false negatives.
+	predicate := func(j *blueprint.JsonModule) (prioritized bool, weight int) {
+		prioritized = false
+		weight = 0
+		for prefix, w := range allowlists.HugeModuleTypePrefixMap {
+			if strings.HasPrefix(j.Type, prefix) {
+				prioritized = true
+				weight = w
+				return
+			}
 		}
+		dep_count := len(j.Deps)
+		src_count := 0
+		for _, a := range j.Module["Actions"].([]blueprint.JSONAction) {
+			src_count += len(a.Inputs)
+		}
+		input_size := dep_count + src_count
+
+		// Current threshold is an arbitrary value which only consider recall rather than accuracy.
+		if input_size > allowlists.INPUT_SIZE_THRESHOLD {
+			prioritized = true
+			weight += ((input_size) / allowlists.INPUT_SIZE_THRESHOLD) * allowlists.DEFAULT_PRIORITIZED_WEIGHT
+
+			// To prevent some modules from having too large a priority value.
+			if weight > allowlists.HIGH_PRIORITIZED_WEIGHT {
+				weight = allowlists.HIGH_PRIORITIZED_WEIGHT
+			}
+		}
+		return
+	}
+
+	outputsMap := ctx.Context.GetWeightedOutputsFromPredicate(predicate)
+	var outputBuilder strings.Builder
+	for output, weight := range outputsMap {
+		outputBuilder.WriteString(fmt.Sprintf("%s,%d\n", output, weight))
 	}
 	weightListFile := filepath.Join(topDir, ctx.Config().OutDir(), ".ninja_weight_list")
 
@@ -298,18 +197,18 @@
 	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")
 
 	globDir := bootstrap.GlobDirectory(ctx.Config().SoongOutDir(), globListDir)
-	bootstrap.WriteBuildGlobsNinjaFile(&bootstrap.GlobSingleton{
+	err := bootstrap.WriteBuildGlobsNinjaFile(&bootstrap.GlobSingleton{
 		GlobLister: ctx.Globs,
 		GlobFile:   globFile,
 		GlobDir:    globDir,
 		SrcDir:     ctx.SrcDir(),
 	}, ctx.Config())
-	return bootstrap.GlobFileListFiles(globDir)
+	maybeQuit(err, "")
 }
 
 func writeDepFile(outputFile string, eventHandler *metrics.EventHandler, ninjaDeps []string) {
@@ -335,11 +234,11 @@
 		stopBefore = bootstrap.DoEverything
 	}
 
-	ninjaDeps := bootstrap.RunBlueprint(cmdlineArgs.Args, stopBefore, ctx.Context, ctx.Config())
+	ninjaDeps, err := bootstrap.RunBlueprint(cmdlineArgs.Args, stopBefore, ctx.Context, ctx.Config())
+	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 {
@@ -364,6 +263,9 @@
 		// The actual output (build.ninja) was written in the RunBlueprint() call
 		// above
 		writeDepFile(cmdlineArgs.OutFile, ctx.EventHandler, ninjaDeps)
+		if needToWriteNinjaHint(ctx) {
+			writeNinjaHint(ctx)
+		}
 		return cmdlineArgs.OutFile
 	}
 }
@@ -416,33 +318,12 @@
 	metricsDir := availableEnv["LOG_DIR"]
 
 	ctx := newContext(configuration)
+	android.StartBackgroundMetrics(configuration)
 
-	var finalOutputFile string
+	ctx.Register()
+	finalOutputFile := runSoongOnlyBuild(ctx, extraNinjaDeps)
+	writeMetrics(configuration, ctx.EventHandler, metricsDir)
 
-	// 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()
-		if configuration.IsMixedBuildsEnabled() {
-			finalOutputFile = runMixedModeBuild(ctx, extraNinjaDeps)
-		} else {
-			finalOutputFile = runSoongOnlyBuild(ctx, extraNinjaDeps)
-		}
-		if ctx.Config().IsEnvTrue("SOONG_GENERATES_NINJA_HINT") {
-			writeNinjaHint(ctx)
-		}
-		writeMetrics(configuration, ctx.EventHandler, metricsDir)
-	}
 	writeUsedEnvironmentFile(configuration)
 
 	// Touch the output file so that it's the newest file created by soong_build.
@@ -484,215 +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",
-
-		// FIXME(b/260809113): 'prebuilts/clang/host/linux-x86/clang-dev' is a tool-generated symlink
-		// directory that contains a BUILD file. The bazel files finder code doesn't traverse into symlink dirs,
-		// and hence is not aware of this BUILD file and exclude it accordingly during symlink forest generation
-		// when checking against keepExistingBuildFiles allowlist.
-		//
-		// This is necessary because globs in //prebuilts/clang/host/linux-x86/BUILD
-		// currently assume no subpackages (keepExistingBuildFile is not recursive for that directory).
-		//
-		// This is a bandaid until we the symlink forest logic can intelligently exclude BUILD files found in
-		// source symlink dirs according to the keepExistingBuildFile allowlist.
-		"prebuilts/clang/host/linux-x86/clang-dev",
-	)
-	return excluded
-}
-
-// 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() {
-
-		// 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)
-
-		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 := bootstrap.RunBlueprint(blueprintArgs.Args,
-				bootstrap.StopBeforePrepareBuildActions, ctx.Context, ctx.Config())
-			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)
-		ctx.EventHandler.Do("codegen", func() {
-			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 ce32184..5c2316a 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -22,6 +22,7 @@
 
 	"android/soong/android"
 	"android/soong/bp2build"
+	"android/soong/starlark_import"
 )
 
 // A helper function to generate a Read-only Bazel workspace in outDir
@@ -34,8 +35,7 @@
 		panic(err)
 	}
 
-	filesToWrite := bp2build.CreateBazelFiles(ctx.Config(), ruleShims, res.BuildDirToTargets(),
-		ctx.Mode())
+	filesToWrite := bp2build.CreateBazelFiles(ruleShims, res.BuildDirToTargets(), ctx.Mode())
 	bazelRcFiles, err2 := CopyBazelRcFiles()
 	if err2 != nil {
 		return err2
@@ -47,6 +47,14 @@
 		}
 	}
 
+	// 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 301246a..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,15 +90,6 @@
 		config:      buildActionConfig,
 		stdio:       stdio,
 		run:         runMake,
-	}, {
-		flag:        "--upload-metrics-only",
-		description: "upload metrics without building anything",
-		config:      uploadOnlyConfig,
-		stdio:       stdio,
-		// Upload-only mode mostly skips to the metrics-uploading phase of soong_ui.
-		// However, this invocation marks the true "end of the build", and thus we
-		// need to update the total runtime of the build to include this upload step.
-		run: updateTotalRealTime,
 	},
 }
 
@@ -191,28 +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")
 
-	//the profile file generated by Bazel"
-	bazelProfileFile := filepath.Join(logsDir, c.logsPrefix+"analyzed_bazel_profile.txt")
 	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)
@@ -221,19 +208,35 @@
 
 	trace.SetOutput(filepath.Join(logsDir, c.logsPrefix+"build.trace"))
 
+	log.Verbose("Command Line: ")
+	for i, arg := range os.Args {
+		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)
 		met.Dump(soongMetricsFile)
 		if !config.SkipMetricsUpload() {
-			build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, bazelProfileFile, bazelMetricsFile, metricsFiles...)
+			build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, metricsFiles...)
 		}
 	}()
 	c.run(buildCtx, config, args)
 
 }
 
-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)
@@ -286,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)
 
@@ -365,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)
@@ -451,14 +433,6 @@
 	return build.NewConfig(ctx)
 }
 
-// uploadOnlyConfig explicitly requires no arguments.
-func uploadOnlyConfig(ctx build.Context, args ...string) build.Config {
-	if len(args) > 0 {
-		fmt.Printf("--upload-only does not require arguments.")
-	}
-	return build.UploadOnlyConfig(ctx)
-}
-
 func buildActionConfig(ctx build.Context, args ...string) build.Config {
 	flags := flag.NewFlagSet("build-mode", flag.ContinueOnError)
 	flags.SetOutput(ctx.Writer)
@@ -553,7 +527,6 @@
 }
 
 func runMake(ctx build.Context, config build.Config, _ []string) {
-	logAndSymlinkSetup(ctx, config)
 	logsDir := config.LogsDir()
 	if config.IsVerbose() {
 		writer := ctx.Writer
@@ -604,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
 
@@ -689,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)
@@ -699,19 +599,3 @@
 		ctx.Println("Failed to increase file limit:", err)
 	}
 }
-
-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.UpdateTotalRealTime(data)
-	if err != nil {
-		ctx.Fatal(err)
-	}
-}
diff --git a/cmd/zip2zip/BUILD.bazel b/cmd/zip2zip/BUILD.bazel
deleted file mode 100644
index 1915a2d..0000000
--- a/cmd/zip2zip/BUILD.bazel
+++ /dev/null
@@ -1,18 +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.
-
-alias(
-    name = "zip2zip",
-    actual = "//prebuilts/build-tools:linux-x86/bin/zip2zip",
-)
diff --git a/cmd/zip2zip/zip2zip.go b/cmd/zip2zip/zip2zip.go
index 491267b..5ab9656 100644
--- a/cmd/zip2zip/zip2zip.go
+++ b/cmd/zip2zip/zip2zip.go
@@ -128,12 +128,6 @@
 	}
 
 	for _, arg := range args {
-		// Reserve escaping for future implementation, so make sure no
-		// one is using \ and expecting a certain behavior.
-		if strings.Contains(arg, "\\") {
-			return fmt.Errorf("\\ characters are not currently supported")
-		}
-
 		input, output := includeSplit(arg)
 
 		var includeMatches []pair
diff --git a/cmd/zip2zip/zip2zip_test.go b/cmd/zip2zip/zip2zip_test.go
index 2c4e005..85a69ef 100644
--- a/cmd/zip2zip/zip2zip_test.go
+++ b/cmd/zip2zip/zip2zip_test.go
@@ -38,13 +38,6 @@
 	storedFiles []string
 	err         error
 }{
-	{
-		name: "unsupported \\",
-
-		args: []string{"a\\b:b"},
-
-		err: fmt.Errorf("\\ characters are not currently supported"),
-	},
 	{ // This is modelled after the update package build rules in build/make/core/Makefile
 		name: "filter globs",
 
@@ -406,6 +399,13 @@
 			"b/a/b",
 		},
 	},
+	{
+		name: "escaping",
+
+		inputFiles:  []string{"a"},
+		args:        []string{"\\a"},
+		outputFiles: []string{"a"},
+	},
 }
 
 func errorString(e error) string {
@@ -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/cmd/zipsync/zipsync.go b/cmd/zipsync/zipsync.go
index aecdc3d..b3e78d0 100644
--- a/cmd/zipsync/zipsync.go
+++ b/cmd/zipsync/zipsync.go
@@ -29,10 +29,14 @@
 var (
 	outputDir  = flag.String("d", "", "output dir")
 	outputFile = flag.String("l", "", "output list file")
-	filter     = flag.String("f", "", "optional filter pattern")
 	zipPrefix  = flag.String("zip-prefix", "", "optional prefix within the zip file to extract, stripping the prefix")
+	filter     multiFlag
 )
 
+func init() {
+	flag.Var(&filter, "f", "optional filter pattern")
+}
+
 func must(err error) {
 	if err != nil {
 		log.Fatal(err)
@@ -107,13 +111,15 @@
 				}
 				name = strings.TrimPrefix(name, *zipPrefix)
 			}
-			if *filter != "" {
-				if match, err := filepath.Match(*filter, filepath.Base(name)); err != nil {
+
+			if filter != nil {
+				if match, err := filter.Match(filepath.Base(name)); err != nil {
 					log.Fatal(err)
 				} else if !match {
 					continue
 				}
 			}
+
 			if filepath.IsAbs(name) {
 				log.Fatalf("%q in %q is an absolute path", name, input)
 			}
@@ -151,3 +157,28 @@
 		must(ioutil.WriteFile(*outputFile, []byte(data), 0666))
 	}
 }
+
+type multiFlag []string
+
+func (m *multiFlag) String() string {
+	return strings.Join(*m, " ")
+}
+
+func (m *multiFlag) Set(s string) error {
+	*m = append(*m, s)
+	return nil
+}
+
+func (m *multiFlag) Match(s string) (bool, error) {
+	if m == nil {
+		return false, nil
+	}
+	for _, f := range *m {
+		if match, err := filepath.Match(f, s); err != nil {
+			return false, err
+		} else if match {
+			return true, nil
+		}
+	}
+	return false, nil
+}
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 afb3de3..57c7ae8 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -17,11 +17,11 @@
 import (
 	"encoding/json"
 	"fmt"
-	"sort"
 	"strconv"
-	"strings"
 
 	"android/soong/android"
+
+	"github.com/google/blueprint/proptools"
 )
 
 // This comment describes the following:
@@ -310,8 +310,8 @@
 	// Nested class loader context shouldn't have conditional part (it is allowed only at the top level).
 	for ver, _ := range nestedClcMap {
 		if ver != AnySdkVersion {
-			clcStr, _ := ComputeClassLoaderContext(nestedClcMap)
-			return fmt.Errorf("nested class loader context shouldn't have conditional part: %s", clcStr)
+			_, clcPaths := ComputeClassLoaderContextDependencies(nestedClcMap)
+			return fmt.Errorf("nested class loader context shouldn't have conditional part: %+v", clcPaths)
 		}
 	}
 	subcontexts := nestedClcMap[AnySdkVersion]
@@ -418,6 +418,15 @@
 	return string(bytes)
 }
 
+func (clcMap ClassLoaderContextMap) DumpForFlag() string {
+	jsonCLC := toJsonClassLoaderContext(clcMap)
+	bytes, err := json.Marshal(jsonCLC)
+	if err != nil {
+		panic(err)
+	}
+	return proptools.ShellEscapeIncludingSpaces(string(bytes))
+}
+
 // excludeLibsFromCLCList excludes the libraries from the ClassLoaderContext in this list.
 //
 // This treats the supplied list as being immutable (as it may come from a dependency). So, it
@@ -544,67 +553,28 @@
 	return true, nil
 }
 
-// Return the class loader context as a string, and a slice of build paths for all dependencies.
+// Returns a slice of library names and a slice of build paths for all possible dependencies that
+// the class loader context may refer to.
 // Perform a depth-first preorder traversal of the class loader context tree for each SDK version.
-// Return the resulting string and a slice of on-host build paths to all library dependencies.
-func ComputeClassLoaderContext(clcMap ClassLoaderContextMap) (clcStr string, paths android.Paths) {
-	// CLC for different SDK versions should come in specific order that agrees with PackageManager.
-	// Since PackageManager processes SDK versions in ascending order and prepends compatibility
-	// libraries at the front, the required order is descending, except for AnySdkVersion that has
-	// numerically the largest order, but must be the last one. Example of correct order: [30, 29,
-	// 28, AnySdkVersion]. There are Soong tests to ensure that someone doesn't change this by
-	// accident, but there is no way to guard against changes in the PackageManager, except for
-	// grepping logcat on the first boot for absence of the following messages:
-	//
-	//   `logcat | grep -E 'ClassLoaderContext [a-z ]+ mismatch`
-	//
-	versions := make([]int, 0, len(clcMap))
-	for ver, _ := range clcMap {
-		if ver != AnySdkVersion {
-			versions = append(versions, ver)
-		}
+func ComputeClassLoaderContextDependencies(clcMap ClassLoaderContextMap) (names []string, paths android.Paths) {
+	for _, clcs := range clcMap {
+		currentNames, currentPaths := ComputeClassLoaderContextDependenciesRec(clcs)
+		names = append(names, currentNames...)
+		paths = append(paths, currentPaths...)
 	}
-	sort.Sort(sort.Reverse(sort.IntSlice(versions))) // descending order
-	versions = append(versions, AnySdkVersion)
-
-	for _, sdkVer := range versions {
-		sdkVerStr := fmt.Sprintf("%d", sdkVer)
-		if sdkVer == AnySdkVersion {
-			sdkVerStr = "any" // a special keyword that means any SDK version
-		}
-		hostClc, targetClc, hostPaths := computeClassLoaderContextRec(clcMap[sdkVer])
-		if hostPaths != nil {
-			clcStr += fmt.Sprintf(" --host-context-for-sdk %s %s", sdkVerStr, hostClc)
-			clcStr += fmt.Sprintf(" --target-context-for-sdk %s %s", sdkVerStr, targetClc)
-		}
-		paths = append(paths, hostPaths...)
-	}
-	return clcStr, android.FirstUniquePaths(paths)
+	return android.FirstUniqueStrings(names), android.FirstUniquePaths(paths)
 }
 
-// Helper function for ComputeClassLoaderContext() that handles recursion.
-func computeClassLoaderContextRec(clcs []*ClassLoaderContext) (string, string, android.Paths) {
-	var paths android.Paths
-	var clcsHost, clcsTarget []string
-
+// Helper function for ComputeClassLoaderContextDependencies() that handles recursion.
+func ComputeClassLoaderContextDependenciesRec(clcs []*ClassLoaderContext) (names []string, paths android.Paths) {
 	for _, clc := range clcs {
-		subClcHost, subClcTarget, subPaths := computeClassLoaderContextRec(clc.Subcontexts)
-		if subPaths != nil {
-			subClcHost = "{" + subClcHost + "}"
-			subClcTarget = "{" + subClcTarget + "}"
-		}
-
-		clcsHost = append(clcsHost, "PCL["+clc.Host.String()+"]"+subClcHost)
-		clcsTarget = append(clcsTarget, "PCL["+clc.Device+"]"+subClcTarget)
-
+		subNames, subPaths := ComputeClassLoaderContextDependenciesRec(clc.Subcontexts)
+		names = append(names, clc.Name)
 		paths = append(paths, clc.Host)
+		names = append(names, subNames...)
 		paths = append(paths, subPaths...)
 	}
-
-	clcHost := strings.Join(clcsHost, "#")
-	clcTarget := strings.Join(clcsTarget, "#")
-
-	return clcHost, clcTarget, paths
+	return names, paths
 }
 
 // Class loader contexts that come from Make via JSON dexpreopt.config. JSON CLC representation is
diff --git a/dexpreopt/class_loader_context_test.go b/dexpreopt/class_loader_context_test.go
index 8b3c013..7260abb 100644
--- a/dexpreopt/class_loader_context_test.go
+++ b/dexpreopt/class_loader_context_test.go
@@ -20,6 +20,7 @@
 import (
 	"fmt"
 	"reflect"
+	"sort"
 	"strings"
 	"testing"
 
@@ -34,7 +35,7 @@
 	// │   └── android.hidl.base
 	// │
 	// └── any
-	//     ├── a
+	//     ├── a'  (a single quotation mark (') is there to test escaping)
 	//     ├── b
 	//     ├── c
 	//     ├── d
@@ -53,7 +54,7 @@
 
 	m := make(ClassLoaderContextMap)
 
-	m.AddContext(ctx, AnySdkVersion, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+	m.AddContext(ctx, AnySdkVersion, "a'", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
 	m.AddContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
 	m.AddContext(ctx, AnySdkVersion, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
 
@@ -96,11 +97,11 @@
 
 	fixClassLoaderContext(m)
 
-	var haveStr string
-	var havePaths android.Paths
+	var actualNames []string
+	var actualPaths android.Paths
 	var haveUsesLibsReq, haveUsesLibsOpt []string
 	if valid && validationError == nil {
-		haveStr, havePaths = ComputeClassLoaderContext(m)
+		actualNames, actualPaths = ComputeClassLoaderContextDependencies(m)
 		haveUsesLibsReq, haveUsesLibsOpt = m.UsesLibs()
 	}
 
@@ -111,46 +112,44 @@
 		}
 	})
 
-	// Test that class loader context structure is correct.
-	t.Run("string", func(t *testing.T) {
-		wantStr := " --host-context-for-sdk 29 " +
-			"PCL[out/soong/" + AndroidHidlManager + ".jar]#" +
-			"PCL[out/soong/" + AndroidHidlBase + ".jar]" +
-			" --target-context-for-sdk 29 " +
-			"PCL[/system/framework/" + AndroidHidlManager + ".jar]#" +
-			"PCL[/system/framework/" + AndroidHidlBase + ".jar]" +
-			" --host-context-for-sdk any " +
-			"PCL[out/soong/a.jar]#PCL[out/soong/b.jar]#PCL[out/soong/c.jar]#PCL[out/soong/d.jar]" +
-			"{PCL[out/soong/a2.jar]#PCL[out/soong/b2.jar]#PCL[out/soong/c2.jar]" +
-			"{PCL[out/soong/a1.jar]#PCL[out/soong/b1.jar]}}#" +
-			"PCL[out/soong/f.jar]#PCL[out/soong/a3.jar]#PCL[out/soong/b3.jar]" +
-			" --target-context-for-sdk any " +
-			"PCL[/system/a.jar]#PCL[/system/b.jar]#PCL[/system/c.jar]#PCL[/system/d.jar]" +
-			"{PCL[/system/a2.jar]#PCL[/system/b2.jar]#PCL[/system/c2.jar]" +
-			"{PCL[/system/a1.jar]#PCL[/system/b1.jar]}}#" +
-			"PCL[/system/f.jar]#PCL[/system/a3.jar]#PCL[/system/b3.jar]"
-		if wantStr != haveStr {
-			t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
-		}
-	})
-
 	// Test that all expected build paths are gathered.
-	t.Run("paths", func(t *testing.T) {
-		wantPaths := []string{
+	t.Run("names and paths", func(t *testing.T) {
+		expectedNames := []string{
+			"a'", "a1", "a2", "a3", "android.hidl.base-V1.0-java", "android.hidl.manager-V1.0-java", "b",
+			"b1", "b2", "b3", "c", "c2", "d", "f",
+		}
+		expectedPaths := []string{
 			"out/soong/android.hidl.manager-V1.0-java.jar", "out/soong/android.hidl.base-V1.0-java.jar",
 			"out/soong/a.jar", "out/soong/b.jar", "out/soong/c.jar", "out/soong/d.jar",
 			"out/soong/a2.jar", "out/soong/b2.jar", "out/soong/c2.jar",
 			"out/soong/a1.jar", "out/soong/b1.jar",
 			"out/soong/f.jar", "out/soong/a3.jar", "out/soong/b3.jar",
 		}
-		if !reflect.DeepEqual(wantPaths, havePaths.Strings()) {
-			t.Errorf("\nwant paths: %s\nhave paths: %s", wantPaths, havePaths)
-		}
+		actualPathsStrs := actualPaths.Strings()
+		// The order does not matter.
+		sort.Strings(expectedNames)
+		sort.Strings(actualNames)
+		android.AssertArrayString(t, "", expectedNames, actualNames)
+		sort.Strings(expectedPaths)
+		sort.Strings(actualPathsStrs)
+		android.AssertArrayString(t, "", expectedPaths, actualPathsStrs)
+	})
+
+	// Test the JSON passed to construct_context.py.
+	t.Run("json", func(t *testing.T) {
+		// The tree structure within each SDK version should be kept exactly the same when serialized
+		// to JSON. The order matters because the Python script keeps the order within each SDK version
+		// as is.
+		// The JSON is passed to the Python script as a commandline flag, so quotation ('') and escaping
+		// must be performed.
+		android.AssertStringEquals(t, "", strings.TrimSpace(`
+'{"29":[{"Name":"android.hidl.manager-V1.0-java","Optional":false,"Host":"out/soong/android.hidl.manager-V1.0-java.jar","Device":"/system/framework/android.hidl.manager-V1.0-java.jar","Subcontexts":[]},{"Name":"android.hidl.base-V1.0-java","Optional":false,"Host":"out/soong/android.hidl.base-V1.0-java.jar","Device":"/system/framework/android.hidl.base-V1.0-java.jar","Subcontexts":[]}],"30":[],"42":[],"any":[{"Name":"a'\''","Optional":false,"Host":"out/soong/a.jar","Device":"/system/a.jar","Subcontexts":[]},{"Name":"b","Optional":false,"Host":"out/soong/b.jar","Device":"/system/b.jar","Subcontexts":[]},{"Name":"c","Optional":false,"Host":"out/soong/c.jar","Device":"/system/c.jar","Subcontexts":[]},{"Name":"d","Optional":false,"Host":"out/soong/d.jar","Device":"/system/d.jar","Subcontexts":[{"Name":"a2","Optional":false,"Host":"out/soong/a2.jar","Device":"/system/a2.jar","Subcontexts":[]},{"Name":"b2","Optional":false,"Host":"out/soong/b2.jar","Device":"/system/b2.jar","Subcontexts":[]},{"Name":"c2","Optional":false,"Host":"out/soong/c2.jar","Device":"/system/c2.jar","Subcontexts":[{"Name":"a1","Optional":false,"Host":"out/soong/a1.jar","Device":"/system/a1.jar","Subcontexts":[]},{"Name":"b1","Optional":false,"Host":"out/soong/b1.jar","Device":"/system/b1.jar","Subcontexts":[]}]}]},{"Name":"f","Optional":false,"Host":"out/soong/f.jar","Device":"/system/f.jar","Subcontexts":[]},{"Name":"a3","Optional":false,"Host":"out/soong/a3.jar","Device":"/system/a3.jar","Subcontexts":[]},{"Name":"b3","Optional":false,"Host":"out/soong/b3.jar","Device":"/system/b3.jar","Subcontexts":[]}]}'
+`), m.DumpForFlag())
 	})
 
 	// Test for libraries that are added by the manifest_fixer.
 	t.Run("uses libs", func(t *testing.T) {
-		wantUsesLibsReq := []string{"a", "b", "c", "d", "f", "a3", "b3"}
+		wantUsesLibsReq := []string{"a'", "b", "c", "d", "f", "a3", "b3"}
 		wantUsesLibsOpt := []string{}
 		if !reflect.DeepEqual(wantUsesLibsReq, haveUsesLibsReq) {
 			t.Errorf("\nwant required uses libs: %s\nhave required uses libs: %s", wantUsesLibsReq, haveUsesLibsReq)
@@ -236,49 +235,6 @@
 	checkError(t, err, "nested class loader context shouldn't have conditional part")
 }
 
-// Test for SDK version order in conditional CLC: no matter in what order the libraries are added,
-// they end up in the order that agrees with PackageManager.
-func TestCLCSdkVersionOrder(t *testing.T) {
-	ctx := testContext()
-	optional := false
-	m := make(ClassLoaderContextMap)
-	m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
-	m.AddContext(ctx, 29, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
-	m.AddContext(ctx, 30, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
-	m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), nil)
-
-	valid, validationError := validateClassLoaderContext(m)
-
-	fixClassLoaderContext(m)
-
-	var haveStr string
-	if valid && validationError == nil {
-		haveStr, _ = ComputeClassLoaderContext(m)
-	}
-
-	// Test that validation is successful (all paths are known).
-	t.Run("validate", func(t *testing.T) {
-		if !(valid && validationError == nil) {
-			t.Errorf("invalid class loader context")
-		}
-	})
-
-	// Test that class loader context structure is correct.
-	t.Run("string", func(t *testing.T) {
-		wantStr := " --host-context-for-sdk 30 PCL[out/soong/c.jar]" +
-			" --target-context-for-sdk 30 PCL[/system/c.jar]" +
-			" --host-context-for-sdk 29 PCL[out/soong/b.jar]" +
-			" --target-context-for-sdk 29 PCL[/system/b.jar]" +
-			" --host-context-for-sdk 28 PCL[out/soong/a.jar]" +
-			" --target-context-for-sdk 28 PCL[/system/a.jar]" +
-			" --host-context-for-sdk any PCL[out/soong/d.jar]" +
-			" --target-context-for-sdk any PCL[/system/d.jar]"
-		if wantStr != haveStr {
-			t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
-		}
-	})
-}
-
 func TestCLCMExcludeLibs(t *testing.T) {
 	ctx := testContext()
 	const optional = false
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 0cc3bd6..6163952 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.
 
@@ -45,7 +45,8 @@
 	BootJars     android.ConfiguredJarList // modules for jars that form the boot class path
 	ApexBootJars android.ConfiguredJarList // jars within apex that form the boot class path
 
-	ArtApexJars android.ConfiguredJarList // modules for jars that are in the ART APEX
+	ArtApexJars              android.ConfiguredJarList // modules for jars that are in the ART APEX
+	TestOnlyArtBootImageJars android.ConfiguredJarList // modules for jars to be included in the ART boot image for testing
 
 	SystemServerJars               android.ConfiguredJarList // system_server classpath jars on the platform
 	SystemServerApps               []string                  // apps that are loaded into system server
@@ -183,8 +184,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
 
@@ -197,7 +196,7 @@
 
 func init() {
 	pctx.Import("android/soong/android")
-	android.RegisterSingletonType("dexpreopt-soong-config", func() android.Singleton {
+	android.RegisterParallelSingletonType("dexpreopt-soong-config", func() android.Singleton {
 		return &globalSoongConfigSingleton{}
 	})
 }
@@ -321,7 +320,7 @@
 				missingDepsCtx.AddMissingDependencies([]string{err.Error()})
 			}
 		} else {
-			android.ReportPathErrorf(ctx, "%w", err)
+			android.ReportPathErrorf(ctx, "%s", err)
 		}
 	}
 
@@ -690,44 +689,45 @@
 
 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(),
-		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:                "",
 	}
 }
 
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 2b38793..94707ba 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -52,7 +52,8 @@
 // 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) (rule *android.RuleBuilder, err error) {
+	global *GlobalConfig, module *ModuleConfig, productPackages android.Path) (
+	rule *android.RuleBuilder, err error) {
 
 	defer func() {
 		if r := recover(); r != nil {
@@ -92,7 +93,8 @@
 			generateDM := shouldGenerateDM(module, global)
 
 			for archIdx, _ := range module.Archs {
-				dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage, generateDM)
+				dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage,
+					generateDM, productPackages)
 			}
 		}
 	}
@@ -122,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
 	}
 
@@ -232,9 +229,9 @@
 		pathtools.ReplaceExtension(filepath.Base(path), "odex"))
 }
 
-func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
-	module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath,
-	appImage bool, generateDM bool) {
+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) {
 
 	arch := module.Archs[archIdx]
 
@@ -351,11 +348,13 @@
 		}
 
 		// Generate command that saves host and target class loader context in shell variables.
-		clc, paths := ComputeClassLoaderContext(module.ClassLoaderContexts)
+		_, paths := ComputeClassLoaderContextDependencies(module.ClassLoaderContexts)
 		rule.Command().
 			Text(`eval "$(`).Tool(globalSoong.ConstructContext).
 			Text(` --target-sdk-version ${target_sdk_version}`).
-			Text(clc).Implicits(paths).
+			FlagWithArg("--context-json=", module.ClassLoaderContexts.DumpForFlag()).
+			FlagWithInput("--product-packages=", productPackages).
+			Implicits(paths).
 			Text(`)"`)
 	}
 
@@ -626,5 +625,3 @@
 	}
 	return false
 }
-
-var copyOf = android.CopyOf
diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index ba05d94..8033b48 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -42,7 +42,8 @@
 	// The flag is useful when running dex2oat on system image and vendor image which are built separately.
 	usesTargetFiles = flag.Bool("uses_target_files", false, "whether or not dexpreopt is running on target_files")
 	// basePath indicates the path where target_files.zip is extracted.
-	basePath = flag.String("base_path", ".", "base path where images and tools are extracted")
+	basePath            = flag.String("base_path", ".", "base path where images and tools are extracted")
+	productPackagesPath = flag.String("product_packages", "", "path to product_packages.txt")
 )
 
 type builderContext struct {
@@ -87,6 +88,10 @@
 		usage("--module configuration file is required")
 	}
 
+	if *productPackagesPath == "" {
+		usage("--product_packages configuration file is required")
+	}
+
 	// NOTE: duplicating --out_dir here is incorrect (one should be the another
 	// plus "/soong" but doing so apparently breaks dexpreopt
 	ctx := &builderContext{android.NullConfig(*outDir, *outDir)}
@@ -159,11 +164,12 @@
 			moduleConfig.DexPreoptImageLocationsOnHost[i] = *basePath + location
 		}
 	}
-	writeScripts(ctx, globalSoongConfig, globalConfig, moduleConfig, *dexpreoptScriptPath)
+	writeScripts(ctx, globalSoongConfig, globalConfig, moduleConfig, *dexpreoptScriptPath, *productPackagesPath)
 }
 
 func writeScripts(ctx android.BuilderContext, globalSoong *dexpreopt.GlobalSoongConfig,
-	global *dexpreopt.GlobalConfig, module *dexpreopt.ModuleConfig, dexpreoptScriptPath string) {
+	global *dexpreopt.GlobalConfig, module *dexpreopt.ModuleConfig, dexpreoptScriptPath string,
+	productPackagesPath string) {
 	write := func(rule *android.RuleBuilder, file string) {
 		script := &bytes.Buffer{}
 		script.WriteString(scriptHeader)
@@ -199,7 +205,8 @@
 			panic(err)
 		}
 	}
-	dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, module)
+	dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
+		ctx, globalSoong, global, module, android.PathForTesting(productPackagesPath))
 	if err != nil {
 		panic(err)
 	}
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 429b5ff..230fbb4 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,
@@ -100,8 +99,9 @@
 	globalSoong := globalSoongConfigForTests()
 	global := GlobalConfigForTests(ctx)
 	module := testSystemModuleConfig(ctx, "test")
+	productPackages := android.PathForTesting("product_packages.txt")
 
-	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -124,6 +124,7 @@
 	systemModule := testSystemModuleConfig(ctx, "Stest")
 	systemProductModule := testSystemProductModuleConfig(ctx, "SPtest")
 	productModule := testProductModuleConfig(ctx, "Ptest")
+	productPackages := android.PathForTesting("product_packages.txt")
 
 	global.HasSystemOther = true
 
@@ -157,7 +158,7 @@
 	for _, test := range tests {
 		global.PatternsOnSystemOther = test.patterns
 		for _, mt := range test.moduleTests {
-			rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module)
+			rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module, productPackages)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -182,11 +183,12 @@
 	globalSoong := globalSoongConfigForTests()
 	global := GlobalConfigForTests(ctx)
 	module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
+	productPackages := android.PathForTesting("product_packages.txt")
 
 	global.ApexSystemServerJars = android.CreateTestConfiguredJarList(
 		[]string{"com.android.apex1:service-A"})
 
-	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -205,11 +207,12 @@
 	globalSoong := globalSoongConfigForTests()
 	global := GlobalConfigForTests(ctx)
 	module := testPlatformSystemServerModuleConfig(ctx, "service-A")
+	productPackages := android.PathForTesting("product_packages.txt")
 
 	global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
 		[]string{"platform:service-A"})
 
-	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -228,11 +231,12 @@
 	globalSoong := globalSoongConfigForTests()
 	global := GlobalConfigForTests(ctx)
 	module := testSystemExtSystemServerModuleConfig(ctx, "service-A")
+	productPackages := android.PathForTesting("product_packages.txt")
 
 	global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
 		[]string{"system_ext:service-A"})
 
-	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -251,11 +255,12 @@
 	globalSoong := globalSoongConfigForTests()
 	global := GlobalConfigForTests(ctx)
 	module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
+	productPackages := android.PathForTesting("product_packages.txt")
 
 	global.ApexStandaloneSystemServerJars = android.CreateTestConfiguredJarList(
 		[]string{"com.android.apex1:service-A"})
 
-	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -274,10 +279,11 @@
 	globalSoong := globalSoongConfigForTests()
 	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)
+	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go
index 6ed0736..147a562 100644
--- a/dexpreopt/testing.go
+++ b/dexpreopt/testing.go
@@ -111,6 +111,13 @@
 	})
 }
 
+// FixtureSetTestOnlyArtBootImageJars enables dexpreopt and sets the TestOnlyArtBootImageJars property.
+func FixtureSetTestOnlyArtBootImageJars(bootJars ...string) android.FixturePreparer {
+	return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
+		dexpreoptConfig.TestOnlyArtBootImageJars = android.CreateTestConfiguredJarList(bootJars)
+	})
+}
+
 // FixtureSetBootJars enables dexpreopt and sets the BootJars property.
 func FixtureSetBootJars(bootJars ...string) android.FixturePreparer {
 	return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) {
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 110891b..8e2c597 100644
--- a/docs/clion.md
+++ b/docs/clion.md
@@ -4,7 +4,7 @@
 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/master/aidegen/README.md)
+[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:
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/etc/Android.bp b/etc/Android.bp
index c670236..cefd717 100644
--- a/etc/Android.bp
+++ b/etc/Android.bp
@@ -14,10 +14,12 @@
     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 3e1bbde..7642378 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -31,13 +31,11 @@
 	"encoding/json"
 	"fmt"
 	"path/filepath"
-	"reflect"
 	"strings"
 
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/snapshot"
 )
 
@@ -63,6 +61,7 @@
 	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)
 
@@ -136,7 +135,6 @@
 type PrebuiltEtc struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
-	android.BazelModuleBase
 
 	snapshot.VendorSnapshotModuleInterface
 	snapshot.RecoverySnapshotModuleInterface
@@ -147,12 +145,19 @@
 	sourceFilePath android.Path
 	outputFilePath android.OutputPath
 	// 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 {
@@ -329,7 +334,6 @@
 		ctx.PropertyErrorf("src", "missing prebuilt source file")
 		return
 	}
-	p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
 
 	if strings.Contains(filename, "/") {
 		ctx.PropertyErrorf("filename", "filename cannot contain separator '/'")
@@ -344,26 +348,55 @@
 	// 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())
+	}
+
 	p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, p.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,
-		Output: p.outputFilePath,
-		Input:  p.sourceFilePath,
-	})
+	// 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)
+}
 
-	if !p.Installable() {
+type installProperties struct {
+	installable    bool
+	filename       string
+	sourceFilePath android.Path
+	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()
 	}
 
-	// Call InstallFile even when uninstallable to make the module included in the package
-	installPath := ctx.InstallFile(p.installDirPath, p.outputFilePath.Base(), p.outputFilePath)
-	for _, sl := range p.properties.Symlinks {
+	// 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,
+		Input:  ip.sourceFilePath,
+	})
+
+	installPath := ctx.InstallFile(p.installDirPath, ip.filename, p.outputFilePath)
+	for _, sl := range ip.symlinks {
 		ctx.InstallSymlink(p.installDirPath, sl, installPath)
 	}
 }
@@ -382,8 +415,14 @@
 	if p.InRecovery() && !p.onlyInRecovery() {
 		nameSuffix = ".recovery"
 	}
+
+	class := p.makeClass
+	if class == "" {
+		class = "ETC"
+	}
+
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
-		Class:      "ETC",
+		Class:      class,
 		SubName:    nameSuffix,
 		OutputFile: android.OptionalPathForPath(p.outputFilePath),
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
@@ -398,11 +437,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)
@@ -422,7 +466,6 @@
 	// This module is device-only
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
 	android.InitDefaultableModule(module)
-	android.InitBazelModule(module)
 	return module
 }
 
@@ -452,7 +495,6 @@
 	// This module is host-only
 	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
-	android.InitBazelModule(module)
 	return module
 }
 
@@ -463,7 +505,6 @@
 	InitPrebuiltEtcModule(module, "cacerts")
 	// This module is device-only
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
-	android.InitBazelModule(module)
 	return module
 }
 
@@ -497,7 +538,6 @@
 	// This module is device-only
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
 	android.InitDefaultableModule(module)
-	android.InitBazelModule(module)
 	return module
 }
 
@@ -549,6 +589,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 {
@@ -676,108 +729,3 @@
 
 	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)
-}
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index 0d44c31..df11709 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -82,7 +82,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)
 	}
 }
 
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..2f6476c 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -36,7 +36,9 @@
 	ctx.RegisterModuleType("android_filesystem", filesystemFactory)
 	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 {
@@ -104,6 +106,9 @@
 	// 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
 }
 
 // android_filesystem packages a set of modules and their transitive dependencies into a filesystem
@@ -332,7 +337,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 +352,16 @@
 		addStr("avb_algorithm", algorithm)
 		key := android.PathForModuleSrc(ctx, proptools.String(f.properties.Avb_private_key))
 		addPath("avb_key_path", key)
+		partitionName := proptools.StringDefault(f.properties.Partition_name, f.Name())
+		addStr("partition_name", 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
 		}
+		securityPatchKey := "com.android.build." + 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())
 	}
 
@@ -504,6 +512,6 @@
 
 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()
 }
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 79d2412..47fd8f4 100644
--- a/fuzz/fuzz_common.go
+++ b/fuzz/fuzz_common.go
@@ -61,6 +61,7 @@
 type FileToZip struct {
 	SourceFilePath        android.Path
 	DestinationPathPrefix string
+	DestinationPath       string
 }
 
 type ArchOs struct {
@@ -169,6 +170,27 @@
 	return false
 }
 
+type UsePlatformLibs string
+
+const (
+	unknown_use_platform_libs UsePlatformLibs = "unknown_use_platform_libs"
+	// Use the native libraries on the device, typically in /system directory
+	use_platform_libs = "use_platform_libs"
+	// Do not use any native libraries (ART will not be initialized)
+	use_none = "use_none"
+)
+
+func (use_platform_libs UsePlatformLibs) isValidUsePlatformLibs() bool {
+	switch use_platform_libs {
+	case "",
+		unknown_use_platform_libs,
+		use_platform_libs,
+		use_none:
+		return true
+	}
+	return false
+}
+
 type UserData string
 
 const (
@@ -283,6 +305,10 @@
 		if !config.Automatically_route_to.isValidAutomaticallyRouteTo() {
 			panic(fmt.Errorf("Invalid automatically_route_to in fuzz config in %s", moduleName))
 		}
+
+		if !config.Use_platform_libs.isValidUsePlatformLibs() {
+			panic(fmt.Errorf("Invalid use_platform_libs in fuzz config in %s", moduleName))
+		}
 	}
 	return true
 }
@@ -339,7 +365,14 @@
 	// List of modules for monitoring coverage drops in directories (e.g. "libicu")
 	Target_modules []string `json:"target_modules,omitempty"`
 	// Specifies a bug assignee to replace default ISE assignment
-	Assignee string `json:"assignee,omitempty"`
+	Triage_assignee string `json:"triage_assignee,omitempty"`
+	// Specifies libs used to initialize ART (java only, 'use_none' for no initialization)
+	Use_platform_libs UsePlatformLibs `json:"use_platform_libs,omitempty"`
+	// Specifies whether fuzz target should check presubmitted code changes for crashes.
+	// Defaults to false.
+	Use_for_presubmit *bool `json:"use_for_presubmit,omitempty"`
+	// Specify which paths to exclude from fuzzing coverage reports
+	Exclude_paths_from_reports []string `json:"exclude_paths_from_reports,omitempty"`
 }
 
 type FuzzFrameworks struct {
@@ -366,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 {
@@ -443,7 +474,7 @@
 			FlagWithOutput("-o ", corpusZip)
 		rspFile := corpusZip.ReplaceExtension(ctx, "rsp")
 		command.FlagWithRspFileInputList("-r ", rspFile, fuzzModule.Corpus)
-		files = append(files, FileToZip{corpusZip, ""})
+		files = append(files, FileToZip{SourceFilePath: corpusZip})
 	}
 
 	// Package the data into a zipfile.
@@ -456,17 +487,17 @@
 			command.FlagWithArg("-C ", intermediateDir)
 			command.FlagWithInput("-f ", f)
 		}
-		files = append(files, FileToZip{dataZip, ""})
+		files = append(files, FileToZip{SourceFilePath: dataZip})
 	}
 
 	// The dictionary.
 	if fuzzModule.Dictionary != nil {
-		files = append(files, FileToZip{fuzzModule.Dictionary, ""})
+		files = append(files, FileToZip{SourceFilePath: fuzzModule.Dictionary})
 	}
 
 	// Additional fuzz config.
 	if fuzzModule.Config != nil && IsValidConfig(fuzzModule, module.Name()) {
-		files = append(files, FileToZip{fuzzModule.Config, ""})
+		files = append(files, FileToZip{SourceFilePath: fuzzModule.Config})
 	}
 
 	return files
@@ -485,24 +516,25 @@
 		} else {
 			command.Flag("-P ''")
 		}
+		if file.DestinationPath != "" {
+			command.FlagWithArg("-e ", file.DestinationPath)
+		}
 		command.FlagWithInput("-f ", file.SourceFilePath)
 	}
 
 	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
 		}
 	}
 
 	s.FuzzTargets[module.Name()] = true
-	archDirs[archOs] = append(archDirs[archOs], FileToZip{fuzzZip, ""})
+	archDirs[archOs] = append(archDirs[archOs], FileToZip{SourceFilePath: fuzzZip})
 
 	return archDirs[archOs], true
 }
diff --git a/genrule/Android.bp b/genrule/Android.bp
index 8fb5c40..7331741 100644
--- a/genrule/Android.bp
+++ b/genrule/Android.bp
@@ -11,10 +11,10 @@
         "sbox_proto",
         "soong",
         "soong-android",
-        "soong-bazel",
         "soong-shared",
     ],
     srcs: [
+        "allowlists.go",
         "genrule.go",
         "locations.go",
     ],
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
new file mode 100644
index 0000000..60b1366
--- /dev/null
+++ b/genrule/allowlists.go
@@ -0,0 +1,29 @@
+// 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 genrule
+
+var (
+	SandboxingDenyModuleList = []string{
+		// go/keep-sorted start
+		"aidl_camera_build_version",
+		"com.google.pixel.camera.hal.manifest",
+		// go/keep-sorted end
+	}
+
+	SandboxingDenyPathList = []string{
+		// go/keep-sorted start
+		// go/keep-sorted end
+	}
+)
diff --git a/genrule/genrule.go b/genrule/genrule.go
index f532297..6f66088 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
@@ -151,12 +143,14 @@
 
 	// input files to exclude
 	Exclude_srcs []string `android:"path,arch_variant"`
+
+	// Enable restat to update the output only if the output is changed
+	Write_if_changed *bool
 }
 
 type Module struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
-	android.BazelModuleBase
 	android.ApexModuleBase
 
 	// For other packages to make their own genrules with extra
@@ -187,21 +181,18 @@
 	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
+	in          android.Paths
+	out         android.WritablePaths
+	copyTo      android.WritablePaths // For gensrcs to set on gensrcsMerge rule.
+	genDir      android.WritablePath
+	extraInputs map[string][]string
 
 	cmd string
 	// For gensrsc sharding.
@@ -253,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
@@ -285,13 +252,13 @@
 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,
 				android.PathForModuleGen(ctx, g.subDir, ctx.ModuleDir(), dir))
+			// Also export without ModuleDir for consistency with Export_include_dirs not being set
+			g.exportedIncludeDirs = append(g.exportedIncludeDirs,
+				android.PathForModuleGen(ctx, g.subDir, dir))
 		}
 	} else {
 		g.exportedIncludeDirs = append(g.exportedIncludeDirs, android.PathForModuleGen(ctx, g.subDir))
@@ -395,31 +362,35 @@
 		addLocationLabel(toolFile, toolLocation{paths})
 	}
 
-	includeDirInPaths := ctx.DeviceConfig().BuildBrokenInputDir(g.Name())
-	var srcFiles android.Paths
-	for _, in := range g.properties.Srcs {
-		paths, missingDeps := android.PathsAndMissingDepsRelativeToModuleSourceDir(android.SourceInput{
-			Context: ctx, Paths: []string{in}, ExcludePaths: g.properties.Exclude_srcs, IncludeDirs: includeDirInPaths,
-		})
-		if len(missingDeps) > 0 {
-			if !ctx.Config().AllowMissingDependencies() {
-				panic(fmt.Errorf("should never get here, the missing dependencies %q should have been reported in DepsMutator",
-					missingDeps))
-			}
+	addLabelsForInputs := func(propName string, include, exclude []string) android.Paths {
+		includeDirInPaths := ctx.DeviceConfig().BuildBrokenInputDir(g.Name())
+		var srcFiles android.Paths
+		for _, in := range include {
+			paths, missingDeps := android.PathsAndMissingDepsRelativeToModuleSourceDir(android.SourceInput{
+				Context: ctx, Paths: []string{in}, ExcludePaths: exclude, IncludeDirs: includeDirInPaths,
+			})
+			if len(missingDeps) > 0 {
+				if !ctx.Config().AllowMissingDependencies() {
+					panic(fmt.Errorf("should never get here, the missing dependencies %q should have been reported in DepsMutator",
+						missingDeps))
+				}
 
-			// If AllowMissingDependencies is enabled, the build will not have stopped when
-			// the dependency was added on a missing SourceFileProducer module, which will result in nonsensical
-			// "cmd: label ":..." has no files" errors later.  Add a placeholder file to the local label.
-			// The command that uses this placeholder file will never be executed because the rule will be
-			// replaced with an android.Error rule reporting the missing dependencies.
-			ctx.AddMissingDependencies(missingDeps)
-			addLocationLabel(in, errorLocation{"***missing srcs " + in + "***"})
-		} else {
-			srcFiles = append(srcFiles, paths...)
-			addLocationLabel(in, inputLocation{paths})
+				// If AllowMissingDependencies is enabled, the build will not have stopped when
+				// the dependency was added on a missing SourceFileProducer module, which will result in nonsensical
+				// "cmd: label ":..." has no files" errors later.  Add a placeholder file to the local label.
+				// The command that uses this placeholder file will never be executed because the rule will be
+				// replaced with an android.Error rule reporting the missing dependencies.
+				ctx.AddMissingDependencies(missingDeps)
+				addLocationLabel(in, errorLocation{"***missing " + propName + " " + in + "***"})
+			} else {
+				srcFiles = append(srcFiles, paths...)
+				addLocationLabel(in, inputLocation{paths})
+			}
 		}
+		return srcFiles
 	}
-	ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcFiles.Strings()})
+	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
@@ -430,13 +401,21 @@
 		cmd = g.CmdModifier(ctx, cmd)
 	}
 
+	var extraInputs android.Paths
 	// Generate tasks, either from genrule or gensrcs.
-	for _, task := range g.taskGenerator(ctx, cmd, srcFiles) {
+	for i, task := range g.taskGenerator(ctx, cmd, srcFiles) {
 		if len(task.out) == 0 {
 			ctx.ModuleErrorf("must have at least one output file")
 			return
 		}
 
+		// Only handle extra inputs once as these currently are the same across all tasks
+		if i == 0 {
+			for name, values := range task.extraInputs {
+				extraInputs = append(extraInputs, addLabelsForInputs(name, values, []string{})...)
+			}
+		}
+
 		// Pick a unique path outside the task.genDir for the sbox manifest textproto,
 		// a unique rule name, and the user-visible description.
 		manifestName := "genrule.sbox.textproto"
@@ -453,15 +432,16 @@
 		manifestPath := android.PathForModuleOut(ctx, manifestName)
 
 		// Use a RuleBuilder to create a rule that runs the command inside an sbox sandbox.
-		rule := android.NewRuleBuilder(pctx, ctx).Sbox(task.genDir, manifestPath).SandboxTools()
+		rule := getSandboxedRuleBuilder(ctx, android.NewRuleBuilder(pctx, ctx).Sbox(task.genDir, manifestPath))
+		if Bool(g.properties.Write_if_changed) {
+			rule.Restat()
+		}
 		cmd := rule.Command()
 
 		for _, out := range task.out {
 			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
@@ -493,12 +473,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:
@@ -523,7 +497,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)
 					}
@@ -538,21 +512,15 @@
 			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)
+		cmd.Implicits(srcFiles) // need to be able to reference other srcs
+		cmd.Implicits(extraInputs)
 		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)
@@ -593,18 +561,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 ctx.ModuleType() == "gensrcs" &&
-		!ctx.DeviceConfig().BuildBrokenDepfile() &&
-		Bool(g.properties.Depfile) {
-		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 use BUILD_BROKEN_DEPFILE to bypass the error.")
-	}
-
 	g.generateCommonBuildActions(ctx)
 
 	// For <= 6 outputs, just embed those directly in the users. Right now, that covers >90% of
@@ -622,15 +578,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.
@@ -642,7 +607,6 @@
 			dpInfo.Deps = append(dpInfo.Deps, src)
 		}
 	}
-	dpInfo.Paths = append(dpInfo.Paths, g.modulePaths...)
 }
 
 func (g *Module) AndroidMk() android.AndroidMkData {
@@ -722,7 +686,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
@@ -738,7 +701,7 @@
 			// TODO(ccross): this RuleBuilder is a hack to be able to call
 			// rule.Command().PathForOutput.  Replace this with passing the rule into the
 			// generator.
-			rule := android.NewRuleBuilder(pctx, ctx).Sbox(genDir, nil).SandboxTools()
+			rule := getSandboxedRuleBuilder(ctx, android.NewRuleBuilder(pctx, ctx).Sbox(genDir, nil))
 
 			for _, in := range shard {
 				outFile := android.GenPathWithExt(ctx, finalSubDir, in, String(properties.Output_extension))
@@ -762,12 +725,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
 					}
@@ -782,30 +739,17 @@
 			}
 			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,
+				},
 			})
 		}
 
@@ -820,7 +764,6 @@
 func GenSrcsFactory() android.Module {
 	m := NewGenSrcs()
 	android.InitAndroidModule(m)
-	android.InitBazelModule(m)
 	return m
 }
 
@@ -830,13 +773,9 @@
 
 	// maximum number of files that will be passed on a single command line.
 	Shard_size *int64
-}
 
-type bazelGensrcsAttributes struct {
-	Srcs             bazel.LabelListAttribute
-	Output_extension *string
-	Tools            bazel.LabelListAttribute
-	Cmd              string
+	// Additional files needed for build that are not tooling related.
+	Data []string `android:"path"`
 }
 
 const defaultShardSize = 50
@@ -846,20 +785,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,
 		}}
 	}
 
@@ -870,7 +803,6 @@
 	m := NewGenRule()
 	android.InitAndroidModule(m)
 	android.InitDefaultableModule(m)
-	android.InitBazelModule(m)
 	return m
 }
 
@@ -879,122 +811,6 @@
 	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))
-
-	// 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)
-
-	if ctx.ModuleType() == "gensrcs" {
-		// 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
-		for _, propIntf := range m.GetProperties() {
-			if props, ok := propIntf.(*genSrcsProperties); ok {
-				outputExtension = props.Output_extension
-				break
-			}
-		}
-		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,
-		}
-		ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-			Name: m.Name(),
-			Tags: tags,
-		}, attrs)
-	} else {
-		// 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 m.GetProperties() {
-			if props, ok := propIntf.(*genRuleProperties); ok {
-				outs = props.Out
-				break
-			}
-		}
-		attrs := &bazelGenruleAttributes{
-			Srcs:  srcs,
-			Outs:  outs,
-			Cmd:   cmd,
-			Tools: tools,
-		}
-		props := bazel.BazelTargetModuleProperties{
-			Rule_class: "genrule",
-		}
-		ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-			Name: m.Name(),
-			Tags: tags,
-		}, attrs)
-	}
-}
-
 var Bool = proptools.Bool
 var String = proptools.String
 
@@ -1021,3 +837,36 @@
 
 	return module
 }
+
+var sandboxingAllowlistKey = android.NewOnceKey("genruleSandboxingAllowlistKey")
+
+type sandboxingAllowlistSets struct {
+	sandboxingDenyModuleSet map[string]bool
+	sandboxingDenyPathSet   map[string]bool
+}
+
+func getSandboxingAllowlistSets(ctx android.PathContext) *sandboxingAllowlistSets {
+	return ctx.Config().Once(sandboxingAllowlistKey, func() interface{} {
+		sandboxingDenyModuleSet := map[string]bool{}
+		sandboxingDenyPathSet := map[string]bool{}
+
+		android.AddToStringSet(sandboxingDenyModuleSet, SandboxingDenyModuleList)
+		android.AddToStringSet(sandboxingDenyPathSet, SandboxingDenyPathList)
+		return &sandboxingAllowlistSets{
+			sandboxingDenyModuleSet: sandboxingDenyModuleSet,
+			sandboxingDenyPathSet:   sandboxingDenyPathSet,
+		}
+	}).(*sandboxingAllowlistSets)
+}
+
+func getSandboxedRuleBuilder(ctx android.ModuleContext, r *android.RuleBuilder) *android.RuleBuilder {
+	if !ctx.DeviceConfig().GenruleSandboxing() {
+		return r.SandboxTools()
+	}
+	sandboxingAllowlistSets := getSandboxingAllowlistSets(ctx)
+	if sandboxingAllowlistSets.sandboxingDenyPathSet[ctx.ModuleDir()] ||
+		sandboxingAllowlistSets.sandboxingDenyModuleSet[ctx.ModuleName()] {
+		return r.SandboxTools()
+	}
+	return r.SandboxInputs()
+}
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 63f8fa9..2dc6a79 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -18,6 +18,7 @@
 	"fmt"
 	"os"
 	"regexp"
+	"strconv"
 	"testing"
 
 	"android/soong/android"
@@ -97,8 +98,9 @@
 
 func TestGenruleCmd(t *testing.T) {
 	testcases := []struct {
-		name string
-		prop string
+		name       string
+		moduleName string
+		prop       string
 
 		allowMissingDependencies bool
 
@@ -285,15 +287,6 @@
 			expect: "echo foo > __SBOX_SANDBOX_DIR__/out/out2",
 		},
 		{
-			name: "depfile",
-			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"],
@@ -389,23 +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",
-			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)",
@@ -440,11 +416,15 @@
 
 	for _, test := range testcases {
 		t.Run(test.name, func(t *testing.T) {
-			bp := "genrule {\n"
-			bp += "name: \"gen\",\n"
-			bp += test.prop
-			bp += "}\n"
-
+			moduleName := "gen"
+			if test.moduleName != "" {
+				moduleName = test.moduleName
+			}
+			bp := fmt.Sprintf(`
+			genrule {
+			   name: "%s",
+			   %s
+			}`, moduleName, test.prop)
 			var expectedErrors []string
 			if test.err != "" {
 				expectedErrors = append(expectedErrors, regexp.QuoteMeta(test.err))
@@ -455,6 +435,9 @@
 				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 					variables.Allow_missing_dependencies = proptools.BoolPtr(test.allowMissingDependencies)
 				}),
+				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+					variables.GenruleSandboxing = proptools.BoolPtr(true)
+				}),
 				android.FixtureModifyContext(func(ctx *android.TestContext) {
 					ctx.SetAllowMissingDependencies(test.allowMissingDependencies)
 				}),
@@ -466,7 +449,7 @@
 				return
 			}
 
-			gen := result.Module("gen", "").(*Module)
+			gen := result.Module(moduleName, "").(*Module)
 			android.AssertStringEquals(t, "raw commands", test.expect, gen.rawCommands[0])
 		})
 	}
@@ -532,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)
@@ -547,10 +530,12 @@
 
 		allowMissingDependencies bool
 
-		err   string
-		cmds  []string
-		deps  []string
-		files []string
+		err    string
+		cmds   []string
+		deps   []string
+		files  []string
+		shards int
+		inputs []string
 	}{
 		{
 			name: "gensrcs",
@@ -594,6 +579,50 @@
 				"out/soong/.intermediates/gen/gen/gensrcs/in3.h",
 			},
 		},
+		{
+			name: "data",
+			prop: `
+				tools: ["tool"],
+				srcs: ["in1.txt", "in2.txt", "in3.txt"],
+				cmd: "$(location) $(in) --extra_input=$(location baz.txt) > $(out)",
+				data: ["baz.txt"],
+				shard_size: 2,
+			`,
+			cmds: []string{
+				"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in1.txt --extra_input=baz.txt > __SBOX_SANDBOX_DIR__/out/in1.h' && bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in2.txt --extra_input=baz.txt > __SBOX_SANDBOX_DIR__/out/in2.h'",
+				"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in3.txt --extra_input=baz.txt > __SBOX_SANDBOX_DIR__/out/in3.h'",
+			},
+			deps: []string{
+				"out/soong/.intermediates/gen/gen/gensrcs/in1.h",
+				"out/soong/.intermediates/gen/gen/gensrcs/in2.h",
+				"out/soong/.intermediates/gen/gen/gensrcs/in3.h",
+			},
+			files: []string{
+				"out/soong/.intermediates/gen/gen/gensrcs/in1.h",
+				"out/soong/.intermediates/gen/gen/gensrcs/in2.h",
+				"out/soong/.intermediates/gen/gen/gensrcs/in3.h",
+			},
+			shards: 2,
+			inputs: []string{
+				"baz.txt",
+			},
+		},
+	}
+
+	checkInputs := func(t *testing.T, rule android.TestingBuildParams, inputs []string) {
+		t.Helper()
+		if len(inputs) == 0 {
+			return
+		}
+		inputBaseNames := map[string]bool{}
+		for _, f := range rule.Implicits {
+			inputBaseNames[f.Base()] = true
+		}
+		for _, f := range inputs {
+			if _, ok := inputBaseNames[f]; !ok {
+				t.Errorf("Expected to find input file %q for %q, but did not", f, rule.Description)
+			}
+		}
 	}
 
 	for _, test := range testcases {
@@ -613,10 +642,21 @@
 				ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
 				RunTestWithBp(t, testGenruleBp()+bp)
 
+			mod := result.ModuleForTests("gen", "")
 			if expectedErrors != nil {
 				return
 			}
 
+			if test.shards > 0 {
+				for i := 0; i < test.shards; i++ {
+					r := mod.Rule("generator" + strconv.Itoa(i))
+					checkInputs(t, r, test.inputs)
+				}
+			} else {
+				r := mod.Rule("generator")
+				checkInputs(t, r, test.inputs)
+			}
+
 			gen := result.Module("gen", "").(*Module)
 			android.AssertDeepEquals(t, "cmd", test.cmds, gen.rawCommands)
 
@@ -627,73 +667,6 @@
 	}
 }
 
-func TestGensrcsBuildBrokenDepfile(t *testing.T) {
-	tests := []struct {
-		name               string
-		prop               string
-		BuildBrokenDepfile *bool
-		err                string
-	}{
-		{
-			name: `error when BuildBrokenDepfile is set to false`,
-			prop: `
-				depfile: true,
-				cmd: "cat $(in) > $(out) && cat $(depfile)",
-			`,
-			BuildBrokenDepfile: proptools.BoolPtr(false),
-			err:                "depfile: Deprecated to ensure the module type is convertible to Bazel",
-		},
-		{
-			name: `error when BuildBrokenDepfile is not set`,
-			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 BuildBrokenDepfile is explicitly set to true`,
-			prop: `
-				depfile: true,
-				cmd: "cat $(in) > $(out) && cat $(depfile)",
-			`,
-			BuildBrokenDepfile: proptools.BoolPtr(true),
-		},
-		{
-			name: `no error if depfile is not set`,
-			prop: `
-				cmd: "cat $(in) > $(out)",
-			`,
-		},
-	}
-	for _, test := range tests {
-		t.Run(test.name, func(t *testing.T) {
-			bp := fmt.Sprintf(`
-			gensrcs {
-			   name: "foo",
-			   srcs: ["data.txt"],
-			   %s
-			}`, test.prop)
-
-			var expectedErrors []string
-			if test.err != "" {
-				expectedErrors = append(expectedErrors, test.err)
-			}
-			android.GroupFixturePreparers(
-				prepareForGenRuleTest,
-				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-					if test.BuildBrokenDepfile != nil {
-						variables.BuildBrokenDepfile = test.BuildBrokenDepfile
-					}
-				}),
-			).
-				ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)).
-				RunTestWithBp(t, bp)
-		})
-
-	}
-}
-
 func TestGenruleDefaults(t *testing.T) {
 	bp := `
 				genrule_defaults {
@@ -790,6 +763,49 @@
 		result.ModuleForTests("gen_all", "").Module().(*useSource).srcs)
 }
 
+func TestGenruleInterface(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForGenRuleTest,
+		android.FixtureMergeMockFs(android.MockFS{
+			"package-dir/Android.bp": []byte(`
+				genrule {
+					name: "module-name",
+					cmd: "mkdir -p $(genDir) && cat $(in) >> $(genDir)/$(out)",
+					srcs: [
+						"src/foo.proto",
+					],
+					out: ["proto.h", "bar/proto.h"],
+					export_include_dirs: [".", "bar"],
+				}
+			`),
+		}),
+	).RunTest(t)
+
+	exportedIncludeDirs := []string{
+		"out/soong/.intermediates/package-dir/module-name/gen/package-dir",
+		"out/soong/.intermediates/package-dir/module-name/gen",
+		"out/soong/.intermediates/package-dir/module-name/gen/package-dir/bar",
+		"out/soong/.intermediates/package-dir/module-name/gen/bar",
+	}
+	gen := result.Module("module-name", "").(*Module)
+
+	android.AssertPathsRelativeToTopEquals(
+		t,
+		"include path",
+		exportedIncludeDirs,
+		gen.GeneratedHeaderDirs(),
+	)
+	android.AssertPathsRelativeToTopEquals(
+		t,
+		"files",
+		[]string{
+			"out/soong/.intermediates/package-dir/module-name/gen/proto.h",
+			"out/soong/.intermediates/package-dir/module-name/gen/bar/proto.h",
+		},
+		gen.GeneratedSourceFiles(),
+	)
+}
+
 func TestGenSrcsWithNonRootAndroidBpOutputFiles(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForGenRuleTest,
@@ -941,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 a5d9dd5..1174958 100644
--- a/go.mod
+++ b/go.mod
@@ -1,9 +1,10 @@
 module android/soong
 
-go 1.19
+go 1.21
 
 require (
 	github.com/google/blueprint v0.0.0
 	google.golang.org/protobuf v0.0.0
 	prebuilts/bazel/common/proto/analysis_v2 v0.0.0
+	go.starlark.net v0.0.0
 )
diff --git a/go.work b/go.work
index 737a9df..7c6022b 100644
--- a/go.work
+++ b/go.work
@@ -1,9 +1,10 @@
-go 1.19
+go 1.21
 
 use (
 	.
 	../../external/go-cmp
 	../../external/golang-protobuf
+	../../external/starlark-go
 	../../prebuilts/bazel/common/proto/analysis_v2
 	../../prebuilts/bazel/common/proto/build
 	../blueprint
@@ -16,4 +17,5 @@
 	google.golang.org/protobuf v0.0.0 => ../../external/golang-protobuf
 	prebuilts/bazel/common/proto/analysis_v2 v0.0.0 => ../../prebuilts/bazel/common/proto/analysis_v2
 	prebuilts/bazel/common/proto/build v0.0.0 => ../../prebuilts/bazel/common/proto/build
+	go.starlark.net v0.0.0 => ../../external/starlark-go
 )
diff --git a/jar/Android.bp b/jar/Android.bp
index 46113d8..c03e491 100644
--- a/jar/Android.bp
+++ b/jar/Android.bp
@@ -21,6 +21,7 @@
     pkgPath: "android/soong/jar",
     srcs: [
         "jar.go",
+        "services.go",
     ],
     testSrcs: [
         "jar_test.go",
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/jar/services.go b/jar/services.go
new file mode 100644
index 0000000..d06a6dc
--- /dev/null
+++ b/jar/services.go
@@ -0,0 +1,128 @@
+// 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 jar
+
+import (
+	"android/soong/third_party/zip"
+	"bufio"
+	"hash/crc32"
+	"sort"
+	"strings"
+)
+
+const servicesPrefix = "META-INF/services/"
+
+// Services is used to collect service files from multiple zip files and produce a list of ServiceFiles containing
+// the unique lines from all the input zip entries with the same name.
+type Services struct {
+	services map[string]*ServiceFile
+}
+
+// ServiceFile contains the combined contents of all input zip entries with a single name.
+type ServiceFile struct {
+	Name       string
+	FileHeader *zip.FileHeader
+	Contents   []byte
+	Lines      []string
+}
+
+// IsServiceFile returns true if the zip entry is in the META-INF/services/ directory.
+func (Services) IsServiceFile(entry *zip.File) bool {
+	return strings.HasPrefix(entry.Name, servicesPrefix)
+}
+
+// AddServiceFile adds a zip entry in the META-INF/services/ directory to the list of service files that need
+// to be combined.
+func (j *Services) AddServiceFile(entry *zip.File) error {
+	if j.services == nil {
+		j.services = map[string]*ServiceFile{}
+	}
+
+	service := entry.Name
+	serviceFile := j.services[service]
+	fh := entry.FileHeader
+	if serviceFile == nil {
+		serviceFile = &ServiceFile{
+			Name:       service,
+			FileHeader: &fh,
+		}
+		j.services[service] = serviceFile
+	}
+
+	f, err := entry.Open()
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	scanner := bufio.NewScanner(f)
+	for scanner.Scan() {
+		line := scanner.Text()
+		if line != "" {
+			serviceFile.Lines = append(serviceFile.Lines, line)
+		}
+	}
+
+	if err := scanner.Err(); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// ServiceFiles returns the list of combined service files, each containing all the unique lines from the
+// corresponding service files in the input zip entries.
+func (j *Services) ServiceFiles() []ServiceFile {
+	services := make([]ServiceFile, 0, len(j.services))
+
+	for _, serviceFile := range j.services {
+		serviceFile.Lines = dedupServicesLines(serviceFile.Lines)
+		serviceFile.Lines = append(serviceFile.Lines, "")
+		serviceFile.Contents = []byte(strings.Join(serviceFile.Lines, "\n"))
+
+		serviceFile.FileHeader.UncompressedSize64 = uint64(len(serviceFile.Contents))
+		serviceFile.FileHeader.CRC32 = crc32.ChecksumIEEE(serviceFile.Contents)
+		if serviceFile.FileHeader.Method == zip.Store {
+			serviceFile.FileHeader.CompressedSize64 = serviceFile.FileHeader.UncompressedSize64
+		}
+
+		services = append(services, *serviceFile)
+	}
+
+	sort.Slice(services, func(i, j int) bool {
+		return services[i].Name < services[j].Name
+	})
+
+	return services
+}
+
+func dedupServicesLines(in []string) []string {
+	writeIndex := 0
+outer:
+	for readIndex := 0; readIndex < len(in); readIndex++ {
+		for compareIndex := 0; compareIndex < writeIndex; compareIndex++ {
+			if interface{}(in[readIndex]) == interface{}(in[compareIndex]) {
+				// The value at readIndex already exists somewhere in the output region
+				// of the slice before writeIndex, skip it.
+				continue outer
+			}
+		}
+		if readIndex != writeIndex {
+			in[writeIndex] = in[readIndex]
+		}
+		writeIndex++
+	}
+	return in[0:writeIndex]
+}
diff --git a/java/Android.bp b/java/Android.bp
index 4d1e34e..54b36ab 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -9,8 +9,8 @@
         "blueprint",
         "blueprint-pathtools",
         "soong",
+        "soong-aconfig",
         "soong-android",
-        "soong-bazel",
         "soong-cc",
         "soong-dexpreopt",
         "soong-genrule",
@@ -49,6 +49,7 @@
         "droidstubs.go",
         "fuzz.go",
         "gen.go",
+        "generated_java_library.go",
         "genrule.go",
         "hiddenapi.go",
         "hiddenapi_modular.go",
@@ -66,7 +67,7 @@
         "plugin.go",
         "prebuilt_apis.go",
         "proto.go",
-        "resourceshrinker.go",
+        "ravenwood.go",
         "robolectric.go",
         "rro.go",
         "sdk.go",
@@ -80,6 +81,7 @@
     ],
     testSrcs: [
         "aar_test.go",
+        "android_manifest_test.go",
         "androidmk_test.go",
         "app_import_test.go",
         "app_set_test.go",
@@ -94,6 +96,7 @@
         "droidstubs_test.go",
         "fuzz_test.go",
         "genrule_test.go",
+        "generated_java_library_test.go",
         "hiddenapi_singleton_test.go",
         "jacoco_test.go",
         "java_test.go",
@@ -105,10 +108,11 @@
         "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",
diff --git a/java/aapt2.go b/java/aapt2.go
index 7845a0b..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
@@ -146,20 +166,25 @@
 
 var aapt2LinkRule = pctx.AndroidStaticRule("aapt2Link",
 	blueprint.RuleParams{
-		Command: `rm -rf $genDir && ` +
-			`${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions ` +
-			`--output-text-symbols ${rTxt} $inFlags && ` +
-			`${config.SoongZipCmd} -write_if_changed -jar -o $genJar -C $genDir -D $genDir &&` +
-			`${config.ExtractJarPackagesCmd} -i $genJar -o $extraPackages --prefix '--extra-packages '`,
+		Command: `$preamble` +
+			`${config.Aapt2Cmd} link -o $out $flags --proguard $proguardOptions ` +
+			`--output-text-symbols ${rTxt} $inFlags` +
+			`$postamble`,
 
 		CommandDeps: []string{
 			"${config.Aapt2Cmd}",
 			"${config.SoongZipCmd}",
-			"${config.ExtractJarPackagesCmd}",
 		},
 		Restat: true,
 	},
-	"flags", "inFlags", "proguardOptions", "genDir", "genJar", "rTxt", "extraPackages")
+	"flags", "inFlags", "proguardOptions", "rTxt", "extraPackages", "preamble", "postamble")
+
+var aapt2ExtractExtraPackagesRule = pctx.AndroidStaticRule("aapt2ExtractExtraPackages",
+	blueprint.RuleParams{
+		Command:     `${config.ExtractJarPackagesCmd} -i $in -o $out --prefix '--extra-packages '`,
+		CommandDeps: []string{"${config.ExtractJarPackagesCmd}"},
+		Restat:      true,
+	})
 
 var fileListToFileRule = pctx.AndroidStaticRule("fileListToFile",
 	blueprint.RuleParams{
@@ -175,11 +200,10 @@
 	})
 
 func aapt2Link(ctx android.ModuleContext,
-	packageRes, genJar, proguardOptions, rTxt, extraPackages android.WritablePath,
+	packageRes, genJar, proguardOptions, rTxt android.WritablePath,
 	flags []string, deps android.Paths,
-	compiledRes, compiledOverlay, assetPackages android.Paths, splitPackages android.WritablePaths) {
-
-	genDir := android.PathForModuleGen(ctx, "aapt2", "R")
+	compiledRes, compiledOverlay, assetPackages android.Paths, splitPackages android.WritablePaths,
+	featureFlagsPaths android.Paths) {
 
 	var inFlags []string
 
@@ -217,7 +241,7 @@
 	}
 
 	// Set auxiliary outputs as implicit outputs to establish correct dependency chains.
-	implicitOutputs := append(splitPackages, proguardOptions, genJar, rTxt, extraPackages)
+	implicitOutputs := append(splitPackages, proguardOptions, rTxt)
 	linkOutput := packageRes
 
 	// AAPT2 ignores assets in overlays. Merge them after linking.
@@ -232,31 +256,61 @@
 		})
 	}
 
+	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
+	// tidy.
+	args := map[string]string{
+		"flags":           strings.Join(flags, " "),
+		"inFlags":         strings.Join(inFlags, " "),
+		"proguardOptions": proguardOptions.String(),
+		"rTxt":            rTxt.String(),
+	}
+
+	if genJar != nil {
+		// Generating java source files from aapt2 was requested, use aapt2LinkAndGenRule and pass it
+		// genJar and genDir args.
+		genDir := android.PathForModuleGen(ctx, "aapt2", "R")
+		ctx.Variable(pctx, "aapt2GenDir", genDir.String())
+		ctx.Variable(pctx, "aapt2GenJar", genJar.String())
+		implicitOutputs = append(implicitOutputs, genJar)
+		args["preamble"] = `rm -rf $aapt2GenDir && `
+		args["postamble"] = `&& ${config.SoongZipCmd} -write_if_changed -jar -o $aapt2GenJar -C $aapt2GenDir -D $aapt2GenDir && ` +
+			`rm -rf $aapt2GenDir`
+		args["flags"] += " --java $aapt2GenDir"
+	}
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:            aapt2LinkRule,
 		Description:     "aapt2 link",
 		Implicits:       deps,
 		Output:          linkOutput,
 		ImplicitOutputs: implicitOutputs,
-		// 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
-		// tidy.
-		Args: map[string]string{
-			"flags":           strings.Join(flags, " "),
-			"inFlags":         strings.Join(inFlags, " "),
-			"proguardOptions": proguardOptions.String(),
-			"genDir":          genDir.String(),
-			"genJar":          genJar.String(),
-			"rTxt":            rTxt.String(),
-			"extraPackages":   extraPackages.String(),
-		},
+		Args:            args,
+	})
+}
+
+// aapt2ExtractExtraPackages takes a srcjar generated by aapt2 or a classes jar generated by ResourceProcessorBusyBox
+// and converts it to a text file containing a list of --extra_package arguments for passing to Make modules so they
+// correctly generate R.java entries for packages provided by transitive dependencies.
+func aapt2ExtractExtraPackages(ctx android.ModuleContext, out android.WritablePath, in android.Path) {
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        aapt2ExtractExtraPackagesRule,
+		Description: "aapt2 extract extra packages",
+		Input:       in,
+		Output:      out,
 	})
 }
 
 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 f1b137d..4a62024 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -17,24 +17,21 @@
 import (
 	"fmt"
 	"path/filepath"
+	"slices"
 	"strconv"
 	"strings"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/dexpreopt"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
 
 type AndroidLibraryDependency interface {
-	LibraryDependency
 	ExportPackage() android.Path
-	ExportedRRODirs() []rroDir
-	ExportedStaticPackages() android.Paths
-	ExportedManifests() android.Paths
-	ExportedAssets() android.OptionalPath
+	ResourcesNodeDepSet() *android.DepSet[*resourcesNode]
+	RRODirsDepSet() *android.DepSet[rroDir]
+	ManifestsDepSet() *android.DepSet[android.Path]
 	SetRROEnforcedForDependent(enforce bool)
 	IsRROEnforced(ctx android.BaseModuleContext) bool
 }
@@ -47,7 +44,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)
 	})
 }
 
@@ -67,6 +64,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.
@@ -89,35 +89,56 @@
 	// do not include AndroidManifest from dependent libraries
 	Dont_merge_manifests *bool
 
+	// If use_resource_processor is set, use Bazel's resource processor instead of aapt2 to generate R.class files.
+	// The resource processor produces more optimal R.class files that only list resources in the package of the
+	// library that provided them, as opposed to aapt2 which produces R.java files for every package containing
+	// every resource.  Using the resource processor can provide significant build time speedups, but requires
+	// fixing the module to use the correct package to reference each resource, and to avoid having any other
+	// libraries in the tree that use the same package name.  Defaults to false, but will default to true in the
+	// future.
+	Use_resource_processor *bool
+
 	// 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"`
 }
 
 type aapt struct {
-	aaptSrcJar              android.Path
-	exportPackage           android.Path
-	manifestPath            android.Path
-	transitiveManifestPaths android.Paths
-	proguardOptionsFile     android.Path
-	rroDirs                 []rroDir
-	rTxt                    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
 
 	aaptProperties aaptProperties
+
+	resourcesNodesDepSet *android.DepSet[*resourcesNode]
+	rroDirsDepSet        *android.DepSet[rroDir]
+	manifestsDepSet      *android.DepSet[android.Path]
+
+	manifestValues struct {
+		applicationId string
+	}
 }
 
 type split struct {
@@ -138,20 +159,27 @@
 	}
 }
 
+func (a *aapt) useResourceProcessorBusyBox(ctx android.BaseModuleContext) bool {
+	return BoolDefault(a.aaptProperties.Use_resource_processor, ctx.Config().UseResourceProcessorByDefault())
+}
+
+func (a *aapt) filterProduct() string {
+	return String(a.aaptProperties.Filter_product)
+}
+
 func (a *aapt) ExportPackage() android.Path {
 	return a.exportPackage
 }
-
-func (a *aapt) ExportedRRODirs() []rroDir {
-	return a.rroDirs
+func (a *aapt) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
+	return a.resourcesNodesDepSet
 }
 
-func (a *aapt) ExportedManifests() android.Paths {
-	return a.transitiveManifestPaths
+func (a *aapt) RRODirsDepSet() *android.DepSet[rroDir] {
+	return a.rroDirsDepSet
 }
 
-func (a *aapt) ExportedAssets() android.OptionalPath {
-	return a.assetPackage
+func (a *aapt) ManifestsDepSet() *android.DepSet[android.Path] {
+	return a.manifestsDepSet
 }
 
 func (a *aapt) SetRROEnforcedForDependent(enforce bool) {
@@ -175,9 +203,14 @@
 	// Flags specified in Android.bp
 	linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)
 
-	linkFlags = append(linkFlags, "--no-static-lib-packages")
+	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)
@@ -212,6 +245,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)
@@ -287,23 +342,30 @@
 		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
+	extraLinkFlags                 []string
+	aconfigTextFiles               android.Paths
+}
 
-	transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, 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)
 
 	// 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,
@@ -311,16 +373,29 @@
 		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)
-	a.transitiveManifestPaths = append(android.Paths{manifestPath}, additionalManifests...)
-	a.transitiveManifestPaths = append(a.transitiveManifestPaths, transitiveStaticLibManifests...)
+	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(a.transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) {
-		a.mergedManifestFile = manifestMerger(ctx, a.transitiveManifestPaths[0], a.transitiveManifestPaths[1:], a.isLibrary)
+	if len(transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) {
+		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
@@ -331,28 +406,41 @@
 		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)
 
-	rroDirs = append(rroDirs, staticRRODirs...)
 	linkFlags = append(linkFlags, libFlags...)
-	linkDeps = append(linkDeps, libDeps...)
-	linkFlags = append(linkFlags, extraLinkFlags...)
+	linkDeps = append(linkDeps, sharedExportPackages...)
+	linkDeps = append(linkDeps, staticDeps.resPackages()...)
+	linkFlags = append(linkFlags, opts.extraLinkFlags...)
 	if a.isLibrary {
 		linkFlags = append(linkFlags, "--static-lib")
 	}
 
+	if a.isLibrary && a.useResourceProcessorBusyBox(ctx) {
+		// 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, "--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")
-	// the subdir "android" is required to be filtered by package names
-	srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar")
 	proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
 	rTxt := android.PathForModuleOut(ctx, "R.txt")
 	// This file isn't used by Soong, but is generated for exporting
 	extraPackages := android.PathForModuleOut(ctx, "extra_packages")
+	var transitiveRJars android.Paths
+	var srcJar android.WritablePath
 
 	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 {
@@ -363,7 +451,32 @@
 
 	var compiledRes, compiledOverlay android.Paths
 
-	compiledOverlay = append(compiledOverlay, transitiveStaticLibs...)
+	// AAPT2 overlays are in lowest to highest priority order, reverse the topological order
+	// of transitiveStaticLibs.
+	transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages())
+
+	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 _, staticDep := range staticDeps {
+			linkDeps = append(linkDeps, staticDep.resPackage)
+			linkFlags = append(linkFlags, "-I "+staticDep.resPackage.String())
+			if staticDep.usedResourceProcessor {
+				transitiveRJars = append(transitiveRJars, staticDep.rJar)
+			}
+		}
+		for _, sharedDep := range sharedDeps {
+			if sharedDep.usedResourceProcessor {
+				transitiveRJars = append(transitiveRJars, sharedDep.rJar)
+			}
+		}
+	} else {
+		// When building an app or building a library without ResourceProcessorBusyBox enabled all static
+		// dependencies are compiled into this module's package-res.apk as overlays.
+		compiledOverlay = append(compiledOverlay, transitiveStaticLibs...)
+	}
 
 	if len(transitiveStaticLibs) > 0 {
 		// If we are using static android libraries, every source file becomes an overlay.
@@ -386,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
@@ -404,12 +517,23 @@
 		})
 	}
 
-	aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, extraPackages,
-		linkFlags, linkDeps, compiledRes, compiledOverlay, assetPackages, splitPackages)
+	if !a.useResourceProcessorBusyBox(ctx) {
+		// the subdir "android" is required to be filtered by package names
+		srcJar = android.PathForModuleGen(ctx, "android", "R.srcjar")
+	}
 
+	// No need to specify assets from dependencies to aapt2Link for libraries, all transitive assets will be
+	// provided to the final app aapt2Link step.
+	var transitiveAssets android.Paths
+	if !a.isLibrary {
+		transitiveAssets = android.ReverseSliceInPlace(staticDeps.assets())
+	}
+	aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt,
+		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 ") || len(assetPackages) > 0 {
+	if android.PrefixInList(linkFlags, "-A ") {
 		assets := android.PathForModuleOut(ctx, "assets.zip")
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        extractAssetsRule,
@@ -420,21 +544,163 @@
 		a.assetPackage = android.OptionalPathForPath(assets)
 	}
 
+	if a.useResourceProcessorBusyBox(ctx) {
+		rJar := android.PathForModuleOut(ctx, "busybox/R.jar")
+		resourceProcessorBusyBoxGenerateBinaryR(ctx, rTxt, a.mergedManifestFile, rJar, staticDeps, a.isLibrary, a.aaptProperties.Aaptflags)
+		aapt2ExtractExtraPackages(ctx, extraPackages, rJar)
+		transitiveRJars = append(transitiveRJars, rJar)
+		a.rJar = rJar
+	} else {
+		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"))
+
 	a.aaptSrcJar = srcJar
+	a.transitiveAaptRJars = transitiveRJars
+	a.transitiveAaptResourcePackagesFile = transitiveAaptResourcePackagesFile
 	a.exportPackage = packageRes
 	a.manifestPath = manifestPath
 	a.proguardOptionsFile = proguardOptionsFile
-	a.rroDirs = rroDirs
 	a.extraAaptPackagesFile = extraPackages
 	a.rTxt = rTxt
 	a.splits = splits
+	a.resourcesNodesDepSet = android.NewDepSetBuilder[*resourcesNode](android.TOPOLOGICAL).
+		Direct(&resourcesNode{
+			resPackage:          a.exportPackage,
+			manifest:            a.manifestPath,
+			additionalManifests: additionalManifests,
+			rTxt:                a.rTxt,
+			rJar:                a.rJar,
+			assets:              a.assetPackage,
+
+			usedResourceProcessor: a.useResourceProcessorBusyBox(ctx),
+		}).
+		Transitive(staticResourcesNodesDepSet).Build()
+	a.rroDirsDepSet = android.NewDepSetBuilder[rroDir](android.TOPOLOGICAL).
+		Direct(rroDirs...).
+		Transitive(staticRRODirsDepSet).Build()
+	a.manifestsDepSet = android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).
+		Direct(a.manifestPath).
+		DirectSlice(additionalManifests).
+		Transitive(staticManifestsDepSet).Build()
+}
+
+var resourceProcessorBusyBox = pctx.AndroidStaticRule("resourceProcessorBusyBox",
+	blueprint.RuleParams{
+		Command: "${config.JavaCmd} -cp ${config.ResourceProcessorBusyBox} " +
+			"com.google.devtools.build.android.ResourceProcessorBusyBox --tool=GENERATE_BINARY_R -- @${out}.args && " +
+			"if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out}; fi",
+		CommandDeps:    []string{"${config.ResourceProcessorBusyBox}"},
+		Rspfile:        "${out}.args",
+		RspfileContent: "--primaryRTxt ${rTxt} --primaryManifest ${manifest} --classJarOutput ${out}.tmp ${args}",
+		Restat:         true,
+	}, "rTxt", "manifest", "args")
+
+// resourceProcessorBusyBoxGenerateBinaryR converts the R.txt file produced by aapt2 into R.class files
+// 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, aaptFlags []string) {
+
+	var args []string
+	var deps android.Paths
+
+	if !isLibrary {
+		// When compiling an app, pass all R.txt and AndroidManifest.xml from transitive static library dependencies
+		// to ResourceProcessorBusyBox so that it can regenerate R.class files with the final resource IDs for each
+		// package.
+		args, deps = transitiveDeps.resourceProcessorDeps()
+	} 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
+		// inlined into the library before the final IDs are assigned during app compilation.
+		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{
+		Rule:        resourceProcessorBusyBox,
+		Output:      rJar,
+		Implicits:   deps,
+		Description: "ResourceProcessorBusyBox",
+		Args: map[string]string{
+			"rTxt":     rTxt.String(),
+			"manifest": manifest.String(),
+			"args":     strings.Join(args, " "),
+		},
+	})
+}
+
+type resourcesNode struct {
+	resPackage          android.Path
+	manifest            android.Path
+	additionalManifests android.Paths
+	rTxt                android.Path
+	rJar                android.Path
+	assets              android.OptionalPath
+
+	usedResourceProcessor bool
+}
+
+type transitiveAarDeps []*resourcesNode
+
+func (t transitiveAarDeps) resPackages() android.Paths {
+	paths := make(android.Paths, 0, len(t))
+	for _, dep := range t {
+		paths = append(paths, dep.resPackage)
+	}
+	return paths
+}
+
+func (t transitiveAarDeps) manifests() android.Paths {
+	paths := make(android.Paths, 0, len(t))
+	for _, dep := range t {
+		paths = append(paths, dep.manifest)
+		paths = append(paths, dep.additionalManifests...)
+	}
+	return paths
+}
+
+func (t transitiveAarDeps) resourceProcessorDeps() (args []string, deps android.Paths) {
+	for _, dep := range t {
+		args = append(args, "--library="+dep.rTxt.String()+","+dep.manifest.String())
+		deps = append(deps, dep.rTxt, dep.manifest)
+	}
+	return args, deps
+}
+
+func (t transitiveAarDeps) assets() android.Paths {
+	paths := make(android.Paths, 0, len(t))
+	for _, dep := range t {
+		if dep.assets.Valid() {
+			paths = append(paths, dep.assets.Path())
+		}
+	}
+	return paths
 }
 
 // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
 func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap) (
-	transitiveStaticLibs, transitiveStaticLibManifests android.Paths, staticRRODirs []rroDir, assets, deps android.Paths, flags []string) {
-
-	var sharedLibs android.Paths
+	staticResourcesNodes, sharedResourcesNodes *android.DepSet[*resourcesNode], staticRRODirs *android.DepSet[rroDir],
+	staticManifests *android.DepSet[android.Path], sharedLibs android.Paths, flags []string) {
 
 	if classLoaderContexts == nil {
 		// Not all callers need to compute class loader context, those who don't just pass nil.
@@ -447,6 +713,11 @@
 		sharedLibs = append(sharedLibs, sdkDep.jars...)
 	}
 
+	var staticResourcesNodeDepSets []*android.DepSet[*resourcesNode]
+	var sharedResourcesNodeDepSets []*android.DepSet[*resourcesNode]
+	rroDirsDepSetBuilder := android.NewDepSetBuilder[rroDir](android.TOPOLOGICAL)
+	manifestsDepSetBuilder := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL)
+
 	ctx.VisitDirectDeps(func(module android.Module) {
 		depTag := ctx.OtherModuleDependencyTag(module)
 
@@ -461,6 +732,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:
@@ -469,32 +741,30 @@
 			}
 		case staticLibTag:
 			if exportPackage != nil {
-				transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
-				transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
-				transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
-				if aarDep.ExportedAssets().Valid() {
-					assets = append(assets, aarDep.ExportedAssets().Path())
-				}
-
-			outer:
-				for _, d := range aarDep.ExportedRRODirs() {
-					for _, e := range staticRRODirs {
-						if d.path == e.path {
-							continue outer
-						}
-					}
-					staticRRODirs = append(staticRRODirs, d)
-				}
+				staticResourcesNodeDepSets = append(staticResourcesNodeDepSets, aarDep.ResourcesNodeDepSet())
+				rroDirsDepSetBuilder.Transitive(aarDep.RRODirsDepSet())
+				manifestsDepSetBuilder.Transitive(aarDep.ManifestsDepSet())
 			}
 		}
 
 		addCLCFromDep(ctx, module, classLoaderContexts)
 	})
 
-	deps = append(deps, sharedLibs...)
-	deps = append(deps, transitiveStaticLibs...)
+	// AAPT2 overlays are in lowest to highest priority order, the topological order will be reversed later.
+	// Reverse the dependency order now going into the depset so that it comes out in order after the second
+	// 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.
+	staticResourcesNodes = android.NewDepSet(android.TOPOLOGICAL, nil,
+		android.ReverseSliceInPlace(staticResourcesNodeDepSets))
+	sharedResourcesNodes = android.NewDepSet(android.TOPOLOGICAL, nil,
+		android.ReverseSliceInPlace(sharedResourcesNodeDepSets))
 
-	if len(transitiveStaticLibs) > 0 {
+	staticRRODirs = rroDirsDepSetBuilder.Build()
+	staticManifests = manifestsDepSetBuilder.Build()
+
+	if len(staticResourcesNodes.ToList()) > 0 {
 		flags = append(flags, "--auto-add-overlay")
 	}
 
@@ -502,22 +772,16 @@
 		flags = append(flags, "-I "+sharedLib.String())
 	}
 
-	transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs)
-	transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests)
-
-	return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags
+	return staticResourcesNodes, sharedResourcesNodes, staticRRODirs, staticManifests, sharedLibs, flags
 }
 
 type AndroidLibrary struct {
 	Library
 	aapt
-	android.BazelModuleBase
 
 	androidLibraryProperties androidLibraryProperties
 
 	aarFile android.WritablePath
-
-	exportedStaticPackages android.Paths
 }
 
 var _ android.OutputFileProducer = (*AndroidLibrary)(nil)
@@ -532,10 +796,6 @@
 	}
 }
 
-func (a *AndroidLibrary) ExportedStaticPackages() android.Paths {
-	return a.exportedStaticPackages
-}
-
 var _ AndroidLibraryDependency = (*AndroidLibrary)(nil)
 
 func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -550,13 +810,26 @@
 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)
+	a.aapt.buildActions(ctx,
+		aaptBuildActionOptions{
+			sdkContext:                     android.SdkContext(a),
+			classLoaderContexts:            a.classLoaderContexts,
+			enforceDefaultTargetSdkVersion: false,
+		},
+	)
 
-	a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform()
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+	a.hideApexVariantFromMake = !apexInfo.IsForPlatform()
 
-	ctx.CheckbuildFile(a.proguardOptionsFile)
-	ctx.CheckbuildFile(a.exportPackage)
-	ctx.CheckbuildFile(a.aaptSrcJar)
+	a.stem = proptools.StringDefault(a.overridableDeviceProperties.Stem, ctx.ModuleName())
+
+	ctx.CheckbuildFile(a.aapt.proguardOptionsFile)
+	ctx.CheckbuildFile(a.aapt.exportPackage)
+	if a.useResourceProcessorBusyBox(ctx) {
+		ctx.CheckbuildFile(a.aapt.rJar)
+	} else {
+		ctx.CheckbuildFile(a.aapt.aaptSrcJar)
+	}
 
 	// apps manifests are handled by aapt, don't let Module see them
 	a.properties.Manifest = nil
@@ -565,10 +838,32 @@
 	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)
 
-	a.Module.compile(ctx, a.aaptSrcJar)
+	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(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.
+		extraClasspathJars = a.transitiveAaptRJars
+	} else {
+		// When building a library without ResourceProcessorBusyBox the aapt2 rule creates R.srcjar containing
+		// R.java files for the library's package and the packages from all transitive static android_library
+		// dependencies.  Compile the srcjar alongside the rest of the sources.
+		extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
+	}
+
+	a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
 
 	a.aarFile = android.PathForModuleOut(ctx, ctx.ModuleName()+".aar")
 	var res android.Paths
@@ -577,35 +872,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()...)
-			}
-			if alib, ok := m.(AndroidLibraryDependency); ok {
-				a.exportedStaticPackages = append(a.exportedStaticPackages, alib.ExportPackage())
-				a.exportedStaticPackages = append(a.exportedStaticPackages, alib.ExportedStaticPackages()...)
-			}
-		}
-	})
-	a.exportedProguardFlagFiles = android.FirstUniquePaths(a.exportedProguardFlagFiles)
-	a.exportedStaticPackages = android.FirstUniquePaths(a.exportedStaticPackages)
-
 	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
@@ -625,7 +915,6 @@
 
 	android.InitApexModule(module)
 	InitJavaModule(module, android.DeviceSupported)
-	android.InitBazelModule(module)
 	return module
 }
 
@@ -664,7 +953,6 @@
 	android.ModuleBase
 	android.DefaultableModuleBase
 	android.ApexModuleBase
-	android.BazelModuleBase
 	prebuilt android.Prebuilt
 
 	// Functionality common to Module and Import.
@@ -674,14 +962,18 @@
 
 	properties AARImportProperties
 
-	classpathFile         android.WritablePath
-	proguardFlags         android.WritablePath
-	exportPackage         android.WritablePath
-	extraAaptPackagesFile android.WritablePath
-	manifest              android.WritablePath
-	assetsPackage         android.WritablePath
+	classpathFile                      android.WritablePath
+	proguardFlags                      android.WritablePath
+	exportPackage                      android.WritablePath
+	transitiveAaptResourcePackagesFile android.Path
+	extraAaptPackagesFile              android.WritablePath
+	manifest                           android.WritablePath
+	assetsPackage                      android.WritablePath
+	rTxt                               android.WritablePath
+	rJar                               android.WritablePath
 
-	exportedStaticPackages android.Paths
+	resourcesNodesDepSet *android.DepSet[*resourcesNode]
+	manifestsDepSet      *android.DepSet[android.Path]
 
 	hideApexVariantFromMake bool
 
@@ -690,6 +982,9 @@
 
 	sdkVersion    android.SdkSpec
 	minSdkVersion android.ApiLevel
+
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
 }
 
 var _ android.OutputFileProducer = (*AARImport)(nil)
@@ -738,25 +1033,16 @@
 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
 }
 
-func (a *AARImport) ExportedRRODirs() []rroDir {
-	return nil
+func (a *AARImport) RRODirsDepSet() *android.DepSet[rroDir] {
+	return android.NewDepSet[rroDir](android.TOPOLOGICAL, nil, nil)
 }
 
-func (a *AARImport) ExportedStaticPackages() android.Paths {
-	return a.exportedStaticPackages
-}
-
-func (a *AARImport) ExportedManifests() android.Paths {
-	return android.Paths{a.manifest}
-}
-
-func (a *AARImport) ExportedAssets() android.OptionalPath {
-	return android.OptionalPathForPath(a.assetsPackage)
+func (a *AARImport) ManifestsDepSet() *android.DepSet[android.Path] {
+	return a.manifestsDepSet
 }
 
 // RRO enforcement is not available on aar_import since its RRO dirs are not
@@ -800,7 +1086,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",
@@ -810,7 +1096,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}"},
 	},
@@ -837,7 +1123,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])
@@ -850,14 +1137,22 @@
 
 	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")
 	a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip")
+	a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
+	android.SetProvider(ctx, ProguardSpecInfoProvider, ProguardSpecInfo{
+		ProguardFlagsFiles: android.NewDepSet[android.Path](
+			android.POSTORDER,
+			android.Paths{a.proguardFlags},
+			nil,
+		),
+	})
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        unzipAAR,
 		Input:       a.aarPath,
-		Outputs:     android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage},
+		Outputs:     android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage, aarRTxt},
 		Description: "unzip AAR",
 		Args: map[string]string{
 			"outDir":             extractedAARDir.String(),
@@ -874,57 +1169,90 @@
 	aapt2CompileZip(ctx, flata, a.aarPath, "res", compileFlags)
 
 	a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk")
-	// the subdir "android" is required to be filtered by package names
-	srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar")
 	proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
-	rTxt := android.PathForModuleOut(ctx, "R.txt")
+	a.rTxt = android.PathForModuleOut(ctx, "R.txt")
 	a.extraAaptPackagesFile = android.PathForModuleOut(ctx, "extra_packages")
 
 	var linkDeps android.Paths
 
 	linkFlags := []string{
 		"--static-lib",
-		"--no-static-lib-packages",
+		"--merge-only",
 		"--auto-add-overlay",
 	}
 
 	linkFlags = append(linkFlags, "--manifest "+a.manifest.String())
 	linkDeps = append(linkDeps, a.manifest)
 
-	transitiveStaticLibs, staticLibManifests, staticRRODirs, transitiveAssets, libDeps, libFlags :=
+	staticResourcesNodesDepSet, sharedResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedLibs, libFlags :=
 		aaptLibs(ctx, android.SdkContext(a), nil)
 
-	_ = staticLibManifests
-	_ = staticRRODirs
+	_ = sharedResourcesNodesDepSet
+	_ = staticRRODirsDepSet
 
-	linkDeps = append(linkDeps, libDeps...)
+	staticDeps := transitiveAarDeps(staticResourcesNodesDepSet.ToList())
+
+	linkDeps = append(linkDeps, sharedLibs...)
+	linkDeps = append(linkDeps, staticDeps.resPackages()...)
 	linkFlags = append(linkFlags, libFlags...)
 
-	overlayRes := append(android.Paths{flata}, transitiveStaticLibs...)
+	overlayRes := android.Paths{flata}
 
-	aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile,
-		linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil)
-
-	// Merge this import's assets with its dependencies' assets (if there are any).
-	if len(transitiveAssets) > 0 {
-		mergedAssets := android.PathForModuleOut(ctx, "merged-assets.zip")
-		inputZips := append(android.Paths{a.assetsPackage}, transitiveAssets...)
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        mergeAssetsRule,
-			Inputs:      inputZips,
-			Output:      mergedAssets,
-			Description: "merge assets from dependencies and self",
-		})
-		a.assetsPackage = mergedAssets
+	// Treat static library dependencies of static libraries as imports.
+	transitiveStaticLibs := staticDeps.resPackages()
+	linkDeps = append(linkDeps, transitiveStaticLibs...)
+	for _, staticLib := range transitiveStaticLibs {
+		linkFlags = append(linkFlags, "-I "+staticLib.String())
 	}
 
+	transitiveAssets := android.ReverseSliceInPlace(staticDeps.assets())
+	aapt2Link(ctx, a.exportPackage, nil, proguardOptionsFile, a.rTxt,
+		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, nil)
+
+	aapt2ExtractExtraPackages(ctx, a.extraAaptPackagesFile, a.rJar)
+
+	resourcesNodesDepSetBuilder := android.NewDepSetBuilder[*resourcesNode](android.TOPOLOGICAL)
+	resourcesNodesDepSetBuilder.Direct(&resourcesNode{
+		resPackage: a.exportPackage,
+		manifest:   a.manifest,
+		rTxt:       a.rTxt,
+		rJar:       a.rJar,
+		assets:     android.OptionalPathForPath(a.assetsPackage),
+
+		usedResourceProcessor: true,
+	})
+	resourcesNodesDepSetBuilder.Transitive(staticResourcesNodesDepSet)
+	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
+	a.manifestsDepSet = manifestDepSetBuilder.Build()
+
+	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{
+	android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
 		HeaderJars:                     android.PathsIfNonNil(a.classpathFile),
 		TransitiveLibsHeaderJars:       a.transitiveLibsHeaderJars,
 		TransitiveStaticLibsHeaderJars: a.transitiveStaticLibsHeaderJars,
 		ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile),
 		ImplementationJars:             android.PathsIfNonNil(a.classpathFile),
+		// TransitiveAconfigFiles: // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
 	})
 
 	if proptools.Bool(a.properties.Extract_jni) {
@@ -946,11 +1274,12 @@
 				},
 			})
 		}
-
-		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 {
@@ -961,7 +1290,7 @@
 	return android.Paths{a.classpathFile}
 }
 
-func (a *AARImport) DexJarBuildPath() android.Path {
+func (a *AARImport) DexJarBuildPath(ctx android.ModuleErrorfContext) android.Path {
 	return nil
 }
 
@@ -1000,135 +1329,5 @@
 	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:rules.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:rules.bzl",
-	}
-}
-
-func (a *AndroidLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	commonAttrs, bp2buildInfo := a.convertLibraryAttrsBp2Build(ctx)
-	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..4d4e5d0 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")
 			}
diff --git a/java/android_manifest.go b/java/android_manifest.go
index f2ebfa6..082b00e 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -200,13 +200,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 +225,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
new file mode 100644
index 0000000..5909b1e
--- /dev/null
+++ b/java/android_manifest_test.go
@@ -0,0 +1,136 @@
+// 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 (
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestManifestMerger(t *testing.T) {
+	bp := `
+		android_app {
+			name: "app",
+			sdk_version: "current",
+			srcs: ["app/app.java"],
+			resource_dirs: ["app/res"],
+			manifest: "app/AndroidManifest.xml",
+			additional_manifests: ["app/AndroidManifest2.xml"],
+			static_libs: ["direct", "direct_import"],
+		}
+
+		android_library {
+			name: "direct",
+			sdk_version: "current",
+			srcs: ["direct/direct.java"],
+			resource_dirs: ["direct/res"],
+			manifest: "direct/AndroidManifest.xml",
+			additional_manifests: ["direct/AndroidManifest2.xml"],
+			static_libs: ["transitive", "transitive_import"],
+		}
+
+		android_library {
+			name: "transitive",
+			sdk_version: "current",
+			srcs: ["transitive/transitive.java"],
+			resource_dirs: ["transitive/res"],
+			manifest: "transitive/AndroidManifest.xml",
+			additional_manifests: ["transitive/AndroidManifest2.xml"],
+		}
+
+		android_library_import {
+			name: "direct_import",
+			sdk_version: "current",
+			aars: ["direct_import.aar"],
+			static_libs: ["direct_import_dep"],
+		}
+
+		android_library_import {
+			name: "direct_import_dep",
+			sdk_version: "current",
+			aars: ["direct_import_dep.aar"],
+		}
+
+		android_library_import {
+			name: "transitive_import",
+			sdk_version: "current",
+			aars: ["transitive_import.aar"],
+			static_libs: ["transitive_import_dep"],
+		}
+
+		android_library_import {
+			name: "transitive_import_dep",
+			sdk_version: "current",
+			aars: ["transitive_import_dep.aar"],
+		}
+	`
+
+	result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, bp)
+
+	manifestMergerRule := result.ModuleForTests("app", "android_common").Rule("manifestMerger")
+	android.AssertPathRelativeToTopEquals(t, "main manifest",
+		"out/soong/.intermediates/app/android_common/manifest_fixer/AndroidManifest.xml",
+		manifestMergerRule.Input)
+	android.AssertPathsRelativeToTopEquals(t, "lib manifests",
+		[]string{
+			"app/AndroidManifest2.xml",
+			"out/soong/.intermediates/direct/android_common/manifest_fixer/AndroidManifest.xml",
+			"direct/AndroidManifest2.xml",
+			"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/direct_import/android_common/aar/AndroidManifest.xml",
+			// TODO(b/288358614): Soong has historically not merged manifests from dependencies of
+			// android_library_import modules.
+
+		},
+		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 9c21633..b523594 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,6 +128,7 @@
 					if library.dexpreopter.configPath != nil {
 						entries.SetPath("LOCAL_SOONG_DEXPREOPT_CONFIG", library.dexpreopter.configPath)
 					}
+					android.SetAconfigFileMkEntries(&library.ModuleBase, entries, library.mergedAconfigFiles)
 				},
 			},
 		})
@@ -200,16 +206,13 @@
 
 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.combinedClasspathFile),
+		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))
@@ -220,6 +223,7 @@
 				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile)
 				entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String())
 				entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
+				// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
 			},
 		},
 	}}
@@ -244,6 +248,7 @@
 					entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", prebuilt.dexpreopter.builtInstalled)
 				}
 				entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
+				// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
 			},
 		},
 	}}
@@ -265,10 +270,12 @@
 				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.classpathFile)
 				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.classpathFile)
 				entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", prebuilt.exportPackage)
+				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)
 				entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion.String())
+				// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
 			},
 		},
 	}}
@@ -295,6 +302,7 @@
 					if len(binary.dexpreopter.builtInstalled) > 0 {
 						entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", binary.dexpreopter.builtInstalled)
 					}
+					android.SetAconfigFileMkEntries(&binary.ModuleBase, entries, binary.mergedAconfigFiles)
 				},
 			},
 			ExtraFooters: []android.AndroidMkExtraFootersFunc{
@@ -331,15 +339,23 @@
 			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.
 				entries.SetString("LOCAL_MODULE", app.installApkName)
 				entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", app.appProperties.PreventInstall)
+				if app.headerJarFile != nil {
+					entries.SetPath("LOCAL_SOONG_HEADER_JAR", app.headerJarFile)
+				}
 				entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", app.exportPackage)
 				if app.dexJarFile.IsSet() {
 					entries.SetPath("LOCAL_SOONG_DEX_JAR", app.dexJarFile.Path())
@@ -368,8 +384,13 @@
 
 				filterRRO := func(filter overlayType) android.Paths {
 					var paths android.Paths
-					for _, d := range app.rroDirs {
+					seen := make(map[android.Path]bool)
+					for _, d := range app.rroDirsDepSet.ToList() {
 						if d.overlayType == filter {
+							if seen[d.path] {
+								continue
+							}
+							seen[d.path] = true
 							paths = append(paths, d.path)
 						}
 					}
@@ -432,6 +453,10 @@
 				}
 
 				entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", app.linter.reports)
+
+				if app.Name() != "framework-res" {
+					android.SetAconfigFileMkEntries(&app.ModuleBase, entries, app.mergedAconfigFiles)
+				}
 			},
 		},
 		ExtraFooters: []android.AndroidMkExtraFootersFunc{
@@ -450,11 +475,6 @@
 	if len(a.overridableAppProperties.Overrides) > 0 {
 		overridden = append(overridden, a.overridableAppProperties.Overrides...)
 	}
-	// When APK name is overridden via PRODUCT_PACKAGE_NAME_OVERRIDES
-	// ensure that the original name is overridden.
-	if a.Stem() != a.installApkName {
-		overridden = append(overridden, a.Stem())
-	}
 	return overridden
 }
 
@@ -508,10 +528,12 @@
 		}
 
 		entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.exportPackage)
+		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)
+		android.SetAconfigFileMkEntries(&a.ModuleBase, entries, a.mergedAconfigFiles)
 	})
 
 	return entriesList
@@ -566,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",
@@ -577,14 +599,14 @@
 				if dstubs.Javadoc.stubsSrcJar != nil {
 					entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", dstubs.Javadoc.stubsSrcJar)
 				}
-				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.everythingArtifacts.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.everythingArtifacts.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.everythingArtifacts.metadataZip)
 				}
 			},
 		},
@@ -684,6 +706,7 @@
 				if Bool(a.properties.Export_package_resources) {
 					entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.outputFile)
 				}
+				// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
 			},
 		},
 	}}
@@ -717,6 +740,7 @@
 				entries.SetString("LOCAL_CERTIFICATE", r.certificate.AndroidMkString())
 				entries.SetPath("LOCAL_MODULE_PATH", r.installDir)
 				entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", r.properties.Overrides...)
+				// TODO: LOCAL_ACONFIG_FILES -- Might eventually need aconfig flags?
 			},
 		},
 	}}
@@ -734,6 +758,7 @@
 					entries.SetPath("LOCAL_APK_SET_INSTALL_FILE", apkSet.PackedAdditionalOutputs())
 					entries.SetPath("LOCAL_APKCERTS_FILE", apkSet.apkcertsFile)
 					entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...)
+					// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts -- Both declarations and values
 				},
 			},
 		},
diff --git a/java/app.go b/java/app.go
index e026fea..0c56d81 100755
--- a/java/app.go
+++ b/java/app.go
@@ -18,17 +18,19 @@
 // related module types, including their override variants.
 
 import (
+	"fmt"
 	"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
@@ -157,10 +169,12 @@
 	// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
 	// from PRODUCT_PACKAGES.
 	Overrides []string
+
+	// Names of aconfig_declarations modules that specify aconfig flags that the app depends on.
+	Flags_packages []string
 }
 
 type AndroidApp struct {
-	android.BazelModuleBase
 	Library
 	aapt
 	android.OverridableModuleBase
@@ -200,12 +214,8 @@
 	return Bool(a.properties.Installable)
 }
 
-func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
-	return nil
-}
-
-func (a *AndroidApp) ExportedStaticPackages() android.Paths {
-	return nil
+func (a *AndroidApp) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
+	return a.aapt.resourcesNodesDepSet
 }
 
 func (a *AndroidApp) OutputFile() android.Path {
@@ -307,9 +317,20 @@
 				`must be names of android_app_certificate modules in the form ":module"`)
 		}
 	}
+
+	for _, aconfig_declaration := range a.overridableAppProperties.Flags_packages {
+		ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration)
+	}
 }
 
 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)
 }
 
@@ -389,7 +410,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()
 }
@@ -410,11 +431,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
 }
@@ -449,8 +470,9 @@
 	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 {
+	if !autogenerateRRO && !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
 		aaptLinkFlags = append(aaptLinkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
 	}
 
@@ -483,8 +505,29 @@
 	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...)
+
+	var 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(),
+			)
+		}
+	})
+
+	a.aapt.buildActions(ctx,
+		aaptBuildActionOptions{
+			sdkContext:                     android.SdkContext(a),
+			classLoaderContexts:            a.classLoaderContexts,
+			excludedLibs:                   a.usesLibraryProperties.Exclude_uses_libs,
+			enforceDefaultTargetSdkVersion: a.enforceDefaultTargetSdkVersion(),
+			extraLinkFlags:                 aaptLinkFlags,
+			aconfigTextFiles:               aconfigTextFilePaths,
+		},
+	)
 
 	// apps manifests are handled by aapt, don't let Module see them
 	a.properties.Manifest = nil
@@ -493,15 +536,17 @@
 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...)
+	a.Module.extraProguardFlagsFiles = append(a.Module.extraProguardFlagsFiles, a.proguardOptionsFile)
 }
 
 func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath {
@@ -518,7 +563,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 {
@@ -531,11 +576,40 @@
 	a.dexpreopter.manifestFile = a.mergedManifestFile
 	a.dexpreopter.preventInstall = a.appProperties.PreventInstall
 
+	var packageResources = a.exportPackage
+
 	if ctx.ModuleName() != "framework-res" {
-		a.Module.compile(ctx, a.aaptSrcJar)
+		if Bool(a.dexProperties.Optimize.Shrink_resources) {
+			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(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.
+			extraClasspathJars = android.Paths{a.aapt.rJar}
+			extraCombinedJars = android.Paths{a.aapt.rJar}
+		} else {
+			// When building an app without ResourceProcessorBusyBox the aapt2 rule creates R.srcjar containing
+			// R.java files for the app's package and the packages from all transitive static android_library
+			// dependencies.  Compile the srcjar alongside the rest of the sources.
+			extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
+		}
+
+		a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
+		if Bool(a.dexProperties.Optimize.Shrink_resources) {
+			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 {
@@ -670,15 +744,25 @@
 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
 	}
 
 	a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
 	a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
 
+	// 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())
+
 	// Check if the install APK name needs to be overridden.
-	a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Stem())
+	// Both android_app and override_android_app module are expected to possess
+	// its module bound apk path. However, override_android_app inherits ctx.ModuleName()
+	// 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()))
 
 	if ctx.ModuleName() == "framework-res" {
 		// framework-res.apk is installed as system/framework/framework-res.apk
@@ -711,7 +795,6 @@
 
 	// 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()
 
@@ -737,7 +820,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)
@@ -761,7 +844,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)
@@ -790,7 +873,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)
@@ -807,8 +890,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 {
@@ -818,7 +899,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)
@@ -892,7 +973,7 @@
 			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...)
 		}
 
@@ -1008,9 +1089,17 @@
 	case ".aapt.proguardOptionsFile":
 		return []android.Path{a.proguardOptionsFile}, nil
 	case ".aapt.srcjar":
-		return []android.Path{a.aaptSrcJar}, nil
+		if a.aaptSrcJar != nil {
+			return []android.Path{a.aaptSrcJar}, nil
+		}
+	case ".aapt.jar":
+		if a.rJar != nil {
+			return []android.Path{a.rJar}, 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)
 }
@@ -1019,7 +1108,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()
 }
 
@@ -1035,12 +1124,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
@@ -1058,11 +1161,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"},
+			Out:   []string{"AndroidManifest.xml"},
+			Srcs:  []string{":" + a.Name() + "{.manifest.xml}"},
+			Cmd:   proptools.StringPtr("$(location characteristics_rro_generator) $(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
@@ -1072,6 +1231,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 {
@@ -1114,6 +1275,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 {
@@ -1125,7 +1293,7 @@
 	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)
-	ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+	android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig android.Path) android.Path {
@@ -1202,6 +1370,7 @@
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
 	android.InitOverridableModule(module, &module.overridableAppProperties.Overrides)
+
 	return module
 }
 
@@ -1217,6 +1386,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 {
@@ -1259,7 +1430,6 @@
 
 type AndroidAppCertificate struct {
 	android.ModuleBase
-	android.BazelModuleBase
 
 	properties  AndroidAppCertificateProperties
 	Certificate Certificate
@@ -1276,7 +1446,6 @@
 	module := &AndroidAppCertificate{}
 	module.AddProperties(&module.properties)
 	android.InitAndroidModule(module)
-	android.InitBazelModule(module)
 	return module
 }
 
@@ -1410,10 +1579,15 @@
 	}
 }
 
-// presentOptionalUsesLibs returns optional_uses_libs after filtering out MissingUsesLibraries, which don't exist in the
-// build.
+// presentOptionalUsesLibs returns optional_uses_libs after filtering out libraries that don't exist in the source tree.
 func (u *usesLibrary) presentOptionalUsesLibs(ctx android.BaseModuleContext) []string {
-	optionalUsesLibs, _ := android.FilterList(u.usesLibraryProperties.Optional_uses_libs, ctx.Config().MissingUsesLibraries())
+	optionalUsesLibs := android.FilterListPred(u.usesLibraryProperties.Optional_uses_libs, func(s string) bool {
+		exists := ctx.OtherModuleExists(s)
+		if !exists && !android.InList(ctx.ModuleName(), ctx.Config().BuildWarningBadOptionalUsesLibsAllowlist()) {
+			fmt.Printf("Warning: Module '%s' depends on non-existing optional_uses_libs '%s'\n", ctx.ModuleName(), s)
+		}
+		return exists
+	})
 	return optionalUsesLibs
 }
 
@@ -1465,7 +1639,7 @@
 				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})
@@ -1505,7 +1679,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
 	}
 
@@ -1545,119 +1719,6 @@
 
 // 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) android.Path {
+func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) {
 	u.verifyUsesLibraries(ctx, apk, nil) // for APKs manifest_check does not write output file
-	outputFile := android.PathForModuleOut(ctx, "verify_uses_libraries", apk.Base())
-	return outputFile
-}
-
-// 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:rules.bzl",
-	}
-
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name()}, attrs)
-}
-
-type manifestValueAttribute struct {
-	MinSdkVersion *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 := a.convertLibraryAttrsBp2Build(ctx)
-	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() {
-		minSdkStr, err := minSdkVersion.EffectiveVersionString(ctx)
-		if err == nil {
-			manifestValues.MinSdkVersion = &minSdkStr
-		}
-	}
-
-	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:rules.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()},
-		appAttrs,
-	)
-
 }
diff --git a/java/app_builder.go b/java/app_builder.go
index d20a6bf..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)
 }
 
@@ -225,8 +219,6 @@
 	})
 }
 
-const jniJarOutputPathString = "jniJarOutput.zip"
-
 func TransformJniLibsToJar(
 	ctx android.ModuleContext,
 	outputFile android.WritablePath,
@@ -258,7 +250,10 @@
 		rule = zipRE
 		args["implicits"] = strings.Join(deps.Strings(), ",")
 	}
-	jniJarPath := android.PathForModuleOut(ctx, jniJarOutputPathString)
+	var jniJarPath android.WritablePath = android.PathForModuleOut(ctx, "jniJarOutput.zip")
+	if len(prebuiltJniPackages) == 0 {
+		jniJarPath = outputFile
+	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rule,
 		Description: "zip jni libs",
@@ -266,12 +261,26 @@
 		Implicits:   deps,
 		Args:        args,
 	})
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        mergeAssetsRule,
-		Description: "merge prebuilt JNI packages",
-		Inputs:      append(prebuiltJniPackages, jniJarPath),
-		Output:      outputFile,
-	})
+	if len(prebuiltJniPackages) > 0 {
+		var mergeJniJarPath android.WritablePath = android.PathForModuleOut(ctx, "mergeJniJarOutput.zip")
+		if !uncompressJNI {
+			mergeJniJarPath = outputFile
+		}
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        mergeAssetsRule,
+			Description: "merge prebuilt JNI packages",
+			Inputs:      append(prebuiltJniPackages, jniJarPath),
+			Output:      mergeJniJarPath,
+		})
+
+		if uncompressJNI {
+			ctx.Build(pctx, android.BuildParams{
+				Rule:   uncompressEmbeddedJniLibsRule,
+				Input:  mergeJniJarPath,
+				Output: outputFile,
+			})
+		}
+	}
 }
 
 func (a *AndroidApp) generateJavaUsedByApex(ctx android.ModuleContext) {
diff --git a/java/app_import.go b/java/app_import.go
index 3097d7f..12ead0a 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -17,7 +17,9 @@
 // This file contains the module implementations for android_app_import and android_test_import.
 
 import (
+	"fmt"
 	"reflect"
+	"strings"
 
 	"github.com/google/blueprint"
 
@@ -49,6 +51,12 @@
 		CommandDeps: []string{"${config.Zip2ZipCmd}"},
 		Description: "Uncompress 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) {
@@ -73,13 +81,14 @@
 
 	usesLibrary usesLibrary
 
-	preprocessed bool
-
 	installPath android.InstallPath
 
 	hideApexVariantFromMake bool
 
 	provenanceMetaDataFile android.OutputPath
+
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
 }
 
 type AndroidAppImportProperties struct {
@@ -128,6 +137,13 @@
 
 	// Optional. Install to a subdirectory of the default install path for the module
 	Relative_install_path *string
+
+	// Whether the prebuilt apk can be installed without additional processing. Default is false.
+	Preprocessed *bool
+
+	// 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
 }
 
 func (a *AndroidAppImport) IsInstallable() bool {
@@ -135,7 +151,9 @@
 }
 
 // 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("Dpi_variants")
@@ -201,7 +219,7 @@
 	ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
 	// Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing
 	// with them may invalidate pre-existing signature data.
-	if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || a.preprocessed) {
+	if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || Bool(a.properties.Preprocessed)) {
 		ctx.Build(pctx, android.BuildParams{
 			Rule:   android.Cp,
 			Output: outputPath,
@@ -219,7 +237,7 @@
 
 // Returns whether this module should have the dex file stored uncompressed in the APK.
 func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
-	if ctx.Config().UnbundledBuild() || a.preprocessed {
+	if ctx.Config().UnbundledBuild() || proptools.Bool(a.properties.Preprocessed) {
 		return false
 	}
 
@@ -228,7 +246,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) {
@@ -244,11 +262,19 @@
 		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++
@@ -260,11 +286,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
 
@@ -297,10 +321,10 @@
 	a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
 
 	if a.usesLibrary.enforceUsesLibraries() {
-		srcApk = a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
+		a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
 	}
 
-	a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
+	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{
@@ -317,12 +341,21 @@
 
 	// Sign or align the package if package has not been preprocessed
 
-	if a.preprocessed {
-		a.outputFile = srcApk
+	if proptools.Bool(a.properties.Preprocessed) {
+		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
@@ -335,8 +368,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
 	}
@@ -348,10 +382,35 @@
 		artifactPath := android.PathForModuleSrc(ctx, *a.properties.Apk)
 		a.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, artifactPath, a.installPath)
 	}
+	android.CollectDependencyAconfigFiles(ctx, &a.mergedAconfigFiles)
 
 	// TODO: androidmk converter jni libs
 }
 
+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() {
+		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:   checkPresignedApkRule,
+		Input:  srcApk,
+		Output: stamp,
+		Args: map[string]string{
+			"extraArgs": strings.Join(extraArgs, " "),
+		},
+	})
+	return stamp
+}
+
 func (a *AndroidAppImport) Prebuilt() *android.Prebuilt {
 	return &a.prebuilt
 }
@@ -364,6 +423,15 @@
 	return a.outputFile
 }
 
+func (a *AndroidAppImport) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		return []android.Path{a.outputFile}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
+}
+
 func (a *AndroidAppImport) JacocoReportClassesFile() android.Path {
 	return nil
 }
@@ -477,7 +545,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)
 	})
 
@@ -491,11 +559,6 @@
 	return module
 }
 
-type androidTestImportProperties struct {
-	// Whether the prebuilt apk can be installed without additional processing. Default is false.
-	Preprocessed *bool
-}
-
 type AndroidTestImport struct {
 	AndroidAppImport
 
@@ -512,14 +575,10 @@
 		Per_testcase_directory *bool
 	}
 
-	testImportProperties androidTestImportProperties
-
 	data android.Paths
 }
 
 func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	a.preprocessed = Bool(a.testImportProperties.Preprocessed)
-
 	a.generateAndroidBuildActions(ctx)
 
 	a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
@@ -536,9 +595,8 @@
 	module.AddProperties(&module.properties)
 	module.AddProperties(&module.dexpreoptProperties)
 	module.AddProperties(&module.testProperties)
-	module.AddProperties(&module.testImportProperties)
 	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 8093024..44f8f16 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 {
@@ -454,26 +475,105 @@
 	}
 
 	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 +729,49 @@
 			presigned: true,
 			preprocessed: true,
 		}
+		`)
 
-		android_test_import {
-			name: "foo_cert",
+	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")
+	}
+}
+
+func TestAndroidAppImport_Preprocessed(t *testing.T) {
+	ctx, _ := testJava(t, `
+		android_app_import {
+			name: "foo",
 			apk: "prebuilts/apk/app.apk",
-			certificate: "cert/new_cert",
+			presigned: true,
 			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")
+	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 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 compression and aligning were validated.
+	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_test.go b/java/app_test.go
index f078021..362bef9 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -443,9 +443,9 @@
 	inputs := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").Description("link").Implicits
 	var crtbeginFound, crtendFound bool
 	expectedCrtBegin := ctx.ModuleForTests("crtbegin_so",
-		"android_arm64_armv8-a_sdk_29").Rule("partialLd").Output
+		"android_arm64_armv8-a_sdk_29").Rule("noAddrSig").Output
 	expectedCrtEnd := ctx.ModuleForTests("crtend_so",
-		"android_arm64_armv8-a_sdk_29").Rule("partialLd").Output
+		"android_arm64_armv8-a_sdk_29").Rule("noAddrSig").Output
 	implicits := []string{}
 	for _, input := range inputs {
 		implicits = append(implicits, input.String())
@@ -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))
 
@@ -599,7 +598,7 @@
 			android_library {
 				name: "lib3",
 				sdk_version: "current",
-				static_libs: ["lib4"],
+				static_libs: ["lib4", "import"],
 			}
 
 			android_library {
@@ -607,20 +606,38 @@
 				sdk_version: "current",
 				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",
+				aars: ["import.aar"],
+			}
 		`
 
 	testCases := []struct {
-		name          string
-		assetFlag     string
-		assetPackages []string
+		name               string
+		assetFlag          string
+		assetPackages      []string
+		tmpAssetDirInputs  []string
+		tmpAssetDirOutputs []string
 	}{
 		{
 			name: "foo",
-			// lib1 has its own asset. lib3 doesn't have any, but provides lib4's transitively.
+			// lib1 has its own assets. lib3 doesn't have any, but lib4 and import have assets.
 			assetPackages: []string{
 				"out/soong/.intermediates/foo/android_common/aapt2/package-res.apk",
 				"out/soong/.intermediates/lib1/android_common/assets.zip",
-				"out/soong/.intermediates/lib3/android_common/assets.zip",
+				"out/soong/.intermediates/lib4/android_common/assets.zip",
+				"out/soong/.intermediates/import/android_common/assets.zip",
 			},
 		},
 		{
@@ -632,15 +649,23 @@
 		},
 		{
 			name: "lib3",
-			assetPackages: []string{
-				"out/soong/.intermediates/lib3/android_common/aapt2/package-res.apk",
-				"out/soong/.intermediates/lib4/android_common/assets.zip",
-			},
 		},
 		{
 			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)
 
@@ -668,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)
+			}
 		})
 	}
 }
@@ -717,7 +750,635 @@
 	}
 }
 
-func TestAndroidResources(t *testing.T) {
+func TestAndroidResourceProcessor(t *testing.T) {
+	testCases := []struct {
+		name                            string
+		appUsesRP                       bool
+		directLibUsesRP                 bool
+		transitiveLibUsesRP             bool
+		sharedLibUsesRP                 bool
+		sharedTransitiveStaticLibUsesRP bool
+		sharedTransitiveSharedLibUsesRP bool
+
+		dontVerifyApp bool
+		appResources  []string
+		appOverlays   []string
+		appImports    []string
+		appSrcJars    []string
+		appClasspath  []string
+		appCombined   []string
+
+		dontVerifyDirect bool
+		directResources  []string
+		directOverlays   []string
+		directImports    []string
+		directSrcJars    []string
+		directClasspath  []string
+		directCombined   []string
+
+		dontVerifyTransitive bool
+		transitiveResources  []string
+		transitiveOverlays   []string
+		transitiveImports    []string
+		transitiveSrcJars    []string
+		transitiveClasspath  []string
+		transitiveCombined   []string
+
+		dontVerifyDirectImport bool
+		directImportResources  []string
+		directImportOverlays   []string
+		directImportImports    []string
+
+		dontVerifyTransitiveImport bool
+		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,
+			// which always use resource processor).
+			name:                "legacy",
+			appUsesRP:           false,
+			directLibUsesRP:     false,
+			transitiveLibUsesRP: false,
+
+			appResources: nil,
+			appOverlays: []string{
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/direct/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+				"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/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",
+			},
+			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",
+			},
+
+			directResources: nil,
+			directOverlays: []string{
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat",
+			},
+			directImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			directSrcJars: []string{"out/soong/.intermediates/direct/android_common/gen/android/R.srcjar"},
+			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",
+			},
+			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",
+			},
+
+			transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
+			transitiveOverlays:  nil,
+			transitiveImports:   []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			transitiveSrcJars:   []string{"out/soong/.intermediates/transitive/android_common/gen/android/R.srcjar"},
+			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{
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+			},
+
+			transitiveImportResources: nil,
+			transitiveImportOverlays:  []string{"out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata"},
+			transitiveImportImports: []string{
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+			},
+		},
+		{
+			// Test with all modules set to use_resource_processor: true.
+			name:                            "resource_processor",
+			appUsesRP:                       true,
+			directLibUsesRP:                 true,
+			transitiveLibUsesRP:             true,
+			sharedLibUsesRP:                 true,
+			sharedTransitiveSharedLibUsesRP: true,
+			sharedTransitiveStaticLibUsesRP: true,
+
+			appResources: nil,
+			appOverlays: []string{
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/direct/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+				"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/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",
+			},
+			appCombined: []string{
+				"out/soong/.intermediates/app/android_common/busybox/R.jar",
+				"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",
+			},
+
+			directResources: nil,
+			directOverlays:  []string{"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat"},
+			directImports: []string{
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+			},
+			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/turbine-combined/transitive.jar",
+				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.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",
+			},
+
+			transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
+			transitiveOverlays:  nil,
+			transitiveImports:   []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			transitiveSrcJars:   nil,
+			transitiveClasspath: []string{
+				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/transitive/android_common/busybox/R.jar",
+			},
+			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_transitive_static/android_common/busybox/R.jar",
+				"out/soong/.intermediates/shared_transitive_shared/android_common/busybox/R.jar",
+				"out/soong/.intermediates/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{
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+			},
+
+			transitiveImportResources: nil,
+			transitiveImportOverlays:  []string{"out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata"},
+			transitiveImportImports: []string{
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+			},
+		}, {
+			// Test an app building with resource processor enabled but with dependencies built without
+			// resource processor.
+			name:                "app_resource_processor",
+			appUsesRP:           true,
+			directLibUsesRP:     false,
+			transitiveLibUsesRP: false,
+
+			appResources: nil,
+			appOverlays: []string{
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/direct/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+				"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/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",
+			},
+			appCombined: []string{
+				"out/soong/.intermediates/app/android_common/busybox/R.jar",
+				"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",
+			},
+
+			dontVerifyDirect:           true,
+			dontVerifyTransitive:       true,
+			dontVerifyShared:           true,
+			dontVerifyDirectImport:     true,
+			dontVerifyTransitiveImport: true,
+		},
+		{
+			// Test an app building without resource processor enabled but with a dependency built with
+			// resource processor.
+			name:                "app_dependency_lib_resource_processor",
+			appUsesRP:           false,
+			directLibUsesRP:     true,
+			transitiveLibUsesRP: false,
+
+			appOverlays: []string{
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/direct/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+				"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/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",
+			},
+			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",
+			},
+
+			directResources: nil,
+			directOverlays:  []string{"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat"},
+			directImports: []string{
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+			},
+			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/android_common/turbine-combined/transitive.jar",
+				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.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",
+			},
+
+			dontVerifyTransitive:       true,
+			dontVerifyShared:           true,
+			dontVerifyDirectImport:     true,
+			dontVerifyTransitiveImport: true,
+		},
+		{
+			// Test a library building without resource processor enabled but with a dependency built with
+			// resource processor.
+			name:                "lib_dependency_lib_resource_processor",
+			appUsesRP:           false,
+			directLibUsesRP:     false,
+			transitiveLibUsesRP: true,
+
+			appOverlays: []string{
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/direct/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+				"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/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",
+			},
+			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",
+			},
+
+			directResources: nil,
+			directOverlays: []string{
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat",
+			},
+			directImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			directSrcJars: []string{"out/soong/.intermediates/direct/android_common/gen/android/R.srcjar"},
+			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",
+			},
+			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",
+			},
+
+			transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
+			transitiveOverlays:  nil,
+			transitiveImports:   []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			transitiveSrcJars:   nil,
+			transitiveClasspath: []string{
+				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/transitive/android_common/busybox/R.jar",
+			},
+			transitiveCombined: nil,
+
+			dontVerifyShared:           true,
+			dontVerifyDirectImport:     true,
+			dontVerifyTransitiveImport: true,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.name, func(t *testing.T) {
+			bp := fmt.Sprintf(`
+				android_app {
+					name: "app",
+					sdk_version: "current",
+					srcs: ["app/app.java"],
+					resource_dirs: ["app/res"],
+					manifest: "app/AndroidManifest.xml",
+					libs: ["shared"],
+					static_libs: ["direct", "direct_import"],
+					use_resource_processor: %v,
+				}
+
+				android_library {
+					name: "direct",
+					sdk_version: "current",
+					srcs: ["direct/direct.java"],
+					resource_dirs: ["direct/res"],
+					manifest: "direct/AndroidManifest.xml",
+					static_libs: ["transitive", "transitive_import"],
+					use_resource_processor: %v,
+				}
+
+				android_library {
+					name: "transitive",
+					sdk_version: "current",
+					srcs: ["transitive/transitive.java"],
+					resource_dirs: ["transitive/res"],
+					manifest: "transitive/AndroidManifest.xml",
+					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",
+					aars: ["direct_import.aar"],
+					static_libs: ["direct_import_dep"],
+				}
+
+				android_library_import {
+					name: "direct_import_dep",
+					sdk_version: "current",
+					aars: ["direct_import_dep.aar"],
+				}
+
+				android_library_import {
+					name: "transitive_import",
+					sdk_version: "current",
+					aars: ["transitive_import.aar"],
+					static_libs: ["transitive_import_dep"],
+				}
+
+				android_library_import {
+					name: "transitive_import_dep",
+					sdk_version: "current",
+					aars: ["transitive_import_dep.aar"],
+				}
+			`, 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,
+				"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,
+				fs.AddToFixture(),
+			).RunTestWithBp(t, bp)
+
+			type aaptInfo struct {
+				resources, overlays, imports, srcJars, classpath, combined android.Paths
+			}
+
+			getAaptInfo := func(moduleName string) (aaptInfo aaptInfo) {
+				mod := result.ModuleForTests(moduleName, "android_common")
+				resourceListRule := mod.MaybeOutput("aapt2/res.list")
+				overlayListRule := mod.MaybeOutput("aapt2/overlay.list")
+				aaptRule := mod.Rule("aapt2Link")
+				javacRule := mod.MaybeRule("javac")
+				combinedRule := mod.MaybeOutput("combined/" + moduleName + ".jar")
+
+				aaptInfo.resources = resourceListRule.Inputs
+				aaptInfo.overlays = overlayListRule.Inputs
+
+				aaptFlags := strings.Split(aaptRule.Args["flags"], " ")
+				for i, flag := range aaptFlags {
+					if flag == "-I" && i+1 < len(aaptFlags) {
+						aaptInfo.imports = append(aaptInfo.imports, android.PathForTesting(aaptFlags[i+1]))
+					}
+				}
+
+				if len(javacRule.Args["srcJars"]) > 0 {
+					aaptInfo.srcJars = android.PathsForTesting(strings.Split(javacRule.Args["srcJars"], " ")...)
+				}
+
+				if len(javacRule.Args["classpath"]) > 0 {
+					classpathArg := strings.TrimPrefix(javacRule.Args["classpath"], "-classpath ")
+					aaptInfo.classpath = android.PathsForTesting(strings.Split(classpathArg, ":")...)
+				}
+
+				aaptInfo.combined = combinedRule.Inputs
+				return
+			}
+
+			app := getAaptInfo("app")
+			direct := getAaptInfo("direct")
+			transitive := getAaptInfo("transitive")
+			shared := getAaptInfo("shared")
+			directImport := getAaptInfo("direct_import")
+			transitiveImport := getAaptInfo("transitive_import")
+
+			if !testCase.dontVerifyApp {
+				android.AssertPathsRelativeToTopEquals(t, "app resources", testCase.appResources, app.resources)
+				android.AssertPathsRelativeToTopEquals(t, "app overlays", testCase.appOverlays, app.overlays)
+				android.AssertPathsRelativeToTopEquals(t, "app imports", testCase.appImports, app.imports)
+				android.AssertPathsRelativeToTopEquals(t, "app srcjars", testCase.appSrcJars, app.srcJars)
+				android.AssertPathsRelativeToTopEquals(t, "app classpath", testCase.appClasspath, app.classpath)
+				android.AssertPathsRelativeToTopEquals(t, "app combined", testCase.appCombined, app.combined)
+			}
+
+			if !testCase.dontVerifyDirect {
+				android.AssertPathsRelativeToTopEquals(t, "direct resources", testCase.directResources, direct.resources)
+				android.AssertPathsRelativeToTopEquals(t, "direct overlays", testCase.directOverlays, direct.overlays)
+				android.AssertPathsRelativeToTopEquals(t, "direct imports", testCase.directImports, direct.imports)
+				android.AssertPathsRelativeToTopEquals(t, "direct srcjars", testCase.directSrcJars, direct.srcJars)
+				android.AssertPathsRelativeToTopEquals(t, "direct classpath", testCase.directClasspath, direct.classpath)
+				android.AssertPathsRelativeToTopEquals(t, "direct combined", testCase.directCombined, direct.combined)
+			}
+
+			if !testCase.dontVerifyTransitive {
+				android.AssertPathsRelativeToTopEquals(t, "transitive resources", testCase.transitiveResources, transitive.resources)
+				android.AssertPathsRelativeToTopEquals(t, "transitive overlays", testCase.transitiveOverlays, transitive.overlays)
+				android.AssertPathsRelativeToTopEquals(t, "transitive imports", testCase.transitiveImports, transitive.imports)
+				android.AssertPathsRelativeToTopEquals(t, "transitive srcjars", testCase.transitiveSrcJars, transitive.srcJars)
+				android.AssertPathsRelativeToTopEquals(t, "transitive classpath", testCase.transitiveClasspath, transitive.classpath)
+				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)
+				android.AssertPathsRelativeToTopEquals(t, "direct_import imports", testCase.directImportImports, directImport.imports)
+			}
+
+			if !testCase.dontVerifyTransitiveImport {
+				android.AssertPathsRelativeToTopEquals(t, "transitive_import resources", testCase.transitiveImportResources, transitiveImport.resources)
+				android.AssertPathsRelativeToTopEquals(t, "transitive_import overlays", testCase.transitiveImportOverlays, transitiveImport.overlays)
+				android.AssertPathsRelativeToTopEquals(t, "transitive_import imports", testCase.transitiveImportImports, transitiveImport.imports)
+			}
+		})
+	}
+}
+
+func TestAndroidResourceOverlays(t *testing.T) {
 	testCases := []struct {
 		name                       string
 		enforceRROTargets          []string
@@ -903,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
@@ -943,7 +1603,7 @@
 					overlayFiles = resourceListToFiles(module, android.PathsRelativeToTop(overlayList.Inputs))
 				}
 
-				for _, d := range module.Module().(AndroidLibraryDependency).ExportedRRODirs() {
+				for _, d := range module.Module().(AndroidLibraryDependency).RRODirsDepSet().ToList() {
 					var prefix string
 					if d.overlayType == device {
 						prefix = "device:"
@@ -1232,7 +1892,7 @@
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
 			app := ctx.ModuleForTests(test.name, "android_common")
-			jniLibZip := app.Output(jniJarOutputPathString)
+			jniLibZip := app.Output("jnilibs.zip")
 			var abis []string
 			args := strings.Fields(jniLibZip.Args["jarArgs"])
 			for i := 0; i < len(args); i++ {
@@ -1365,7 +2025,7 @@
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
 			app := ctx.ModuleForTests(test.name, "android_common")
-			jniLibZip := app.MaybeOutput(jniJarOutputPathString)
+			jniLibZip := app.MaybeOutput("jnilibs.zip")
 			if g, w := (jniLibZip.Rule != nil), test.packaged; g != w {
 				t.Errorf("expected jni packaged %v, got %v", w, g)
 			}
@@ -1449,14 +2109,14 @@
 		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 {
 		t.Run(test.name, func(t *testing.T) {
 			app := ctx.ModuleForTests(test.name, "android_common")
 
-			jniLibZip := app.MaybeOutput(jniJarOutputPathString)
+			jniLibZip := app.MaybeOutput("jnilibs.zip")
 			if len(jniLibZip.Implicits) != 1 {
 				t.Fatalf("expected exactly one jni library, got %q", jniLibZip.Implicits.Strings())
 			}
@@ -2476,7 +3136,7 @@
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
 			app := ctx.ModuleForTests(test.name, "android_common")
-			jniLibZip := app.Output(jniJarOutputPathString)
+			jniLibZip := app.Output("jnilibs.zip")
 			var jnis []string
 			args := strings.Fields(jniLibZip.Args["jarArgs"])
 			for i := 0; i < len(args); i++ {
@@ -2645,7 +3305,7 @@
 		PrepareForTestWithJavaSdkLibraryFiles,
 		FixtureWithLastReleaseApis("runtime-library", "foo", "quuz", "qux", "bar", "fred"),
 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-			variables.MissingUsesLibraries = []string{"baz"}
+			variables.BuildWarningBadOptionalUsesLibsAllowlist = []string{"app", "prebuilt"}
 		}),
 	).RunTestWithBp(t, bp)
 
@@ -2693,52 +3353,11 @@
 		`--optional-uses-library baz `
 	android.AssertStringDoesContain(t, "verify apk cmd args", verifyApkCmd, verifyApkArgs)
 
-	// Test that all present libraries are preopted, including implicit SDK dependencies, possibly stubs
+	// Test that necessary args are passed for constructing CLC in Ninja phase.
 	cmd := app.Rule("dexpreopt").RuleParams.Command
-	w := `--target-context-for-sdk any ` +
-		`PCL[/system/framework/qux.jar]#` +
-		`PCL[/system/framework/quuz.jar]#` +
-		`PCL[/system/framework/foo.jar]#` +
-		`PCL[/system/framework/non-sdk-lib.jar]#` +
-		`PCL[/system/framework/bar.jar]#` +
-		`PCL[/system/framework/runtime-library.jar]#` +
-		`PCL[/system/framework/runtime-required-x.jar]#` +
-		`PCL[/system/framework/runtime-optional-x.jar]#` +
-		`PCL[/system/framework/runtime-required-y.jar]#` +
-		`PCL[/system/framework/runtime-optional-y.jar] `
-	android.AssertStringDoesContain(t, "dexpreopt app cmd args", cmd, w)
-
-	// Test conditional context for target SDK version 28.
-	android.AssertStringDoesContain(t, "dexpreopt app cmd 28", cmd,
-		`--target-context-for-sdk 28`+
-			` PCL[/system/framework/org.apache.http.legacy.jar] `)
-
-	// Test conditional context for target SDK version 29.
-	android.AssertStringDoesContain(t, "dexpreopt app cmd 29", cmd,
-		`--target-context-for-sdk 29`+
-			` PCL[/system/framework/android.hidl.manager-V1.0-java.jar]`+
-			`#PCL[/system/framework/android.hidl.base-V1.0-java.jar] `)
-
-	// Test conditional context for target SDK version 30.
-	// "android.test.mock" is absent because "android.test.runner" is not used.
-	android.AssertStringDoesContain(t, "dexpreopt app cmd 30", cmd,
-		`--target-context-for-sdk 30`+
-			` PCL[/system/framework/android.test.base.jar] `)
-
-	cmd = prebuilt.Rule("dexpreopt").RuleParams.Command
-	android.AssertStringDoesContain(t, "dexpreopt prebuilt cmd", cmd,
-		`--target-context-for-sdk any`+
-			` PCL[/system/framework/foo.jar]`+
-			`#PCL[/system/framework/non-sdk-lib.jar]`+
-			`#PCL[/system/framework/android.test.runner.jar]`+
-			`#PCL[/system/framework/bar.jar] `)
-
-	// Test conditional context for target SDK version 30.
-	// "android.test.mock" is present because "android.test.runner" is used.
-	android.AssertStringDoesContain(t, "dexpreopt prebuilt cmd 30", cmd,
-		`--target-context-for-sdk 30`+
-			` PCL[/system/framework/android.test.base.jar]`+
-			`#PCL[/system/framework/android.test.mock.jar] `)
+	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/app/product_packages.txt")
 }
 
 func TestDexpreoptBcp(t *testing.T) {
@@ -3714,3 +4333,48 @@
 	)
 
 }
+
+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",
+	)
+}
diff --git a/java/base.go b/java/base.go
index 025fc7e..e52cedd 100644
--- a/java/base.go
+++ b/java/base.go
@@ -20,9 +20,9 @@
 	"strconv"
 	"strings"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 	"github.com/google/blueprint/proptools"
-	"github.com/google/blueprint"
 
 	"android/soong/android"
 	"android/soong/dexpreopt"
@@ -80,6 +80,9 @@
 	// list of java libraries that will be compiled into the resulting jar
 	Static_libs []string `android:"arch_variant"`
 
+	// list of java libraries that should not be used to build this module
+	Exclude_static_libs []string `android:"arch_variant"`
+
 	// manifest file to be included in resulting jar
 	Manifest *string `android:"path"`
 
@@ -130,7 +133,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
@@ -185,6 +188,18 @@
 
 	// A list of java_library instances that provide additional hiddenapi annotations for the library.
 	Hiddenapi_additional_annotations []string
+
+	// Additional srcJars tacked in by GeneratedJavaLibraryModule
+	Generated_srcjars []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"`
 }
 
 // Properties that are specific to device modules. Host module factories should not add these when
@@ -396,7 +411,6 @@
 	android.ModuleBase
 	android.DefaultableModuleBase
 	android.ApexModuleBase
-	android.BazelModuleBase
 
 	// Functionality common to Module and Import.
 	embeddableInModuleAndImport
@@ -422,6 +436,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
@@ -484,9 +501,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
@@ -494,6 +508,16 @@
 	maxSdkVersion android.ApiLevel
 
 	sourceExtensions []string
+
+	annoSrcJars android.Paths
+
+	// output file name based on Stem property.
+	// This should be set in every ModuleWithStem's GenerateAndroidBuildActions
+	// or the module should override Stem().
+	stem string
+
+	// Single aconfig "cache file" merged from this module and all dependencies.
+	mergedAconfigFiles map[string]android.Paths
 }
 
 func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
@@ -552,6 +576,17 @@
 	}
 }
 
+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,
@@ -582,7 +617,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) {
@@ -600,6 +635,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)
 	}
@@ -642,7 +684,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) {
@@ -673,6 +715,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)
@@ -725,6 +771,8 @@
 	}
 
 	libDeps := ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
+
+	j.properties.Static_libs = android.RemoveListFromList(j.properties.Static_libs, j.properties.Exclude_static_libs)
 	ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...)
 
 	// Add dependency on libraries that provide additional hidden api annotations.
@@ -962,8 +1010,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")
@@ -972,44 +1028,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)
@@ -1037,7 +1067,11 @@
 
 }
 
-func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.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) {
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
 
 	deps := j.collectDeps(ctx)
@@ -1045,6 +1079,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)
@@ -1075,16 +1112,15 @@
 
 	srcJars := srcFiles.FilterByExt(".srcjar")
 	srcJars = append(srcJars, deps.srcJars...)
-	if aaptSrcJar != nil {
-		srcJars = append(srcJars, aaptSrcJar)
-	}
+	srcJars = append(srcJars, extraSrcJars...)
+	srcJars = append(srcJars, j.properties.Generated_srcjars...)
 	srcFiles = srcFiles.FilterOutByExt(".srcjar")
 
 	if j.properties.Jarjar_rules != nil {
 		j.expandJarjarRules = android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
 	}
 
-	jarName := ctx.ModuleName() + ".jar"
+	jarName := j.Stem() + ".jar"
 
 	var uniqueJavaFiles android.Paths
 	set := make(map[string]bool)
@@ -1106,7 +1142,7 @@
 	uniqueSrcFiles = append(uniqueSrcFiles, uniqueJavaFiles...)
 	uniqueSrcFiles = append(uniqueSrcFiles, uniqueKtFiles...)
 	j.uniqueSrcFiles = uniqueSrcFiles
-	ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: uniqueSrcFiles.Strings()})
+	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
@@ -1120,6 +1156,41 @@
 	var kotlinJars android.Paths
 	var kotlinHeaderJars android.Paths
 
+	// Prepend extraClasspathJars to classpath so that the resource processor R.jar comes before
+	// any dependencies so that it can override any non-final R classes from dependencies with the
+	// final R classes from the app.
+	flags.classpath = append(android.CopyOf(extraClasspathJars), flags.classpath...)
+
+	// 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,
+		})
+
+		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
@@ -1213,8 +1284,9 @@
 			// 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 =
-			j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, kotlinHeaderJars)
+			j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
 		if ctx.Failed() {
 			return
 		}
@@ -1243,8 +1315,9 @@
 			// this module, or else we could have duplicated errorprone messages.
 			errorproneFlags := enableErrorproneFlags(flags)
 			errorprone := android.PathForModuleOut(ctx, "errorprone", jarName)
+			errorproneAnnoSrcJar := android.PathForModuleOut(ctx, "errorprone", "anno.srcjar")
 
-			transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneFlags, nil,
+			transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneAnnoSrcJar, errorproneFlags, nil,
 				"errorprone", "errorprone")
 
 			extraJarDeps = append(extraJarDeps, errorprone)
@@ -1264,10 +1337,17 @@
 					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)
+					jars = append(jars, classes)
+				}
 			}
 		} else {
 			classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, extraJarDeps)
@@ -1364,6 +1444,8 @@
 		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
@@ -1374,12 +1456,20 @@
 		// prebuilt dependencies until we support modules in the platform build, so there shouldn't be
 		// any if len(jars) == 1.
 
+		// moduleStubLinkType determines if the module is the TopLevelStubLibrary generated
+		// from sdk_library. The TopLevelStubLibrary contains only one static lib,
+		// either with .from-source or .from-text suffix.
+		// outputFile should be agnostic to the build configuration,
+		// thus "combine" the single static lib in order to prevent the static lib from being exposed
+		// to the copy rules.
+		stub, _ := moduleStubLinkType(ctx.ModuleName())
+
 		// Transform the single path to the jar into an OutputPath as that is required by the following
 		// code.
-		if moduleOutPath, ok := jars[0].(android.ModuleOutPath); ok {
+		if moduleOutPath, ok := jars[0].(android.ModuleOutPath); ok && !stub {
 			// The path contains an embedded OutputPath so reuse that.
 			outputFile = moduleOutPath.OutputPath
-		} else if outputPath, ok := jars[0].(android.OutputPath); ok {
+		} else if outputPath, ok := jars[0].(android.OutputPath); ok && !stub {
 			// The path is an OutputPath so reuse it directly.
 			outputFile = outputPath
 		} else {
@@ -1448,7 +1538,13 @@
 
 	j.implementationJarFile = outputFile
 	if j.headerJarFile == nil {
-		j.headerJarFile = j.implementationJarFile
+		// If this module couldn't generate a header jar (for example due to api generating annotation processors)
+		// then use the implementation jar.  Run it through zip2zip first to remove any files in META-INF/services
+		// so that javac on modules that depend on this module don't pick up annotation processors (which may be
+		// missing their implementations) from META-INF/services/javax.annotation.processing.Processor.
+		headerJarFile := android.PathForModuleOut(ctx, "javac-header", jarName)
+		convertImplementationJarToHeaderJar(ctx, j.implementationJarFile, headerJarFile)
+		j.headerJarFile = headerJarFile
 	}
 
 	// enforce syntax check to jacoco filters for any build (http://b/183622051)
@@ -1475,7 +1571,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)
@@ -1488,7 +1584,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
@@ -1513,7 +1609,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
@@ -1530,7 +1626,7 @@
 			j.dexJarFile = makeDexJarPathFromPath(dexOutputFile)
 
 			// Dexpreopting
-			j.dexpreopt(ctx, dexOutputFile)
+			j.dexpreopt(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), dexOutputFile)
 
 			outputFile = dexOutputFile
 		} else {
@@ -1548,30 +1644,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)
 			}
 		}
 
@@ -1586,15 +1663,20 @@
 		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)
 
-	ctx.SetProvider(JavaInfoProvider, JavaInfo{
+	android.CollectDependencyAconfigFiles(ctx, &j.mergedAconfigFiles)
+
+	android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
 		HeaderJars:                     android.PathsIfNonNil(j.headerJarFile),
 		TransitiveLibsHeaderJars:       j.transitiveLibsHeaderJars,
 		TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
@@ -1604,6 +1686,7 @@
 		AidlIncludeDirs:                j.exportAidlIncludeDirs,
 		SrcJarArgs:                     j.srcJarArgs,
 		SrcJarDeps:                     j.srcJarDeps,
+		TransitiveSrcFiles:             j.transitiveSrcFiles,
 		ExportedPlugins:                j.exportedPluginJars,
 		ExportedPluginClasses:          j.exportedPluginClasses,
 		ExportedPluginDisableTurbine:   j.exportedDisableTurbine,
@@ -1618,6 +1701,49 @@
 	return android.InList("androidx.compose.runtime_runtime", j.properties.Static_libs)
 }
 
+func (j *Module) collectProguardSpecInfo(ctx android.ModuleContext) ProguardSpecInfo {
+	transitiveUnconditionalExportedFlags := []*android.DepSet[android.Path]{}
+	transitiveProguardFlags := []*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)
+		}
+	})
+
+	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 {
@@ -1637,13 +1763,15 @@
 	srcFiles, srcJars android.Paths, flags javaBuilderFlags, extraJarDeps android.Paths) android.WritablePath {
 
 	kzipName := pathtools.ReplaceExtension(jarName, "kzip")
+	annoSrcJar := android.PathForModuleOut(ctx, "javac", "anno.srcjar")
 	if idx >= 0 {
 		kzipName = strings.TrimSuffix(jarName, filepath.Ext(jarName)) + strconv.Itoa(idx) + ".kzip"
+		annoSrcJar = android.PathForModuleOut(ctx, "javac", "anno-"+strconv.Itoa(idx)+".srcjar")
 		jarName += strconv.Itoa(idx)
 	}
 
 	classes := android.PathForModuleOut(ctx, "javac", jarName).OutputPath
-	TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, flags, extraJarDeps)
+	TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, annoSrcJar, flags, extraJarDeps)
 
 	if ctx.Config().EmitXrefRules() {
 		extractionFile := android.PathForModuleOut(ctx, kzipName)
@@ -1651,6 +1779,10 @@
 		j.kytheFiles = append(j.kytheFiles, extractionFile)
 	}
 
+	if len(flags.processorPath) > 0 {
+		j.annoSrcJars = append(j.annoSrcJars, annoSrcJar)
+	}
+
 	return classes
 }
 
@@ -1736,44 +1868,47 @@
 
 type providesTransitiveHeaderJars struct {
 	// set of header jars for all transitive libs deps
-	transitiveLibsHeaderJars *android.DepSet
+	transitiveLibsHeaderJars *android.DepSet[android.Path]
 	// set of header jars for all transitive static libs deps
-	transitiveStaticLibsHeaderJars *android.DepSet
+	transitiveStaticLibsHeaderJars *android.DepSet[android.Path]
 }
 
-func (j *providesTransitiveHeaderJars) TransitiveLibsHeaderJars() *android.DepSet {
+func (j *providesTransitiveHeaderJars) TransitiveLibsHeaderJars() *android.DepSet[android.Path] {
 	return j.transitiveLibsHeaderJars
 }
 
-func (j *providesTransitiveHeaderJars) TransitiveStaticLibsHeaderJars() *android.DepSet {
+func (j *providesTransitiveHeaderJars) TransitiveStaticLibsHeaderJars() *android.DepSet[android.Path] {
 	return j.transitiveStaticLibsHeaderJars
 }
 
 func (j *providesTransitiveHeaderJars) collectTransitiveHeaderJars(ctx android.ModuleContext) {
 	directLibs := android.Paths{}
 	directStaticLibs := android.Paths{}
-	transitiveLibs := []*android.DepSet{}
-	transitiveStaticLibs := []*android.DepSet{}
+	transitiveLibs := []*android.DepSet[android.Path]{}
+	transitiveStaticLibs := []*android.DepSet[android.Path]{}
 	ctx.VisitDirectDeps(func(module android.Module) {
 		// don't add deps of the prebuilt version of the same library
 		if ctx.ModuleName() == android.RemoveOptionalPrebuiltPrefix(module.Name()) {
 			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)
@@ -1794,7 +1929,7 @@
 	return android.Paths{j.implementationJarFile}
 }
 
-func (j *Module) DexJarBuildPath() OptionalDexJarPath {
+func (j *Module) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
 	return j.dexJarFile
 }
 
@@ -1827,9 +1962,9 @@
 	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()...)
 }
 
 func (j *Module) CompilerDeps() []string {
@@ -1867,13 +2002,31 @@
 }
 
 func (j *Module) Stem() string {
-	return proptools.StringDefault(j.overridableDeviceProperties.Stem, j.Name())
+	if j.stem == "" {
+		panic("Stem() called before stem property was set")
+	}
+	return j.stem
 }
 
 func (j *Module) JacocoReportClassesFile() android.Path {
 	return j.jacocoReportClassesFile
 }
 
+func (j *Module) collectTransitiveSrcFiles(ctx android.ModuleContext, mine android.Paths) {
+	var fromDeps []*android.DepSet[android.Path]
+	ctx.VisitDirectDeps(func(module android.Module) {
+		tag := ctx.OtherModuleDependencyTag(module)
+		if tag == staticLibTag {
+			depInfo, _ := android.OtherModuleProvider(ctx, module, JavaInfoProvider)
+			if depInfo.TransitiveSrcFiles != nil {
+				fromDeps = append(fromDeps, depInfo.TransitiveSrcFiles)
+			}
+		}
+	})
+
+	j.transitiveSrcFiles = android.NewDepSet(android.POSTORDER, mine, fromDeps)
+}
+
 func (j *Module) IsInstallable() bool {
 	return Bool(j.properties.Installable)
 }
@@ -1925,19 +2078,22 @@
 
 func (m *Module) getSdkLinkType(ctx android.BaseModuleContext, name string) (ret sdkLinkType, stubs bool) {
 	switch name {
-	case android.SdkCore.JavaLibraryName(ctx.Config()), "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs",
+	case android.SdkCore.DefaultJavaLibraryName(),
+		"legacy.core.platform.api.stubs",
+		"stable.core.platform.api.stubs",
 		"stub-annotations", "private-stub-annotations-jar",
-		"core-lambda-stubs", "core-generated-annotation-stubs":
+		"core-lambda-stubs",
+		"core-generated-annotation-stubs":
 		return javaCore, true
-	case android.SdkPublic.JavaLibraryName(ctx.Config()):
+	case android.SdkPublic.DefaultJavaLibraryName():
 		return javaSdk, true
-	case android.SdkSystem.JavaLibraryName(ctx.Config()):
+	case android.SdkSystem.DefaultJavaLibraryName():
 		return javaSystem, true
-	case android.SdkModule.JavaLibraryName(ctx.Config()):
+	case android.SdkModule.DefaultJavaLibraryName():
 		return javaModule, true
-	case android.SdkSystemServer.JavaLibraryName(ctx.Config()):
+	case android.SdkSystemServer.DefaultJavaLibraryName():
 		return javaSystemServer, true
-	case android.SdkTest.JavaLibraryName(ctx.Config()):
+	case android.SdkTest.DefaultJavaLibraryName():
 		return javaSystem, true
 	}
 
@@ -2033,15 +2189,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:
@@ -2113,7 +2268,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,
 				})
 			}
@@ -2176,16 +2331,3 @@
 }
 
 var _ ModuleWithStem = (*Module)(nil)
-
-func (j *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	switch ctx.ModuleType() {
-	case "java_library", "java_library_host", "java_library_static":
-		if lib, ok := ctx.Module().(*Library); ok {
-			javaLibraryBp2Build(ctx, lib)
-		}
-	case "java_binary_host":
-		if binary, ok := ctx.Module().(*Binary); ok {
-			javaBinaryHostBp2Build(ctx, binary)
-		}
-	}
-}
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index f4cef7f..c7dc3af 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -77,7 +77,7 @@
 // Use gatherApexModulePairDepsWithTag to retrieve the dependencies.
 func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex string, name string, tag blueprint.DependencyTag) {
 	var variations []blueprint.Variation
-	if apex != "platform" && apex != "system_ext" {
+	if !android.IsConfiguredJarForPlatform(apex) {
 		// Pick the correct apex variant.
 		variations = []blueprint.Variation{
 			{Mutator: "apex", Variation: apex},
@@ -185,6 +185,9 @@
 // The tag used for dependencies onto bootclasspath_fragments.
 var bootclasspathFragmentDepTag = bootclasspathDependencyTag{name: "fragment"}
 
+// The tag used for dependencies onto platform_bootclasspath.
+var platformBootclasspathDepTag = bootclasspathDependencyTag{name: "platform"}
+
 // BootclasspathNestedAPIProperties defines properties related to the API provided by parts of the
 // bootclasspath that are nested within the main BootclasspathAPIProperties.
 type BootclasspathNestedAPIProperties struct {
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index f815954..7c45d30 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -229,6 +229,7 @@
 
 type BootclasspathFragmentModule struct {
 	android.ModuleBase
+	android.DefaultableModuleBase
 	android.ApexModuleBase
 	ClasspathFragmentBase
 
@@ -239,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.Path
+	profilePath    android.WritablePath
+	profilePathErr error
 }
 
 // commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt
@@ -257,16 +256,6 @@
 	// versioned sdk.
 	produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput
 
-	// produceBootImageFiles will attempt to produce rules to create the boot image files at the paths
-	// predefined in the bootImageConfig.
-	//
-	// If it could not create the files then it will return nil. Otherwise, it will return a map from
-	// android.ArchType to the predefined paths of the boot image files.
-	produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs
-
-	// getImageName returns the `image_name` property of this fragment.
-	getImageName() *string
-
 	// getProfilePath returns the path to the boot image profile.
 	getProfilePath() android.Path
 }
@@ -279,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
@@ -296,9 +286,6 @@
 				return
 			}
 		}
-
-		// Initialize the contents property from the image_name.
-		bootclasspathFragmentInitContentsFromImage(ctx, m)
 	})
 	return m
 }
@@ -309,9 +296,7 @@
 	return m
 }
 
-// bootclasspathFragmentInitContentsFromImage will initialize the contents property from the image_name if
-// necessary.
-func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext, m *BootclasspathFragmentModule) {
+func (m *BootclasspathFragmentModule) bootclasspathFragmentPropertyCheck(ctx android.EarlyModuleContext) {
 	contents := m.properties.Contents
 	if len(contents) == 0 {
 		ctx.PropertyErrorf("contents", "required property is missing")
@@ -333,6 +318,18 @@
 	// too early in the Soong processing for that to work.
 	global := dexpreopt.GetGlobalConfig(ctx)
 	modules := global.ArtApexJars
+	configuredJars := modules.CopyOfJars()
+
+	// Skip the check if the configured jars list is empty as that is a common configuration when
+	// building targets that do not result in a system image.
+	if len(configuredJars) == 0 {
+		return
+	}
+
+	if !reflect.DeepEqual(configuredJars, contents) {
+		ctx.ModuleErrorf("inconsistency in specification of contents. ArtApexJars configuration specifies %#v, contents property specifies %#v",
+			configuredJars, contents)
+	}
 
 	// Make sure that the apex specified in the configuration is consistent and is one for which
 	// this boot image is available.
@@ -358,42 +355,11 @@
 	}
 }
 
-// bootclasspathImageNameContentsConsistencyCheck checks that the configuration that applies to this
-// module (if any) matches the contents.
-//
-// This should be a noop as if image_name="art" then the contents will be set from the ArtApexJars
-// config by bootclasspathFragmentInitContentsFromImage so it will be guaranteed to match. However,
-// in future this will not be the case.
-func (b *BootclasspathFragmentModule) bootclasspathImageNameContentsConsistencyCheck(ctx android.BaseModuleContext) {
-	imageName := proptools.String(b.properties.Image_name)
-	if imageName == "art" {
-		// Get the configuration for the art apex jars.
-		modules := b.getImageConfig(ctx).modules
-		configuredJars := modules.CopyOfJars()
-
-		// Skip the check if the configured jars list is empty as that is a common configuration when
-		// building targets that do not result in a system image.
-		if len(configuredJars) == 0 {
-			return
-		}
-
-		contents := b.properties.Contents
-		if !reflect.DeepEqual(configuredJars, contents) {
-			ctx.ModuleErrorf("inconsistency in specification of contents. ArtApexJars configuration specifies %#v, contents property specifies %#v",
-				configuredJars, contents)
-		}
-	}
-}
-
-var BootclasspathFragmentApexContentInfoProvider = blueprint.NewProvider(BootclasspathFragmentApexContentInfo{})
+var BootclasspathFragmentApexContentInfoProvider = blueprint.NewProvider[BootclasspathFragmentApexContentInfo]()
 
 // BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the
 // apex contents.
 type BootclasspathFragmentApexContentInfo struct {
-	// The configured modules, will be empty if this is from a bootclasspath_fragment that does not
-	// set image_name: "art".
-	modules android.ConfiguredJarList
-
 	// Map from the base module name (without prebuilt_ prefix) of a fragment's contents module to the
 	// hidden API encoded dex jar path.
 	contentModuleDexJarPaths bootDexJarByModule
@@ -406,10 +372,6 @@
 	profileInstallPathInApex string
 }
 
-func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarList {
-	return i.modules
-}
-
 // DexBootJarPathForContentModule returns the path to the dex boot jar for specified module.
 //
 // The dex boot jar is one which has had hidden API encoding performed on it.
@@ -425,6 +387,10 @@
 	}
 }
 
+func (i BootclasspathFragmentApexContentInfo) DexBootJarPathMap() bootDexJarByModule {
+	return i.contentModuleDexJarPaths
+}
+
 func (i BootclasspathFragmentApexContentInfo) ProfilePathOnHost() android.Path {
 	return i.profilePathOnHost
 }
@@ -435,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
@@ -480,8 +451,6 @@
 		for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
 			// Add a dependency onto a possibly scope specific stub library.
 			scopeSpecificDependency := apiScope.scopeSpecificStubModule(ctx, additionalStubModule)
-			// Use JavaApiLibraryName function to be redirected to stubs generated from .txt if applicable
-			scopeSpecificDependency = android.JavaApiLibraryName(ctx.Config(), scopeSpecificDependency)
 			tag := hiddenAPIStubsDependencyTag{apiScope: apiScope, fromAdditionalDependency: true}
 			ctx.AddVariationDependencies(nil, tag, scopeSpecificDependency)
 		}
@@ -506,15 +475,12 @@
 	// unused prebuilt that was created without instrumentation from breaking an instrumentation
 	// build.
 	if isActiveModule(ctx.Module()) {
-		b.bootclasspathImageNameContentsConsistencyCheck(ctx)
+		b.bootclasspathFragmentPropertyCheck(ctx)
 	}
 
 	// 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) {
@@ -526,34 +492,15 @@
 
 	fragments := gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag)
 
-	// Verify that the image_name specified on a bootclasspath_fragment is valid even if this is a
-	// prebuilt which will not use the image config.
-	imageConfig := b.getImageConfig(ctx)
-
 	// Perform hidden API processing.
 	hiddenAPIOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments)
 
-	var bootImageFiles bootImageOutputs
-	if imageConfig != nil {
-		// Delegate the production of the boot image files to a module type specific method.
-		common := ctx.Module().(commonBootclasspathFragment)
-		bootImageFiles = common.produceBootImageFiles(ctx, imageConfig)
-		b.profilePath = bootImageFiles.profile
-
-		if shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) {
-			// Zip the boot image files up, if available. This will generate the zip file in a
-			// predefined location.
-			buildBootImageZipInPredefinedLocation(ctx, imageConfig, bootImageFiles.byArch)
-
-			// Copy the dex jars of this fragment's content modules to their predefined locations.
-			copyBootJarsToPredefinedLocations(ctx, hiddenAPIOutput.EncodedBootDexFilesByModule, imageConfig.dexPathsByModule)
-		}
-	}
-
-	// A prebuilt fragment cannot contribute to an apex.
-	if !android.IsModulePrebuilt(ctx.Module()) {
-		// Provide the apex content info.
-		b.provideApexContentInfo(ctx, imageConfig, hiddenAPIOutput, bootImageFiles)
+	if android.IsModulePrebuilt(ctx.Module()) {
+		b.profilePath = ctx.Module().(*PrebuiltBootclasspathFragmentModule).produceBootImageProfile(ctx)
+	} else {
+		b.profilePath = b.produceBootImageProfileFromSource(ctx, contents, hiddenAPIOutput.EncodedBootDexFilesByModule)
+		// Provide the apex content info. A prebuilt fragment cannot contribute to an apex.
+		b.provideApexContentInfo(ctx, hiddenAPIOutput, b.profilePath)
 	}
 
 	// In order for information about bootclasspath_fragment modules to be added to module-info.json
@@ -565,52 +512,44 @@
 	if ctx.Module() != ctx.FinalModule() {
 		b.HideFromMake()
 	}
-	ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+	android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
-// shouldCopyBootFilesToPredefinedLocations determines whether the current module should copy boot
-// files, e.g. boot dex jars or boot image files, to the predefined location expected by the rest
-// of the build.
-//
-// This ensures that only a single module will copy its files to the image configuration.
-func shouldCopyBootFilesToPredefinedLocations(ctx android.ModuleContext, imageConfig *bootImageConfig) bool {
+// getProfileProviderApex returns the name of the apex that provides a boot image profile, or an
+// empty string if this module should not provide a boot image profile.
+func (b *BootclasspathFragmentModule) getProfileProviderApex(ctx android.BaseModuleContext) string {
+	// Only use the profile from the module that is preferred.
+	if !isActiveModule(ctx.Module()) {
+		return ""
+	}
+
 	// Bootclasspath fragment modules that are for the platform do not produce boot related files.
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
-	if apexInfo.IsForPlatform() {
-		return false
+	apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+	for _, apex := range apexInfo.InApexVariants {
+		if isProfileProviderApex(ctx, apex) {
+			return apex
+		}
 	}
 
-	// If the image configuration has no modules specified then it means that the build has been
-	// configured to build something other than a boot image, e.g. an sdk, so do not try and copy the
-	// files.
-	if imageConfig.modules.Len() == 0 {
-		return false
-	}
-
-	// Only copy files from the module that is preferred.
-	return isActiveModule(ctx.Module())
+	return ""
 }
 
 // provideApexContentInfo creates, initializes and stores the apex content info for use by other
 // modules.
-func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, hiddenAPIOutput *HiddenAPIOutput, bootImageFiles bootImageOutputs) {
+func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, hiddenAPIOutput *HiddenAPIOutput, profile android.WritablePath) {
 	// Construct the apex content info from the config.
 	info := BootclasspathFragmentApexContentInfo{
 		// Populate the apex content info with paths to the dex jars.
 		contentModuleDexJarPaths: hiddenAPIOutput.EncodedBootDexFilesByModule,
 	}
 
-	if imageConfig != nil {
-		info.modules = imageConfig.modules
-		global := dexpreopt.GetGlobalConfig(ctx)
-		if !global.DisableGenerateProfile {
-			info.profilePathOnHost = bootImageFiles.profile
-			info.profileInstallPathInApex = imageConfig.profileInstallPathInApex
-		}
+	if profile != nil {
+		info.profilePathOnHost = profile
+		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
@@ -627,12 +566,12 @@
 }
 
 func (b *BootclasspathFragmentModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList {
-	if "art" == proptools.String(b.properties.Image_name) {
-		return b.getImageConfig(ctx).modules
-	}
-
 	global := dexpreopt.GetGlobalConfig(ctx)
 
+	if "art" == proptools.String(b.properties.Image_name) {
+		return global.ArtApexJars
+	}
+
 	possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, b.properties.Contents, bootclasspathFragmentContentDepTag)
 	jars, unknown := global.ApexBootJars.Filter(possibleUpdatableModules)
 
@@ -651,32 +590,13 @@
 		// 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)
 		}
 	}
 	return jars
 }
 
-func (b *BootclasspathFragmentModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
-	// Get a map of the image configs that are supported.
-	imageConfigs := genBootImageConfigs(ctx)
-
-	// Retrieve the config for this image.
-	imageNamePtr := b.properties.Image_name
-	if imageNamePtr == nil {
-		return nil
-	}
-
-	imageName := *imageNamePtr
-	imageConfig := imageConfigs[imageName]
-	if imageConfig == nil {
-		ctx.PropertyErrorf("image_name", "Unknown image name %q, expected one of %s", imageName, strings.Join(android.SortedKeys(imageConfigs), ", "))
-		return nil
-	}
-	return imageConfig
-}
-
 // generateHiddenAPIBuildActions generates all the hidden API related build rules.
 func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) *HiddenAPIOutput {
 
@@ -715,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 {
@@ -851,7 +756,7 @@
 	}
 
 	// Make the information available for the sdk snapshot.
-	ctx.SetProvider(HiddenAPIInfoForSdkProvider, HiddenAPIInfoForSdk{
+	android.SetProvider(ctx, HiddenAPIInfoForSdkProvider, HiddenAPIInfoForSdk{
 		FlagFilesByCategory: flagFilesByCategory,
 		HiddenAPIFlagOutput: flagOutput,
 	})
@@ -859,48 +764,22 @@
 	return output
 }
 
-// produceBootImageFiles builds the boot image files from the source if it is required.
-func (b *BootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs {
-	// Only generate the boot image if the configuration does not skip it.
-	return b.generateBootImageBuildActions(ctx, imageConfig)
-}
-
-// generateBootImageBuildActions generates ninja rules to create the boot image if required for this
-// module.
-//
-// If it could not create the files then it will return nil. Otherwise, it will return a map from
-// android.ArchType to the predefined paths of the boot image files.
-func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs {
-	global := dexpreopt.GetGlobalConfig(ctx)
-	if !shouldBuildBootImages(ctx.Config(), global) {
-		return bootImageOutputs{}
+// produceBootImageProfileFromSource builds the boot image profile from the source if it is required.
+func (b *BootclasspathFragmentModule) produceBootImageProfileFromSource(ctx android.ModuleContext, contents []android.Module, modules bootDexJarByModule) android.WritablePath {
+	apex := b.getProfileProviderApex(ctx)
+	if apex == "" {
+		return nil
 	}
 
-	// Bootclasspath fragment modules that are for the platform do not produce a boot image.
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
-	if apexInfo.IsForPlatform() {
-		return bootImageOutputs{}
+	dexPaths := make(android.Paths, 0, len(contents))
+	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"))
 	}
 
-	// Build a profile for the image config and then use that to build the boot image.
-	profile := bootImageProfileRule(ctx, imageConfig)
-
-	// If dexpreopt of boot image jars should be skipped, generate only a profile.
-	if SkipDexpreoptBootJars(ctx) {
-		return bootImageOutputs{
-			profile: profile,
-		}
-	}
-
-	// Build boot image files for the host variants.
-	buildBootImageVariantsForBuildOs(ctx, imageConfig, profile)
-
-	// Build boot image files for the android variants.
-	bootImageFiles := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile)
-
-	// Return the boot image files for the android variants for inclusion in an APEX and to be zipped
-	// up for the dist.
-	return bootImageFiles
+	// Build a profile for the modules in this fragment.
+	return bootImageProfileRuleCommon(ctx, b.Name(), dexPaths, dexLocations)
 }
 
 func (b *BootclasspathFragmentModule) AndroidMkEntries() []android.AndroidMkEntries {
@@ -923,10 +802,6 @@
 	return entriesList
 }
 
-func (b *BootclasspathFragmentModule) getImageName() *string {
-	return b.properties.Image_name
-}
-
 func (b *BootclasspathFragmentModule) getProfilePath() android.Path {
 	return b.profilePath
 }
@@ -934,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 {
@@ -1014,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.
@@ -1075,7 +949,7 @@
 					builder.CopyToSnapshot(p, dest)
 					dests = append(dests, dest)
 				}
-				hiddenAPISet.AddProperty(category.PropertyName, dests)
+				hiddenAPISet.AddProperty(category.PropertyName(), dests)
 			}
 		}
 	}
@@ -1171,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),
@@ -1185,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.
@@ -1196,42 +1064,28 @@
 	return &output
 }
 
-// produceBootImageFiles extracts the boot image files from the APEX if available.
-func (module *PrebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageOutputs {
-	if !shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) {
-		return bootImageOutputs{}
+// produceBootImageProfile extracts the boot image profile from the APEX if available.
+func (module *PrebuiltBootclasspathFragmentModule) produceBootImageProfile(ctx android.ModuleContext) android.WritablePath {
+	// This module does not provide a boot image profile.
+	if module.getProfileProviderApex(ctx) == "" {
+		return nil
 	}
 
-	di := android.FindDeapexerProviderForModule(ctx)
-	if di == nil {
-		return bootImageOutputs{} // 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 getProfilePath
+		module.profilePathErr = err
+		return nil // An error has been reported by FindDeapexerProviderForModule.
 	}
 
-	profile := (android.WritablePath)(nil)
-	if imageConfig.profileInstallPathInApex != "" {
-		profile = di.PrebuiltExportPath(imageConfig.profileInstallPathInApex)
-	}
-
-	// Build the boot image files for the host variants. These are always built from the dex files
-	// provided by the contents of this module as prebuilt versions of the host boot image files are
-	// not available, i.e. there is no host specific prebuilt apex containing them. This has to be
-	// built without a profile as the prebuilt modules do not provide a profile.
-	buildBootImageVariantsForBuildOs(ctx, imageConfig, profile)
-
-	if profile == nil && imageConfig.isProfileGuided() {
-		ctx.ModuleErrorf("Unable to produce boot image files: profiles not found in the prebuilt apex")
-		return bootImageOutputs{}
-	}
-	// Build boot image files for the android variants from the dex files provided by the contents
-	// of this module.
-	return buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile)
-}
-
-func (b *PrebuiltBootclasspathFragmentModule) getImageName() *string {
-	return b.properties.Image_name
+	return di.PrebuiltExportPath(ProfileInstallPathInApex)
 }
 
 func (b *PrebuiltBootclasspathFragmentModule) getProfilePath() android.Path {
+	if b.profilePathErr != nil {
+		panic(b.profilePathErr.Error())
+	}
 	return b.profilePath
 }
 
@@ -1243,18 +1097,18 @@
 // If there is no image config associated with this fragment then it returns nil. Otherwise, it
 // returns the files that are listed in the image config.
 func (module *PrebuiltBootclasspathFragmentModule) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string {
-	imageConfig := module.getImageConfig(ctx)
-	if imageConfig != nil {
-		files := []string{}
-		if imageConfig.profileInstallPathInApex != "" {
-			// Add the boot image profile.
-			files = append(files, imageConfig.profileInstallPathInApex)
+	for _, apex := range module.ApexProperties.Apex_available {
+		if isProfileProviderApex(ctx, apex) {
+			return []string{ProfileInstallPathInApex}
 		}
-		return files
 	}
 	return nil
 }
 
+func (module *PrebuiltBootclasspathFragmentModule) UseProfileGuidedDexpreopt() bool {
+	return false
+}
+
 var _ android.RequiredFilesFromPrebuiltApex = (*PrebuiltBootclasspathFragmentModule)(nil)
 
 func prebuiltBootclasspathFragmentFactory() android.Module {
@@ -1266,9 +1120,5 @@
 	android.InitApexModule(m)
 	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
 
-	// Initialize the contents property from the image_name.
-	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
-		bootclasspathFragmentInitContentsFromImage(ctx, &m.BootclasspathFragmentModule)
-	})
 	return m
 }
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 2541f14..8bc0a7e 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -40,6 +40,12 @@
 				image_name: "unknown",
 				contents: ["foo"],
 			}
+
+			java_library {
+				name: "foo",
+				srcs: ["foo.java"],
+				installable: true,
+			}
 		`)
 }
 
@@ -53,6 +59,11 @@
 				image_name: "unknown",
 				contents: ["foo"],
 			}
+
+			java_import {
+				name: "foo",
+				jars: ["foo.jar"],
+			}
 		`)
 }
 
@@ -72,6 +83,18 @@
 					"apex",
 				],
 			}
+
+			java_library {
+				name: "foo",
+				srcs: ["foo.java"],
+				installable: true,
+			}
+
+			java_library {
+				name: "bar",
+				srcs: ["bar.java"],
+				installable: true,
+			}
 		`)
 }
 
@@ -92,6 +115,18 @@
 					"apex2",
 				],
 			}
+
+			java_library {
+				name: "foo",
+				srcs: ["foo.java"],
+				installable: true,
+			}
+
+			java_library {
+				name: "bar",
+				srcs: ["bar.java"],
+				installable: true,
+			}
 		`)
 }
 
@@ -187,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",
@@ -237,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))
@@ -281,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,
@@ -367,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 4626267..085e7a1 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -42,7 +42,8 @@
 	// TODO(b/143658984): goma can't handle the --system argument to javac.
 	javac, javacRE = pctx.MultiCommandRemoteStaticRules("javac",
 		blueprint.RuleParams{
-			Command: `rm -rf "$outDir" "$annoDir" "$srcJarDir" "$out" && mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
+			Command: `rm -rf "$outDir" "$annoDir" "$annoSrcJar.tmp" "$srcJarDir" "$out.tmp" && ` +
+				`mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` +
 				`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
 				`(if [ -s $srcJarDir/list ] || [ -s $out.rsp ] ; then ` +
 				`${config.SoongJavacWrapper} $javaTemplate${config.JavacCmd} ` +
@@ -50,14 +51,18 @@
 				`$processorpath $processor $javacFlags $bootClasspath $classpath ` +
 				`-source $javaVersion -target $javaVersion ` +
 				`-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list ; fi ) && ` +
-				`$zipTemplate${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir && ` +
-				`rm -rf "$srcJarDir"`,
+				`$annoSrcJarTemplate${config.SoongZipCmd} -jar -o $annoSrcJar.tmp -C $annoDir -D $annoDir && ` +
+				`$zipTemplate${config.SoongZipCmd} -jar -o $out.tmp -C $outDir -D $outDir && ` +
+				`if ! cmp -s "$out.tmp" "$out"; then mv "$out.tmp" "$out"; fi && ` +
+				`if ! cmp -s "$annoSrcJar.tmp" "$annoSrcJar"; then mv "$annoSrcJar.tmp" "$annoSrcJar"; fi && ` +
+				`rm -rf "$srcJarDir" "$outDir"`,
 			CommandDeps: []string{
 				"${config.JavacCmd}",
 				"${config.SoongZipCmd}",
 				"${config.ZipSyncCmd}",
 			},
 			CommandOrderOnly: []string{"${config.SoongJavacWrapper}"},
+			Restat:           true,
 			Rspfile:          "$out.rsp",
 			RspfileContent:   "$in",
 		}, map[string]*remoteexec.REParams{
@@ -69,12 +74,19 @@
 			"$zipTemplate": &remoteexec.REParams{
 				Labels:       map[string]string{"type": "tool", "name": "soong_zip"},
 				Inputs:       []string{"${config.SoongZipCmd}", "$outDir"},
-				OutputFiles:  []string{"$out"},
+				OutputFiles:  []string{"$out.tmp"},
+				ExecStrategy: "${config.REJavacExecStrategy}",
+				Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+			},
+			"$annoSrcJarTemplate": &remoteexec.REParams{
+				Labels:       map[string]string{"type": "tool", "name": "soong_zip"},
+				Inputs:       []string{"${config.SoongZipCmd}", "$annoDir"},
+				OutputFiles:  []string{"$annoSrcJar.tmp"},
 				ExecStrategy: "${config.REJavacExecStrategy}",
 				Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
 			},
 		}, []string{"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir",
-			"outDir", "annoDir", "javaVersion"}, nil)
+			"outDir", "annoDir", "annoSrcJar", "javaVersion"}, nil)
 
 	_ = pctx.VariableFunc("kytheCorpus",
 		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() })
@@ -246,11 +258,46 @@
 			CommandDeps: []string{"${config.ZipAlign}"},
 		},
 	)
+
+	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 --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 {
@@ -292,8 +339,14 @@
 	proto android.ProtoFlags
 }
 
+func DefaultJavaBuilderFlags() javaBuilderFlags {
+	return javaBuilderFlags{
+		javaVersion: JAVA_VERSION_8,
+	}
+}
+
 func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, shardIdx int,
-	srcFiles, srcJars android.Paths, flags javaBuilderFlags, deps android.Paths) {
+	srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, flags javaBuilderFlags, deps android.Paths) {
 
 	// Compile java sources into .class files
 	desc := "javac"
@@ -301,7 +354,7 @@
 		desc += strconv.Itoa(shardIdx)
 	}
 
-	transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, flags, deps, "javac", desc)
+	transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, annoSrcJar, flags, deps, "javac", desc)
 }
 
 // Emits the rule to generate Xref input file (.kzip file) for the given set of source files and source jars
@@ -475,7 +528,7 @@
 // suffix will be appended to various intermediate files and directories to avoid collisions when
 // this function is called twice in the same module directory.
 func transformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath,
-	shardIdx int, srcFiles, srcJars android.Paths,
+	shardIdx int, srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath,
 	flags javaBuilderFlags, deps android.Paths,
 	intermediatesDir, desc string) {
 
@@ -522,11 +575,12 @@
 		rule = javacRE
 	}
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        rule,
-		Description: desc,
-		Output:      outputFile,
-		Inputs:      srcFiles,
-		Implicits:   deps,
+		Rule:           rule,
+		Description:    desc,
+		Output:         outputFile,
+		ImplicitOutput: annoSrcJar,
+		Inputs:         srcFiles,
+		Implicits:      deps,
 		Args: map[string]string{
 			"javacFlags":    flags.javacFlags,
 			"bootClasspath": bootClasspath,
@@ -537,6 +591,7 @@
 			"srcJarDir":     android.PathForModuleOut(ctx, intermediatesDir, srcJarDir).String(),
 			"outDir":        android.PathForModuleOut(ctx, intermediatesDir, outDir).String(),
 			"annoDir":       android.PathForModuleOut(ctx, intermediatesDir, annoDir).String(),
+			"annoSrcJar":    annoSrcJar.String(),
 			"javaVersion":   flags.javaVersion.String(),
 		},
 	})
@@ -600,6 +655,15 @@
 	})
 }
 
+func convertImplementationJarToHeaderJar(ctx android.ModuleContext, implementationJarFile android.Path,
+	headerJarFile android.WritablePath) {
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   convertImplementationJarToHeaderJarRule,
+		Input:  implementationJarFile,
+		Output: headerJarFile,
+	})
+}
+
 func TransformJarJar(ctx android.ModuleContext, outputFile android.WritablePath,
 	classesJar android.Path, rulesFile android.Path) {
 	ctx.Build(pctx, android.BuildParams{
@@ -641,12 +705,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..2017801 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -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
index 4b05d9e..0ef348a 100644
--- a/java/code_metadata_test.go
+++ b/java/code_metadata_test.go
@@ -25,14 +25,10 @@
 	}`
 	result := runCodeMetadataTest(t, android.FixtureExpectsNoErrors, bp)
 
-	module := result.ModuleForTests(
-		"module-name", "",
-	).Module().(*soongTesting.CodeMetadataModule)
+	module := result.ModuleForTests("module-name", "")
 
 	// Check that the provider has the right contents
-	data := result.ModuleProvider(
-		module, soongTesting.CodeMetadataProviderKey,
-	).(soongTesting.CodeMetadataProviderData)
+	data, _ := android.SingletonModuleProvider(result, module.Module(), soongTesting.CodeMetadataProviderKey)
 	if !strings.HasSuffix(
 		data.IntermediatePath.String(), "/intermediateCodeMetadata.pb",
 	) {
@@ -42,13 +38,8 @@
 		)
 	}
 
-	buildParamsSlice := module.BuildParamsForTests()
-	var metadata = ""
-	for _, params := range buildParamsSlice {
-		if params.Rule.String() == "android/soong/android.writeFile" {
-			metadata = params.Args["content"]
-		}
-	}
+	metadata := android.ContentFromFileRuleForTests(t, result.TestContext,
+		module.Output(data.IntermediatePath.String()))
 
 	metadataList := make([]*code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership, 0, 2)
 	teamId := "12345"
@@ -65,9 +56,7 @@
 
 	CodeMetadataMetadata := code_metadata_internal_proto.CodeMetadataInternal{TargetOwnershipList: metadataList}
 	protoData, _ := proto.Marshal(&CodeMetadataMetadata)
-	rawData := string(protoData)
-	formattedData := strings.ReplaceAll(rawData, "\n", "\\n")
-	expectedMetadata := "'" + formattedData + "\\n'"
+	expectedMetadata := string(protoData)
 
 	if metadata != expectedMetadata {
 		t.Errorf(
@@ -114,7 +103,7 @@
 	}
 }
 func runCodeMetadataTest(
-		t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
+	t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
 ) *android.TestResult {
 	return android.GroupFixturePreparers(
 		soongTesting.PrepareForTestWithTestingBuildComponents, prepareForJavaTest,
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 b82a137..6a945ac 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -95,13 +95,11 @@
 		"-JXX:TieredStopAtLevel=1",
 		"-JDcom.android.tools.r8.emitRecordAnnotationsInDex",
 		"-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex",
-		"-JDcom.android.tools.r8.emitRecordAnnotationsExInDex",
 	}, dexerJavaVmFlagsList...))
 	exportedVars.ExportStringListStaticVariable("R8Flags", append([]string{
-		"-JXmx2048M",
+		"-JXmx4096M",
 		"-JDcom.android.tools.r8.emitRecordAnnotationsInDex",
 		"-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex",
-		"-JDcom.android.tools.r8.emitRecordAnnotationsExInDex",
 	}, dexerJavaVmFlagsList...))
 
 	exportedVars.ExportStringListStaticVariable("CommonJdkFlags", []string{
@@ -133,7 +131,12 @@
 		if override := ctx.Config().Getenv("OVERRIDE_JLINK_VERSION_NUMBER"); override != "" {
 			return override
 		}
-		return "17"
+		switch ctx.Config().Getenv("EXPERIMENTAL_USE_OPENJDK21_TOOLCHAIN") {
+		case "true":
+			return "21"
+		default:
+			return "17"
+		}
 	})
 
 	pctx.SourcePathVariable("JavaToolchain", "${JavaHome}/bin")
@@ -148,6 +151,8 @@
 	pctx.SourcePathVariable("JavaKytheExtractorJar", "prebuilts/build-tools/common/framework/javac_extractor.jar")
 	pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime")
 
+	pctx.SourcePathVariable("ResourceProcessorBusyBox", "prebuilts/bazel/common/android_tools/android_tools/all_android_tools_deploy.jar")
+
 	pctx.HostBinToolVariable("GenKotlinBuildFileCmd", "gen-kotlin-build-file")
 
 	pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
@@ -214,10 +219,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..39eec44
--- /dev/null
+++ b/java/config/droidstubs.go
@@ -0,0 +1,68 @@
+// 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() {
+	exportedVars.ExportStringList("MetalavaFlags", metalavaFlags)
+
+	exportedVars.ExportString("MetalavaAddOpens", MetalavaAddOpens)
+
+	exportedVars.ExportStringListStaticVariable("MetalavaAnnotationsFlags", metalavaAnnotationsFlags)
+
+	exportedVars.ExportStringListStaticVariable("MetalavaAnnotationWarningsFlags", metalavaAnnotationsWarningsFlags)
+}
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 273aca0..649b6c5 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -28,13 +28,12 @@
 	ctx.Strict("FRAMEWORK_LIBRARIES", strings.Join(FrameworkLibraries, " "))
 
 	// These are used by make when LOCAL_PRIVATE_PLATFORM_APIS is set (equivalent to platform_apis in blueprint):
-	ctx.Strict("LEGACY_CORE_PLATFORM_BOOTCLASSPATH_LIBRARIES", strings.Join(LegacyCorePlatformBootclasspathLibraries, " "))
+	ctx.Strict("LEGACY_CORE_PLATFORM_BOOTCLASSPATH_LIBRARIES",
+		strings.Join(LegacyCorePlatformBootclasspathLibraries, " "))
 	ctx.Strict("LEGACY_CORE_PLATFORM_SYSTEM_MODULES", LegacyCorePlatformSystemModules)
 
 	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 958f4ce..8ffe511 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -33,22 +33,85 @@
     "win_sdk",
 ]
 
-java_library {
-    name: "core.current.stubs",
+java_defaults {
+    name: "core.current.stubs.defaults",
     visibility: ["//visibility:public"],
+    sdk_version: "none",
+    system_modules: "none",
+}
+
+java_library {
+    name: "core.current.stubs.from-source",
+    defaults: [
+        "core.current.stubs.defaults",
+    ],
     static_libs: [
         "art.module.public.api.stubs",
         "conscrypt.module.public.api.stubs",
         "i18n.module.public.api.stubs",
     ],
-    sdk_version: "none",
-    system_modules: "none",
+}
 
+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,
+}
+
+java_library {
+    name: "core.current.stubs",
+    defaults: [
+        "core.current.stubs.defaults",
+    ],
+    static_libs: [
+        "core.current.stubs.from-source",
+    ],
+    product_variables: {
+        build_from_text_stub: {
+            static_libs: [
+                "core.current.stubs.from-text",
+            ],
+            exclude_static_libs: [
+                "core.current.stubs.from-source",
+            ],
+        },
+    },
+}
+
+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.
 //
@@ -120,12 +183,42 @@
     ],
 }
 
+java_defaults {
+    name: "core.module_lib.stubs.defaults",
+    visibility: ["//visibility:private"],
+    sdk_version: "none",
+    system_modules: "none",
+}
+
 // A stubs target containing the parts of the public SDK & @SystemApi(MODULE_LIBRARIES) API
 // provided by the core libraries.
 //
 // Don't use this directly, use "sdk_version: module_current".
 java_library {
     name: "core.module_lib.stubs",
+    defaults: [
+        "core.module_lib.stubs.defaults",
+    ],
+    static_libs: [
+        "core.module_lib.stubs.from-source",
+    ],
+    product_variables: {
+        build_from_text_stub: {
+            static_libs: [
+                "core.module_lib.stubs.from-text",
+            ],
+            exclude_static_libs: [
+                "core.module_lib.stubs.from-source",
+            ],
+        },
+    },
+}
+
+java_library {
+    name: "core.module_lib.stubs.from-source",
+    defaults: [
+        "core.module_lib.stubs.defaults",
+    ],
     static_libs: [
         "art.module.public.api.stubs.module_lib",
 
@@ -135,8 +228,25 @@
         "conscrypt.module.public.api.stubs",
         "i18n.module.public.api.stubs",
     ],
-    sdk_version: "none",
-    system_modules: "none",
+}
+
+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"],
 }
 
@@ -199,18 +309,96 @@
 // API annotations are available to the dex tools that enable enforcement of runtime
 // accessibility. b/119068555
 java_library {
-    name: "legacy.core.platform.api.stubs",
+    name: "legacy.core.platform.api.stubs.from-source",
     visibility: core_platform_visibility,
-    hostdex: true,
-    compile_dex: true,
-
-    sdk_version: "none",
-    system_modules: "none",
+    defaults: [
+        "core.platform.api.stubs.defaults",
+    ],
     static_libs: [
         "art.module.public.api.stubs.module_lib",
         "conscrypt.module.platform.api.stubs",
         "legacy.i18n.module.platform.api.stubs",
     ],
+}
+
+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",
+    ],
+}
+
+java_library {
+    name: "legacy.core.platform.api.stubs",
+    visibility: core_platform_visibility,
+    defaults: [
+        "core.platform.api.stubs.defaults",
+    ],
+    static_libs: [
+        "legacy.core.platform.api.stubs.from-source",
+    ],
+    product_variables: {
+        build_from_text_stub: {
+            static_libs: [
+                "legacy.core.platform.api.stubs.from-text",
+            ],
+            exclude_static_libs: [
+                "legacy.core.platform.api.stubs.from-source",
+            ],
+        },
+    },
+}
+
+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,
+    compile_dex: true,
+
+    sdk_version: "none",
+    system_modules: "none",
     patch_module: "java.base",
 }
 
@@ -233,20 +421,52 @@
 }
 
 java_library {
-    name: "stable.core.platform.api.stubs",
+    name: "stable.core.platform.api.stubs.from-source",
     visibility: core_platform_visibility,
-    hostdex: true,
-    compile_dex: true,
-
-    sdk_version: "none",
-    system_modules: "none",
+    defaults: [
+        "core.platform.api.stubs.defaults",
+    ],
     static_libs: [
         "art.module.public.api.stubs.module_lib",
         // conscrypt only has a stable version, so it is okay to depend on it here:
         "conscrypt.module.platform.api.stubs",
         "stable.i18n.module.platform.api.stubs",
     ],
-    patch_module: "java.base",
+}
+
+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",
+    ],
+}
+
+java_library {
+    name: "stable.core.platform.api.stubs",
+    visibility: core_platform_visibility,
+    defaults: [
+        "core.platform.api.stubs.defaults",
+    ],
+    static_libs: [
+        "stable.core.platform.api.stubs.from-source",
+    ],
+    product_variables: {
+        build_from_text_stub: {
+            static_libs: [
+                "stable.core.platform.api.stubs.from-text",
+            ],
+            exclude_static_libs: [
+                "stable.core.platform.api.stubs.from-source",
+            ],
+        },
+    },
 }
 
 // Same as stable.core.platform.api.stubs, but android annotations are
@@ -351,7 +571,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 813187e..0000000
--- a/java/core-libraries/TxtStubLibraries.bp
+++ /dev/null
@@ -1,156 +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",
-    ],
-    // TODO: Enable after stub generation from .txt file is available
-    enabled: false,
-}
-
-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",
-    ],
-    // TODO: Enable after stub generation from .txt file is available
-    enabled: false,
-}
-
-// 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",
-    ],
-    // TODO: Enable after stub generation from .txt file is available
-    enabled: false,
-}
-
-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",
-    ],
-    // TODO: Enable after stub generation from .txt file is available
-    enabled: false,
-}
-
-java_library {
-    name: "core.module_lib.stubs.from-text",
-    static_libs: [
-        "art.module.public.api.stubs.module_lib.from-text",
-
-        // Replace the following with 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.from-text",
-        "i18n.module.public.api.stubs.from-text",
-    ],
-    sdk_version: "none",
-    system_modules: "none",
-    visibility: ["//visibility:private"],
-    // TODO: Enable after stub generation from .txt file is available
-    enabled: false,
-}
-
-// 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",
-    ],
-    // TODO: Enable after stub generation from .txt file is available
-    enabled: false,
-}
-
-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",
-    // TODO: Enable after stub generation from .txt file is available
-    enabled: false,
-}
-
-// 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",
-    ],
-    // TODO: Enable after stub generation from .txt file is available
-    enabled: false,
-}
-
-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",
-    // TODO: Enable after stub generation from .txt file is available
-    enabled: false,
-}
-
-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",
-    ],
-    // TODO: Enable after stub generation from .txt file is available
-    enabled: false,
-}
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 3581040..efd13b8 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,15 @@
 		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,
+		// TODO: Not sure if aconfig flags that have been moved between device and host variants
+		// make sense.
 	})
 
 }
@@ -155,7 +151,7 @@
 	return d.implementationAndResourceJars
 }
 
-func (d *DeviceHostConverter) DexJarBuildPath() android.Path {
+func (d *DeviceHostConverter) DexJarBuildPath(ctx android.ModuleErrorfContext) android.Path {
 	return nil
 }
 
@@ -191,32 +187,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 3c9a0f3..3413da0 100644
--- a/java/device_host_converter_test.go
+++ b/java/device_host_converter_test.go
@@ -135,6 +135,7 @@
 
 	hostModule := ctx.ModuleForTests("host_module", config.BuildOSCommonTarget.String())
 	hostJavac := hostModule.Output("javac/host_module.jar")
+	hostJavacHeader := hostModule.Output("javac-header/host_module.jar")
 	hostRes := hostModule.Output("res/host_module.jar")
 
 	hostImportModule := ctx.ModuleForTests("host_import_module", config.BuildOSCommonTarget.String())
@@ -148,7 +149,7 @@
 
 	// check classpath of device module with dependency on host_for_device_module
 	expectedClasspath := "-classpath " + strings.Join(android.Paths{
-		hostJavac.Output,
+		hostJavacHeader.Output,
 		hostImportCombined.Output,
 	}.Strings(), ":")
 
diff --git a/java/dex.go b/java/dex.go
index 4d6aa34..cdae0a2 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,
@@ -71,6 +71,10 @@
 
 		// 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 +91,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
 }
@@ -102,14 +108,12 @@
 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 +132,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} ` +
-			`--pg-conf-output ${outConfig} ` +
+			`-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 +162,7 @@
 		"$r8Template": &remoteexec.REParams{
 			Labels:          map[string]string{"type": "compile", "compiler": "r8"},
 			Inputs:          []string{"$implicits", "${config.R8Jar}"},
-			OutputFiles:     []string{"${outUsage}"},
+			OutputFiles:     []string{"${outUsage}", "${outConfig}", "${outDict}", "${resourcesOutput}"},
 			ExecStrategy:    "${config.RER8ExecStrategy}",
 			ToolchainInputs: []string{"${config.JavaCmd}"},
 			Platform:        map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
@@ -181,7 +182,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 +214,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 +224,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,7 +261,7 @@
 	// See b/20667396
 	var proguardRaiseDeps classpath
 	ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(m android.Module) {
-		dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo)
+		dep, _ := android.OtherModuleProvider(ctx, m, JavaInfoProvider)
 		proguardRaiseDeps = append(proguardRaiseDeps, dep.HeaderJars...)
 	})
 
@@ -283,11 +296,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 +314,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 +351,12 @@
 		r8Flags = append(r8Flags, "-ignorewarnings")
 	}
 
+	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())
+	}
+
 	return r8Flags, r8Deps
 }
 
@@ -353,7 +373,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 +398,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,18 +412,25 @@
 			"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},
+			ImplicitOutputs: implicitOutputs,
 			Input:           dexParams.classesJar,
 			Implicits:       r8Deps,
 			Args:            args,
@@ -424,14 +452,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 a96b312..9db9b1b 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -16,6 +16,7 @@
 
 import (
 	"path/filepath"
+	"sort"
 	"strings"
 
 	"android/soong/android"
@@ -28,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
@@ -78,18 +79,25 @@
 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
@@ -165,24 +173,18 @@
 }
 
 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())
-}
-
 // 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
 	}
@@ -205,11 +207,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
 		}
@@ -226,14 +237,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.
@@ -244,20 +261,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
@@ -270,7 +309,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 {
@@ -280,11 +319,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
@@ -303,7 +342,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.
@@ -326,6 +365,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) {
@@ -339,17 +379,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,
@@ -373,32 +417,62 @@
 		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
 	}
 
 	globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
 
-	dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, dexpreoptConfig)
+	// The root "product_packages.txt" is generated by `build/make/core/Makefile`. It contains a list
+	// of all packages that are installed on the device. We use `grep` to filter the list by the app's
+	// 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", dexJarStem, "product_packages.txt")
+	appProductPackagesStaging := appProductPackages.ReplaceExtension(ctx, "txt.tmp")
+	clcNames, _ := dexpreopt.ComputeClassLoaderContextDependencies(dexpreoptConfig.ClassLoaderContexts)
+	sort.Strings(clcNames) // The order needs to be deterministic.
+	productPackagesRule := android.NewRuleBuilder(pctx, ctx)
+	if len(clcNames) > 0 {
+		productPackagesRule.Command().
+			Text("grep -F -x").
+			FlagForEachArg("-e ", clcNames).
+			Input(productPackages).
+			FlagWithOutput("> ", appProductPackagesStaging).
+			Text("|| true")
+	} else {
+		productPackagesRule.Command().
+			Text("rm -f").Output(appProductPackagesStaging).
+			Text("&&").
+			Text("touch").Output(appProductPackagesStaging)
+	}
+	productPackagesRule.Command().
+		Text("rsync --checksum").
+		Input(appProductPackagesStaging).
+		Output(appProductPackages)
+	productPackagesRule.Restat().Build("product_packages."+dexJarStem, "dexpreopt product_packages")
+
+	dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
+		ctx, globalSoong, global, dexpreoptConfig, appProductPackages)
 	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.
@@ -423,7 +497,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,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index f477f40..ec8b4c8 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -16,12 +16,12 @@
 
 import (
 	"path/filepath"
-	"sort"
 	"strings"
 
 	"android/soong/android"
 	"android/soong/dexpreopt"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -224,6 +224,12 @@
 	"com.google.android.art.testing",
 }
 
+var (
+	dexpreoptBootJarDepTag          = bootclasspathDependencyTag{name: "dexpreopt-boot-jar"}
+	dexBootJarsFragmentsKey         = android.NewOnceKey("dexBootJarsFragments")
+	apexContributionsMetadataDepTag = dependencyTag{name: "all_apex_contributions"}
+)
+
 func init() {
 	RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext)
 }
@@ -232,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
@@ -241,6 +246,9 @@
 	// Image name (used in directory names and ninja rule names).
 	name string
 
+	// If the module with the given name exists, this config is enabled.
+	enabledIfExists string
+
 	// Basename of the image: the resulting filenames are <stem>[-<jar>].{art,oat,vdex}.
 	stem string
 
@@ -257,10 +265,6 @@
 	// the location is relative to "/".
 	installDir string
 
-	// Install path of the boot image profile if it needs to be installed in the APEX, or empty if not
-	// needed.
-	profileInstallPathInApex string
-
 	// A list of (location, jar) pairs for the Java modules in this image.
 	modules android.ConfiguredJarList
 
@@ -274,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
 
@@ -296,10 +290,9 @@
 	// The "--single-image" argument.
 	singleImage bool
 
-	// Profiles imported from other boot image configs. Each element must represent a
-	// `bootclasspath_fragment` of an APEX (i.e., the `name` field of each element must refer to the
-	// `image_name` property of a `bootclasspath_fragment`).
-	profileImports []*bootImageConfig
+	// Profiles imported from APEXes, in addition to the profile at the default path. Each entry must
+	// be the name of an APEX module.
+	profileImports []string
 }
 
 // Target-dependent description of a boot image.
@@ -384,7 +377,7 @@
 	m := image.modules.Jar(idx)
 	name := image.stem
 	if idx != 0 || image.extends != nil {
-		name += "-" + android.ModuleStem(m)
+		name += "-" + android.ModuleStem(ctx.Config(), image.modules.Apex(idx), m)
 	}
 	return name
 }
@@ -458,18 +451,26 @@
 	return image.compilerFilter == "speed-profile"
 }
 
+func (image *bootImageConfig) isEnabled(ctx android.BaseModuleContext) bool {
+	return ctx.OtherModuleExists(image.enabledIfExists)
+}
+
 func dexpreoptBootJarsFactory() android.SingletonModule {
 	m := &dexpreoptBootJars{}
-	android.InitAndroidModule(m)
+	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
 	return m
 }
 
 func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) {
-	ctx.RegisterSingletonModuleType("dex_bootjars", dexpreoptBootJarsFactory)
+	ctx.RegisterParallelSingletonModuleType("dex_bootjars", dexpreoptBootJarsFactory)
+	ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("dex_bootjars_deps", DexpreoptBootJarsMutator).Parallel()
+	})
 }
 
 func SkipDexpreoptBootJars(ctx android.PathContext) bool {
-	return dexpreopt.GetGlobalConfig(ctx).DisablePreoptBootImages
+	global := dexpreopt.GetGlobalConfig(ctx)
+	return global.DisablePreoptBootImages || !shouldBuildBootImages(ctx.Config(), global)
 }
 
 // Singleton module for generating boot image build rules.
@@ -492,39 +493,134 @@
 	dexpreoptConfigForMake android.WritablePath
 }
 
-// Provide paths to boot images for use by modules that depend upon them.
-//
-// The build rules are created in GenerateSingletonBuildActions().
-func (d *dexpreoptBootJars) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	// Placeholder for now.
+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")
 }
 
-// Generate build rules for boot images.
-func (d *dexpreoptBootJars) GenerateSingletonBuildActions(ctx android.SingletonContext) {
-	if dexpreopt.GetCachedGlobalSoongConfig(ctx) == nil {
-		// No module has enabled dexpreopting, so we assume there will be no boot image to make.
-		return
-	}
-	archType := ctx.Config().Targets[android.Android][0].Arch.ArchType
-	d.dexpreoptConfigForMake = android.PathForOutput(ctx, toDexpreoptDirName(archType), "dexpreopt.config")
-	writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
-
-	global := dexpreopt.GetGlobalConfig(ctx)
-	if !shouldBuildBootImages(ctx.Config(), global) {
+func DexpreoptBootJarsMutator(ctx android.BottomUpMutatorContext) {
+	if _, ok := ctx.Module().(*dexpreoptBootJars); !ok {
 		return
 	}
 
-	defaultImageConfig := defaultBootImageConfig(ctx)
-	d.defaultBootImage = defaultImageConfig
+	if dexpreopt.IsDex2oatNeeded(ctx) {
+		// Add a dependency onto the dex2oat tool which is needed for creating the boot image. The
+		// path is retrieved from the dependency by GetGlobalSoongConfig(ctx).
+		dexpreopt.RegisterToolDeps(ctx)
+	}
+
 	imageConfigs := genBootImageConfigs(ctx)
-	d.otherImages = make([]*bootImageConfig, 0, len(imageConfigs)-1)
 	for _, config := range imageConfigs {
-		if config != defaultImageConfig {
-			d.otherImages = append(d.otherImages, config)
+		if !config.isEnabled(ctx) {
+			continue
+		}
+		// 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") {
+		// For accessing all bootclasspath fragments.
+		addDependencyOntoApexModulePair(ctx, "platform", "platform-bootclasspath", platformBootclasspathDepTag)
+	} else if ctx.OtherModuleExists("art-bootclasspath-fragment") {
+		// For accessing the ART bootclasspath fragment on a thin manifest (e.g., master-art) where
+		// platform-bootclasspath doesn't exist.
+		addDependencyOntoApexModulePair(ctx, "com.android.art", "art-bootclasspath-fragment", bootclasspathFragmentDepTag)
+	}
+}
+
+// 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)
+		ctx.WalkDeps(func(child, parent android.Module) bool {
+			if !isActiveModule(child) {
+				return false
+			}
+			tag := ctx.OtherModuleDependencyTag(child)
+			if tag == platformBootclasspathDepTag {
+				return true
+			}
+			if tag == bootclasspathFragmentDepTag {
+				apexInfo, _ := android.OtherModuleProvider(ctx, child, android.ApexInfoProvider)
+				for _, apex := range apexInfo.InApexVariants {
+					fragments[apex] = child
+				}
+				return false
+			}
+			return false
+		})
+		return fragments
+	}).(map[string]android.Module)
+}
+
+func getBootclasspathFragmentByApex(ctx android.ModuleContext, apexName string) android.Module {
+	return gatherBootclasspathFragments(ctx)[apexName]
+}
+
+// GenerateAndroidBuildActions generates the build rules for boot images.
+func (d *dexpreoptBootJars) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	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 {
+			d.otherImages = append(d.otherImages, config)
+		}
+		if !config.isEnabled(ctx) {
+			continue
+		}
+		installs := generateBootImage(ctx, config)
+		profileInstalls = append(profileInstalls, installs...)
+		if config == d.defaultBootImage {
+			_, 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")
+	writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake)
+}
+
 // shouldBuildBootImages determines whether boot images should be built.
 func shouldBuildBootImages(config android.Config, global *dexpreopt.GlobalConfig) bool {
 	// Skip recompiling the boot image for the second sanitization phase. We'll get separate paths
@@ -537,6 +633,135 @@
 	return true
 }
 
+func generateBootImage(ctx android.ModuleContext, imageConfig *bootImageConfig) android.RuleBuilderInstalls {
+	apexJarModulePairs := getModulesForImage(ctx, imageConfig)
+
+	// Copy module dex jars to their predefined locations.
+	bootDexJarsByModule := extractEncodedDexJarsFromModulesOrBootclasspathFragments(ctx, apexJarModulePairs)
+	copyBootJarsToPredefinedLocations(ctx, bootDexJarsByModule, imageConfig.dexPathsByModule)
+
+	// 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, profileInstalls := bootImageProfileRule(ctx, imageConfig)
+
+	// If dexpreopt of boot image jars should be skipped, stop after generating a profile.
+	global := dexpreopt.GetGlobalConfig(ctx)
+	if SkipDexpreoptBootJars(ctx) || (global.OnlyPreoptArtBootImage && imageConfig.name != "art") {
+		return profileInstalls
+	}
+
+	// Build boot image files for the android variants.
+	androidBootImageFiles := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile)
+
+	// Zip the android variant boot image files up.
+	buildBootImageZipInPredefinedLocation(ctx, imageConfig, androidBootImageFiles.byArch)
+
+	// Build boot image files for the host variants. There are use directly by ART host side tests.
+	buildBootImageVariantsForBuildOs(ctx, imageConfig, profile)
+
+	// Create a `dump-oat-<image-name>` rule that runs `oatdump` for debugging purposes.
+	dumpOatRules(ctx, imageConfig)
+
+	return profileInstalls
+}
+
+type apexJarModulePair struct {
+	apex      string
+	jarModule android.Module
+}
+
+func getModulesForImage(ctx android.ModuleContext, imageConfig *bootImageConfig) []apexJarModulePair {
+	modules := make([]apexJarModulePair, 0, imageConfig.modules.Len())
+	for i := 0; i < imageConfig.modules.Len(); i++ {
+		found := false
+		for _, module := range gatherApexModulePairDepsWithTag(ctx, dexpreoptBootJarDepTag) {
+			name := android.RemoveOptionalPrebuiltPrefix(module.Name())
+			if name == imageConfig.modules.Jar(i) {
+				modules = append(modules, apexJarModulePair{
+					apex:      imageConfig.modules.Apex(i),
+					jarModule: module,
+				})
+				found = true
+				break
+			}
+		}
+		if !found && !ctx.Config().AllowMissingDependencies() {
+			ctx.ModuleErrorf(
+				"Boot image '%s' module '%s' not added as a dependency of dex_bootjars",
+				imageConfig.name,
+				imageConfig.modules.Jar(i))
+			return []apexJarModulePair{}
+		}
+	}
+	return modules
+}
+
+// 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 {
+		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 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, android.RemoveOptionalPrebuiltPrefix(pair.jarModule.Name())); 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) {
@@ -666,6 +891,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 {
 
@@ -687,10 +943,12 @@
 	rule.Command().Text("rm").Flag("-f").
 		Flag(symbolsDir.Join(ctx, "*.art").String()).
 		Flag(symbolsDir.Join(ctx, "*.oat").String()).
+		Flag(symbolsDir.Join(ctx, "*.vdex").String()).
 		Flag(symbolsDir.Join(ctx, "*.invocation").String())
 	rule.Command().Text("rm").Flag("-f").
 		Flag(outputDir.Join(ctx, "*.art").String()).
 		Flag(outputDir.Join(ctx, "*.oat").String()).
+		Flag(outputDir.Join(ctx, "*.vdex").String()).
 		Flag(outputDir.Join(ctx, "*.invocation").String())
 
 	cmd := rule.Command()
@@ -706,42 +964,30 @@
 
 	invocationPath := outputPath.ReplaceExtension(ctx, "invocation")
 
+	apexNameToApexExportsInfoMap := getApexNameToApexExportsInfoMap(ctx)
+
 	cmd.Tool(globalSoong.Dex2oat).
 		Flag("--avoid-storing-invocation").
 		FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath).
 		Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatImageXms).
 		Flag("--runtime-arg").FlagWithArg("-Xmx", global.Dex2oatImageXmx)
 
-	if profile != nil {
-		cmd.FlagWithInput("--profile-file=", profile)
-	}
+	if image.isProfileGuided() && !global.DisableGenerateProfile {
+		if profile != nil {
+			cmd.FlagWithInput("--profile-file=", profile)
+		}
 
-	fragments := make(map[string]commonBootclasspathFragment)
-	ctx.VisitDirectDepsWithTag(bootclasspathFragmentDepTag, func(child android.Module) {
-		fragment := child.(commonBootclasspathFragment)
-		if fragment.getImageName() != nil && android.IsModulePreferred(child) {
-			fragments[*fragment.getImageName()] = fragment
+		for _, apex := range image.profileImports {
+			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",
+					image.name,
+					apex)
+				return bootImageVariantOutputs{}
+			}
+			cmd.FlagWithInput("--profile-file=", importedProfile)
 		}
-	})
-
-	for _, profileImport := range image.profileImports {
-		fragment := fragments[profileImport.name]
-		if fragment == nil {
-			ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but a "+
-				"bootclasspath_fragment with image name '%[2]s' doesn't exist or is not added as a "+
-				"dependency of '%[1]s'",
-				image.name,
-				profileImport.name)
-			return bootImageVariantOutputs{}
-		}
-		if fragment.getProfilePath() == nil {
-			ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but '%[2]s' "+
-				"doesn't provide a profile",
-				image.name,
-				profileImport.name)
-			return bootImageVariantOutputs{}
-		}
-		cmd.FlagWithInput("--profile-file=", fragment.getProfilePath())
 	}
 
 	dirtyImageFile := "frameworks/base/config/dirty-image-objects"
@@ -789,7 +1035,6 @@
 		Flag("--generate-build-id").
 		Flag("--image-format=lz4hc").
 		FlagWithArg("--oat-symbols=", symbolsFile.String()).
-		Flag("--strip").
 		FlagWithArg("--oat-file=", outputPath.String()).
 		FlagWithArg("--oat-location=", oatLocation).
 		FlagWithArg("--image=", imagePath.String()).
@@ -799,6 +1044,11 @@
 		Flag("--force-determinism").
 		Flag("--abort-on-hard-verifier-error")
 
+	// We don't strip on host to make perf tools work.
+	if image.target.Os == android.Android {
+		cmd.Flag("--strip")
+	}
+
 	// If the image is profile-guided but the profile is disabled, we omit "--compiler-filter" to
 	// leave the decision to dex2oat to pick the compiler filter.
 	if !(image.isProfileGuided() && global.DisableGenerateProfile) {
@@ -816,7 +1066,7 @@
 		cmd.FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch])
 	}
 
-	if global.EnableUffdGc {
+	if global.EnableUffdGc && image.target.Os == android.Android {
 		cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
 	}
 
@@ -881,11 +1131,7 @@
 It is likely that the boot classpath is inconsistent.
 Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.`
 
-func bootImageProfileRule(ctx android.ModuleContext, image *bootImageConfig) android.WritablePath {
-	if !image.isProfileGuided() {
-		return nil
-	}
-
+func bootImageProfileRuleCommon(ctx android.ModuleContext, name string, dexFiles android.Paths, dexLocations []string) android.WritablePath {
 	globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
 	global := dexpreopt.GetGlobalConfig(ctx)
 
@@ -912,39 +1158,58 @@
 	if path := android.ExistentPathForSource(ctx, extraProfile); path.Valid() {
 		profiles = append(profiles, path.Path())
 	}
-	bootImageProfile := image.dir.Join(ctx, "boot-image-profile.txt")
+	bootImageProfile := android.PathForModuleOut(ctx, name, "boot-image-profile.txt")
 	rule.Command().Text("cat").Inputs(profiles).Text(">").Output(bootImageProfile)
 
-	profile := image.dir.Join(ctx, "boot.prof")
+	profile := android.PathForModuleOut(ctx, name, "boot.prof")
 
 	rule.Command().
 		Text(`ANDROID_LOG_TAGS="*:e"`).
 		Tool(globalSoong.Profman).
 		Flag("--output-profile-type=boot").
 		FlagWithInput("--create-profile-from=", bootImageProfile).
-		FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
-		FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
+		FlagForEachInput("--apk=", dexFiles).
+		FlagForEachArg("--dex-location=", dexLocations).
 		FlagWithOutput("--reference-profile-file=", profile)
 
-	if image == defaultBootImageConfig(ctx) {
-		rule.Install(profile, "/system/etc/boot-image.prof")
-		image.profileInstalls = append(image.profileInstalls, rule.Installs()...)
-		image.profileLicenseMetadataFile = android.OptionalPathForPath(ctx.LicenseMetadataFile())
-	}
-
-	rule.Build("bootJarsProfile", "profile boot jars")
+	rule.Build("bootJarsProfile_"+name, "profile boot jars "+name)
 
 	return profile
 }
 
+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, nil
+	}
+
+	profile := bootImageProfileRuleCommon(ctx, image.name, image.dexPathsDeps.Paths(), image.getAnyAndroidVariant().dexLocationsDeps)
+
+	if image == defaultBootImageConfig(ctx) {
+		rule := android.NewRuleBuilder(pctx, ctx)
+		rule.Install(profile, "/system/etc/boot-image.prof")
+		return profile, rule.Installs()
+	}
+	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"
@@ -964,14 +1229,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)
 	for _, image := range image.variants {
 		arch := image.target.Arch.ArchType
 		suffix := arch.String()
@@ -980,36 +1244,39 @@
 			suffix = "host-" + suffix
 		}
 		// Create a rule to call oatdump.
-		output := android.PathForOutput(ctx, "boot."+suffix+".oatdump.txt")
+		output := android.PathForOutput(ctx, name+"."+suffix+".oatdump.txt")
 		rule := android.NewRuleBuilder(pctx, ctx)
 		imageLocationsOnHost, _ := image.imageLocations()
-		rule.Command().
+		cmd := rule.Command().
 			BuiltTool("oatdump").
 			FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
 			FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":").
 			FlagWithArg("--image=", strings.Join(imageLocationsOnHost, ":")).Implicits(image.imagesDeps.Paths()).
 			FlagWithOutput("--output=", output).
 			FlagWithArg("--instruction-set=", arch.String())
-		rule.Build("dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
+		if global.EnableUffdGc && image.target.Os == android.Android {
+			cmd.Flag("--runtime-arg").Flag("-Xgc:CMC")
+		}
+		rule.Build("dump-oat-"+name+"-"+suffix, "dump oat "+name+" "+arch.String())
 
 		// Create a phony rule that depends on the output file and prints the path.
-		phony := android.PathForPhony(ctx, "dump-oat-boot-"+suffix)
+		phony := android.PathForPhony(ctx, "dump-oat-"+name+"-"+suffix)
 		rule = android.NewRuleBuilder(pctx, ctx)
 		rule.Command().
 			Implicit(output).
 			ImplicitOutput(phony).
 			Text("echo").FlagWithArg("Output in ", output.String())
-		rule.Build("phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
+		rule.Build("phony-dump-oat-"+name+"-"+suffix, "dump oat "+name+" "+arch.String())
 
 		allPhonies = append(allPhonies, phony)
 	}
 
-	phony := android.PathForPhony(ctx, "dump-oat-boot")
+	phony := android.PathForPhony(ctx, "dump-oat-"+name)
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        android.Phony,
 		Output:      phony,
 		Inputs:      allPhonies,
-		Description: "dump-oat-boot",
+		Description: "dump-oat-" + name,
 	})
 }
 
@@ -1030,9 +1297,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) {
@@ -1044,11 +1313,9 @@
 		ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(dexPaths.Strings(), " "))
 		ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(dexLocations, " "))
 
-		var imageNames []string
 		// The primary ART boot image is exposed to Make for testing (gtests) and benchmarking
 		// (golem) purposes.
 		for _, current := range append(d.otherImages, image) {
-			imageNames = append(imageNames, current.name)
 			for _, variant := range current.variants {
 				suffix := ""
 				if variant.target.Os.Class == android.Host {
@@ -1069,8 +1336,6 @@
 			ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICE"+current.name, strings.Join(imageLocationsOnDevice, ":"))
 			ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String())
 		}
-		// Ensure determinism.
-		sort.Strings(imageNames)
-		ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " "))
+		ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(getImageNames(), " "))
 	}
 }
diff --git a/java/dexpreopt_check.go b/java/dexpreopt_check.go
index 83c088c..33be603 100644
--- a/java/dexpreopt_check.go
+++ b/java/dexpreopt_check.go
@@ -28,7 +28,7 @@
 }
 
 func RegisterDexpreoptCheckBuildComponents(ctx android.RegistrationContext) {
-	ctx.RegisterSingletonModuleType("dexpreopt_systemserver_check", dexpreoptSystemserverCheckFactory)
+	ctx.RegisterParallelSingletonModuleType("dexpreopt_systemserver_check", dexpreoptSystemserverCheckFactory)
 }
 
 // A build-time check to verify if all compilation artifacts of system server jars are installed
@@ -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 9100e87..254b2c1 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -40,57 +40,67 @@
 }
 
 var (
-	bootImageConfigKey     = android.NewOnceKey("bootImageConfig")
-	bootImageConfigRawKey  = android.NewOnceKey("bootImageConfigRaw")
-	artBootImageName       = "art"
-	frameworkBootImageName = "boot"
-	mainlineBootImageName  = "mainline"
-	bootImageStem          = "boot"
+	bootImageConfigKey       = android.NewOnceKey("bootImageConfig")
+	bootImageConfigRawKey    = android.NewOnceKey("bootImageConfigRaw")
+	frameworkBootImageName   = "boot"
+	mainlineBootImageName    = "mainline"
+	bootImageStem            = "boot"
+	ProfileInstallPathInApex = "etc/boot-image.prof"
 )
 
+// getImageNames returns an ordered list of image names. The order doesn't matter but needs to be
+// deterministic. The names listed here must match the map keys returned by genBootImageConfigs.
+func getImageNames() []string {
+	return []string{"art", "boot", "mainline"}
+}
+
 func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig {
 	return ctx.Config().Once(bootImageConfigRawKey, func() interface{} {
 		global := dexpreopt.GetGlobalConfig(ctx)
 
-		artModules := global.ArtApexJars
-		frameworkModules := global.BootJars // This includes `artModules`.
+		artBootImageName := "art"           // Keep this local to avoid accidental references.
+		frameworkModules := global.BootJars // This includes `global.ArtApexJars`.
 		mainlineBcpModules := global.ApexBootJars
 		frameworkSubdir := "system/framework"
 
-		// ART config for the primary boot image in the ART apex.
-		// It includes the Core Libraries.
+		profileImports := []string{"com.android.art"}
+
+		// ART boot image for testing only. Do not rely on it to make any build-time decision.
 		artCfg := bootImageConfig{
-			name:                     artBootImageName,
-			stem:                     bootImageStem,
-			installDir:               "apex/art_boot_images/javalib",
-			profileInstallPathInApex: "etc/boot-image.prof",
-			modules:                  artModules,
-			preloadedClassesFile:     "art/build/boot/preloaded-classes",
-			compilerFilter:           "speed-profile",
-			singleImage:              false,
+			name:                 artBootImageName,
+			enabledIfExists:      "art-bootclasspath-fragment",
+			stem:                 bootImageStem,
+			installDir:           "apex/art_boot_images/javalib",
+			modules:              global.TestOnlyArtBootImageJars,
+			preloadedClassesFile: "art/build/boot/preloaded-classes",
+			compilerFilter:       "speed-profile",
+			singleImage:          false,
+			profileImports:       profileImports,
 		}
 
 		// Framework config for the boot image extension.
 		// It includes framework libraries and depends on the ART config.
 		frameworkCfg := bootImageConfig{
 			name:                 frameworkBootImageName,
+			enabledIfExists:      "platform-bootclasspath",
 			stem:                 bootImageStem,
 			installDir:           frameworkSubdir,
 			modules:              frameworkModules,
 			preloadedClassesFile: "frameworks/base/config/preloaded-classes",
 			compilerFilter:       "speed-profile",
 			singleImage:          false,
-			profileImports:       []*bootImageConfig{&artCfg},
+			profileImports:       profileImports,
 		}
 
 		mainlineCfg := bootImageConfig{
-			extends:        &frameworkCfg,
-			name:           mainlineBootImageName,
-			stem:           bootImageStem,
-			installDir:     frameworkSubdir,
-			modules:        mainlineBcpModules,
-			compilerFilter: "verify",
-			singleImage:    true,
+			extends:         &frameworkCfg,
+			name:            mainlineBootImageName,
+			enabledIfExists: "platform-bootclasspath",
+			stem:            bootImageStem,
+			installDir:      frameworkSubdir,
+			modules:         mainlineBcpModules,
+			compilerFilter:  "verify",
+			singleImage:     true,
 		}
 
 		return map[string]*bootImageConfig{
@@ -105,8 +115,7 @@
 func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
 	return ctx.Config().Once(bootImageConfigKey, func() interface{} {
 		targets := dexpreoptTargets(ctx)
-		archType := ctx.Config().Targets[android.Android][0].Arch.ArchType
-		deviceDir := android.PathForOutput(ctx, toDexpreoptDirName(archType))
+		deviceDir := android.PathForOutput(ctx, getDexpreoptDirName(ctx))
 
 		configs := genBootImageConfigRaw(ctx)
 
@@ -181,10 +190,6 @@
 	}
 }
 
-func artBootImageConfig(ctx android.PathContext) *bootImageConfig {
-	return genBootImageConfigs(ctx)[artBootImageName]
-}
-
 func defaultBootImageConfig(ctx android.PathContext) *bootImageConfig {
 	return genBootImageConfigs(ctx)[frameworkBootImageName]
 }
@@ -193,65 +198,35 @@
 	return genBootImageConfigs(ctx)[mainlineBootImageName]
 }
 
-// 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
-		archType := ctx.Config().Targets[android.Android][0].Arch.ArchType
-		dir := android.PathForOutput(ctx, toDexpreoptDirName(archType), "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)
+// isProfileProviderApex returns true if this apex provides a boot image profile.
+func isProfileProviderApex(ctx android.PathContext, apexName string) bool {
+	for _, config := range genBootImageConfigs(ctx) {
+		for _, profileImport := range config.profileImports {
+			if profileImport == apexName {
+				return true
+			}
+		}
+	}
+	return false
 }
 
 // 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
 }
 
 var defaultBootclasspathKey = android.NewOnceKey("defaultBootclasspath")
 
-var copyOf = android.CopyOf
-
 func init() {
 	android.RegisterMakeVarsProvider(pctx, dexpreoptConfigMakevars)
 }
@@ -260,6 +235,11 @@
 	ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules.CopyOfApexJarPairs(), ":"))
 }
 
-func toDexpreoptDirName(arch android.ArchType) string {
-	return "dexpreopt_" + arch.String()
+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_test.go b/java/dexpreopt_config_test.go
index cd7f295..44d2127 100644
--- a/java/dexpreopt_config_test.go
+++ b/java/dexpreopt_config_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"runtime"
+	"sort"
 	"testing"
 
 	"android/soong/android"
@@ -35,3 +36,22 @@
 	CheckFrameworkBootImageConfig(t, result)
 	CheckMainlineBootImageConfig(t, result)
 }
+
+func TestImageNames(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		PrepareForBootImageConfigTest,
+	).RunTest(t)
+
+	names := getImageNames()
+	sort.Strings(names)
+
+	ctx := &android.TestPathContext{TestResult: result}
+	configs := genBootImageConfigs(ctx)
+	namesFromConfigs := make([]string, 0, len(configs))
+	for name, _ := range configs {
+		namesFromConfigs = append(namesFromConfigs, name)
+	}
+	sort.Strings(namesFromConfigs)
+
+	android.AssertArrayString(t, "getImageNames vs genBootImageConfigs", names, namesFromConfigs)
+}
diff --git a/java/dexpreopt_config_testing.go b/java/dexpreopt_config_testing.go
index 6f3aa2b..104829f 100644
--- a/java/dexpreopt_config_testing.go
+++ b/java/dexpreopt_config_testing.go
@@ -29,6 +29,7 @@
 	"testing"
 
 	"android/soong/android"
+	"android/soong/dexpreopt"
 )
 
 // PrepareForBootImageConfigTest is the minimal set of preparers that are needed to be able to use
@@ -36,7 +37,17 @@
 var PrepareForBootImageConfigTest = android.GroupFixturePreparers(
 	android.PrepareForTestWithArchMutator,
 	android.PrepareForTestAccessingMakeVars,
+	PrepareForTestWithDexpreopt,
 	FixtureConfigureBootJars("com.android.art:core1", "com.android.art:core2", "platform:framework"),
+	dexpreopt.FixtureSetTestOnlyArtBootImageJars("com.android.art:core1", "com.android.art:core2", "platform:extra1"),
+	android.FixtureAddTextFile("extra1/Android.bp", `
+		java_library {
+			name: "extra1",
+			srcs: ["extra1.java"],
+			installable: true,
+		}
+	`),
+	android.FixtureAddFile("extra1/extra1.java", nil),
 )
 
 var PrepareApexBootJarConfigs = FixtureConfigureApexBootJars(
@@ -44,18 +55,18 @@
 
 var PrepareApexBootJarConfigsAndModules = android.GroupFixturePreparers(
 	PrepareApexBootJarConfigs,
-	prepareApexBootJarModule("com.android.foo", "framework-foo"),
-	prepareApexBootJarModule("com.android.bar", "framework-bar"),
+	PrepareApexBootJarModule("com.android.foo", "framework-foo"),
+	PrepareApexBootJarModule("com.android.bar", "framework-bar"),
 )
 
 var ApexBootJarFragmentsForPlatformBootclasspath = fmt.Sprintf(`
 	{
 		apex: "%[1]s",
-		module: "%[1]s-bootclasspathfragment",
+		module: "%[1]s-bootclasspath-fragment",
 	},
 	{
 		apex: "%[2]s",
-		module: "%[2]s-bootclasspathfragment",
+		module: "%[2]s-bootclasspath-fragment",
 	},
 `, "com.android.foo", "com.android.bar")
 
@@ -64,15 +75,22 @@
 	"out/soong/.intermediates/packages/modules/com.android.foo/framework-foo/android_common_apex10000/aligned/framework-foo.jar",
 }
 
-func prepareApexBootJarModule(apexName string, moduleName string) android.FixturePreparer {
+func PrepareApexBootJarModule(apexName string, moduleName string) android.FixturePreparer {
 	moduleSourceDir := fmt.Sprintf("packages/modules/%s", apexName)
+	fragmentName := apexName + "-bootclasspath-fragment"
+	imageNameProp := ""
+	if apexName == "com.android.art" {
+		fragmentName = "art-bootclasspath-fragment"
+		imageNameProp = `image_name: "art",`
+	}
+
 	return android.GroupFixturePreparers(
 		android.FixtureAddTextFile(moduleSourceDir+"/Android.bp", fmt.Sprintf(`
 			apex {
 				name: "%[1]s",
 				key: "%[1]s.key",
 				bootclasspath_fragments: [
-					"%[1]s-bootclasspathfragment",
+					"%[3]s",
 				],
 				updatable: false,
 			}
@@ -84,7 +102,8 @@
 			}
 
 			bootclasspath_fragment {
-				name: "%[1]s-bootclasspathfragment",
+				name: "%[3]s",
+				%[4]s
 				contents: ["%[2]s"],
 				apex_available: ["%[1]s"],
 				hidden_api: {
@@ -100,7 +119,7 @@
 				compile_dex: true,
 				apex_available: ["%[1]s"],
 			}
-		`, apexName, moduleName)),
+		`, apexName, moduleName, fragmentName, imageNameProp)),
 		android.FixtureMergeMockFs(android.MockFS{
 			fmt.Sprintf("%s/apex_manifest.json", moduleSourceDir):          nil,
 			fmt.Sprintf("%s/%s.avbpubkey", moduleSourceDir, apexName):      nil,
@@ -192,7 +211,7 @@
 // getArtImageConfig gets the ART bootImageConfig that was created during the test.
 func getArtImageConfig(result *android.TestResult) *bootImageConfig {
 	pathCtx := &android.TestPathContext{TestResult: result}
-	imageConfig := artBootImageConfig(pathCtx)
+	imageConfig := genBootImageConfigs(pathCtx)["art"]
 	return imageConfig
 }
 
@@ -210,15 +229,15 @@
 		symbolsDir:               "out/soong/dexpreopt_arm64/dex_artjars_unstripped",
 		installDir:               "apex/art_boot_images/javalib",
 		profileInstallPathInApex: "etc/boot-image.prof",
-		modules:                  android.CreateTestConfiguredJarList([]string{"com.android.art:core1", "com.android.art:core2"}),
-		dexPaths:                 []string{"out/soong/dexpreopt_arm64/dex_artjars_input/core1.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/core2.jar"},
-		dexPathsDeps:             []string{"out/soong/dexpreopt_arm64/dex_artjars_input/core1.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/core2.jar"},
+		modules:                  android.CreateTestConfiguredJarList([]string{"com.android.art:core1", "com.android.art:core2", "platform:extra1"}),
+		dexPaths:                 []string{"out/soong/dexpreopt_arm64/dex_artjars_input/core1.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/core2.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/extra1.jar"},
+		dexPathsDeps:             []string{"out/soong/dexpreopt_arm64/dex_artjars_input/core1.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/core2.jar", "out/soong/dexpreopt_arm64/dex_artjars_input/extra1.jar"},
 		zip:                      "out/soong/dexpreopt_arm64/dex_artjars/art.zip",
 		variants: []*expectedVariant{
 			{
 				archType:          android.Arm64,
-				dexLocations:      []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"},
-				dexLocationsDeps:  []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"},
+				dexLocations:      []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar", "/system/framework/extra1.jar"},
+				dexLocationsDeps:  []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar", "/system/framework/extra1.jar"},
 				imagePathOnHost:   "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art",
 				imagePathOnDevice: "/apex/art_boot_images/javalib/arm64/boot.art",
 				imagesDeps: []string{
@@ -228,6 +247,9 @@
 					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art",
 					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
 					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.vdex",
 				},
 				installs: []normalizedInstall{
 					{
@@ -246,6 +268,14 @@
 						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/arm64/boot-core2.oat",
 					},
+					{
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.art",
+						to:   "/apex/art_boot_images/javalib/arm64/boot-extra1.art",
+					},
+					{
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat",
+						to:   "/apex/art_boot_images/javalib/arm64/boot-extra1.oat",
+					},
 				},
 				vdexInstalls: []normalizedInstall{
 					{
@@ -256,6 +286,10 @@
 						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
 						to:   "/apex/art_boot_images/javalib/arm64/boot-core2.vdex",
 					},
+					{
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.vdex",
+						to:   "/apex/art_boot_images/javalib/arm64/boot-extra1.vdex",
+					},
 				},
 				unstrippedInstalls: []normalizedInstall{
 					{
@@ -266,13 +300,17 @@
 						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/arm64/boot-core2.oat",
 					},
+					{
+						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat",
+						to:   "/apex/art_boot_images/javalib/arm64/boot-extra1.oat",
+					},
 				},
 				licenseMetadataFile: expectedLicenseMetadataFile,
 			},
 			{
 				archType:          android.Arm,
-				dexLocations:      []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"},
-				dexLocationsDeps:  []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar"},
+				dexLocations:      []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar", "/system/framework/extra1.jar"},
+				dexLocationsDeps:  []string{"/apex/com.android.art/javalib/core1.jar", "/apex/com.android.art/javalib/core2.jar", "/system/framework/extra1.jar"},
 				imagePathOnHost:   "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art",
 				imagePathOnDevice: "/apex/art_boot_images/javalib/arm/boot.art",
 				imagesDeps: []string{
@@ -282,6 +320,9 @@
 					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art",
 					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
 					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.vdex",
 				},
 				installs: []normalizedInstall{
 					{
@@ -300,6 +341,14 @@
 						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/arm/boot-core2.oat",
 					},
+					{
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.art",
+						to:   "/apex/art_boot_images/javalib/arm/boot-extra1.art",
+					},
+					{
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.oat",
+						to:   "/apex/art_boot_images/javalib/arm/boot-extra1.oat",
+					},
 				},
 				vdexInstalls: []normalizedInstall{
 					{
@@ -310,6 +359,10 @@
 						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex",
 						to:   "/apex/art_boot_images/javalib/arm/boot-core2.vdex",
 					},
+					{
+						from: "out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.vdex",
+						to:   "/apex/art_boot_images/javalib/arm/boot-extra1.vdex",
+					},
 				},
 				unstrippedInstalls: []normalizedInstall{
 					{
@@ -320,13 +373,17 @@
 						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/arm/boot-core2.oat",
 					},
+					{
+						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-extra1.oat",
+						to:   "/apex/art_boot_images/javalib/arm/boot-extra1.oat",
+					},
 				},
 				licenseMetadataFile: expectedLicenseMetadataFile,
 			},
 			{
 				archType:          android.X86_64,
-				dexLocations:      []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"},
-				dexLocationsDeps:  []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"},
+				dexLocations:      []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar", "host/linux-x86/system/framework/extra1.jar"},
+				dexLocationsDeps:  []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar", "host/linux-x86/system/framework/extra1.jar"},
 				imagePathOnHost:   "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art",
 				imagePathOnDevice: "/apex/art_boot_images/javalib/x86_64/boot.art",
 				imagesDeps: []string{
@@ -336,6 +393,9 @@
 					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art",
 					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
 					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.vdex",
 				},
 				installs: []normalizedInstall{
 					{
@@ -352,6 +412,13 @@
 						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
 					},
+					{
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.art",
+						to:   "/apex/art_boot_images/javalib/x86_64/boot-extra1.art",
+					}, {
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.oat",
+						to:   "/apex/art_boot_images/javalib/x86_64/boot-extra1.oat",
+					},
 				},
 				vdexInstalls: []normalizedInstall{
 					{
@@ -362,6 +429,10 @@
 						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
 						to:   "/apex/art_boot_images/javalib/x86_64/boot-core2.vdex",
 					},
+					{
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.vdex",
+						to:   "/apex/art_boot_images/javalib/x86_64/boot-extra1.vdex",
+					},
 				},
 				unstrippedInstalls: []normalizedInstall{
 					{
@@ -372,13 +443,17 @@
 						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/x86_64/boot-core2.oat",
 					},
+					{
+						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.oat",
+						to:   "/apex/art_boot_images/javalib/x86_64/boot-extra1.oat",
+					},
 				},
 				licenseMetadataFile: expectedLicenseMetadataFile,
 			},
 			{
 				archType:          android.X86,
-				dexLocations:      []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"},
-				dexLocationsDeps:  []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar"},
+				dexLocations:      []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar", "host/linux-x86/system/framework/extra1.jar"},
+				dexLocationsDeps:  []string{"host/linux-x86/apex/com.android.art/javalib/core1.jar", "host/linux-x86/apex/com.android.art/javalib/core2.jar", "host/linux-x86/system/framework/extra1.jar"},
 				imagePathOnHost:   "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art",
 				imagePathOnDevice: "/apex/art_boot_images/javalib/x86/boot.art",
 				imagesDeps: []string{
@@ -388,6 +463,9 @@
 					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art",
 					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
 					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.art",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat",
+					"out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.vdex",
 				},
 				installs: []normalizedInstall{
 					{
@@ -404,6 +482,13 @@
 						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/x86/boot-core2.oat",
 					},
+					{
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.art",
+						to:   "/apex/art_boot_images/javalib/x86/boot-extra1.art",
+					}, {
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat",
+						to:   "/apex/art_boot_images/javalib/x86/boot-extra1.oat",
+					},
 				},
 				vdexInstalls: []normalizedInstall{
 					{
@@ -414,6 +499,10 @@
 						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex",
 						to:   "/apex/art_boot_images/javalib/x86/boot-core2.vdex",
 					},
+					{
+						from: "out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.vdex",
+						to:   "/apex/art_boot_images/javalib/x86/boot-extra1.vdex",
+					},
 				},
 				unstrippedInstalls: []normalizedInstall{
 					{
@@ -424,13 +513,17 @@
 						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat",
 						to:   "/apex/art_boot_images/javalib/x86/boot-core2.oat",
 					},
+					{
+						from: "out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat",
+						to:   "/apex/art_boot_images/javalib/x86/boot-extra1.oat",
+					},
 				},
 				licenseMetadataFile: expectedLicenseMetadataFile,
 			},
 		},
 	}
 
-	checkBootImageConfig(t, imageConfig, mutated, expected)
+	checkBootImageConfig(t, result, imageConfig, mutated, expected)
 }
 
 // getFrameworkImageConfig gets the framework bootImageConfig that was created during the test.
@@ -805,13 +898,13 @@
 			},
 		},
 		profileInstalls: []normalizedInstall{
+			{from: "out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof", to: "/system/etc/boot-image.prof"},
 			{from: "out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof", to: "/system/etc/boot-image.bprof"},
-			{from: "out/soong/dexpreopt_arm64/dex_bootjars/boot.prof", to: "/system/etc/boot-image.prof"},
 		},
 		profileLicenseMetadataFile: expectedLicenseMetadataFile,
 	}
 
-	checkBootImageConfig(t, imageConfig, mutated, expected)
+	checkBootImageConfig(t, result, imageConfig, mutated, expected)
 }
 
 // getMainlineImageConfig gets the framework bootImageConfig that was created during the test.
@@ -1090,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
@@ -1118,32 +1211,36 @@
 // 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)
 	android.AssertPathRelativeToTopEquals(t, "symbolsDir", expected.symbolsDir, imageConfig.symbolsDir)
 	android.AssertStringEquals(t, "installDir", expected.installDir, imageConfig.installDir)
-	android.AssertStringEquals(t, "profileInstallPathInApex", expected.profileInstallPathInApex, imageConfig.profileInstallPathInApex)
 	android.AssertDeepEquals(t, "modules", expected.modules, imageConfig.modules)
 	android.AssertPathsRelativeToTopEquals(t, "dexPaths", expected.dexPaths, imageConfig.dexPaths.Paths())
 	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 {
@@ -1195,10 +1292,10 @@
 DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS=/apex/com.android.art/javalib/core1.jar /apex/com.android.art/javalib/core2.jar /system/framework/framework.jar
 DEXPREOPT_BOOT_JARS_MODULES=com.android.art:core1:com.android.art:core2:platform:framework
 DEXPREOPT_GEN=out/host/linux-x86/bin/dexpreopt_gen
-DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art:/apex/art_boot_images/javalib/arm/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art:/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat
-DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art:/apex/art_boot_images/javalib/arm64/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art:/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat
-DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art:/apex/art_boot_images/javalib/x86/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art:/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat
-DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art:/apex/art_boot_images/javalib/x86_64/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art:/apex/art_boot_images/javalib/x86_64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art:/apex/art_boot_images/javalib/arm/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art:/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.art:/apex/art_boot_images/javalib/arm/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.oat:/apex/art_boot_images/javalib/arm/boot-extra1.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art:/apex/art_boot_images/javalib/arm64/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art:/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.art:/apex/art_boot_images/javalib/arm64/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat:/apex/art_boot_images/javalib/arm64/boot-extra1.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art:/apex/art_boot_images/javalib/x86/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art:/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.art:/apex/art_boot_images/javalib/x86/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat:/apex/art_boot_images/javalib/x86/boot-extra1.oat
+DEXPREOPT_IMAGE_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art:/apex/art_boot_images/javalib/x86_64/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art:/apex/art_boot_images/javalib/x86_64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.art:/apex/art_boot_images/javalib/x86_64/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.oat:/apex/art_boot_images/javalib/x86_64/boot-extra1.oat
 DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_arm=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot.art:/system/framework/arm/boot.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot.oat:/system/framework/arm/boot.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-core2.art:/system/framework/arm/boot-core2.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-core2.oat:/system/framework/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.art:/system/framework/arm/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.oat:/system/framework/arm/boot-framework.oat
 DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_arm64=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art:/system/framework/arm64/boot.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.oat:/system/framework/arm64/boot.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-core2.art:/system/framework/arm64/boot-core2.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-core2.oat:/system/framework/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.art:/system/framework/arm64/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.oat:/system/framework/arm64/boot-framework.oat
 DEXPREOPT_IMAGE_BUILT_INSTALLED_boot_host_x86=out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot.art:/system/framework/x86/boot.art out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot.oat:/system/framework/x86/boot.oat out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-core2.art:/system/framework/x86/boot-core2.art out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-core2.oat:/system/framework/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art:/system/framework/x86/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat:/system/framework/x86/boot-framework.oat
@@ -1207,10 +1304,10 @@
 DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_arm64=out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.art:/system/framework/arm64/boot-framework-foo.art out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/arm64/boot-framework-foo.oat:/system/framework/arm64/boot-framework-foo.oat
 DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_host_x86=out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.art:/system/framework/x86/boot-framework-foo.art out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86/boot-framework-foo.oat:/system/framework/x86/boot-framework-foo.oat
 DEXPREOPT_IMAGE_BUILT_INSTALLED_mainline_host_x86_64=out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.art:/system/framework/x86_64/boot-framework-foo.art out/soong/dexpreopt_arm64/dex_mainlinejars/linux_glibc/system/framework/x86_64/boot-framework-foo.oat:/system/framework/x86_64/boot-framework-foo.oat
-DEXPREOPT_IMAGE_DEPS_art_arm=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex
-DEXPREOPT_IMAGE_DEPS_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex
-DEXPREOPT_IMAGE_DEPS_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex
-DEXPREOPT_IMAGE_DEPS_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex
+DEXPREOPT_IMAGE_DEPS_art_arm=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.vdex
+DEXPREOPT_IMAGE_DEPS_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.vdex
+DEXPREOPT_IMAGE_DEPS_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.vdex
+DEXPREOPT_IMAGE_DEPS_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.art out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.oat out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.vdex
 DEXPREOPT_IMAGE_DEPS_boot_arm=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-core2.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-core2.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.vdex
 DEXPREOPT_IMAGE_DEPS_boot_arm64=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-core2.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-core2.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.oat out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.vdex
 DEXPREOPT_IMAGE_DEPS_boot_host_x86=out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot.art out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot.oat out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot.vdex out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-core2.art out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-core2.vdex out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.art out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.oat out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex
@@ -1223,14 +1320,14 @@
 DEXPREOPT_IMAGE_LICENSE_METADATA_art_arm64=%[1]s
 DEXPREOPT_IMAGE_LICENSE_METADATA_art_host_x86=%[1]s
 DEXPREOPT_IMAGE_LICENSE_METADATA_art_host_x86_64=%[1]s
-DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
-DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
-DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
-DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86_64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
-DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
-DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
-DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
-DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86_64=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_boot_arm64=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_boot_host_x86_64=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_arm64=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
+DEXPREOPT_IMAGE_LICENSE_METADATA_mainline_host_x86_64=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
 DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEart=/apex/art_boot_images/javalib/boot.art
 DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEboot=/system/framework/boot.art
 DEXPREOPT_IMAGE_LOCATIONS_ON_DEVICEmainline=/system/framework/boot.art:/system/framework/boot-framework-foo.art
@@ -1238,12 +1335,12 @@
 DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTboot=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art
 DEXPREOPT_IMAGE_LOCATIONS_ON_HOSTmainline=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/boot.art:out/soong/dexpreopt_arm64/dex_mainlinejars/android/system/framework/boot-framework-foo.art
 DEXPREOPT_IMAGE_NAMES=art boot mainline
-DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof out/soong/dexpreopt_arm64/dex_bootjars/boot.prof:/system/etc/boot-image.prof
-DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA=out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic
-DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat
-DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat
-DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat
-DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat
+DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED=out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof:/system/etc/boot-image.prof out/soong/dexpreopt_arm64/dex_bootjars/boot.bprof:/system/etc/boot-image.bprof
+DEXPREOPT_IMAGE_PROFILE_LICENSE_METADATA=out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot.oat:/apex/art_boot_images/javalib/arm/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-core2.oat:/apex/art_boot_images/javalib/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm/boot-extra1.oat:/apex/art_boot_images/javalib/arm/boot-extra1.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot.oat:/apex/art_boot_images/javalib/arm64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-core2.oat:/apex/art_boot_images/javalib/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/android/apex/art_boot_images/javalib/arm64/boot-extra1.oat:/apex/art_boot_images/javalib/arm64/boot-extra1.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot.oat:/apex/art_boot_images/javalib/x86/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.oat:/apex/art_boot_images/javalib/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.oat:/apex/art_boot_images/javalib/x86/boot-extra1.oat
+DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.oat:/apex/art_boot_images/javalib/x86_64/boot.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.oat:/apex/art_boot_images/javalib/x86_64/boot-core2.oat out/soong/dexpreopt_arm64/dex_artjars_unstripped/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.oat:/apex/art_boot_images/javalib/x86_64/boot-extra1.oat
 DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_arm=out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm/boot.oat:/system/framework/arm/boot.oat out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm/boot-core2.oat:/system/framework/arm/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm/boot-framework.oat:/system/framework/arm/boot-framework.oat
 DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_arm64=out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot.oat:/system/framework/arm64/boot.oat out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-core2.oat:/system/framework/arm64/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars_unstripped/android/system/framework/arm64/boot-framework.oat:/system/framework/arm64/boot-framework.oat
 DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_boot_host_x86=out/soong/dexpreopt_arm64/dex_bootjars_unstripped/linux_glibc/system/framework/x86/boot.oat:/system/framework/x86/boot.oat out/soong/dexpreopt_arm64/dex_bootjars_unstripped/linux_glibc/system/framework/x86/boot-core2.oat:/system/framework/x86/boot-core2.oat out/soong/dexpreopt_arm64/dex_bootjars_unstripped/linux_glibc/system/framework/x86/boot-framework.oat:/system/framework/x86/boot-framework.oat
@@ -1252,10 +1349,10 @@
 DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_arm64=out/soong/dexpreopt_arm64/dex_mainlinejars_unstripped/android/system/framework/arm64/boot-framework-foo.oat:/system/framework/arm64/boot-framework-foo.oat
 DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_host_x86=out/soong/dexpreopt_arm64/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86/boot-framework-foo.oat:/system/framework/x86/boot-framework-foo.oat
 DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_mainline_host_x86_64=out/soong/dexpreopt_arm64/dex_mainlinejars_unstripped/linux_glibc/system/framework/x86_64/boot-framework-foo.oat:/system/framework/x86_64/boot-framework-foo.oat
-DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex:/apex/art_boot_images/javalib/arm/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex:/apex/art_boot_images/javalib/arm/boot-core2.vdex
-DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex:/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex:/apex/art_boot_images/javalib/arm64/boot-core2.vdex
-DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex:/apex/art_boot_images/javalib/x86/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex:/apex/art_boot_images/javalib/x86/boot-core2.vdex
-DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex:/apex/art_boot_images/javalib/x86_64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex:/apex/art_boot_images/javalib/x86_64/boot-core2.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex:/apex/art_boot_images/javalib/arm/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-core2.vdex:/apex/art_boot_images/javalib/arm/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-extra1.vdex:/apex/art_boot_images/javalib/arm/boot-extra1.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_arm64=out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex:/apex/art_boot_images/javalib/arm64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-core2.vdex:/apex/art_boot_images/javalib/arm64/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-extra1.vdex:/apex/art_boot_images/javalib/arm64/boot-extra1.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot.vdex:/apex/art_boot_images/javalib/x86/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-core2.vdex:/apex/art_boot_images/javalib/x86/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86/boot-extra1.vdex:/apex/art_boot_images/javalib/x86/boot-extra1.vdex
+DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_art_host_x86_64=out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot.vdex:/apex/art_boot_images/javalib/x86_64/boot.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-core2.vdex:/apex/art_boot_images/javalib/x86_64/boot-core2.vdex out/soong/dexpreopt_arm64/dex_artjars/linux_glibc/apex/art_boot_images/javalib/x86_64/boot-extra1.vdex:/apex/art_boot_images/javalib/x86_64/boot-extra1.vdex
 DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_arm=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot.vdex:/system/framework/arm/boot.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-core2.vdex:/system/framework/arm/boot-core2.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm/boot-framework.vdex:/system/framework/arm/boot-framework.vdex
 DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_arm64=out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot.vdex:/system/framework/arm64/boot.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-core2.vdex:/system/framework/arm64/boot-core2.vdex out/soong/dexpreopt_arm64/dex_bootjars/android/system/framework/arm64/boot-framework.vdex:/system/framework/arm64/boot-framework.vdex
 DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_boot_host_x86=out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot.vdex:/system/framework/x86/boot.vdex out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-core2.vdex:/system/framework/x86/boot-core2.vdex out/soong/dexpreopt_arm64/dex_bootjars/linux_glibc/system/framework/x86/boot-framework.vdex:/system/framework/x86/boot-framework.vdex
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 1f9f773..cfbf2b4 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,8 +388,7 @@
 		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...)
 			} else if dep, ok := module.(android.SourceFileProducer); ok {
@@ -384,8 +398,7 @@
 				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 +410,15 @@
 			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 {
+				ctx.ModuleErrorf("Only aconfig_declarations module type is allowed for "+
+					"flags_packages property, but %s is not aconfig_declarations module type",
+					module.Name(),
+				)
+			}
 		}
 	})
 	// do not pass exclude_srcs directly when expanding srcFiles since exclude_srcs
@@ -608,6 +630,11 @@
 		FlagWithArg("-Xmaxerrs ", "10").
 		FlagWithArg("-Xmaxwarns ", "10").
 		Flag("-J--add-exports=jdk.javadoc/jdk.javadoc.internal.doclets.formats.html=ALL-UNNAMED").
+		Flag("-J--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED").
+		Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED").
+		Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED").
+		Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED").
+		Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED").
 		Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED").
 		FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-$(cat "+buildNumberFile.String()+")").OrderOnly(buildNumberFile).
 		FlagWithArg("-hdf page.now ", `"$(date -d @$(cat `+ctx.Config().Getenv("BUILD_DATETIME_FILE")+`) "+%d %b %Y %k:%M")" `)
@@ -659,6 +686,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 ea9305f..6ef2afe 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,28 @@
 // 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 init() {
 	RegisterStubsBuildComponents(android.InitRegistrationContext)
 }
@@ -45,14 +65,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 +90,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 +154,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.
@@ -160,22 +191,56 @@
 
 // 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.
@@ -184,6 +249,7 @@
 
 	module.AddProperties(&module.properties,
 		&module.Javadoc.properties)
+	module.initModuleAndImport(module)
 
 	InitDroiddocModule(module, android.HostAndDeviceSupported)
 
@@ -207,46 +273,137 @@
 	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) (android.Path, error) {
+	switch stubsType {
+	case Everything:
+		return d.everythingArtifacts.annotationsZip, nil
+	case Exportable:
+		return d.exportableArtifacts.annotationsZip, nil
+	default:
+		return nil, fmt.Errorf("annotations zip not supported for the stub type %s", stubsType.String())
+	}
 }
 
-func (d *Droidstubs) ApiFilePath() android.Path {
-	return d.apiFile
+func (d *Droidstubs) ApiFilePath(stubsType StubsType) (android.Path, error) {
+	switch stubsType {
+	case Everything:
+		return d.apiFile, nil
+	case Exportable:
+		return d.exportableApiFile, nil
+	default:
+		return nil, fmt.Errorf("api file path not supported for the stub type %s", stubsType.String())
+	}
 }
 
-func (d *Droidstubs) RemovedApiFilePath() android.Path {
-	return d.removedApiFile
+func (d *Droidstubs) ApiVersionsXmlFilePath(stubsType StubsType) (android.Path, error) {
+	switch stubsType {
+	case Everything:
+		return d.everythingArtifacts.apiVersionsXml, nil
+	default:
+		return nil, fmt.Errorf("api versions xml file path not supported for the stub type %s", stubsType.String())
+	}
 }
 
-func (d *Droidstubs) StubsSrcJar() android.Path {
-	return d.stubsSrcJar
+func (d *Droidstubs) DocZip(stubsType StubsType) (android.Path, error) {
+	switch stubsType {
+	case Everything:
+		return d.docZip, nil
+	default:
+		return nil, fmt.Errorf("docs zip not supported for the stub type %s", stubsType.String())
+	}
+}
+
+func (d *Droidstubs) RemovedApiFilePath(stubsType StubsType) (android.Path, error) {
+	switch stubsType {
+	case Everything:
+		return d.removedApiFile, nil
+	case Exportable:
+		return d.exportableRemovedApiFile, nil
+	default:
+		return nil, fmt.Errorf("removed api file path not supported for the stub type %s", stubsType.String())
+	}
+}
+
+func (d *Droidstubs) StubsSrcJar(stubsType StubsType) (android.Path, error) {
+	switch stubsType {
+	case Everything:
+		return d.stubsSrcJar, nil
+	case Exportable:
+		return d.exportableStubsSrcJar, nil
+	default:
+		return nil, fmt.Errorf("stubs srcjar not supported for the stub type %s", stubsType.String())
+	}
+}
+
+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)
@@ -269,41 +426,52 @@
 		}
 	}
 
+	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) != "" {
+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) {
+	if checkApi || String(d.properties.Api_filename) != "" {
 		filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
-		uncheckedApiFile := android.PathForModuleOut(ctx, "metalava", filename)
+		uncheckedApiFile := android.PathForModuleOut(ctx, stubsType.String(), filename)
 		cmd.FlagWithOutput("--api ", uncheckedApiFile)
-		d.apiFile = uncheckedApiFile
+
+		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 apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
-		apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
-		String(d.properties.Removed_api_filename) != "" {
+	if checkApi || String(d.properties.Removed_api_filename) != "" {
 		filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
-		uncheckedRemovedFile := android.PathForModuleOut(ctx, "metalava", filename)
+		uncheckedRemovedFile := android.PathForModuleOut(ctx, stubsType.String(), filename)
 		cmd.FlagWithOutput("--removed-api ", uncheckedRemovedFile)
-		d.removedApiFile = uncheckedRemovedFile
+
+		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 stubsDir.Valid() {
 		if Bool(d.properties.Create_doc_stubs) {
 			cmd.FlagWithArg("--doc-stubs ", stubsDir.String())
@@ -316,18 +484,11 @@
 	}
 }
 
-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 {
+		if params.migratingNullability {
 			previousApi := android.PathForModuleSrc(ctx, String(d.properties.Previous_api))
 			cmd.FlagWithInput("--migrate-nullness ", previousApi)
 		}
@@ -336,26 +497,17 @@
 			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)
 	}
 }
 
@@ -381,15 +533,15 @@
 	})
 }
 
-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 = d.everythingArtifacts.apiVersionsXml
 	} else {
 		ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) {
 			if s, ok := m.(*Droidstubs); ok {
-				apiVersions = s.apiVersionsXml
+				apiVersions = s.everythingArtifacts.apiVersionsXml
 			} else {
 				ctx.PropertyErrorf("api_levels_module",
 					"module %q is not a droidstubs module", ctx.OtherModuleName(m))
@@ -403,14 +555,13 @@
 	}
 }
 
-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")
 
@@ -502,20 +653,26 @@
 	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").
+		Flag(config.MetalavaAddOpens).
 		FlagWithArg("--java-source ", javaVersion.String()).
 		FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
 		FlagWithInput("@", srcJarList)
@@ -528,70 +685,96 @@
 		cmd.FlagWithInputList("--classpath ", combinedPaths, ":")
 	}
 
-	cmd.Flag("--no-banner").
-		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.
-	// And add concrete overrides of abstract methods, see b/299366704 for more
-	// information.
-	cmd.FlagWithArg("--format-defaults ", "overloaded-method-order=source,add-additional-overrides=yes")
+	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 (d *Droidstubs) 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:
+		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, params.stubConfig.javaVersion, d.Javadoc.srcFiles, srcJarList,
+		params.stubConfig.deps.bootClasspath, params.stubConfig.deps.classpath, homeDir)
 	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)
 
 	d.expandArgs(ctx, cmd)
 
@@ -599,24 +782,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
-
+	if doApiLint {
 		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")
 		}
-		d.apiLintReport = android.PathForModuleOut(ctx, "metalava", "api_lint_report.txt")
+		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.
@@ -627,8 +891,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.
 		//
@@ -669,10 +933,7 @@
 	}
 
 	// 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 doCheckReleased {
 		if len(d.Javadoc.properties.Out) > 0 {
 			ctx.PropertyErrorf("out", "out property may not be combined with check_api")
 		}
@@ -680,9 +941,9 @@
 		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))
 		baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Last_released.Baseline_file)
-		updatedBaselineOutput := android.PathForModuleOut(ctx, "metalava", "last_released_baseline.txt")
+		updatedBaselineOutput := android.PathForModuleOut(ctx, Everything.String(), "last_released_baseline.txt")
 
-		d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "metalava", "check_last_released_api.timestamp")
+		d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_last_released_api.timestamp")
 
 		cmd.FlagWithInput("--check-compatibility:api:released ", apiFile)
 		cmd.FlagWithInput("--check-compatibility:removed:released ", removedApiFile)
@@ -707,35 +968,93 @@
 		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,
+	}
+
+	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)
+
+	d.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
@@ -743,9 +1062,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") {
 
@@ -761,7 +1124,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)
 
@@ -788,6 +1151,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().
@@ -799,7 +1168,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)
@@ -827,14 +1196,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`+
@@ -844,13 +1213,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(") || (").
@@ -860,34 +1229,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) {
@@ -929,28 +1271,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{}
 
@@ -973,6 +1293,8 @@
 type PrebuiltStubsSources struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	embeddableInModuleAndImport
+
 	prebuilt android.Prebuilt
 
 	properties PrebuiltStubsSourcesProperties
@@ -982,15 +1304,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) {
@@ -1051,6 +1375,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..52cd1c5 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -82,7 +82,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 +131,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 +210,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 +300,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 {
@@ -390,7 +348,7 @@
 						removed_api_file: "A/removed.txt",
 					}
 				},
-				visibility: ["//a"],
+				visibility: ["//a", "//b"],
 			}
 		`,
 		map[string][]byte{
@@ -403,3 +361,54 @@
 
 	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")
+}
diff --git a/java/fuzz.go b/java/fuzz.go
index 2b9e22b..dc4c6be 100644
--- a/java/fuzz.go
+++ b/java/fuzz.go
@@ -30,15 +30,19 @@
 const (
 	hostString   = "host"
 	targetString = "target"
+	deviceString = "device"
 )
 
+// Any shared libs for these deps will also be packaged
+var artDeps = []string{"libdl_android"}
+
 func init() {
 	RegisterJavaFuzzBuildComponents(android.InitRegistrationContext)
 }
 
 func RegisterJavaFuzzBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("java_fuzz", JavaFuzzFactory)
-	ctx.RegisterSingletonType("java_fuzz_packaging", javaFuzzPackagingFactory)
+	ctx.RegisterParallelSingletonType("java_fuzz_packaging", javaFuzzPackagingFactory)
 }
 
 type JavaFuzzTest struct {
@@ -78,7 +82,18 @@
 }
 
 func (j *JavaFuzzTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if j.Os().Class.String() == deviceString {
+		j.testProperties.Jni_libs = append(j.testProperties.Jni_libs, artDeps...)
+	}
+
 	if len(j.testProperties.Jni_libs) > 0 {
+		if j.fuzzPackagedModule.FuzzProperties.Fuzz_config == nil {
+			config := &fuzz.FuzzConfig{}
+			j.fuzzPackagedModule.FuzzProperties.Fuzz_config = config
+		}
+		// this will be used by the ingestion pipeline to determine the version
+		// of jazzer to add to the fuzzer package
+		j.fuzzPackagedModule.FuzzProperties.Fuzz_config.IsJni = proptools.BoolPtr(true)
 		for _, target := range ctx.MultiTargets() {
 			sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"})
 			ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, j.testProperties.Jni_libs...)
@@ -106,7 +121,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" {
@@ -150,7 +165,9 @@
 		}
 
 		hostOrTargetString := "target"
-		if javaFuzzModule.Host() {
+		if javaFuzzModule.Target().HostCross {
+			hostOrTargetString = "host_cross"
+		} else if javaFuzzModule.Host() {
 			hostOrTargetString = "host"
 		}
 
@@ -175,11 +192,15 @@
 		files = s.PackageArtifacts(ctx, module, javaFuzzModule.fuzzPackagedModule, archDir, builder)
 
 		// Add .jar
-		files = append(files, fuzz.FileToZip{javaFuzzModule.implementationJarFile, ""})
+		if !javaFuzzModule.Host() {
+			files = append(files, fuzz.FileToZip{SourceFilePath: javaFuzzModule.implementationJarFile, DestinationPathPrefix: "classes"})
+		}
+
+		files = append(files, fuzz.FileToZip{SourceFilePath: javaFuzzModule.outputFile})
 
 		// Add jni .so files
 		for _, fPath := range javaFuzzModule.jniFilePaths {
-			files = append(files, fuzz.FileToZip{fPath, ""})
+			files = append(files, fuzz.FileToZip{SourceFilePath: fPath})
 		}
 
 		archDirs[archOs], ok = s.BuildZipFile(ctx, module, javaFuzzModule.fuzzPackagedModule, files, builder, archDir, archString, hostOrTargetString, archOs, archDirs)
diff --git a/java/fuzz_test.go b/java/fuzz_test.go
index dd1e96b..f29c913 100644
--- a/java/fuzz_test.go
+++ b/java/fuzz_test.go
@@ -71,8 +71,8 @@
 	}
 
 	baz := result.ModuleForTests("baz", osCommonTarget).Rule("javac").Output.String()
-	barOut := filepath.Join("out", "soong", ".intermediates", "bar", osCommonTarget, "javac", "bar.jar")
-	bazOut := filepath.Join("out", "soong", ".intermediates", "baz", osCommonTarget, "javac", "baz.jar")
+	barOut := filepath.Join("out", "soong", ".intermediates", "bar", osCommonTarget, "javac-header", "bar.jar")
+	bazOut := filepath.Join("out", "soong", ".intermediates", "baz", osCommonTarget, "javac-header", "baz.jar")
 
 	android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], barOut)
 	android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], bazOut)
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
new file mode 100644
index 0000000..40f780c
--- /dev/null
+++ b/java/generated_java_library.go
@@ -0,0 +1,109 @@
+// 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"
+)
+
+type GeneratedJavaLibraryModule struct {
+	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 {
+	// Called from inside DepsMutator, gives a chance to AddDependencies
+	DepsMutator(module *GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext)
+
+	// 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
+}
+
+// GeneratedJavaLibraryModuleFactory provides a utility for modules that are generated
+// source code, including ones outside the java package to build jar files
+// from that generated source.
+//
+// To use GeneratedJavaLibraryModule, call GeneratedJavaLibraryModuleFactory with
+// a callback interface and a properties object to add to the module.
+//
+// These modules will have some properties blocked, and it will be an error if
+// modules attempt to set them. See the list of property names in GeneratedAndroidBuildActions
+// for the list of those properties.
+func GeneratedJavaLibraryModuleFactory(moduleName string, callbacks GeneratedJavaLibraryCallbacks, properties interface{}) android.Module {
+	module := &GeneratedJavaLibraryModule{
+		callbacks:  callbacks,
+		moduleName: moduleName,
+	}
+	module.addHostAndDeviceProperties()
+	module.initModuleAndImport(module)
+	android.InitApexModule(module)
+	InitJavaModule(module, android.HostAndDeviceSupported)
+	if properties != nil {
+		module.AddProperties(properties)
+	}
+	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)
+}
+
+func checkPropertyEmpty(ctx android.ModuleContext, module *GeneratedJavaLibraryModule, name string, value []string) {
+	if len(value) != 0 {
+		ctx.PropertyErrorf(name, "%s not allowed on %s", name, module.moduleName)
+	}
+}
+
+func (module *GeneratedJavaLibraryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// These modules are all-generated, so disallow these properties to keep it simple.
+	// No additional sources
+	checkPropertyEmpty(ctx, module, "srcs", module.Library.properties.Srcs)
+	checkPropertyEmpty(ctx, module, "common_srcs", module.Library.properties.Common_srcs)
+	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)
+	// 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)
+	module.Library.properties.Generated_srcjars = append(module.Library.properties.Generated_srcjars, srcJarPath)
+	module.Library.GenerateAndroidBuildActions(ctx)
+}
diff --git a/java/generated_java_library_test.go b/java/generated_java_library_test.go
new file mode 100644
index 0000000..be816cd
--- /dev/null
+++ b/java/generated_java_library_test.go
@@ -0,0 +1,65 @@
+// 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 java
+
+import (
+	"testing"
+
+	"android/soong/android"
+)
+
+func JavaGenLibTestFactory() android.Module {
+	callbacks := &JavaGenLibTestCallbacks{}
+	return GeneratedJavaLibraryModuleFactory("test_java_gen_lib", callbacks, &callbacks.properties)
+}
+
+type JavaGenLibTestProperties struct {
+	Foo string
+}
+
+type JavaGenLibTestCallbacks struct {
+	properties JavaGenLibTestProperties
+}
+
+func (callbacks *JavaGenLibTestCallbacks) DepsMutator(module *GeneratedJavaLibraryModule, ctx android.BottomUpMutatorContext) {
+}
+
+func (callbacks *JavaGenLibTestCallbacks) GenerateSourceJarBuildActions(module *GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path {
+	return android.PathForOutput(ctx, "blah.srcjar")
+}
+
+func testGenLib(t *testing.T, errorHandler android.FixtureErrorHandler, bp string) *android.TestResult {
+	return android.GroupFixturePreparers(
+		PrepareForIntegrationTestWithJava,
+		android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+			ctx.RegisterModuleType("test_java_gen_lib", JavaGenLibTestFactory)
+		}),
+	).
+		ExtendWithErrorHandler(errorHandler).
+		RunTestWithBp(t, bp)
+}
+
+func TestGenLib(t *testing.T) {
+	bp := `
+				test_java_gen_lib {
+					name: "javagenlibtest",
+                    foo: "bar",  // Note: This won't parse if the property didn't get added
+				}
+			`
+	result := testGenLib(t, android.FixtureExpectsNoErrors, bp)
+
+	javagenlibtest := result.ModuleForTests("javagenlibtest", "android_common").Module().(*GeneratedJavaLibraryModule)
+	android.AssertPathsEndWith(t, "Generated_srcjars", []string{"/blah.srcjar"}, javagenlibtest.Library.properties.Generated_srcjars)
+}
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 d25096b..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
@@ -106,7 +110,7 @@
 	h.uncompressDexState = uncompressedDexState
 
 	// If hiddenapi processing is disabled treat this as inactive.
-	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+	if ctx.Config().DisableHiddenApiChecks() {
 		return
 	}
 
@@ -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 c6176e6..e4beb5e 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.JavaLibraryName(config))
-		systemStubModules = append(systemStubModules, android.SdkSystem.JavaLibraryName(config))
-		testStubModules = append(testStubModules, android.SdkTest.JavaLibraryName(config))
+		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)
 
@@ -1236,7 +1255,6 @@
 	rule := android.NewRuleBuilder(pctx, ctx)
 	rule.Command().
 		BuiltTool("metalava").
-		Flag("--no-banner").
 		Inputs(removedTxtFiles).
 		FlagWithOutput("--dex-api ", output)
 	rule.Build("modular-hiddenapi-removed-dex-signatures"+suffix, "modular hiddenapi removed dex signatures"+suffix)
@@ -1244,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
@@ -1317,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())
@@ -1397,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
 			}
@@ -1432,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())
diff --git a/java/hiddenapi_monolithic.go b/java/hiddenapi_monolithic.go
index 5956e3c..a61018d 100644
--- a/java/hiddenapi_monolithic.go
+++ b/java/hiddenapi_monolithic.go
@@ -67,8 +67,7 @@
 
 		case *ClasspathFragmentElement:
 			fragment := e.Module()
-			if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
-				info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
+			if info, ok := android.OtherModuleProvider(ctx, fragment, HiddenAPIInfoProvider); ok {
 				monolithicInfo.append(&info)
 			} else {
 				ctx.ModuleErrorf("%s does not provide hidden API information", fragment)
@@ -90,4 +89,4 @@
 	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 52934a3..8cb78cd 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -25,7 +25,7 @@
 }
 
 func RegisterHiddenApiSingletonComponents(ctx android.RegistrationContext) {
-	ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
+	ctx.RegisterParallelSingletonType("hiddenapi", hiddenAPISingletonFactory)
 }
 
 var PrepareForTestWithHiddenApiBuildComponents = android.FixtureRegisterWithContext(RegisterHiddenApiSingletonComponents)
@@ -121,8 +121,8 @@
 
 // hiddenAPI singleton rules
 func (h *hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	// Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true
-	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+	// Don't run any hiddenapi rules if hiddenapi checks are disabled
+	if ctx.Config().DisableHiddenApiChecks() {
 		return
 	}
 
@@ -162,11 +162,11 @@
 		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)
-	if requiredApex == "platform" || requiredApex == "system_ext" {
+	if android.IsConfiguredJarForPlatform(requiredApex) {
 		if len(apexInfo.InApexVariants) != 0 {
 			// A platform variant is required but this is for an apex so ignore it.
 			return false
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 e7def4b..cd249ed 100644
--- a/java/java.go
+++ b/java/java.go
@@ -21,12 +21,12 @@
 import (
 	"fmt"
 	"path/filepath"
+	"sort"
 	"strings"
 
-	"android/soong/bazel"
-	"android/soong/bazel/cquery"
 	"android/soong/remoteexec"
 	"android/soong/testing"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -62,6 +62,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
@@ -73,8 +74,8 @@
 		ctx.BottomUp("jacoco_deps", jacocoDepsMutator).Parallel()
 	})
 
-	ctx.RegisterSingletonType("logtags", LogtagsSingleton)
-	ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
+	ctx.RegisterParallelSingletonType("logtags", LogtagsSingleton)
+	ctx.RegisterParallelSingletonType("kythe_java_extract", kytheExtractJavaFactory)
 }
 
 func RegisterJavaSdkMemberTypes() {
@@ -224,6 +225,23 @@
 	}, "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
@@ -231,10 +249,10 @@
 	HeaderJars android.Paths
 
 	// set of header jars for all transitive libs deps
-	TransitiveLibsHeaderJars *android.DepSet
+	TransitiveLibsHeaderJars *android.DepSet[android.Path]
 
 	// set of header jars for all transitive static libs deps
-	TransitiveStaticLibsHeaderJars *android.DepSet
+	TransitiveStaticLibsHeaderJars *android.DepSet[android.Path]
 
 	// ImplementationAndResourceJars is a list of jars that contain the implementations of classes
 	// in the module as well as any resources included in the module.
@@ -258,6 +276,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,7 +296,7 @@
 	JacocoReportClassesFile android.Path
 }
 
-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.
@@ -285,7 +306,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 {
@@ -295,16 +316,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
@@ -390,6 +406,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)
@@ -456,7 +473,9 @@
 		ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
 		ctx.AddVariationDependencies(nil, sdkLibTag, sdkDep.classpath...)
 		if d.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
-			ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...)
+			ctx.AddVariationDependencies(nil, proguardRaiseTag,
+				config.LegacyCorePlatformBootclasspathLibraries...,
+			)
 		}
 		if d.effectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() {
 			ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...)
@@ -501,6 +520,7 @@
 	kotlinStdlib            android.Paths
 	kotlinAnnotations       android.Paths
 	kotlinPlugins           android.Paths
+	aconfigProtoFiles       android.Paths
 
 	disableTurbine bool
 }
@@ -544,9 +564,11 @@
 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:
@@ -563,10 +585,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:
@@ -582,9 +606,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":
@@ -609,15 +635,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)
@@ -633,9 +653,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
 	}
 
@@ -645,7 +665,7 @@
 	}
 
 	// Store uncompressed dex files that are preopted on /system.
-	if !dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !dexpreopter.odexOnSystemOther(ctx, dexpreopter.installPath)) {
+	if !dexpreopter.dexpreoptDisabled(ctx, libName) && (ctx.Host() || !dexpreopter.odexOnSystemOther(ctx, libName, dexpreopter.installPath)) {
 		return true
 	}
 	if ctx.Config().UncompressPrivAppDex() &&
@@ -660,7 +680,7 @@
 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))
 	}
 }
 
@@ -672,28 +692,37 @@
 	j.minSdkVersion = j.MinSdkVersion(ctx)
 	j.maxSdkVersion = j.MaxSdkVersion(ctx)
 
-	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	j.stem = proptools.StringDefault(j.overridableDeviceProperties.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)
 	}
-	j.compile(ctx, nil)
-
-	// Collect the module directory for IDE info in java/jdeps.go.
-	j.modulePaths = append(j.modulePaths, ctx.ModuleDir())
+	j.compile(ctx, nil, nil, nil)
 
 	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)
 		}
@@ -715,15 +744,6 @@
 		}
 		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()...)
-		}
-	})
-	j.exportedProguardFlagFiles = android.FirstUniquePaths(j.exportedProguardFlagFiles)
 }
 
 func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -813,7 +833,10 @@
 	// If the min_sdk_version was set then add the canonical representation of the API level to the
 	// snapshot.
 	if j.deviceProperties.Min_sdk_version != nil {
-		canonical := android.ReplaceFinalizedCodenames(ctx.SdkModuleContext().Config(), j.minSdkVersion.String())
+		canonical, err := android.ReplaceFinalizedCodenames(ctx.SdkModuleContext().Config(), j.minSdkVersion.String())
+		if err != nil {
+			ctx.ModuleErrorf("%s", err)
+		}
 		p.MinSdkVersion = proptools.StringPtr(canonical)
 	}
 
@@ -890,7 +913,6 @@
 	module.initModuleAndImport(module)
 
 	android.InitApexModule(module)
-	android.InitBazelModule(module)
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
 }
@@ -912,7 +934,6 @@
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 
 	android.InitApexModule(module)
-	android.InitBazelModule(module)
 	InitJavaModule(module, android.HostSupported)
 	return module
 }
@@ -1063,7 +1084,7 @@
 	return true
 }
 
-func (j *TestHost) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
+func (j *TestHost) IsNativeCoverageNeeded(ctx android.IncomingTransitionContext) bool {
 	return ctx.DeviceConfig().NativeCoverageEnabled()
 }
 
@@ -1203,12 +1224,12 @@
 	}
 
 	j.Test.generateAndroidBuildActionsWithConfig(ctx, configs)
-	ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+	android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.generateAndroidBuildActionsWithConfig(ctx, nil)
-	ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+	android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, configs []tradefed.Config) {
@@ -1244,7 +1265,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.
@@ -1465,6 +1486,8 @@
 }
 
 func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	j.stem = proptools.StringDefault(j.overridableDeviceProperties.Stem, ctx.ModuleName())
+
 	if ctx.Arch().ArchType == android.Common {
 		// Compile the jar
 		if j.binaryProperties.Main_class != nil {
@@ -1560,7 +1583,6 @@
 
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommonFirst)
 	android.InitDefaultableModule(module)
-	android.InitBazelModule(module)
 
 	return module
 }
@@ -1579,13 +1601,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
@@ -1601,14 +1623,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
@@ -1616,24 +1640,19 @@
 		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),
 	})
 }
 
-type JavaApiLibraryDepsInfo struct {
-	JavaInfo
-	StubsSrcJar android.Path
-}
-
-var JavaApiLibraryDepsProvider = blueprint.NewProvider(JavaApiLibraryDepsInfo{})
-
 type ApiLibrary struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
 
 	hiddenAPI
 	dexer
+	embeddableInModuleAndImport
 
 	properties JavaApiLibraryProperties
 
@@ -1643,6 +1662,8 @@
 	extractedSrcJar           android.WritablePath
 	// .dex of stubs, used for hiddenapi processing
 	dexJarFile OptionalDexJarPath
+
+	validationPaths android.Paths
 }
 
 type JavaApiLibraryProperties struct {
@@ -1653,11 +1674,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
-
 	// List of flags to be passed to the javac compiler to generate jar file
 	Javacflags []string
 
@@ -1669,16 +1685,33 @@
 	// merge zipped after metalava invocation
 	Static_libs []string
 
-	// Java Api library to provide the full API surface text files and jar file.
-	// If this property is set, the provided full API surface text files and
-	// jar file are passed to metalava invocation.
-	Dep_api_srcs *string
+	// Java Api library to provide the full API surface stub jar file.
+	// If this property is set, the stub jar of this module is created by
+	// 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
 }
 
 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
 }
@@ -1692,7 +1725,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())
 
@@ -1718,10 +1752,8 @@
 		Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
 		FlagWithInputList("--source-files ", srcs, " ")
 
-	cmd.Flag("--no-banner").
-		Flag("--color").
+	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,
@@ -1733,13 +1765,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
 }
@@ -1758,47 +1794,98 @@
 	}
 }
 
-// This method extracts the stub java files from the srcjar file provided from dep_api_srcs module
-// and replaces the java stubs generated by invoking metalava in this module.
+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
-// the codebase encompasses all classes listed in the input API text file, but a class can extend
+// the codebase encompasses all classes listed in the input API text file, and a class can extend
 // a class that is not within the same API domain.
-func (al *ApiLibrary) extractApiSrcs(ctx android.ModuleContext, rule *android.RuleBuilder, stubsDir android.OptionalPath, depApiSrcsSrcJar android.Path) {
-	generatedStubsList := android.PathForModuleOut(ctx, "metalava", "sources.txt")
+func (al *ApiLibrary) extractApiSrcs(ctx android.ModuleContext, rule *android.RuleBuilder, stubsDir android.OptionalPath, fullApiSurfaceStubJar android.Path) {
+	classFilesList := android.PathForModuleOut(ctx, "metalava", "classes.txt")
 	unzippedSrcJarDir := android.PathForModuleOut(ctx, "metalava", "unzipDir")
 
 	rule.Command().
 		BuiltTool("list_files").
 		Text(stubsDir.String()).
-		FlagWithOutput("--out ", generatedStubsList).
+		FlagWithOutput("--out ", classFilesList).
 		FlagWithArg("--extensions ", ".java").
-		FlagWithArg("--root ", unzippedSrcJarDir.String())
+		FlagWithArg("--root ", unzippedSrcJarDir.String()).
+		Flag("--classes")
 
 	rule.Command().
 		Text("unzip").
 		Flag("-q").
-		Input(depApiSrcsSrcJar).
+		Input(fullApiSurfaceStubJar).
 		FlagWithArg("-d ", unzippedSrcJarDir.String())
 
 	rule.Command().
 		BuiltTool("soong_zip").
-		Flag("-srcjar").
+		Flag("-jar").
 		Flag("-write_if_changed").
+		Flag("-ignore_missing_files").
+		Flag("-quiet").
 		FlagWithArg("-C ", unzippedSrcJarDir.String()).
-		FlagWithInput("-l ", generatedStubsList).
-		FlagWithOutput("-o ", al.stubsSrcJar)
+		FlagWithInput("-l ", classFilesList).
+		FlagWithOutput("-o ", al.stubsJarWithoutStaticLibs)
 }
 
 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.Dep_api_srcs != nil {
-		ctx.AddVariationDependencies(nil, depApiSrcsTag, String(al.properties.Dep_api_srcs))
+	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))
+	}
+}
+
+// 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, srcFilesInfo []JavaApiImportInfo) []JavaApiImportInfo {
+	for _, srcFileInfo := range srcFilesInfo {
+		if srcFileInfo.ApiSurface == "" {
+			ctx.ModuleErrorf("Api surface not defined for the associated api file %s", srcFileInfo.ApiFile)
+		}
+	}
+	sort.Slice(srcFilesInfo, func(i, j int) bool {
+		return scopeOrderMap[srcFilesInfo[i].ApiSurface] < scopeOrderMap[srcFilesInfo[j].ApiSurface]
+	})
+
+	return srcFilesInfo
 }
 
 func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -1809,81 +1896,96 @@
 		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 depApiSrcsStubsSrcJar android.Path
+	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 {
+			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, JavaApiLibraryDepsProvider).(JavaApiLibraryDepsInfo)
-			classPaths = append(classPaths, provider.HeaderJars...)
-			depApiSrcsStubsSrcJar = provider.StubsSrcJar
+			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())
+			}
 		}
 	})
 
-	// Add the api_files inputs
-	for _, api := range al.properties.Api_files {
-		// Use MaybeExistentPathForSource since the api file might not exist during analysis.
-		// This will be provided by the orchestrator in the combined execution.
-		srcFiles = append(srcFiles, android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), 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 {
+	if srcFiles == nil && !ctx.Config().AllowMissingDependencies() {
 		ctx.ModuleErrorf("Error: %s has an empty api file.", ctx.ModuleName())
 	}
 
-	cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir)
+	cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir, systemModulesPaths)
 
 	al.stubsFlags(ctx, cmd, stubsDir)
 
-	al.stubsSrcJar = android.PathForModuleOut(ctx, "metalava", ctx.ModuleName()+"-"+"stubs.srcjar")
-
-	if depApiSrcsStubsSrcJar != nil {
-		al.extractApiSrcs(ctx, rule, stubsDir, depApiSrcsStubsSrcJar)
-	} else {
-		rule.Command().
-			BuiltTool("soong_zip").
-			Flag("-write_if_changed").
-			Flag("-jar").
-			FlagWithOutput("-o ", al.stubsSrcJar).
-			FlagWithArg("-C ", stubsDir.String()).
-			FlagWithArg("-D ", stubsDir.String())
+	migratingNullability := String(al.properties.Previous_api) != ""
+	if migratingNullability {
+		previousApi := android.PathForModuleSrc(ctx, String(al.properties.Previous_api))
+		cmd.FlagWithInput("--migrate-nullness ", previousApi)
 	}
 
-	rule.Build("metalava", "metalava merged")
+	al.addValidation(ctx, cmd, al.validationPaths)
 
-	al.stubsJarWithoutStaticLibs = android.PathForModuleOut(ctx, ctx.ModuleName(), "stubs.jar")
+	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()))
 
-	var flags javaBuilderFlags
-	flags.javaVersion = getStubsJavaVersion()
-	flags.javacFlags = strings.Join(al.properties.Javacflags, " ")
-	flags.classpath = classpath(classPaths)
+	if depApiSrcsStubsJar != nil {
+		al.extractApiSrcs(ctx, rule, stubsDir, depApiSrcsStubsJar)
+	}
+	rule.Command().
+		BuiltTool("soong_zip").
+		Flag("-write_if_changed").
+		Flag("-jar").
+		FlagWithOutput("-o ", al.stubsSrcJar).
+		FlagWithArg("-C ", stubsDir.String()).
+		FlagWithArg("-D ", stubsDir.String())
 
-	TransformJavaToClasses(ctx, al.stubsJarWithoutStaticLibs, 0, android.Paths{},
-		android.Paths{al.stubsSrcJar}, flags, android.Paths{})
+	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")
+
+		TransformJavaToClasses(ctx, al.stubsJarWithoutStaticLibs, 0, android.Paths{},
+			android.Paths{al.stubsSrcJar}, annoSrcJar, flags, android.Paths{})
+	}
 
 	builder := android.NewRuleBuilder(pctx, ctx)
 	builder.Command().
@@ -1909,22 +2011,16 @@
 
 	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{},
-	})
-
-	ctx.SetProvider(JavaApiLibraryDepsProvider, JavaApiLibraryDepsInfo{
-		JavaInfo: JavaInfo{
-			HeaderJars: android.PathsIfNonNil(al.stubsJar),
-		},
-		StubsSrcJar: al.stubsSrcJar,
+		// No aconfig libraries on api libraries
 	})
 }
 
-func (al *ApiLibrary) DexJarBuildPath() OptionalDexJarPath {
+func (al *ApiLibrary) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
 	return al.dexJarFile
 }
 
@@ -1994,13 +2090,17 @@
 		// 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
 }
 
 type Import struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
 	android.ApexModuleBase
-	android.BazelModuleBase
 	prebuilt android.Prebuilt
 
 	// Functionality common to Module and Import.
@@ -2014,6 +2114,7 @@
 
 	// output file containing classes.dex and resources
 	dexJarFile        OptionalDexJarPath
+	dexJarFileErr     error
 	dexJarInstallFile android.Path
 
 	combinedClasspathFile android.Path
@@ -2067,12 +2168,16 @@
 	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 (a *Import) JacocoReportClassesFile() android.Path {
@@ -2099,11 +2204,11 @@
 }
 
 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
 	}
 
@@ -2134,8 +2239,7 @@
 	j.collectTransitiveHeaderJars(ctx)
 	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...)
@@ -2162,21 +2266,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
 
@@ -2184,8 +2292,6 @@
 					j.dexpreopter.inputProfilePathOnHost = profilePath
 				}
 
-				j.dexpreopt(ctx, dexOutputPath)
-
 				// Initialize the hiddenapi structure.
 				j.initHiddenAPI(ctx, dexJarFile, outputFile, j.dexProperties.Uncompress_dex)
 			} else {
@@ -2206,7 +2312,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
 
@@ -2235,13 +2341,14 @@
 		}
 	}
 
-	ctx.SetProvider(JavaInfoProvider, JavaInfo{
+	android.SetProvider(ctx, JavaInfoProvider, JavaInfo{
 		HeaderJars:                     android.PathsIfNonNil(j.combinedClasspathFile),
 		TransitiveLibsHeaderJars:       j.transitiveLibsHeaderJars,
 		TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
 		ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedClasspathFile),
 		ImplementationJars:             android.PathsIfNonNil(j.combinedClasspathFile),
 		AidlIncludeDirs:                j.exportAidlIncludeDirs,
+		// TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts
 	})
 }
 
@@ -2288,7 +2395,10 @@
 	return android.Paths{j.combinedClasspathFile}
 }
 
-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
 }
 
@@ -2329,7 +2439,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,
@@ -2340,9 +2450,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")
 }
 
@@ -2353,6 +2463,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)
@@ -2400,7 +2514,6 @@
 
 	android.InitPrebuiltModule(module, &module.properties.Jars)
 	android.InitApexModule(module)
-	android.InitBazelModule(module)
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
 }
@@ -2417,7 +2530,6 @@
 
 	android.InitPrebuiltModule(module, &module.properties.Jars)
 	android.InitApexModule(module)
-	android.InitBazelModule(module)
 	InitJavaModule(module, android.HostSupported)
 	return module
 }
@@ -2486,14 +2598,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")
@@ -2532,7 +2644,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"),
@@ -2540,7 +2652,7 @@
 	}
 }
 
-func (j *DexImport) DexJarBuildPath() OptionalDexJarPath {
+func (j *DexImport) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath {
 	return j.dexJarFile
 }
 
@@ -2621,6 +2733,7 @@
 		&appProperties{},
 		&appTestProperties{},
 		&overridableAppProperties{},
+		&hostTestProperties{},
 		&testProperties{},
 		&ImportProperties{},
 		&AARImportProperties{},
@@ -2632,6 +2745,8 @@
 		&LintProperties{},
 		&appTestHelperAppProperties{},
 		&JavaApiLibraryProperties{},
+		&bootclasspathFragmentProperties{},
+		&SourceOnlyBootclasspathProperties{},
 	)
 
 	android.InitDefaultsModule(module)
@@ -2661,7 +2776,7 @@
 var Bool = proptools.Bool
 var BoolDefault = proptools.BoolDefault
 var String = proptools.String
-var inList = android.InList
+var inList = android.InList[string]
 
 // Add class loader context (CLC) of a given dependency to the current CLC.
 func addCLCFromDep(ctx android.ModuleContext, depModule android.Module,
@@ -2707,519 +2822,36 @@
 	// 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())
+			dep.DexJarBuildPath(ctx).PathOrNil(), dep.DexJarInstallPath(), dep.ClassLoaderContexts())
 	} else {
 		clcMap.AddContextMap(dep.ClassLoaderContexts(), depName)
 	}
 }
 
-type javaResourcesAttributes struct {
-	Resources             bazel.LabelListAttribute
-	Resource_strip_prefix *string
+type JavaApiContributionImport struct {
+	JavaApiContribution
+
+	prebuilt android.Prebuilt
 }
 
-func (m *Library) convertJavaResourcesAttributes(ctx android.TopDownMutatorContext) *javaResourcesAttributes {
-	var resources bazel.LabelList
-	var resourceStripPrefix *string
-
-	if m.properties.Java_resources != nil {
-		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,
-	}
+func ApiContributionImportFactory() android.Module {
+	module := &JavaApiContributionImport{}
+	android.InitAndroidModule(module)
+	android.InitDefaultableModule(module)
+	android.InitPrebuiltModule(module, &[]string{""})
+	module.AddProperties(&module.properties)
+	module.AddProperties(&module.sdkLibraryComponentProperties)
+	return module
 }
 
-type javaCommonAttributes struct {
-	*javaResourcesAttributes
-	*kotlinAttributes
-	Srcs         bazel.LabelListAttribute
-	Plugins      bazel.LabelListAttribute
-	Javacopts    bazel.StringListAttribute
-	Sdk_version  bazel.StringAttribute
-	Java_version bazel.StringAttribute
+func (module *JavaApiContributionImport) Prebuilt() *android.Prebuilt {
+	return &module.prebuilt
 }
 
-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
+func (module *JavaApiContributionImport) Name() string {
+	return module.prebuilt.Name(module.ModuleBase.Name())
 }
 
-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
-}
-
-// 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) {
-	var srcs bazel.LabelListAttribute
-	var deps bazel.LabelListAttribute
-	var staticDeps bazel.LabelList
-
-	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)
-			}
-		}
-	}
-	srcs.ResolveExcludes()
-
-	javaSrcPartition := "java"
-	protoSrcPartition := "proto"
-	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,
-		kotlinPartition:    bazel.LabelPartition{Extensions: []string{".kt"}},
-	})
-
-	javaSrcs := srcPartitions[javaSrcPartition]
-	kotlinSrcs := srcPartitions[kotlinPartition]
-	javaSrcs.Append(kotlinSrcs)
-
-	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.Add(&bazel.Label{Label: ":" + javaAidlLibName})
-	}
-
-	var javacopts []string
-	if m.properties.Javacflags != nil {
-		javacopts = append(javacopts, m.properties.Javacflags...)
-	}
-
-	epEnabled := m.properties.Errorprone.Enabled
-	//TODO(b/227504307) add configuration that depends on RUN_ERROR_PRONE environment variable
-	if Bool(epEnabled) {
-		javacopts = append(javacopts, m.properties.Errorprone.Javacflags...)
-	}
-
-	commonAttrs := &javaCommonAttributes{
-		Srcs:                    javaSrcs,
-		javaResourcesAttributes: m.convertJavaResourcesAttributes(ctx),
-		Plugins: bazel.MakeLabelListAttribute(
-			android.BazelLabelForModuleDeps(ctx, m.properties.Plugins),
-		),
-		Javacopts:    bazel.MakeStringListAttribute(javacopts),
-		Java_version: bazel.StringAttribute{Value: m.properties.Java_version},
-		Sdk_version:  bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
-	}
-
-	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.
-	staticDeps.Add(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.Value.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
-}
-
-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:rules.bzl",
-	}
-}
-
-func javaLibraryBazelTargetModuleProperties() bazel.BazelTargetModuleProperties {
-	return bazel.BazelTargetModuleProperties{
-		Rule_class:        "java_library",
-		Bzl_load_location: "//build/bazel/rules/java:rules.bzl",
-	}
-}
-
-func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) {
-	commonAttrs, bp2BuildInfo := m.convertLibraryAttrsBp2Build(ctx)
-	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 := m.convertLibraryAttrsBp2Build(ctx)
-	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 := map[string]bool{}
-		for _, jniLibLabel := range android.BazelLabelForModuleDeps(ctx, m.binaryProperties.Jni_libs).Includes {
-			jniLibPackage := jniLibLabel.Label
-			indexOfColon := strings.Index(jniLibLabel.Label, ":")
-			if indexOfColon > 0 {
-				// JNI lib from other package
-				jniLibPackage = jniLibLabel.Label[2:indexOfColon]
-			} else if indexOfColon == 0 {
-				// JNI lib in the same package of java_binary
-				packageOfCurrentModule := m.GetBazelLabel(ctx, m)
-				jniLibPackage = packageOfCurrentModule[2:strings.Index(packageOfCurrentModule, ":")]
-			}
-			if _, inMap := jniLibPackages[jniLibPackage]; !inMap {
-				jniLibPackages[jniLibPackage] = true
-			}
-		}
-		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: "//build/bazel/rules/java:rules.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)
-		return
-	}
-
-	libName := m.Name() + "_lib"
-	var libProps bazel.BazelTargetModuleProperties
-	if bp2BuildInfo.hasKotlin {
-		libProps = ktJvmLibraryBazelTargetModuleProperties()
-	} else {
-		libProps = javaLibraryBazelTargetModuleProperties()
-	}
-	libAttrs := &javaLibraryAttributes{
-		Deps:                 deps,
-		javaCommonAttributes: commonAttrs,
-	}
-
-	ctx.CreateBazelTargetModule(libProps, android.CommonAttributes{Name: libName}, libAttrs)
-	binAttrs.Runtime_deps.Add(&bazel.LabelAttribute{Value: &bazel.Label{Label: ":" + libName}})
-
-	// Create the BazelTargetModule.
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, binAttrs)
-}
-
-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)
-			}
-		}
-	}
-
-	attrs := &bazelJavaImportAttributes{
-		Jars: jars,
-	}
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "java_import",
-		Bzl_load_location: "//build/bazel/rules/java:rules.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)
-
-func (i *Import) getBazelModuleLabel(ctx android.BaseModuleContext) string {
-	return android.RemoveOptionalPrebuiltPrefixFromBazelLabel(i.GetBazelLabel(ctx, i))
-}
-
-func (i *Import) ProcessBazelQueryResponse(ctx android.ModuleContext) {
-	i.commonBuildActions(ctx)
-
-	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
-	})
-
-	i.maybeInstall(ctx, jarName, outputFile)
-}
-
-func (i *Import) QueueBazelCall(ctx android.BaseModuleContext) {
-	bazelCtx := ctx.Config().BazelContext
-	bazelCtx.QueueBazelRequest(i.getBazelModuleLabel(ctx), cquery.GetOutputFiles, android.GetConfigKey(ctx))
-}
-
-func (i *Import) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
-	return true
+func (ap *JavaApiContributionImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	ap.JavaApiContribution.GenerateAndroidBuildActions(ctx)
 }
diff --git a/java/java_test.go b/java/java_test.go
index 0c002f3..42301d8 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 {
@@ -596,7 +605,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 +619,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 +629,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{}) {
@@ -1206,7 +1214,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 +1299,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 +1715,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,9 +1739,17 @@
 }
 
 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 {
@@ -1864,15 +1764,30 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	provider_bp_b := `java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		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",
@@ -1883,13 +1798,8 @@
 			name: "bar2",
 			api_surface: "system",
 			api_contributions: ["foo1", "foo2"],
-			api_files: ["api1/current.txt", "api2/current.txt"]
 		}
-		`,
-		map[string][]byte{
-			"a/Android.bp": []byte(provider_bp_a),
-			"b/Android.bp": []byte(provider_bp_b),
-		})
+	`)
 
 	testcases := []struct {
 		moduleName         string
@@ -1897,17 +1807,17 @@
 	}{
 		{
 			moduleName:         "bar1",
-			sourceTextFileDirs: []string{"a/foo1.txt"},
+			sourceTextFileDirs: []string{"a/current.txt"},
 		},
 		{
 			moduleName:         "bar2",
-			sourceTextFileDirs: []string{"a/foo1.txt", "b/foo2.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)
@@ -1918,28 +1828,47 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	provider_bp_c := `
 	java_api_contribution {
 		name: "foo3",
-		api_file: "foo3.txt",
+		api_file: "system-current.txt",
+		api_surface: "system",
 	}
 	`
 	provider_bp_d := `
 	java_api_contribution {
 		name: "foo4",
-		api_file: "foo4.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",
@@ -1969,15 +1898,8 @@
 			api_surface: "system",
 			defaults:["baz1", "baz2"],
 			api_contributions: ["foo4"],
-			api_files: ["api1/current.txt", "api2/current.txt"]
 		}
-		`,
-		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
@@ -1985,21 +1907,22 @@
 	}{
 		{
 			moduleName:         "bar1",
-			sourceTextFileDirs: []string{"a/foo1.txt"},
+			sourceTextFileDirs: []string{"a/current.txt"},
 		},
 		{
 			moduleName:         "bar2",
-			sourceTextFileDirs: []string{"a/foo1.txt", "b/foo2.txt"},
+			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt"},
 		},
 		{
-			moduleName:         "bar3",
-			sourceTextFileDirs: []string{"c/foo3.txt", "a/foo1.txt", "b/foo2.txt", "d/foo4.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)
@@ -2010,16 +1933,31 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		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",
@@ -2031,11 +1969,7 @@
 			api_surface: "system",
 			api_contributions: ["foo1", "foo2"],
 		}
-		`,
-		map[string][]byte{
-			"a/Android.bp": []byte(provider_bp_a),
-			"b/Android.bp": []byte(provider_bp_b),
-		})
+	`)
 
 	testcases := []struct {
 		moduleName    string
@@ -2063,13 +1997,15 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	lib_bp_a := `
@@ -2085,7 +2021,24 @@
 	}
 	`
 
-	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",
@@ -2099,15 +2052,7 @@
 			api_contributions: ["foo1", "foo2"],
 			libs: ["lib1", "lib2", "bar1"],
 		}
-		`,
-		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
@@ -2138,13 +2083,15 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	lib_bp_a := `
@@ -2160,7 +2107,24 @@
 	}
 	`
 
-	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",
@@ -2174,15 +2138,7 @@
 			api_contributions: ["foo1", "foo2"],
 			static_libs: ["lib1", "lib2", "bar1"],
 		}
-		`,
-		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
@@ -2208,17 +2164,19 @@
 	}
 }
 
-func TestJavaApiLibraryDepApiSrcs(t *testing.T) {
+func TestJavaApiLibraryFullApiSurfaceStub(t *testing.T) {
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
+		api_surface: "public",
 	}
 	`
 	lib_bp_a := `
@@ -2229,27 +2187,57 @@
 	}
 	`
 
-	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"],
-			dep_api_srcs: "lib1",
+			full_api_surface_stub: "lib1",
 		}
-		`,
-		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")
+}
 
-	android.AssertStringDoesContain(t, "Command expected to contain module srcjar file", manifestCommand, "bar1-stubs.srcjar")
-	android.AssertStringDoesContain(t, "Command expected to contain output files list text file flag", manifestCommand, "--out __SBOX_SANDBOX_DIR__/out/sources.txt")
+func TestTransitiveSrcFiles(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_library {
+			name: "a",
+			srcs: ["a.java"],
+		}
+		java_library {
+			name: "b",
+			srcs: ["b.java"],
+		}
+		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) {
@@ -2299,3 +2287,340 @@
 		t.Errorf("Expected args[\"extraTestRunnerConfigs\"] to equal %q, was %q", expected, args["extraTestRunnerConfigs"])
 	}
 }
+
+func TestJavaExcludeStaticLib(t *testing.T) {
+	ctx, _ := testJava(t, `
+	java_library {
+		name: "bar",
+	}
+	java_library {
+		name: "foo",
+	}
+	java_library {
+		name: "baz",
+		static_libs: [
+			"foo",
+			"bar",
+		],
+		exclude_static_libs: [
+			"bar",
+		],
+	}
+	`)
+
+	// "bar" not included as dependency of "baz"
+	CheckModuleDependencies(t, ctx, "baz", "android_common", []string{
+		`core-lambda-stubs`,
+		`ext`,
+		`foo`,
+		`framework`,
+		`stable-core-platform-api-stubs-system-modules`,
+		`stable.core.platform.api.stubs`,
+	})
+}
+
+func TestJavaLibraryWithResourcesStem(t *testing.T) {
+	ctx, _ := testJavaWithFS(t, `
+    java_library {
+        name: "foo",
+        java_resource_dirs: ["test-jar"],
+        stem: "test",
+    }
+    `,
+		map[string][]byte{
+			"test-jar/test/resource.txt": nil,
+		})
+
+	m := ctx.ModuleForTests("foo", "android_common")
+	outputs := fmt.Sprint(m.AllOutputs())
+	if !strings.Contains(outputs, "test.jar") {
+		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"],
+		}
+		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",
+			],
+		}
+	`)
+	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,
+		}
+		java_api_library {
+			name: "bar",
+			api_contributions: [
+				"api-stubs-docs-non-updatable.api.contribution",
+			],
+			enable_validation: false,
+		}
+	`)
+
+	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])
+	}
+}
diff --git a/java/jdeps.go b/java/jdeps.go
index a52b867..91f7ce7 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -26,7 +26,7 @@
 // called. Dependency info file is generated in $OUT/module_bp_java_depend.json.
 
 func init() {
-	android.RegisterSingletonType("jdeps_generator", jDepsGeneratorSingleton)
+	android.RegisterParallelSingletonType("jdeps_generator", jDepsGeneratorSingleton)
 }
 
 func jDepsGeneratorSingleton() android.Singleton {
@@ -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 9bff5ea..aa2db0e 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -30,7 +30,7 @@
 	blueprint.RuleParams{
 		Command: `rm -rf "$classesDir" "$headerClassesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` +
 			`mkdir -p "$classesDir" "$headerClassesDir" "$srcJarDir" "$emptyDir" && ` +
-			`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
+			`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" -f "*.kt" $srcJars && ` +
 			`${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
 			` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
 			` $commonSrcFilesArg --out "$kotlinBuildFile" && ` +
@@ -42,7 +42,7 @@
 			` -P plugin:org.jetbrains.kotlin.jvm.abi:outputDir=$headerClassesDir && ` +
 			`${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir -write_if_changed && ` +
 			`${config.SoongZipCmd} -jar -o $headerJar -C $headerClassesDir -D $headerClassesDir -write_if_changed && ` +
-			`rm -rf "$srcJarDir"`,
+			`rm -rf "$srcJarDir" "$classesDir" "$headerClassesDir"`,
 		CommandDeps: []string{
 			"${config.KotlincCmd}",
 			"${config.KotlinCompilerJar}",
@@ -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 40ef484..c79f6e7 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
 
@@ -117,18 +122,18 @@
 }
 
 type LintDepSets struct {
-	HTML, Text, XML *android.DepSet
+	HTML, Text, XML *android.DepSet[android.Path]
 }
 
 type LintDepSetsBuilder struct {
-	HTML, Text, XML *android.DepSetBuilder
+	HTML, Text, XML *android.DepSetBuilder[android.Path]
 }
 
 func NewLintDepSetBuilder() LintDepSetsBuilder {
 	return LintDepSetsBuilder{
-		HTML: android.NewDepSetBuilder(android.POSTORDER),
-		Text: android.NewDepSetBuilder(android.POSTORDER),
-		XML:  android.NewDepSetBuilder(android.POSTORDER),
+		HTML: android.NewDepSetBuilder[android.Path](android.POSTORDER),
+		Text: android.NewDepSetBuilder[android.Path](android.POSTORDER),
+		XML:  android.NewDepSetBuilder[android.Path](android.POSTORDER),
 	}
 }
 
@@ -314,25 +319,19 @@
 	cmd.FlagWithInput("@",
 		android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
 
-	if l.compileSdkKind == android.SdkPublic {
-		cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
-	} else {
-		// TODO(b/268261262): Remove this branch. We're demoting NewApi to a warning due to pre-existing issues that need to be fixed.
-		cmd.FlagForEachArg("--warning_check ", l.extraMainlineLintErrors)
-	}
+	cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
 	cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
 	cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
 	cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
 	cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
 
-	// TODO(b/193460475): Re-enable strict updatability linting
-	//if l.GetStrictUpdatabilityLinting() {
-	//	// Verify the module does not baseline issues that endanger safe updatability.
-	//	if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
-	//		cmd.FlagWithInput("--baseline ", baselinePath.Path())
-	//		cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
-	//	}
-	//}
+	if l.GetStrictUpdatabilityLinting() {
+		// Verify the module does not baseline issues that endanger safe updatability.
+		if l.properties.Lint.Baseline_filename != nil {
+			cmd.FlagWithInput("--baseline ", android.PathForModuleSrc(ctx, *l.properties.Lint.Baseline_filename))
+			cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
+		}
+	}
 
 	return lintPaths{
 		projectXML: projectXMLPath,
@@ -352,33 +351,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 +400,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 +435,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 +478,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 +496,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 +505,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,12 +542,16 @@
 	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 {
-	htmlList := depSets.HTML.ToSortedList()
-	textList := depSets.Text.ToSortedList()
-	xmlList := depSets.XML.ToSortedList()
+	htmlList := android.SortedUniquePaths(depSets.HTML.ToList())
+	textList := android.SortedUniquePaths(depSets.Text.ToList())
+	xmlList := android.SortedUniquePaths(depSets.XML.ToList())
 
 	if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
 		return nil
@@ -654,7 +650,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.
@@ -705,7 +701,7 @@
 var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
 
 func init() {
-	android.RegisterSingletonType("lint",
+	android.RegisterParallelSingletonType("lint",
 		func() android.Singleton { return &lintSingleton{} })
 
 	registerLintBuildComponents(android.InitRegistrationContext)
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
index 1bb4996..b8ce95c 100644
--- a/java/lint_defaults.txt
+++ b/java/lint_defaults.txt
@@ -122,3 +122,17 @@
 --warning_check RemoteViewLayout
 --warning_check SupportAnnotationUsage
 --warning_check UniqueConstants
+--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
+--warning_check ForegroundServicePermission
+--warning_check ObsoleteSdkInt
+--warning_check ScheduleExactAlarm
+--warning_check StartActivityAndCollapseDeprecated
+--warning_check UnspecifiedRegisterReceiverFlag
+--warning_check WearMaterialTheme
+--warning_check WearStandaloneAppFlag
diff --git a/java/lint_test.go b/java/lint_test.go
index ec901aa..b51753f 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,14 +86,13 @@
 
 	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")
 	}
 
-	if !strings.Contains(*sboxProto.Commands[0].Command, "--warning_check NewApi") {
-		// TODO(b/268261262): Change this to check for --error_check
-		t.Error("should check NewApi warnings")
+	if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check NewApi") {
+		t.Error("should check NewApi errors")
 	}
 
 	if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check SomeCheck") {
@@ -175,52 +152,55 @@
 	}
 }
 
-// TODO(b/193460475): Re-enable this test
-//func TestJavaLintStrictUpdatabilityLinting(t *testing.T) {
-//	bp := `
-//		java_library {
-//			name: "foo",
-//			srcs: [
-//				"a.java",
-//			],
-//			static_libs: ["bar"],
-//			min_sdk_version: "29",
-//			sdk_version: "current",
-//			lint: {
-//				strict_updatability_linting: true,
-//			},
-//		}
-//
-//		java_library {
-//			name: "bar",
-//			srcs: [
-//				"a.java",
-//			],
-//			min_sdk_version: "29",
-//			sdk_version: "current",
-//		}
-//	`
-//	fs := android.MockFS{
-//		"lint-baseline.xml": nil,
-//	}
-//
-//	result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules, fs.AddToFixture()).
-//		RunTestWithBp(t, bp)
-//
-//	foo := result.ModuleForTests("foo", "android_common")
-//	sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
-//	if !strings.Contains(*sboxProto.Commands[0].Command,
-//		"--baseline lint-baseline.xml --disallowed_issues NewApi") {
-//		t.Error("did not restrict baselining NewApi")
-//	}
-//
-//	bar := result.ModuleForTests("bar", "android_common")
-//	sboxProto = android.RuleBuilderSboxProtoForTests(t, bar.Output("lint.sbox.textproto"))
-//	if !strings.Contains(*sboxProto.Commands[0].Command,
-//		"--baseline lint-baseline.xml --disallowed_issues NewApi") {
-//		t.Error("did not restrict baselining NewApi")
-//	}
-//}
+func TestJavaLintStrictUpdatabilityLinting(t *testing.T) {
+	bp := `
+		java_library {
+			name: "foo",
+			srcs: [
+				"a.java",
+			],
+			static_libs: ["bar"],
+			min_sdk_version: "29",
+			sdk_version: "current",
+			lint: {
+				strict_updatability_linting: true,
+				baseline_filename: "lint-baseline.xml",
+			},
+		}
+
+		java_library {
+			name: "bar",
+			srcs: [
+				"a.java",
+			],
+			min_sdk_version: "29",
+			sdk_version: "current",
+			lint: {
+				baseline_filename: "lint-baseline.xml",
+			}
+		}
+	`
+	fs := android.MockFS{
+		"lint-baseline.xml": nil,
+	}
+
+	result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules, fs.AddToFixture()).
+		RunTestWithBp(t, bp)
+
+	foo := result.ModuleForTests("foo", "android_common")
+	sboxProto := android.RuleBuilderSboxProtoForTests(t, result.TestContext, foo.Output("lint.sbox.textproto"))
+	if !strings.Contains(*sboxProto.Commands[0].Command,
+		"--baseline lint-baseline.xml --disallowed_issues NewApi") {
+		t.Error("did not restrict baselining NewApi")
+	}
+
+	bar := result.ModuleForTests("bar", "android_common")
+	sboxProto = android.RuleBuilderSboxProtoForTests(t, result.TestContext, bar.Output("lint.sbox.textproto"))
+	if !strings.Contains(*sboxProto.Commands[0].Command,
+		"--baseline lint-baseline.xml --disallowed_issues NewApi") {
+		t.Error("did not restrict baselining NewApi")
+	}
+}
 
 func TestJavaLintDatabaseSelectionFull(t *testing.T) {
 	testCases := []struct {
@@ -276,9 +256,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 07fb92c..4db426e 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -26,7 +26,7 @@
 }
 
 func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) {
-	ctx.RegisterSingletonModuleType("platform_bootclasspath", platformBootclasspathFactory)
+	ctx.RegisterParallelSingletonModuleType("platform_bootclasspath", platformBootclasspathFactory)
 }
 
 // The tags used for the dependencies between the platform bootclasspath and any configured boot
@@ -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) {
@@ -113,7 +121,7 @@
 }
 
 func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) {
-	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+	if ctx.Config().DisableHiddenApiChecks() {
 		return
 	}
 
@@ -123,16 +131,24 @@
 }
 
 func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
-	// Add dependencies on all the modules configured in the "art" boot image.
-	artImageConfig := genBootImageConfigs(ctx)[artBootImageName]
-	addDependenciesOntoBootImageModules(ctx, artImageConfig.modules, platformBootclasspathArtBootJarDepTag)
+	// 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 module configured in the "boot" boot image. That does
-	// not include modules configured in the "art" boot image.
+	// Add dependencies on all the non-updatable jars, which are on the platform or in non-updatable
+	// APEXes.
 	addDependenciesOntoBootImageModules(ctx, b.platformJars(ctx), platformBootclasspathBootJarDepTag)
 
-	// Add dependencies on all the apex jars.
+	// 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,9 +213,6 @@
 
 	bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments)
 	buildRuleForBootJarsPackageCheck(ctx, bootDexJarByModule)
-
-	b.generateBootImageBuildActions(ctx)
-	b.copyApexBootJarsForAppsDexpreopt(ctx, apexModules)
 }
 
 // Generate classpaths.proto config
@@ -205,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)
 		}
@@ -218,7 +243,8 @@
 }
 
 func (b *platformBootclasspathModule) platformJars(ctx android.PathContext) android.ConfiguredJarList {
-	return defaultBootImageConfig(ctx).modules.RemoveList(artBootImageConfig(ctx).modules)
+	global := dexpreopt.GetGlobalConfig(ctx)
+	return global.BootJars.RemoveList(global.ArtApexJars)
 }
 
 // checkPlatformModules ensures that the non-updatable modules supplied are not part of an
@@ -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
@@ -275,10 +301,10 @@
 
 	bootDexJarByModule := extractBootDexJarsFromModules(ctx, modules)
 
-	// Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true. This is a performance
+	// Don't run any hiddenapi rules if hidden api checks are disabled. This is a performance
 	// optimization that can be used to reduce the incremental build time but as its name suggests it
 	// can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath.
-	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+	if ctx.Config().DisableHiddenApiChecks() {
 		paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV}
 		for _, path := range paths {
 			ctx.Build(pctx, android.BuildParams{
@@ -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,79 +424,3 @@
 	// INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/.
 	ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", b.hiddenAPIFlagsCSV.String())
 }
-
-// generateBootImageBuildActions generates ninja rules related to the boot image creation.
-func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext) {
-	// Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
-	// GenerateSingletonBuildActions method as it cannot create it for itself.
-	dexpreopt.GetGlobalSoongConfig(ctx)
-
-	global := dexpreopt.GetGlobalConfig(ctx)
-	if !shouldBuildBootImages(ctx.Config(), global) {
-		return
-	}
-
-	frameworkBootImageConfig := defaultBootImageConfig(ctx)
-	bootFrameworkProfileRule(ctx, frameworkBootImageConfig)
-	b.generateBootImage(ctx, frameworkBootImageName)
-	b.generateBootImage(ctx, mainlineBootImageName)
-	dumpOatRules(ctx, frameworkBootImageConfig)
-}
-
-func (b *platformBootclasspathModule) generateBootImage(ctx android.ModuleContext, imageName string) {
-	imageConfig := genBootImageConfigs(ctx)[imageName]
-
-	modules := b.getModulesForImage(ctx, imageConfig)
-
-	// Copy module dex jars to their predefined locations.
-	bootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, modules)
-	copyBootJarsToPredefinedLocations(ctx, bootDexJarsByModule, imageConfig.dexPathsByModule)
-
-	// Build a profile for the image config and then use that to build the boot image.
-	profile := bootImageProfileRule(ctx, imageConfig)
-
-	// If dexpreopt of boot image jars should be skipped, generate only a profile.
-	global := dexpreopt.GetGlobalConfig(ctx)
-	if global.DisablePreoptBootImages {
-		return
-	}
-
-	// Build boot image files for the android variants.
-	androidBootImageFiles := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile)
-
-	// Zip the android variant boot image files up.
-	buildBootImageZipInPredefinedLocation(ctx, imageConfig, androidBootImageFiles.byArch)
-
-	// Build boot image files for the host variants. There are use directly by ART host side tests.
-	buildBootImageVariantsForBuildOs(ctx, imageConfig, profile)
-}
-
-// 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)
-}
-
-func (b *platformBootclasspathModule) getModulesForImage(ctx android.ModuleContext, imageConfig *bootImageConfig) []android.Module {
-	modules := make([]android.Module, 0, imageConfig.modules.Len())
-	for i := 0; i < imageConfig.modules.Len(); i++ {
-		found := false
-		for _, module := range b.configuredModules {
-			name := android.RemoveOptionalPrebuiltPrefix(module.Name())
-			if name == imageConfig.modules.Jar(i) {
-				modules = append(modules, module)
-				found = true
-				break
-			}
-		}
-		if !found && !ctx.Config().AllowMissingDependencies() {
-			ctx.ModuleErrorf(
-				"Boot image '%s' module '%s' not added as a dependency of platform_bootclasspath",
-				imageConfig.name,
-				imageConfig.modules.Jar(i))
-			return []android.Module{}
-		}
-	}
-	return modules
-}
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 d417291..2197304 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -36,7 +36,7 @@
 }
 
 func registerPlatformCompatConfigBuildComponents(ctx android.RegistrationContext) {
-	ctx.RegisterSingletonType("platform_compat_config_singleton", platformCompatConfigSingletonFactory)
+	ctx.RegisterParallelSingletonType("platform_compat_config_singleton", platformCompatConfigSingletonFactory)
 	ctx.RegisterModuleType("platform_compat_config", PlatformCompatConfigFactory)
 	ctx.RegisterModuleType("prebuilt_platform_compat_config", prebuiltCompatConfigFactory)
 	ctx.RegisterModuleType("global_compat_config", globalCompatConfigFactory)
diff --git a/java/plugin.go b/java/plugin.go
index 731dfda..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,35 +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 := p.convertLibraryAttrsBp2Build(ctx)
-	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 0740467..94e9c6c 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,7 +127,6 @@
 func prebuiltApiModuleName(mctx android.LoadHookContext, module, scope, version string) string {
 	return fmt.Sprintf("%s_%s_%s_%s", mctx.ModuleName(), scope, version, module)
 }
-
 func createImport(mctx android.LoadHookContext, module, scope, version, path, sdkVersion string, compileDex bool) {
 	props := struct {
 		Name        *string
@@ -111,13 +134,13 @@
 		Sdk_version *string
 		Installable *bool
 		Compile_dex *bool
-	}{}
-	props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, version))
-	props.Jars = append(props.Jars, path)
-	props.Sdk_version = proptools.StringPtr(sdkVersion)
-	props.Installable = proptools.BoolPtr(false)
-	props.Compile_dex = proptools.BoolPtr(compileDex)
-
+	}{
+		Name:        proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, version)),
+		Jars:        []string{path},
+		Sdk_version: proptools.StringPtr(sdkVersion),
+		Installable: proptools.BoolPtr(false),
+		Compile_dex: proptools.BoolPtr(compileDex),
+	}
 	mctx.CreateModule(ImportFactory, &props)
 }
 
@@ -237,29 +260,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
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..e362003
--- /dev/null
+++ b/java/ravenwood.go
@@ -0,0 +1,191 @@
+// 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/proptools"
+)
+
+func init() {
+	RegisterRavenwoodBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterRavenwoodBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("android_ravenwood_test", ravenwoodTestFactory)
+	ctx.RegisterModuleType("android_ravenwood_libgroup", ravenwoodLibgroupFactory)
+}
+
+var ravenwoodTag = dependencyTag{name: "ravenwood"}
+
+const ravenwoodUtilsName = "ravenwood-utils"
+const ravenwoodRuntimeName = "ravenwood-runtime"
+
+type ravenwoodTest struct {
+	Library
+
+	testProperties testProperties
+	testConfig     android.Path
+
+	forceOSType   android.OsType
+	forceArchType android.ArchType
+}
+
+func ravenwoodTestFactory() android.Module {
+	module := &ravenwoodTest{}
+
+	module.addHostAndDeviceProperties()
+	module.AddProperties(&module.testProperties)
+
+	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, ravenwoodTag, ravenwoodRuntimeName)
+
+	// Directly depend on any utils so that we link against them
+	utils := ctx.AddVariationDependencies(nil, ravenwoodTag, ravenwoodUtilsName)[0]
+	if utils != nil {
+		for _, lib := range utils.(*ravenwoodLibgroup).ravenwoodLibgroupProperties.Libs {
+			ctx.AddVariationDependencies(nil, libTag, 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 dependancies
+	var installDeps android.InstallPaths
+	for _, dep := range ctx.GetDirectDepsWithTag(ravenwoodTag) {
+		for _, installFile := range dep.FilesToInstall() {
+			installDeps = append(installDeps, installFile)
+		}
+	}
+
+	// Also depend on our config
+	installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
+	installConfig := ctx.InstallFile(installPath, ctx.ModuleName()+".config", r.testConfig)
+	installDeps = append(installDeps, installConfig)
+
+	// Finally 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
+}
+
+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, ravenwoodTag, lib)
+	}
+}
+
+func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	r.forceOSType = ctx.Config().BuildOS
+	r.forceArchType = ctx.Config().BuildArch
+
+	// Install our runtime into expected location for packaging
+	installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
+	for _, lib := range r.ravenwoodLibgroupProperties.Libs {
+		libModule := ctx.GetDirectDepWithTag(lib, ravenwoodTag)
+		libJar := android.OutputFileForModule(ctx, libModule, "")
+		ctx.InstallFile(installPath, lib+".jar", libJar)
+	}
+
+	// Normal build should perform install steps
+	ctx.Phony(r.BaseModuleName(), android.PathForPhony(ctx, r.BaseModuleName()+"-install"))
+}
diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go
new file mode 100644
index 0000000..2443ea8
--- /dev/null
+++ b/java/ravenwood_test.go
@@ -0,0 +1,122 @@
+// 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", `
+		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",
+			],
+		}
+		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-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")
+	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, `
+		android_ravenwood_test {
+			name: "ravenwood-test",
+			srcs: ["Test.java"],
+			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")
+
+	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")
+
+	// 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-utils/framework-rules.ravenwood.jar")
+}
diff --git a/java/resourceshrinker.go b/java/resourceshrinker.go
deleted file mode 100644
index 6d59601..0000000
--- a/java/resourceshrinker.go
+++ /dev/null
@@ -1,43 +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{
-		Command:     `${config.ResourceShrinkerCmd} --output $out --input $in --raw_resources $raw_resources`,
-		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 f394006..9e8850c 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -35,7 +35,7 @@
 
 var robolectricDefaultLibs = []string{
 	"mockito-robolectric-prebuilt",
-	"truth-prebuilt",
+	"truth",
 	// TODO(ccross): this is not needed at link time
 	"junitxml",
 }
@@ -67,7 +67,7 @@
 	// 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
 }
@@ -145,29 +145,37 @@
 	roboTestConfig := android.PathForModuleGen(ctx, "robolectric").
 		Join(ctx, "com/android/tools/test_config.properties")
 
+	var ok bool
+	var instrumentedApp *AndroidApp
+
 	// TODO: this inserts paths to built files into the test, it should really be inserting the contents.
 	instrumented := ctx.GetDirectDepsWithTag(instrumentationForTag)
 
-	if len(instrumented) != 1 {
+	if len(instrumented) == 1 {
+		instrumentedApp, ok = instrumented[0].(*AndroidApp)
+		if !ok {
+			ctx.PropertyErrorf("instrumentation_for", "dependency must be an android_app")
+		}
+	} else if !ctx.Config().AllowMissingDependencies() {
 		panic(fmt.Errorf("expected exactly 1 instrumented dependency, got %d", len(instrumented)))
 	}
 
-	instrumentedApp, ok := instrumented[0].(*AndroidApp)
-	if !ok {
-		ctx.PropertyErrorf("instrumentation_for", "dependency must be an android_app")
+	if instrumentedApp != nil {
+		r.manifest = instrumentedApp.mergedManifestFile
+		r.resourceApk = instrumentedApp.outputFile
+
+		generateRoboTestConfig(ctx, roboTestConfig, instrumentedApp)
+		r.extraResources = android.Paths{roboTestConfig}
 	}
 
-	r.manifest = instrumentedApp.mergedManifestFile
-	r.resourceApk = instrumentedApp.outputFile
-
-	generateRoboTestConfig(ctx, roboTestConfig, instrumentedApp)
-	r.extraResources = android.Paths{roboTestConfig}
-
 	r.Library.GenerateAndroidBuildActions(ctx)
 
 	roboSrcJar := android.PathForModuleGen(ctx, "robolectric", ctx.ModuleName()+".srcjar")
-	r.generateRoboSrcJar(ctx, roboSrcJar, instrumentedApp)
-	r.roboSrcJar = roboSrcJar
+
+	if instrumentedApp != nil {
+		r.generateRoboSrcJar(ctx, roboSrcJar, instrumentedApp)
+		r.roboSrcJar = roboSrcJar
+	}
 
 	roboTestConfigJar := android.PathForModuleOut(ctx, "robolectric_samedir", "samedir_config.jar")
 	generateSameDirRoboTestConfigJar(ctx, roboTestConfigJar)
@@ -178,11 +186,14 @@
 		// once the Make test runner is removed.
 		roboTestConfigJar,
 		r.outputFile,
-		instrumentedApp.implementationAndResourcesJar,
+	}
+
+	if instrumentedApp != nil {
+		combinedJarJars = append(combinedJarJars, instrumentedApp.implementationAndResourcesJar)
 	}
 
 	handleLibDeps := func(dep android.Module) {
-		m := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+		m, _ := android.OtherModuleProvider(ctx, dep, JavaInfoProvider)
 		r.libs = append(r.libs, ctx.OtherModuleName(dep))
 		if !android.InList(ctx.OtherModuleName(dep), config.FrameworkLibraries) {
 			combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars...)
@@ -214,21 +225,28 @@
 		r.tests = append(r.tests, s)
 	}
 
-	r.data = append(r.data, r.manifest, r.resourceApk)
+	installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
+	var installDeps android.InstallPaths
+
+	if r.manifest != nil {
+		r.data = append(r.data, r.manifest)
+		installedManifest := ctx.InstallFile(installPath, ctx.ModuleName()+"-AndroidManifest.xml", r.manifest)
+		installDeps = append(installDeps, installedManifest)
+	}
+
+	if r.resourceApk != nil {
+		r.data = append(r.data, r.resourceApk)
+		installedResourceApk := ctx.InstallFile(installPath, ctx.ModuleName()+".apk", r.resourceApk)
+		installDeps = append(installDeps, installedResourceApk)
+	}
 
 	runtimes := ctx.GetDirectDepWithTag("robolectric-android-all-prebuilts", roboRuntimesTag)
-
-	installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
-
-	installedResourceApk := ctx.InstallFile(installPath, ctx.ModuleName()+".apk", r.resourceApk)
-	installedManifest := ctx.InstallFile(installPath, ctx.ModuleName()+"-AndroidManifest.xml", r.manifest)
-	installedConfig := ctx.InstallFile(installPath, ctx.ModuleName()+".config", r.testConfig)
-
-	var installDeps android.Paths
 	for _, runtime := range runtimes.(*robolectricRuntimes).runtimes {
 		installDeps = append(installDeps, runtime)
 	}
-	installDeps = append(installDeps, installedResourceApk, installedManifest, installedConfig)
+
+	installedConfig := ctx.InstallFile(installPath, ctx.ModuleName()+".config", r.testConfig)
+	installDeps = append(installDeps, installedConfig)
 
 	for _, data := range android.PathsForModuleSrc(ctx, r.testProperties.Data) {
 		installedData := ctx.InstallFile(installPath, data.Rel(), data)
@@ -236,7 +254,7 @@
 	}
 
 	r.installFile = ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...)
-	ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+	android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath,
@@ -283,12 +301,11 @@
 func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFile android.WritablePath,
 	instrumentedApp *AndroidApp) {
 
-	srcJarArgs := copyOf(instrumentedApp.srcJarArgs)
+	srcJarArgs := android.CopyOf(instrumentedApp.srcJarArgs)
 	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...)
 		}
@@ -342,7 +359,9 @@
 	fmt.Fprintln(w, "LOCAL_MODULE :=", name)
 	android.AndroidMkEmitAssignList(w, "LOCAL_JAVA_LIBRARIES", []string{module}, r.libs)
 	fmt.Fprintln(w, "LOCAL_TEST_PACKAGE :=", String(r.robolectricProperties.Instrumentation_for))
-	fmt.Fprintln(w, "LOCAL_INSTRUMENT_SRCJARS :=", r.roboSrcJar.String())
+	if r.roboSrcJar != nil {
+		fmt.Fprintln(w, "LOCAL_INSTRUMENT_SRCJARS :=", r.roboSrcJar.String())
+	}
 	android.AndroidMkEmitAssignList(w, "LOCAL_ROBOTEST_FILES", tests)
 	if t := r.robolectricProperties.Test_options.Timeout; t != nil {
 		fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t)
diff --git a/java/rro.go b/java/rro.go
index 53faca0..3e0f8e9 100644
--- a/java/rro.go
+++ b/java/rro.go
@@ -146,7 +146,13 @@
 		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,
+		},
+	)
 
 	// Sign the built package
 	_, _, certificates := collectAppDeps(ctx, r, false, false)
diff --git a/java/rro_test.go b/java/rro_test.go
index 8067a47..c4a4d04 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
diff --git a/java/sdk.go b/java/sdk.go
index 8b4918a..81be991 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,12 +25,10 @@
 )
 
 func init() {
-	android.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory)
-	android.RegisterSingletonType("sdk", sdkSingletonFactory)
+	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")
@@ -51,9 +47,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 +70,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
@@ -148,10 +143,10 @@
 	toModule := func(module string, aidl android.Path) sdkDep {
 		// Select the kind of system modules needed for the sdk version.
 		systemModulesKind := systemModuleKind(sdkVersion.Kind, android.FutureApiLevel)
-		systemModules := android.JavaApiLibraryName(ctx.Config(), fmt.Sprintf("core-%s-stubs-system-modules", systemModulesKind))
+		systemModules := fmt.Sprintf("core-%s-stubs-system-modules", systemModulesKind)
 		return sdkDep{
 			useModule:          true,
-			bootclasspath:      []string{module, android.JavaApiLibraryName(ctx.Config(), config.DefaultLambdaStubsLibrary)},
+			bootclasspath:      []string{module, config.DefaultLambdaStubsLibrary},
 			systemModules:      systemModules,
 			java9Classpath:     []string{module},
 			frameworkResModule: "framework-res",
@@ -192,64 +187,26 @@
 			bootclasspath:    corePlatformBootclasspathLibraries(ctx),
 			noFrameworksLibs: true,
 		}
-	case android.SdkPublic, android.SdkSystem, android.SdkTest:
-		return toModule(sdkVersion.Kind.JavaLibraryName(ctx.Config()), sdkFrameworkAidlPath(ctx))
+	case android.SdkPublic, android.SdkSystem, android.SdkTest, android.SdkTestFrameworksCore:
+		return toModule(sdkVersion.Kind.DefaultJavaLibraryName(), sdkFrameworkAidlPath(ctx))
 	case android.SdkCore:
 		return sdkDep{
 			useModule:        true,
-			bootclasspath:    []string{android.SdkCore.JavaLibraryName(ctx.Config()), android.JavaApiLibraryName(ctx.Config(), config.DefaultLambdaStubsLibrary)},
-			systemModules:    android.JavaApiLibraryName(ctx.Config(), "core-public-stubs-system-modules"),
+			bootclasspath:    []string{android.SdkCore.DefaultJavaLibraryName(), config.DefaultLambdaStubsLibrary},
+			systemModules:    "core-public-stubs-system-modules",
 			noFrameworksLibs: true,
 		}
 	case android.SdkModule:
 		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
-		return toModule(sdkVersion.Kind.JavaLibraryName(ctx.Config()), nonUpdatableFrameworkAidlPath(ctx))
+		return toModule(sdkVersion.Kind.DefaultJavaLibraryName(), nonUpdatableFrameworkAidlPath(ctx))
 	case android.SdkSystemServer:
 		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
-		return toModule(sdkVersion.Kind.JavaLibraryName(ctx.Config()), sdkFrameworkAidlPath(ctx))
+		return toModule(sdkVersion.Kind.DefaultJavaLibraryName(), sdkFrameworkAidlPath(ctx))
 	default:
 		panic(fmt.Errorf("invalid sdk %q", sdkVersion.Raw))
 	}
 }
 
-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{}
 }
@@ -269,9 +226,9 @@
 // Create framework.aidl by extracting anything that implements android.os.Parcelable from the SDK stubs modules.
 func createSdkFrameworkAidl(ctx android.SingletonContext) {
 	stubsModules := []string{
-		android.SdkPublic.JavaLibraryName(ctx.Config()),
-		android.SdkTest.JavaLibraryName(ctx.Config()),
-		android.SdkSystem.JavaLibraryName(ctx.Config()),
+		android.SdkPublic.DefaultJavaLibraryName(),
+		android.SdkTest.DefaultJavaLibraryName(),
+		android.SdkSystem.DefaultJavaLibraryName(),
 	}
 
 	combinedAidl := sdkFrameworkAidlPath(ctx)
@@ -286,7 +243,7 @@
 
 // Creates a version of framework.aidl for the non-updatable part of the platform.
 func createNonUpdatableFrameworkAidl(ctx android.SingletonContext) {
-	stubsModules := []string{android.SdkModule.JavaLibraryName(ctx.Config())}
+	stubsModules := []string{android.SdkModule.DefaultJavaLibraryName()}
 
 	combinedAidl := nonUpdatableFrameworkAidlPath(ctx)
 	tempPath := tempPathForRestat(ctx, combinedAidl)
@@ -303,8 +260,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
diff --git a/java/sdk_library.go b/java/sdk_library.go
index d461882..49e6727 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"errors"
 	"fmt"
 	"path"
 	"path/filepath"
@@ -28,7 +29,6 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/dexpreopt"
 )
 
@@ -105,8 +105,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
@@ -156,6 +162,9 @@
 
 	// Whether the api scope can be treated as unstable, and should skip compat checks.
 	unstable bool
+
+	// Represents the SDK kind of this scope.
+	kind android.SdkKind
 }
 
 // Initialize a scope, creating and adding appropriate dependency tags
@@ -165,11 +174,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,
@@ -229,10 +248,30 @@
 	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"
+}
+
+func (scope *apiScope) sourceStubLibraryModuleName(baseName string) string {
+	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
 }
@@ -273,6 +312,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
@@ -289,6 +339,7 @@
 			return &module.sdkLibraryProperties.Public
 		},
 		sdkVersion: "current",
+		kind:       android.SdkPublic,
 	})
 	apiScopeSystem = initApiScope(&apiScope{
 		name:                "system",
@@ -301,6 +352,7 @@
 		moduleSuffix:  ".system",
 		sdkVersion:    "system_current",
 		annotation:    "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS)",
+		kind:          android.SdkSystem,
 	})
 	apiScopeTest = initApiScope(&apiScope{
 		name:                "test",
@@ -314,6 +366,7 @@
 		sdkVersion:    "test_current",
 		annotation:    "android.annotation.TestApi",
 		unstable:      true,
+		kind:          android.SdkTest,
 	})
 	apiScopeModuleLib = initApiScope(&apiScope{
 		name:    "module-lib",
@@ -331,6 +384,7 @@
 		moduleSuffix:  ".module_lib",
 		sdkVersion:    "module_current",
 		annotation:    "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES)",
+		kind:          android.SdkModule,
 	})
 	apiScopeSystemServer = initApiScope(&apiScope{
 		name:    "system-server",
@@ -361,6 +415,7 @@
 			// com.android.* classes are okay in this interface"
 			"--hide", "InternalClasses",
 		},
+		kind: android.SdkSystemServer,
 	})
 	allApiScopes = apiScopes{
 		apiScopePublic,
@@ -369,6 +424,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 (
@@ -424,6 +496,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 {
@@ -569,8 +644,19 @@
 	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
@@ -600,6 +686,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
 
@@ -620,63 +711,120 @@
 }
 
 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)
 	})
 }
 
@@ -839,6 +987,12 @@
 	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.BaseModuleName()
+	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 {
@@ -846,6 +1000,27 @@
 	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()
+	return c.namingScheme.apiLibraryModuleName(apiScope, baseName)
+}
+
+// Name of the java_library module that compiles the stubs
+// generated from source Java files.
+func (c *commonToSdkLibraryAndImport) sourceStubsLibraryModuleName(apiScope *apiScope) string {
+	baseName := c.module.BaseModuleName()
+	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.BaseModuleName()
+	return c.namingScheme.exportableSourceStubsLibraryModuleName(apiScope, baseName)
+}
+
 // The component names for different outputs of the java_sdk_library.
 //
 // They are similar to the names used for the child modules it creates
@@ -1037,6 +1212,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)
@@ -1154,10 +1339,16 @@
 	// 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
 
@@ -1168,8 +1359,6 @@
 type SdkLibrary struct {
 	Library
 
-	android.BazelModuleBase
-
 	sdkLibraryProperties sdkLibraryProperties
 
 	// Map from api scope to the scope specific property structure.
@@ -1272,9 +1461,10 @@
 	for _, apiScope := range module.getGeneratedApiScopes(ctx) {
 		// Add dependencies to the stubs library
 		stubModuleName := module.stubsLibraryModuleName(apiScope)
-		// Use JavaApiLibraryName function to be redirected to stubs generated from .txt if applicable
-		stubModuleName = android.JavaApiLibraryName(ctx.Config(), stubModuleName)
-		ctx.AddVariationDependencies(nil, apiScope.stubsTag, stubModuleName)
+		ctx.AddVariationDependencies(nil, apiScope.everythingStubsTag, 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))
@@ -1387,7 +1577,7 @@
 
 	// 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{}{}
@@ -1407,7 +1597,7 @@
 			scopeInfo["latest_removed_api"] = p.Path().String()
 		}
 	}
-	ctx.SetProvider(android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo})
+	android.SetProvider(ctx, android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo})
 }
 
 func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries {
@@ -1481,6 +1671,34 @@
 	return latestPrebuiltApiModuleName(module.distStem()+"-incompatibilities", apiScope)
 }
 
+func (module *SdkLibrary) contributesToApiSurface(c android.Config) bool {
+	_, exists := c.GetApiLibraries()[module.Name()]
+	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.
@@ -1534,42 +1752,41 @@
 	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
+	}
+}
 
-	props.Name = proptools.StringPtr(module.stubsLibraryModuleName(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.
@@ -1582,20 +1799,24 @@
 	// interop with older developer tools that don't support 1.9.
 	props.Java_version = proptools.StringPtr("1.8")
 
-	// The imports need to be compiled to dex if the java_sdk_library requests it.
-	compileDex := module.dexProperties.Compile_dex
-	if module.stubLibrariesCompiledForDex() {
-		compileDex = proptools.BoolPtr(true)
-	}
-	props.Compile_dex = compileDex
+	return props
+}
 
-	// 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")
-	}
+// 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())
 }
@@ -1621,6 +1842,7 @@
 		Merge_inclusion_annotations_dirs []string
 		Generate_stubs                   *bool
 		Previous_api                     *string
+		Aconfig_declarations             []string
 		Check_api                        struct {
 			Current       ApiToCheck
 			Last_released ApiToCheck
@@ -1657,6 +1879,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
@@ -1664,6 +1887,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 {
@@ -1674,36 +1898,18 @@
 			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 "))
 
-	droidstubsFiles := append([]string{}, module.sdkLibraryProperties.Droiddoc_option_files...)
-
-	// If requested hide the flagged APIs from the output of metalava. This
-	// should be implemented in the module SDK snapshot code by depending on
-	// special metalava rules that hide the flagged APIs but that will take
-	// lots of work. In the meantime, this is a temporary workaround that
-	// can and will only be used when building module SDK snapshots. This
-	// delegates the decision as to what options are passed to metalava to
-	// the "sdkext-released-flagged-apis" module by using metalava's support
-	// for expanding an argument of the form "@<file>" to the list of
-	// arguments found in <file>.
-	if mctx.Config().GetenvWithDefault("SOONG_SDK_SNAPSHOT_HIDE_FLAGGED_APIS", "false") == "true" {
-		metalavaHideFlaggedApisSource := ":sdkext-released-flagged-apis"
-		droidstubsArgs = append(droidstubsArgs,
-			fmt.Sprintf("@$(location %s)", metalavaHideFlaggedApisSource))
-		droidstubsFiles = append(droidstubsFiles, metalavaHideFlaggedApisSource)
-	}
-
 	// Output Javadoc comments for public scope.
 	if apiScope == apiScopePublic {
 		props.Output_javadoc_comments = proptools.BoolPtr(true)
@@ -1711,7 +1917,7 @@
 
 	// Add in scope specific arguments.
 	droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...)
-	props.Arg_files = droidstubsFiles
+	props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
 	props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
 
 	// List of APIs identified from the provided source files are created. They are later
@@ -1776,7 +1982,126 @@
 		}
 	}
 
-	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, alternativeFullApiSurfaceStub string) {
+	props := struct {
+		Name                  *string
+		Visibility            []string
+		Api_contributions     []string
+		Libs                  []string
+		Static_libs           []string
+		Full_api_surface_stub *string
+		System_modules        *string
+		Enable_validation     *bool
+	}{}
+
+	props.Name = proptools.StringPtr(module.apiLibraryModuleName(apiScope))
+	props.Visibility = []string{"//visibility:override", "//visibility:private"}
+
+	apiContributions := []string{}
+
+	// Api surfaces are not independent of each other, but have subset relationships,
+	// and so does the api files. To generate from-text stubs for api surfaces other than public,
+	// all subset api domains' api_contriubtions must be added as well.
+	scope := apiScope
+	for scope != nil {
+		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())
+	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.
+	if apiScope.kind == android.SdkModule {
+		props.Full_api_surface_stub = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName() + "_full.from-text")
+	}
+
+	// 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)
+
+	mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
+}
+
+func (module *SdkLibrary) topLevelStubsLibraryProps(mctx android.DefaultableHookContext, apiScope *apiScope) libraryProperties {
+	props := libraryProperties{}
+
+	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
+	sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
+	props.Sdk_version = proptools.StringPtr(sdkVersion)
+
+	props.System_modules = module.deviceProperties.System_modules
+
+	// The imports need to be compiled to dex if the java_sdk_library requests it.
+	compileDex := module.dexProperties.Compile_dex
+	if module.stubLibrariesCompiledForDex() {
+		compileDex = proptools.BoolPtr(true)
+	}
+	props.Compile_dex = compileDex
+
+	return props
+}
+
+func (module *SdkLibrary) createTopLevelStubsLibrary(
+	mctx android.DefaultableHookContext, apiScope *apiScope, contributesToApiSurface bool) {
+
+	props := module.topLevelStubsLibraryProps(mctx, apiScope)
+	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) {
+
+	props := module.topLevelStubsLibraryProps(mctx, apiScope)
+	props.Name = proptools.StringPtr(module.exportableStubsLibraryModuleName(apiScope))
+
+	// Dist the class jar artifact for sdk builds.
+	// "exportable" stubs are copied to dist for sdk builds instead of the "everything" stubs.
+	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")
+	}
+
+	staticLib := module.exportableSourceStubsLibraryModuleName(apiScope)
+	props.Static_libs = append(props.Static_libs, staticLib)
+
+	mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
 }
 
 func (module *SdkLibrary) compareAgainstLatestApi(apiScope *apiScope) bool {
@@ -1797,6 +2122,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)
@@ -1813,6 +2142,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()),
@@ -1822,6 +2152,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)
@@ -1859,8 +2190,8 @@
 // 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)
 }
 
@@ -1975,6 +2306,19 @@
 		module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs)
 
 		module.createStubsLibrary(mctx, scope)
+		module.createExportableStubsLibrary(mctx, scope)
+
+		alternativeFullApiSurfaceStubLib := ""
+		if scope == apiScopePublic {
+			alternativeFullApiSurfaceStubLib = module.alternativeFullApiSurfaceStubLib()
+		}
+		contributesToApiSurface := module.contributesToApiSurface(mctx.Config()) || alternativeFullApiSurfaceStubLib != ""
+		if contributesToApiSurface {
+			module.createApiLibrary(mctx, scope, alternativeFullApiSurfaceStubLib)
+		}
+
+		module.createTopLevelStubsLibrary(mctx, scope, contributesToApiSurface)
+		module.createTopLevelExportableStubsLibrary(mctx, scope)
 	}
 
 	if module.requiresRuntimeImplementationLibrary() {
@@ -2027,6 +2371,14 @@
 	stubsLibraryModuleName(scope *apiScope, baseName string) string
 
 	stubsSourceModuleName(scope *apiScope, baseName string) string
+
+	apiLibraryModuleName(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 {
@@ -2040,27 +2392,53 @@
 	return scope.stubsSourceModuleName(baseName)
 }
 
+func (s *defaultNamingScheme) apiLibraryModuleName(scope *apiScope, baseName string) string {
+	return scope.apiLibraryModuleName(baseName)
+}
+
+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 hasStubsLibrarySuffix(name, apiScopeSystemServer) {
+		return true, javaSystemServer
+	}
 	return false, javaPlatform
 }
 
@@ -2108,48 +2486,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" {
-		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
 //
@@ -2213,7 +2552,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.
@@ -2315,6 +2655,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())
@@ -2367,7 +2711,26 @@
 	// 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
+		Api_surface *string
+		Api_file    *string
+		Visibility  []string
+	}{}
+
+	props.Name = proptools.StringPtr(module.stubsSourceModuleName(apiScope) + ".api.contribution")
+	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
@@ -2379,7 +2742,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
@@ -2403,14 +2766,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
@@ -2504,14 +2859,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
@@ -2520,16 +2879,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.
@@ -2568,16 +2924,19 @@
 }
 
 // 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)
 	}
 }
 
@@ -2660,6 +3019,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
@@ -2709,6 +3072,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.
@@ -2766,7 +3134,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.
@@ -2817,6 +3185,13 @@
 	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 {
 	libName := proptools.String(module.properties.Lib_name)
 	libNameAttr := formattedOptionalAttribute("name", &libName)
@@ -2826,6 +3201,7 @@
 	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
@@ -2859,12 +3235,14 @@
 		implicitUntilAttr,
 		minSdkAttr,
 		maxSdkAttr,
+		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)
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 1d0c13d..3326ec5 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -35,6 +35,14 @@
 			"29": {"foo"},
 			"30": {"bar", "barney", "baz", "betty", "foo", "fred", "quuz", "wilma"},
 		}),
+		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",
@@ -71,6 +79,8 @@
 		    name: "quuz",
 				public: {
 					jars: ["c.jar"],
+					current_api: "api/current.txt",
+					removed_api: "api/removed.txt",
 				},
 		}
 		java_sdk_library_import {
@@ -121,18 +131,22 @@
 	result.ModuleForTests(apiScopeSystem.stubsSourceModuleName("foo"), "android_common")
 	result.ModuleForTests(apiScopeTest.stubsSourceModuleName("foo"), "android_common")
 	result.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo")+".api.contribution", "")
+	result.ModuleForTests(apiScopePublic.apiLibraryModuleName("foo"), "android_common")
 	result.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
 	result.ModuleForTests("foo.api.public.28", "")
 	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.stubs",
+		"foo.stubs.exportable",
+		"foo.stubs.exportable.system",
+		"foo.stubs.exportable.test",
 		"foo.stubs.source",
 		"foo.stubs.source.system",
 		"foo.stubs.source.test",
@@ -169,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")
@@ -407,10 +424,9 @@
 		android.AssertStringListContainsEquals(t, "bad combined inputs for "+sdklib, combineJarInputs, depPath, combined)
 	}
 	for _, expectation := range expectations {
-		verify("sdklib", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined)
 		verify("sdklib.impl", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined)
 
-		stubName := apiScopePublic.stubsLibraryModuleName("sdklib")
+		stubName := apiScopePublic.sourceStubLibraryModuleName("sdklib")
 		verify(stubName, expectation.lib, expectation.on_stub_classpath, expectation.in_stub_combined)
 	}
 }
@@ -521,6 +537,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",
@@ -539,6 +560,7 @@
 		`sdklib.api.public.latest`,
 		`sdklib.impl`,
 		`sdklib.stubs`,
+		`sdklib.stubs.exportable`,
 		`sdklib.stubs.source`,
 		`sdklib.xml`,
 	})
@@ -911,6 +933,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",
@@ -937,11 +964,13 @@
 		`sdklib.api.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
@@ -957,6 +986,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",
@@ -1009,11 +1043,13 @@
 		`sdklib.api.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`,
@@ -1060,6 +1096,131 @@
 	})
 }
 
+// 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) {
 	partitionToBpOption := func(partition string) string {
 		switch partition {
@@ -1288,7 +1449,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))
@@ -1412,3 +1573,202 @@
 	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_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,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("foo"),
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.SetApiLibraries([]string{"foo"})
+		}),
+	).RunTestWithBp(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["a.java", "b.java"],
+			api_packages: ["foo"],
+			system: {
+				enabled: true,
+			},
+			module_lib: {
+				enabled: true,
+			},
+			test: {
+				enabled: true,
+			},
+		}
+	`)
+
+	testCases := []struct {
+		scope              *apiScope
+		apiContributions   []string
+		fullApiSurfaceStub string
+	}{
+		{
+			scope:              apiScopePublic,
+			apiContributions:   []string{"foo.stubs.source.api.contribution"},
+			fullApiSurfaceStub: "android_stubs_current",
+		},
+		{
+			scope:              apiScopeSystem,
+			apiContributions:   []string{"foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
+			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",
+		},
+		{
+			scope:              apiScopeModuleLib,
+			apiContributions:   []string{"foo.stubs.source.module_lib.api.contribution", "foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
+			fullApiSurfaceStub: "android_module_lib_stubs_current_full.from-text",
+		},
+	}
+
+	for _, c := range testCases {
+		m := result.ModuleForTests(c.scope.apiLibraryModuleName("foo"), "android_common").Module().(*ApiLibrary)
+		android.AssertArrayString(t, "Module expected to contain api contributions", c.apiContributions, m.properties.Api_contributions)
+		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").Rule("java_sdk_xml")
+
+	android.AssertStringDoesContain(t, "bar.xml java_sdk_xml command", barPermissions.RuleParams.Command, `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)
+}
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..f344648 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -55,7 +55,8 @@
 			`${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
@@ -159,7 +160,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...)
 	})
 
diff --git a/java/system_modules_test.go b/java/system_modules_test.go
index 7b5a386..2ceca5d 100644
--- a/java/system_modules_test.go
+++ b/java/system_modules_test.go
@@ -24,7 +24,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
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index 17d301b..59c5466 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 {
@@ -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
index 7f06785..4144dad 100644
--- a/java/test_spec_test.go
+++ b/java/test_spec_test.go
@@ -29,14 +29,10 @@
 	}`
 	result := runTestSpecTest(t, android.FixtureExpectsNoErrors, bp)
 
-	module := result.ModuleForTests(
-		"module-name", "",
-	).Module().(*soongTesting.TestSpecModule)
+	module := result.ModuleForTests("module-name", "")
 
 	// Check that the provider has the right contents
-	data := result.ModuleProvider(
-		module, soongTesting.TestSpecProviderKey,
-	).(soongTesting.TestSpecProviderData)
+	data, _ := android.SingletonModuleProvider(result, module.Module(), soongTesting.TestSpecProviderKey)
 	if !strings.HasSuffix(
 		data.IntermediatePath.String(), "/intermediateTestSpecMetadata.pb",
 	) {
@@ -46,13 +42,8 @@
 		)
 	}
 
-	buildParamsSlice := module.BuildParamsForTests()
-	var metadata = ""
-	for _, params := range buildParamsSlice {
-		if params.Rule.String() == "android/soong/android.writeFile" {
-			metadata = params.Args["content"]
-		}
-	}
+	metadata := android.ContentFromFileRuleForTests(t, result.TestContext,
+		module.Output(data.IntermediatePath.String()))
 
 	metadataList := make([]*test_spec_proto.TestSpec_OwnershipMetadata, 0, 2)
 	teamId := "12345"
@@ -72,9 +63,7 @@
 	}
 	testSpecMetadata := test_spec_proto.TestSpec{OwnershipMetadataList: metadataList}
 	protoData, _ := proto.Marshal(&testSpecMetadata)
-	rawData := string(protoData)
-	formattedData := strings.ReplaceAll(rawData, "\n", "\\n")
-	expectedMetadata := "'" + formattedData + "\\n'"
+	expectedMetadata := string(protoData)
 
 	if metadata != expectedMetadata {
 		t.Errorf(
@@ -122,7 +111,7 @@
 }
 
 func runTestSpecTest(
-		t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
+	t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
 ) *android.TestResult {
 	return android.GroupFixturePreparers(
 		soongTesting.PrepareForTestWithTestingBuildComponents,
diff --git a/java/testing.go b/java/testing.go
index 6671bf0..04e8c73 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -71,7 +71,17 @@
 		// Needed for framework
 		defaultJavaDir + "/framework/aidl": nil,
 		// Needed for various deps defined in GatherRequiredDepsForTest()
-		defaultJavaDir + "/a.java": nil,
+		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,
@@ -108,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.
@@ -220,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...)
 
@@ -352,6 +383,7 @@
 	RegisterSystemModulesBuildComponents(ctx)
 	registerSystemserverClasspathBuildComponents(ctx)
 	registerLintBuildComponents(ctx)
+	android.RegisterApexContributionsBuildComponents(ctx)
 }
 
 // gatherRequiredDepsForTest gathers the module definitions used by
@@ -375,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 {
@@ -394,26 +437,97 @@
 		`, 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",
+	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(`
+			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_files: ["%s"],
+                api_contributions: ["%s"],
             }
-        `, libName, apiFile)
+        `, libName, droidstubs.name+".api.contribution")
 	}
 
 	bp += `
@@ -465,10 +579,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{}
@@ -477,11 +596,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) {
@@ -494,7 +631,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())
@@ -514,7 +651,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 {
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 dee72ed..d045725 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -1027,42 +1027,42 @@
 
 license_kind {
     name: "SPDX-license-identifier-OFL",
-    conditions: ["by_exception_only"],
+    conditions: ["notice"],
 }
 
 license_kind {
     name: "SPDX-license-identifier-OFL-1.0",
-    conditions: ["by_exception_only"],
+    conditions: ["notice"],
     url: "https://spdx.org/licenses/OFL-1.0.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-OFL-1.0-RFN",
-    conditions: ["by_exception_only"],
+    conditions: ["notice"],
     url: "https://spdx.org/licenses/OFL-1.0-RFN.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-OFL-1.0-no-RFN",
-    conditions: ["by_exception_only"],
+    conditions: ["notice"],
     url: "https://spdx.org/licenses/OFL-1.0-no-RFN.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-OFL-1.1",
-    conditions: ["by_exception_only"],
+    conditions: ["notice"],
     url: "https://spdx.org/licenses/OFL-1.1.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-OFL-1.1-RFN",
-    conditions: ["by_exception_only"],
+    conditions: ["notice"],
     url: "https://spdx.org/licenses/OFL-1.1-RFN.html",
 }
 
 license_kind {
     name: "SPDX-license-identifier-OFL-1.1-no-RFN",
-    conditions: ["by_exception_only"],
+    conditions: ["notice"],
     url: "https://spdx.org/licenses/OFL-1.1-no-RFN.html",
 }
 
diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go
index 412a23b..78b62d9 100644
--- a/linkerconfig/linkerconfig.go
+++ b/linkerconfig/linkerconfig.go
@@ -22,7 +22,6 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/cc"
 	"android/soong/etc"
 )
@@ -53,7 +52,6 @@
 
 type linkerConfig struct {
 	android.ModuleBase
-	android.BazelModuleBase
 	properties linkerConfigProperties
 
 	outputFilePath android.OutputPath
@@ -102,28 +100,6 @@
 	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")
-		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) {
 
@@ -164,12 +140,11 @@
 
 // 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 77394d9..78ab771 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -163,6 +163,21 @@
 
 var identifierFullMatchRegex = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
 
+func RelativeToCwd(path string) (string, error) {
+	cwd, err := os.Getwd()
+	if err != nil {
+		return "", err
+	}
+	path, err = filepath.Rel(cwd, path)
+	if err != nil {
+		return "", err
+	}
+	if strings.HasPrefix(path, "../") {
+		return "", fmt.Errorf("Could not make path relative to current working directory: " + path)
+	}
+	return path, nil
+}
+
 // Conversion request parameters
 type Request struct {
 	MkFile          string    // file to convert
@@ -320,6 +335,14 @@
 	loadedSubConfigs := make(map[string]string)
 	for _, mi := range gctx.starScript.inherited {
 		uri := mi.path
+		if strings.HasPrefix(uri, "/") && !strings.HasPrefix(uri, "//") {
+			var err error
+			uri, err = RelativeToCwd(uri)
+			if err != nil {
+				panic(err)
+			}
+			uri = "//" + uri
+		}
 		if m, ok := loadedSubConfigs[uri]; ok {
 			// No need to emit load statement, but fix module name.
 			mi.moduleLocalName = m
@@ -612,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))
@@ -918,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/mk2rbc.go b/mk2rbc/mk2rbc/mk2rbc.go
index cc83430..08c363f 100644
--- a/mk2rbc/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc/mk2rbc.go
@@ -187,7 +187,7 @@
 			quit(fmt.Errorf("the product launcher input variables file failed to convert"))
 		}
 
-		err := writeGenerated(*launcher, mk2rbc.Launcher(outputFilePath(files[0]), outputFilePath(*inputVariables),
+		err := writeGenerated(*launcher, mk2rbc.Launcher(outputModulePath(files[0]), outputModulePath(*inputVariables),
 			mk2rbc.MakePath2ModuleName(files[0])))
 		if err != nil {
 			fmt.Fprintf(os.Stderr, "%s: %s", files[0], err)
@@ -205,7 +205,7 @@
 			quit(fmt.Errorf("the board launcher input variables file failed to convert"))
 		}
 		err := writeGenerated(*boardlauncher, mk2rbc.BoardLauncher(
-			outputFilePath(files[0]), outputFilePath(*inputVariables)))
+			outputModulePath(files[0]), outputModulePath(*inputVariables)))
 		if err != nil {
 			fmt.Fprintf(os.Stderr, "%s: %s", files[0], err)
 			ok = false
@@ -402,6 +402,15 @@
 	return path
 }
 
+func outputModulePath(mkFile string) string {
+	path := outputFilePath(mkFile)
+	path, err := mk2rbc.RelativeToCwd(path)
+	if err != nil {
+		panic(err)
+	}
+	return "//" + path
+}
+
 func writeGenerated(path string, contents string) error {
 	if err := os.MkdirAll(filepath.Dir(path), os.ModeDir|os.ModePerm); err != nil {
 		return err
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/soong_variables_test.go b/mk2rbc/soong_variables_test.go
index c883882..58e98f6 100644
--- a/mk2rbc/soong_variables_test.go
+++ b/mk2rbc/soong_variables_test.go
@@ -42,8 +42,8 @@
 		{"BUILD_ID", VarClassSoong, starlarkTypeString},
 		{"PLATFORM_SDK_VERSION", VarClassSoong, starlarkTypeInt},
 		{"DEVICE_PACKAGE_OVERLAYS", VarClassSoong, starlarkTypeList},
-		{"ENABLE_CFI", VarClassSoong, starlarkTypeBool},
-		{"ENABLE_PREOPT", VarClassSoong, starlarkTypeBool},
+		{"ENABLE_CFI", VarClassSoong, starlarkTypeString},
+		{"ENABLE_PREOPT", VarClassSoong, starlarkTypeString},
 	}}
 	if !reflect.DeepEqual(expected, actual) {
 		t.Errorf("\nExpected: %v\n  Actual: %v", expected, actual)
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/multitree/metadata.go b/multitree/metadata.go
index 3fd7215..0eb0efc 100644
--- a/multitree/metadata.go
+++ b/multitree/metadata.go
@@ -20,7 +20,7 @@
 )
 
 func init() {
-	android.RegisterSingletonType("update-meta", UpdateMetaSingleton)
+	android.RegisterParallelSingletonType("update-meta", UpdateMetaSingleton)
 }
 
 func UpdateMetaSingleton() android.Singleton {
diff --git a/phony/phony.go b/phony/phony.go
index 760b79b..b8dbd00 100644
--- a/phony/phony.go
+++ b/phony/phony.go
@@ -24,6 +24,7 @@
 
 func init() {
 	android.RegisterModuleType("phony", PhonyFactory)
+	android.RegisterModuleType("phony_rule", PhonyRuleFactory)
 }
 
 type phony struct {
@@ -52,7 +53,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 +68,48 @@
 				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
+
+	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)
+	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)
+			}
+		},
+	}
+}
diff --git a/provenance/provenance_singleton.go b/provenance/provenance_singleton.go
index fbb6212..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`,
 		})
 )
 
@@ -51,7 +53,7 @@
 }
 
 func RegisterProvenanceSingleton(ctx android.RegistrationContext) {
-	ctx.RegisterSingletonType("provenance_metadata_singleton", provenanceInfoSingletonFactory)
+	ctx.RegisterParallelSingletonType("provenance_metadata_singleton", provenanceInfoSingletonFactory)
 }
 
 var PrepareForTestWithProvenanceSingleton = android.FixtureRegisterWithContext(RegisterProvenanceSingleton)
diff --git a/python/Android.bp b/python/Android.bp
index 87810c9..14e83c1 100644
--- a/python/Android.bp
+++ b/python/Android.bp
@@ -14,7 +14,6 @@
     ],
     srcs: [
         "binary.go",
-        "bp2build.go",
         "builder.go",
         "defaults.go",
         "library.go",
diff --git a/python/binary.go b/python/binary.go
index a5db2f6..d6750c6 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}
diff --git a/python/bp2build.go b/python/bp2build.go
deleted file mode 100644
index cd3f2a1..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"])
-		protoLabel := bazel.Label{Label: ":" + protoInfo.Name}
-
-		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.MakeSingleLabelListAttribute(protoLabel),
-		})
-
-		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",
-	}
-
-	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 353cc65..d3cbd76 100644
--- a/python/python.go
+++ b/python/python.go
@@ -129,7 +129,6 @@
 type PythonLibraryModule struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
-	android.BazelModuleBase
 
 	properties      BaseProperties
 	protoProperties android.ProtoProperties
@@ -169,6 +168,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 +191,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
 }
@@ -201,7 +206,6 @@
 	p.AddProperties(&p.properties, &p.protoProperties)
 	android.InitAndroidArchModule(p, p.hod, p.multilib)
 	android.InitDefaultableModule(p)
-	android.InitBazelModule(p)
 	return p
 }
 
@@ -265,7 +269,6 @@
 			}
 			if proptools.BoolDefault(props.Version.Py2.Enabled, false) {
 				if !mctx.DeviceConfig().BuildBrokenUsesSoongPython2Modules() &&
-					mctx.ModuleName() != "par_test" &&
 					mctx.ModuleName() != "py2-cmd" &&
 					mctx.ModuleName() != "py2-stdlib" {
 					mctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3. This error can be temporarily overridden by setting BUILD_BROKEN_USES_SOONG_PYTHON2_MODULES := true in the product configuration")
@@ -371,7 +374,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 {
@@ -404,7 +420,7 @@
 // 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)
-	ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: expandedSrcs.Strings()})
+	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: expandedSrcs.Strings()})
 
 	// expand data files from "data" property.
 	expandedData := android.PathsForModuleSrc(ctx, p.properties.Data)
@@ -463,14 +479,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})
@@ -593,13 +614,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()
 			}
 		})
 	}
@@ -638,6 +662,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/test.go b/python/test.go
index 18da72a..7eb9136 100644
--- a/python/test.go
+++ b/python/test.go
@@ -40,7 +40,7 @@
 }
 
 func PythonTestHostFactory() android.Module {
-	return NewTest(android.HostSupportedNoCross).init()
+	return NewTest(android.HostSupported).init()
 }
 
 func PythonTestFactory() android.Module {
@@ -67,6 +67,10 @@
 
 	// Test options.
 	Test_options TestOptions
+
+	// list of device binary modules that should be installed alongside the test
+	// This property adds 64bit AND 32bit variants of the dependency
+	Data_device_bins_both []string `android:"arch_variant"`
 }
 
 type TestOptions struct {
@@ -98,18 +102,54 @@
 	p.AddProperties(&p.testProperties)
 	android.InitAndroidArchModule(p, p.hod, p.multilib)
 	android.InitDefaultableModule(p)
-	android.InitBazelModule(p)
-	if p.hod == android.HostSupportedNoCross && p.testProperties.Test_options.Unit_test == nil {
+	if p.isTestHost() && p.testProperties.Test_options.Unit_test == nil {
 		p.testProperties.Test_options.Unit_test = proptools.BoolPtr(true)
 	}
 	return p
 }
 
+func (p *PythonTestModule) isTestHost() bool {
+	return p.hod == android.HostSupported
+}
+
+var dataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"}
+
+// python_test_host DepsMutator uses this method to add multilib dependencies of
+// data_device_bin_both
+func (p *PythonTestModule) addDataDeviceBinsDeps(ctx android.BottomUpMutatorContext, filter string) {
+	if len(p.testProperties.Data_device_bins_both) < 1 {
+		return
+	}
+
+	var maybeAndroidTarget *android.Target
+	androidTargetList := android.FirstTarget(ctx.Config().Targets[android.Android], filter)
+	if len(androidTargetList) > 0 {
+		maybeAndroidTarget = &androidTargetList[0]
+	}
+
+	if maybeAndroidTarget != nil {
+		ctx.AddFarVariationDependencies(
+			maybeAndroidTarget.Variations(),
+			dataDeviceBinsTag,
+			p.testProperties.Data_device_bins_both...,
+		)
+	}
+}
+
+func (p *PythonTestModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+	p.PythonBinaryModule.DepsMutator(ctx)
+	if p.isTestHost() {
+		p.addDataDeviceBinsDeps(ctx, "lib32")
+		p.addDataDeviceBinsDeps(ctx, "lib64")
+	}
+}
+
 func (p *PythonTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	// We inherit from only the library's GenerateAndroidBuildActions, and then
 	// 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
@@ -148,19 +188,28 @@
 		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)
-
 	for _, dataSrcPath := range android.PathsForModuleSrc(ctx, p.testProperties.Data) {
 		p.data = append(p.data, android.DataPath{SrcPath: dataSrcPath})
 	}
 
+	if p.isTestHost() && len(p.testProperties.Data_device_bins_both) > 0 {
+		ctx.VisitDirectDepsWithTag(dataDeviceBinsTag, func(dep android.Module) {
+			p.data = append(p.data, android.DataPath{SrcPath: android.OutputFileForModule(ctx, dep, "")})
+		})
+	}
+
 	// Emulate the data property for java_data dependencies.
 	for _, javaData := range ctx.GetDirectDepsWithTag(javaDataTag) {
 		for _, javaDataSrcPath := range android.OutputFilesForModule(ctx, javaData, "") {
 			p.data = append(p.data, android.DataPath{SrcPath: javaDataSrcPath})
 		}
 	}
-	ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+
+	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 {
@@ -180,8 +229,7 @@
 			}
 
 			entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(p.binaryProperties.Auto_gen_config, true))
-
-			entries.AddStrings("LOCAL_TEST_DATA", android.AndroidMkDataPaths(p.data)...)
+			android.SetAconfigFileMkEntries(&p.ModuleBase, entries, p.mergedAconfigFiles)
 
 			p.testProperties.Test_options.SetAndroidMkEntries(entries)
 		})
diff --git a/python/tests/Android.bp b/python/tests/Android.bp
index a656859..e5569ba 100644
--- a/python/tests/Android.bp
+++ b/python/tests/Android.bp
@@ -28,29 +28,6 @@
         unit_test: false,
     },
     version: {
-        py2: {
-            enabled: true,
-            embedded_launcher: true,
-        },
-        py3: {
-            enabled: false,
-            embedded_launcher: true,
-        },
-    },
-}
-
-python_test_host {
-    name: "par_test3",
-    main: "par_test.py",
-    srcs: [
-        "par_test.py",
-        "testpkg/par_test.py",
-    ],
-    // Is not implemented as a python unittest
-    test_options: {
-        unit_test: false,
-    },
-    version: {
         py3: {
             embedded_launcher: true,
         },
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 acda2d7..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.dirname(__file__))
+    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 35941dc..c44ec58 100755
--- a/python/tests/runtest.sh
+++ b/python/tests/runtest.sh
@@ -24,12 +24,16 @@
 fi
 
 if [[ ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test/par_test ) ||
-      ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3 ) ||
-      ( ! -f $ANDROID_HOST_OUT/bin/py2-cmd ) ||
       ( ! -f $ANDROID_HOST_OUT/bin/py3-cmd )]]; then
-  echo "Run 'm par_test par_test3 py2-cmd py3-cmd' first"
+  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
 
@@ -41,19 +45,17 @@
 
 ARGTEST=true $ANDROID_HOST_OUT/nativetest64/par_test/par_test --arg1 arg2
 
-PYTHONHOME= PYTHONPATH= $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3
-PYTHONHOME=/usr $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3
-PYTHONPATH=/usr $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3
-
-ARGTEST=true $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3 --arg1 arg2
-
 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/python/tests/testpkg/par_test.py b/python/tests/testpkg/par_test.py
index b513409..e12c527 100644
--- a/python/tests/testpkg/par_test.py
+++ b/python/tests/testpkg/par_test.py
@@ -33,11 +33,7 @@
     fileName = fileName[:-1]
 assert_equal("__file__", fileName, os.path.join(archive, "testpkg/par_test.py"))
 
-# Python3 is returning None here for me, and I haven't found any problems caused by this.
-if sys.version_info[0] == 2:
-  assert_equal("__package__", __package__, "testpkg")
-else:
-  assert_equal("__package__", __package__, None)
+assert_equal("__package__", __package__, "testpkg")
 
 assert_equal("__loader__.archive", __loader__.archive, archive)
 assert_equal("__loader__.prefix", __loader__.prefix, "testpkg/")
diff --git a/remoteexec/remoteexec.go b/remoteexec/remoteexec.go
index 6076c74..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:953fed4a6b2501256a0d17f055dc17884ff71b024e50ade773e0b348a6c303e6"
+	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 c5b2000..637042d 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -7,6 +7,7 @@
     pkgPath: "android/soong/rust",
     deps: [
         "soong",
+        "soong-aconfig",
         "soong-android",
         "soong-bloaty",
         "soong-cc",
diff --git a/rust/afdo.go b/rust/afdo.go
index 3534ee6..323ee36 100644
--- a/rust/afdo.go
+++ b/rust/afdo.go
@@ -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..17fd2d8 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,13 @@
 				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_SOONG_LINK_TYPE", mod.makeLinkType)
 				if mod.UseVndk() {
 					entries.SetBool("LOCAL_USE_VNDK", true)
 				}
-
+				android.SetAconfigFileMkEntries(mod.AndroidModuleBase(), entries, mod.mergedAconfigFiles)
 			},
 		},
 	}
@@ -114,8 +113,6 @@
 
 			test.Properties.Test_options.SetAndroidMkEntries(entries)
 		})
-
-	cc.AndroidMkWriteTestData(test.data, ret)
 }
 
 func (benchmark *benchmarkDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) {
@@ -216,33 +213,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 2de92c1..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
 }
 
@@ -158,9 +155,6 @@
 	// Binaries default to dylib dependencies for device, rlib for host.
 	if binary.preferRlib() {
 		return rlibAutoDep
-	} else if mod, ok := ctx.Module().(*Module); ok && mod.InVendor() {
-		// Vendor Rust binaries should prefer rlibs.
-		return rlibAutoDep
 	} else if ctx.Device() {
 		return dylibAutoDep
 	} else {
@@ -171,8 +165,6 @@
 func (binary *binaryDecorator) stdLinkage(ctx *depsContext) RustLinkage {
 	if binary.preferRlib() {
 		return RlibLinkage
-	} else if ctx.RustModule().InVendor() {
-		return RlibLinkage
 	}
 	return binary.baseCompiler.stdLinkage(ctx)
 }
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 96645b0..77ba277 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-r487747c"
+	bindgenClangVersion = "clang-r498229b"
 
 	_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
@@ -61,15 +61,18 @@
 		"${cc_config.ClangBase}/${bindgenHostPrebuiltTag}/${bindgenClangVersion}/${bindgenClangLibdir}")
 
 	//TODO(ivanlozano) Switch this to RuleBuilder
+	//
+	//TODO Pass the flag files directly to bindgen e.g. with @file when it supports that.
+	//See https://github.com/rust-lang/rust-bindgen/issues/2508.
 	bindgen = pctx.AndroidStaticRule("bindgen",
 		blueprint.RuleParams{
 			Command: "CLANG_PATH=$bindgenClang LIBCLANG_PATH=$bindgenLibClang RUSTFMT=${config.RustBin}/rustfmt " +
-				"$cmd $flags $in -o $out -- -MD -MF $out.d $cflags",
+				"$cmd $flags $$(cat $flagfiles) $in -o $out -- -MD -MF $out.d $cflags",
 			CommandDeps: []string{"$cmd"},
 			Deps:        blueprint.DepsGCC,
 			Depfile:     "$out.d",
 		},
-		"cmd", "flags", "cflags")
+		"cmd", "flags", "flagfiles", "cflags")
 )
 
 func init() {
@@ -90,6 +93,9 @@
 	// list of bindgen-specific flags and options
 	Bindgen_flags []string `android:"arch_variant"`
 
+	// list of files containing extra bindgen flags
+	Bindgen_flag_files []string `android:"arch_variant"`
+
 	// module name of a custom binary/script which should be used instead of the 'bindgen' binary. This custom
 	// binary must expect arguments in a similar fashion to bindgen, e.g.
 	//
@@ -118,18 +124,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)
@@ -162,10 +170,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__")
 		}
@@ -216,6 +233,14 @@
 	bindgenFlags := defaultBindgenFlags
 	bindgenFlags = append(bindgenFlags, esc(b.Properties.Bindgen_flags)...)
 
+	// cat reads from stdin if its command line is empty,
+	// so we pass in /dev/null if there are no other flag files
+	bindgenFlagFiles := []string{"/dev/null"}
+	for _, flagFile := range b.Properties.Bindgen_flag_files {
+		bindgenFlagFiles = append(bindgenFlagFiles, android.PathForModuleSrc(ctx, flagFile).String())
+		implicits = append(implicits, android.PathForModuleSrc(ctx, flagFile))
+	}
+
 	wrapperFile := android.OptionalPathForModuleSrc(ctx, b.Properties.Wrapper_src)
 	if !wrapperFile.Valid() {
 		ctx.PropertyErrorf("wrapper_src", "invalid path to wrapper source")
@@ -247,7 +272,7 @@
 
 	var cmd, cmdDesc string
 	if b.Properties.Custom_bindgen != "" {
-		cmd = ctx.GetDirectDepWithTag(b.Properties.Custom_bindgen, customBindgenDepTag).(*Module).HostToolPath().String()
+		cmd = ctx.GetDirectDepWithTag(b.Properties.Custom_bindgen, customBindgenDepTag).(android.HostToolProvider).HostToolPath().String()
 		cmdDesc = b.Properties.Custom_bindgen
 	} else {
 		cmd = "$bindgenCmd"
@@ -261,9 +286,10 @@
 		Input:       wrapperFile.Path(),
 		Implicits:   implicits,
 		Args: map[string]string{
-			"cmd":    cmd,
-			"flags":  strings.Join(bindgenFlags, " "),
-			"cflags": strings.Join(cflags, " "),
+			"cmd":       cmd,
+			"flags":     strings.Join(bindgenFlags, " "),
+			"flagfiles": strings.Join(bindgenFlagFiles, " "),
+			"cflags":    strings.Join(cflags, " "),
 		},
 	})
 
@@ -279,7 +305,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)
diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go
index af04cfc..0ba0ff8 100644
--- a/rust/bindgen_test.go
+++ b/rust/bindgen_test.go
@@ -115,7 +115,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 +141,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) {
@@ -168,3 +178,28 @@
 		}
 	`)
 }
+
+func TestBindgenFlagFile(t *testing.T) {
+	ctx := testRust(t, `
+		rust_bindgen {
+			name: "libbindgen",
+			wrapper_src: "src/any.h",
+			crate_name: "bindgen",
+			stem: "libbindgen",
+			source_stem: "bindings",
+			bindgen_flag_files: [
+				"flag_file.txt",
+			],
+		}
+	`)
+	libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs")
+
+	if !strings.Contains(libbindgen.Args["flagfiles"], "/dev/null") {
+		t.Errorf("missing /dev/null in rust_bindgen rule: flags %#v", libbindgen.Args["flagfiles"])
+	}
+	if !strings.Contains(libbindgen.Args["flagfiles"], "flag_file.txt") {
+		t.Errorf("missing bindgen flags file in rust_bindgen rule: flags %#v", libbindgen.Args["flagfiles"])
+	}
+	// 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)
+}
diff --git a/rust/builder.go b/rust/builder.go
index 0aa2225..c855cfb 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"},
+			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} ${config.RustLinkerArgs} @$in ${linkFlags} ${crtEnd}",
-		},
-		"linkFlags", "crtBegin", "crtEnd")
+		"rustcFlags", "earlyLinkFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars")
 
 	_       = pctx.SourcePathVariable("rustdocCmd", "${config.RustBin}/rustdoc")
 	rustdoc = pctx.AndroidStaticRule("rustdoc",
@@ -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
@@ -217,6 +213,35 @@
 		envVars = append(envVars, "OUT_DIR=out")
 	}
 
+	envVars = append(envVars, "ANDROID_RUST_VERSION="+config.GetRustVersion(ctx))
+
+	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()
+		if pkgVersion != "" {
+			envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion)
+
+			// Ensure the version is in the form of "x.y.z" (approximately semver compliant).
+			//
+			// For our purposes, we don't care to enforce that these are integers since they may
+			// include other characters at times (e.g. sometimes the patch version is more than an integer).
+			if strings.Count(pkgVersion, ".") == 2 {
+				var semver_parts = strings.Split(pkgVersion, ".")
+				envVars = append(envVars, "CARGO_PKG_VERSION_MAJOR="+semver_parts[0])
+				envVars = append(envVars, "CARGO_PKG_VERSION_MINOR="+semver_parts[1])
+				envVars = append(envVars, "CARGO_PKG_VERSION_PATCH="+semver_parts[2])
+			}
+		}
+	}
+
+	if ctx.Darwin() {
+		envVars = append(envVars, "ANDROID_RUST_DARWIN=true")
+	}
+
 	return envVars
 }
 
@@ -224,9 +249,11 @@
 	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
 
 	output.outputFile = outputFile
 	crateName := ctx.RustModule().CrateName()
@@ -255,16 +282,22 @@
 	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=\"custom_inner_attributes,mixed_integer_ops\"")
+		rustcFlags = append(rustcFlags, "-Zallow-features=\"\"")
 	}
 
 	// Collect linker flags
+	if !ctx.Darwin() {
+		earlyLinkFlags = "-Wl,--as-needed"
+	}
+
 	linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
 	linkFlags = append(linkFlags, flags.LinkFlags...)
 
@@ -283,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 {
@@ -317,29 +350,16 @@
 		implicits = append(implicits, outputs.Paths()...)
 	}
 
-	envVars = append(envVars, "ANDROID_RUST_VERSION="+config.GetRustVersion(ctx))
-
-	if ctx.RustModule().compiler.CargoEnvCompat() {
-		if _, ok := ctx.RustModule().compiler.(*binaryDecorator); ok {
-			envVars = append(envVars, "CARGO_BIN_NAME="+strings.TrimSuffix(outputFile.Base(), outputFile.Ext()))
-		}
-		envVars = append(envVars, "CARGO_CRATE_NAME="+ctx.RustModule().CrateName())
-		pkgVersion := ctx.RustModule().compiler.CargoPkgVersion()
-		if pkgVersion != "" {
-			envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion)
-		}
-	}
-
-	envVars = append(envVars, "AR=${cc_config.ClangBin}/llvm-ar")
-
 	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, " "),
@@ -351,41 +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{
-				"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{
@@ -394,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, " "),
 			},
 		})
@@ -429,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..c1bdbeb 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,48 @@
 	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)
+}
+
 func (compiler *baseCompiler) edition() string {
 	return proptools.StringDefault(compiler.Properties.Edition, config.DefaultEdition)
 }
@@ -73,6 +116,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
@@ -91,10 +143,8 @@
 	// 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 +203,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 +239,8 @@
 
 	distFile android.OptionalPath
 
+	installDeps android.InstallPaths
+
 	// unstripped output file.
 	unstrippedOutputFile android.Path
 
@@ -197,7 +249,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 {
@@ -250,9 +311,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 +332,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 +385,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 +413,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 +444,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 +520,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 +540,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 +565,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 +591,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 ae783e8..6c021c7 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -21,16 +21,25 @@
 )
 
 var (
-	Arm64RustFlags            = []string{}
+	Arm64RustFlags = []string{
+		"-C force-frame-pointers=y",
+	}
 	Arm64ArchFeatureRustFlags = map[string][]string{}
 	Arm64LinkFlags            = []string{}
 
 	Arm64ArchVariantRustFlags = map[string][]string{
-		"armv8-a":            []string{},
-		"armv8-a-branchprot": []string{},
-		"armv8-2a":           []string{},
-		"armv8-2a-dotprod":   []string{},
-		"armv9-a":            []string{},
+		"armv8-a": []string{},
+		"armv8-a-branchprot": []string{
+			// branch-protection=bti,pac-ret is equivalent to Clang's mbranch-protection=standard
+			"-Z branch-protection=bti,pac-ret",
+		},
+		"armv8-2a":         []string{},
+		"armv8-2a-dotprod": []string{},
+		"armv9-a": []string{
+			// branch-protection=bti,pac-ret is equivalent to Clang's mbranch-protection=standard
+			"-Z branch-protection=bti,pac-ret",
+			"-Z stack-protector=none",
+		},
 	}
 )
 
@@ -45,6 +54,7 @@
 			strings.Join(rustFlags, " "))
 	}
 
+	ExportedVars.ExportStringListStaticVariable("DEVICE_ARM64_RUSTC_FLAGS", Arm64RustFlags)
 }
 
 type toolchainArm64 struct {
diff --git a/rust/config/arm_device.go b/rust/config/arm_device.go
index 42c1c02..a5f4afb 100644
--- a/rust/config/arm_device.go
+++ b/rust/config/arm_device.go
@@ -44,6 +44,7 @@
 			strings.Join(rustFlags, " "))
 	}
 
+	ExportedVars.ExportStringListStaticVariable("DEVICE_ARM_RUSTC_FLAGS", ArmRustFlags)
 }
 
 type toolchainArm struct {
diff --git a/rust/config/global.go b/rust/config/global.go
index 2d1f0c1..aebbb1b 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -21,10 +21,11 @@
 	_ "android/soong/cc/config"
 )
 
-var pctx = android.NewPackageContext("android/soong/rust/config")
-
 var (
-	RustDefaultVersion = "1.68.0"
+	pctx         = android.NewPackageContext("android/soong/rust/config")
+	ExportedVars = android.NewExportedVariables(pctx)
+
+	RustDefaultVersion = "1.74.1"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2021"
 	Stdlibs            = []string{
@@ -41,8 +42,8 @@
 	}
 
 	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",
@@ -50,18 +51,27 @@
 		"-C force-unwind-tables=yes",
 		// Use v0 mangling to distinguish from C++ symbols
 		"-C symbol-mangling-version=v0",
-		"--color always",
-		// TODO (b/267698452): Temporary workaround until the "no unstable
-		// features" policy is enforced.
-		"-A stable-features",
-		"-Zdylib-lto",
+		"--color=always",
+		"-Z dylib-lto",
+		"-Z link-native-libraries=no",
+	}
+
+	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{
@@ -77,18 +87,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 != "" {
@@ -104,10 +109,28 @@
 
 	pctx.ImportAs("cc_config", "android/soong/cc/config")
 	pctx.StaticVariable("RustLinker", "${cc_config.ClangBin}/clang++")
-	pctx.StaticVariable("RustLinkerArgs", "-Wl,--as-needed")
 
 	pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " "))
 
+	ExportedVars.ExportStringStaticVariable("RUST_DEFAULT_VERSION", RustDefaultVersion)
+	ExportedVars.ExportStringListStaticVariable("GLOBAL_RUSTC_FLAGS", GlobalRustFlags)
+	ExportedVars.ExportStringListStaticVariable("LINUX_HOST_GLOBAL_LINK_FLAGS", LinuxHostGlobalLinkFlags)
+
+	ExportedVars.ExportStringListStaticVariable("DEVICE_GLOBAL_RUSTC_FLAGS", deviceGlobalRustFlags)
+	ExportedVars.ExportStringListStaticVariable("DEVICE_GLOBAL_LINK_FLAGS",
+		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..9322981 100644
--- a/rust/config/lints.go
+++ b/rust/config/lints.go
@@ -46,6 +46,7 @@
 		"-A deprecated",
 		"-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
@@ -55,6 +56,7 @@
 		"-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..49f7c77 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, " "))
 	}
-
+	ExportedVars.ExportStringListStaticVariable("DEVICE_X86_64_RUSTC_FLAGS", x86_64RustFlags)
 }
 
 type toolchainX86_64 struct {
diff --git a/rust/config/x86_device.go b/rust/config/x86_device.go
index 43f7340..2a57e73 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, " "))
 	}
 
+	ExportedVars.ExportStringListStaticVariable("DEVICE_X86_RUSTC_FLAGS", x86RustFlags)
 }
 
 type toolchainX86 struct {
diff --git a/rust/coverage.go b/rust/coverage.go
index 5216d60..bc6504d 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -65,7 +65,7 @@
 			"-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())
+		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/doc.go b/rust/doc.go
index fe3581b..6970d79 100644
--- a/rust/doc.go
+++ b/rust/doc.go
@@ -19,7 +19,7 @@
 )
 
 func init() {
-	android.RegisterSingletonType("rustdoc", RustdocSingleton)
+	android.RegisterParallelSingletonType("rustdoc", RustdocSingleton)
 }
 
 func RustdocSingleton() android.Singleton {
diff --git a/rust/fuzz.go b/rust/fuzz.go
index d7e7ddf..1770d2e 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -15,23 +15,23 @@
 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 {
 	*binaryDecorator
 
 	fuzzPackagedModule  fuzz.FuzzPackagedModule
-	sharedLibraries     android.Paths
+	sharedLibraries     android.RuleBuilderInstalls
 	installedSharedDeps []string
 }
 
@@ -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"
@@ -119,15 +137,43 @@
 	// Grab the list of required shared libraries.
 	fuzz.sharedLibraries, _ = cc.CollectAllSharedDependencies(ctx)
 
-	for _, lib := range fuzz.sharedLibraries {
+	for _, ruleBuilderInstall := range fuzz.sharedLibraries {
+		install := ruleBuilderInstall.To
+
 		fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
 			cc.SharedLibraryInstallLocation(
-				lib, 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(lib, 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 865665e..ee28c6d 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -19,6 +19,7 @@
 	"testing"
 
 	"android/soong/android"
+	"android/soong/cc"
 )
 
 func TestRustFuzz(t *testing.T) {
@@ -33,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.
@@ -46,18 +51,87 @@
 
 	// Check that compiler flags are set appropriately .
 	fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc")
-	if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-Z sanitizer=hwaddress") ||
-		!strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov-module'") ||
+	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, hwaddress sanitizer).")
+		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.
 	libtest_fuzzer := ctx.ModuleForTests("libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Output("libtest_fuzzing.rlib")
-	if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-Z sanitizer=hwaddress") ||
-		!strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") ||
+	if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") ||
 		!strings.Contains(libtest_fuzzer.Args["rustcFlags"], "--cfg fuzzing") {
-		t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing, hwaddress sanitizer).")
+		t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing).")
+	}
+}
+
+func TestRustFuzzDepBundling(t *testing.T) {
+	ctx := testRust(t, `
+			cc_library {
+				name: "libcc_transitive_dep",
+			}
+			cc_library {
+				name: "libcc_direct_dep",
+			}
+			rust_library {
+				name: "libtest_fuzzing",
+				crate_name: "test_fuzzing",
+				srcs: ["foo.rs"],
+				shared_libs: ["libcc_transitive_dep"],
+			}
+			rust_fuzz {
+				name: "fuzz_libtest",
+				srcs: ["foo.rs"],
+				rustlibs: ["libtest_fuzzing"],
+				shared_libs: ["libcc_direct_dep"],
+			}
+	`)
+
+	fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Module().(*Module)
+
+	if !strings.Contains(fuzz_libtest.FuzzSharedLibraries().String(), ":libcc_direct_dep.so") {
+		t.Errorf("rust_fuzz does not contain the expected bundled direct shared libs ('libcc_direct_dep'): %#v", fuzz_libtest.FuzzSharedLibraries().String())
+	}
+	if !strings.Contains(fuzz_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
+		t.Errorf("rust_fuzz does not contain the expected bundled transitive shared libs ('libcc_transitive_dep'): %#v", fuzz_libtest.FuzzSharedLibraries().String())
+	}
+}
+
+func TestCCFuzzDepBundling(t *testing.T) {
+	ctx := testRust(t, `
+			cc_library {
+				name: "libcc_transitive_dep",
+			}
+			rust_ffi {
+				name: "libtest_fuzzing",
+				crate_name: "test_fuzzing",
+				srcs: ["foo.rs"],
+				shared_libs: ["libcc_transitive_dep"],
+			}
+			cc_fuzz {
+				name: "fuzz_shared_libtest",
+				shared_libs: ["libtest_fuzzing"],
+			}
+			cc_fuzz {
+				name: "fuzz_static_libtest",
+				static_libs: ["libtest_fuzzing"],
+			}
+
+	`)
+
+	fuzz_shared_libtest := ctx.ModuleForTests("fuzz_shared_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface)
+	fuzz_static_libtest := ctx.ModuleForTests("fuzz_static_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface)
+
+	if !strings.Contains(fuzz_shared_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
+		t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_shared ('libcc_transitive_dep'): %#v", fuzz_shared_libtest.FuzzSharedLibraries().String())
+	}
+	if !strings.Contains(fuzz_static_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
+		t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_static ('libcc_transitive_dep'): %#v", fuzz_static_libtest.FuzzSharedLibraries().String())
 	}
 }
diff --git a/rust/image.go b/rust/image.go
index 50bf02a..530c56e 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,9 +203,11 @@
 		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)
+	} 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)
+		}
 
 		// Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION.
 		// Hide other vendor variants to avoid collision.
@@ -213,16 +216,15 @@
 			m.Properties.HideFromMake = true
 			m.HideFromMake()
 		}
-	} 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)
+		}
 	}
 }
 
 func (mod *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
-	// Rust does not support installing to the product image yet.
-	vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
-
 	if Bool(mod.VendorProperties.Double_loadable) {
 		mctx.PropertyErrorf("double_loadable",
 			"Rust modules do not yet support double loading")
@@ -232,16 +234,6 @@
 			mctx.PropertyErrorf("vendor_ramdisk_available", "cannot be set for rust_ffi or rust_ffi_shared modules.")
 		}
 	}
-	if vendorSpecific {
-		if lib, ok := mod.compiler.(libraryInterface); ok && lib.buildDylib() {
-			mctx.PropertyErrorf("vendor", "Vendor-only dylibs are not yet supported, use rust_library_rlib.")
-		}
-	}
-	if mctx.ProductSpecific() {
-		if lib, ok := mod.compiler.(libraryInterface); ok && lib.buildDylib() {
-			mctx.PropertyErrorf("product", "Product-only dylibs are not yet supported, use rust_library_rlib.")
-		}
-	}
 
 	cc.MutateImage(mctx, mod)
 
diff --git a/rust/library.go b/rust/library.go
index a3a5672..7f004fc 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -15,18 +15,17 @@
 package rust
 
 import (
+	"errors"
 	"fmt"
 	"regexp"
 	"strings"
 
 	"android/soong/android"
 	"android/soong/cc"
-	"android/soong/snapshot"
 )
 
 var (
-	DylibStdlibSuffix = ".dylib-std"
-	RlibStdlibSuffix  = ".rlib-std"
+	RlibStdlibSuffix = ".rlib-std"
 )
 
 func init() {
@@ -237,10 +236,7 @@
 }
 
 func (library *libraryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
-	if ctx.Module().(*Module).InVendor() {
-		// Vendor modules should statically link libstd.
-		return rlibAutoDep
-	} else if library.preferRlib() {
+	if library.preferRlib() {
 		return rlibAutoDep
 	} else if library.rlib() || library.static() {
 		return rlibAutoDep
@@ -252,10 +248,7 @@
 }
 
 func (library *libraryDecorator) stdLinkage(ctx *depsContext) RustLinkage {
-	if ctx.RustModule().InVendor() {
-		// Vendor modules should statically link libstd.
-		return RlibLinkage
-	} else if library.static() || library.MutatedProperties.VariantIsStaticStd {
+	if library.static() || library.MutatedProperties.VariantIsStaticStd {
 		return RlibLinkage
 	} else if library.baseCompiler.preferRlib() {
 		return RlibLinkage
@@ -474,7 +467,15 @@
 		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.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
@@ -484,7 +485,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()...)
@@ -520,7 +521,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:
@@ -531,23 +532,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,
 		})
 	}
@@ -559,7 +559,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(),
@@ -567,8 +567,8 @@
 	}
 
 	if library.static() {
-		depSet := android.NewDepSetBuilder(android.TOPOLOGICAL).Direct(outputFile).Build()
-		ctx.SetProvider(cc.StaticLibraryInfoProvider, cc.StaticLibraryInfo{
+		depSet := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL).Direct(outputFile).Build()
+		android.SetProvider(ctx, cc.StaticLibraryInfoProvider, cc.StaticLibraryInfo{
 			StaticLibrary: outputFile,
 
 			TransitiveStaticLibrariesForOrdering: depSet,
@@ -580,13 +580,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()
 	}
 }
 
@@ -601,7 +604,7 @@
 		return android.OptionalPath{}
 	}
 
-	return android.OptionalPathForPath(Rustdoc(ctx, library.srcPath(ctx, deps),
+	return android.OptionalPathForPath(Rustdoc(ctx, crateRootPath(ctx, library),
 		deps, flags))
 }
 
@@ -694,24 +697,6 @@
 				v.(*Module).Disable()
 			}
 
-			variation := v.(*Module).ModuleBase.ImageVariation().Variation
-			if strings.HasPrefix(variation, cc.VendorVariationPrefix) {
-				// TODO(b/204303985)
-				// Disable vendor dylibs until they are supported
-				v.(*Module).Disable()
-			}
-
-			if strings.HasPrefix(variation, cc.VendorVariationPrefix) &&
-				m.HasVendorVariant() &&
-				!snapshot.IsVendorProprietaryModule(mctx) &&
-				strings.TrimPrefix(variation, cc.VendorVariationPrefix) == mctx.DeviceConfig().VndkVersion() {
-
-				// cc.MutateImage runs before LibraryMutator, so vendor variations which are meant for rlibs only are
-				// produced for Dylibs; however, dylibs should not be enabled for boardVndkVersion for
-				// non-vendor proprietary modules.
-				v.(*Module).Disable()
-			}
-
 		case "source":
 			v.(*Module).compiler.(libraryInterface).setSource()
 			// The source variant does not produce any library.
@@ -748,15 +733,13 @@
 				dylib := modules[1].(*Module)
 				rlib.compiler.(libraryInterface).setRlibStd()
 				dylib.compiler.(libraryInterface).setDylibStd()
-				if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation ||
-					strings.HasPrefix(dylib.ModuleBase.ImageVariation().Variation, cc.VendorVariationPrefix) {
+				if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
 					// TODO(b/165791368)
-					// Disable rlibs that link against dylib-std on vendor and vendor ramdisk variations until those dylib
+					// Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib
 					// variants are properly supported.
 					dylib.Disable()
 				}
 				rlib.Properties.RustSubName += RlibStdlibSuffix
-				dylib.Properties.RustSubName += DylibStdlibSuffix
 			}
 		}
 	}
diff --git a/rust/library_test.go b/rust/library_test.go
index d4b525f..e03074d 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) {
 
@@ -247,10 +306,10 @@
 		if !android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkDylibs) {
 			t.Errorf("libbar not present as dynamic dependency in dynamic lib")
 		}
-		if android.InList("libbar.dylib-std", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
+		if android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
 			t.Errorf("libbar present as rlib dependency in dynamic lib")
 		}
-		if !android.InList("librlib_only.dylib-std", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
+		if !android.InList("librlib_only", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
 			t.Errorf("librlib_only should be selected by rustlibs as an rlib.")
 		}
 	}
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 fe259d6..ad9b690 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 {
@@ -74,86 +74,7 @@
 }
 
 func init() {
-	android.RegisterSingletonType("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
+	android.RegisterParallelSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
 }
 
 // mergeDependencies visits all the dependencies for module and updates crate and deps
@@ -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, make(map[string]int))
 			if !ok {
 				return
 			}
@@ -191,41 +112,25 @@
 	})
 }
 
-// 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, deps map[string]int) (int, bool) {
+	rootModule, err := rModule.compiler.checkedCrateRootPath()
+	if err != nil {
 		return 0, false
 	}
 
@@ -233,28 +138,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 +172,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, cInfo.Deps)
+			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, make(map[string]int))
 }
 
 func (singleton *projectGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
diff --git a/rust/protobuf.go b/rust/protobuf.go
index e30f25d..0b26b80 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -19,6 +19,7 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/cc"
 )
 
 var (
@@ -52,14 +53,18 @@
 
 	// List of libraries which export include paths required for this module
 	Header_libs []string `android:"arch_variant,variant_prepend"`
+
+	// 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
@@ -73,7 +78,8 @@
 	outDir := android.PathForModuleOut(ctx)
 	protoFiles := android.PathsForModuleSrc(ctx, proto.Properties.Protos)
 	grpcFiles := android.PathsForModuleSrc(ctx, proto.Properties.Grpc_protos)
-	protoPluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust-deprecated")
+
+	protoPluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
 
 	commonProtoFlags = append(commonProtoFlags, defaultProtobufFlags...)
 	commonProtoFlags = append(commonProtoFlags, proto.Properties.Proto_flags...)
@@ -167,6 +173,10 @@
 	// 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
 }
@@ -175,10 +185,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))
@@ -187,13 +203,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;",
 			"}")
 	}
 
@@ -206,7 +216,7 @@
 
 func (proto *protobufDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
 	deps = proto.BaseSourceProvider.SourceProviderDeps(ctx, deps)
-	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 {
@@ -219,7 +229,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 0aa4549..cae071b 100644
--- a/rust/protobuf_test.go
+++ b/rust/protobuf_test.go
@@ -21,7 +21,7 @@
 	"android/soong/android"
 )
 
-func TestRustProtobuf(t *testing.T) {
+func TestRustProtobuf3(t *testing.T) {
 	ctx := testRust(t, `
 		rust_protobuf {
 			name: "librust_proto",
@@ -42,14 +42,14 @@
 	`)
 	// 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)")
+	if !android.InList("libprotobuf", librust_proto.Properties.AndroidMkDylibs) {
+		t.Errorf("libprotobuf 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) {
+	if w := "protoc-gen-rust"; !strings.Contains(cmd, w) {
 		t.Errorf("expected %q in %q", w, cmd)
 	}
 
@@ -69,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 fdc7849..245ed2e 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -15,11 +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"
 
@@ -44,9 +45,10 @@
 	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
 	})
+	pctx.Import("android/soong/android")
 	pctx.Import("android/soong/rust/config")
 	pctx.ImportAs("cc_config", "android/soong/cc/config")
-	android.InitRegistrationContext.RegisterSingletonType("kythe_rust_extract", kytheExtractRustFactory)
+	android.InitRegistrationContext.RegisterParallelSingletonType("kythe_rust_extract", kytheExtractRustFactory)
 }
 
 type Flags struct {
@@ -66,12 +68,11 @@
 	AndroidMkRlibs         []string `blueprint:"mutated"`
 	AndroidMkDylibs        []string `blueprint:"mutated"`
 	AndroidMkProcMacroLibs []string `blueprint:"mutated"`
-	AndroidMkSharedLibs    []string `blueprint:"mutated"`
 	AndroidMkStaticLibs    []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
@@ -92,6 +93,8 @@
 	// Used by vendor snapshot to record dependencies from snapshot modules.
 	SnapshotSharedLibs []string `blueprint:"mutated"`
 	SnapshotStaticLibs []string `blueprint:"mutated"`
+	SnapshotRlibs      []string `blueprint:"mutated"`
+	SnapshotDylibs     []string `blueprint:"mutated"`
 
 	// Make this module available when building for ramdisk.
 	// On device without a dedicated recovery partition, the module is only
@@ -167,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 {
@@ -260,6 +268,24 @@
 	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() {
+			return library.rlibStd()
+		}
+	}
+	panic(fmt.Errorf("RlibStd() called on non-rlib module: %q", mod.BaseModuleName()))
+}
+
 func (mod *Module) Rlib() bool {
 	if mod.compiler != nil {
 		if library, ok := mod.compiler.(libraryInterface); ok {
@@ -422,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
@@ -436,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
@@ -459,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 {
@@ -508,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,
 	})
 }
 
@@ -541,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
@@ -553,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
 }
 
@@ -603,6 +585,7 @@
 		&cc.RustBindgenClangProperties{},
 		&ClippyProperties{},
 		&SanitizeProperties{},
+		&fuzz.FuzzProperties{},
 	)
 
 	android.InitDefaultsModule(module)
@@ -633,6 +616,15 @@
 	return false
 }
 
+func (mod *Module) RustLibraryInterface() bool {
+	if mod.compiler != nil {
+		if _, ok := mod.compiler.(libraryInterface); ok {
+			return true
+		}
+	}
+	return false
+}
+
 func (mod *Module) IsFuzzModule() bool {
 	if _, ok := mod.compiler.(*fuzzDecorator); ok {
 		return true
@@ -651,7 +643,7 @@
 	panic(fmt.Errorf("FuzzPackagedModule called on non-fuzz module: %q", mod.BaseModuleName()))
 }
 
-func (mod *Module) FuzzSharedLibraries() android.Paths {
+func (mod *Module) FuzzSharedLibraries() android.RuleBuilderInstalls {
 	if fuzzer, ok := mod.compiler.(*fuzzDecorator); ok {
 		return fuzzer.sharedLibraries
 	}
@@ -755,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)
@@ -905,7 +898,7 @@
 		ModuleContext: actx,
 	}
 
-	apexInfo := actx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+	apexInfo, _ := android.ModuleProvider(actx, android.ApexInfoProvider)
 	if !apexInfo.IsForPlatform() {
 		mod.hideApexVariantFromMake = true
 	}
@@ -958,7 +951,7 @@
 			sourceLib := sourceMod.(*Module).compiler.(*libraryDecorator)
 			mod.sourceProvider.setOutputFiles(sourceLib.sourceProvider.Srcs())
 		}
-		ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: mod.sourceProvider.Srcs().Strings()})
+		android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: mod.sourceProvider.Srcs().Strings()})
 	}
 
 	if mod.compiler != nil && !mod.compiler.Disabled() {
@@ -986,7 +979,7 @@
 			}
 		}
 
-		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
@@ -1011,8 +1004,10 @@
 		ctx.Phony("rust", ctx.RustModule().OutputFile().Path())
 	}
 	if mod.testModule {
-		ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+		android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 	}
+
+	android.CollectDependencyAconfigFiles(ctx, &mod.mergedAconfigFiles)
 }
 
 func (mod *Module) deps(ctx DepsContext) Deps {
@@ -1134,6 +1129,13 @@
 	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
 
@@ -1147,7 +1149,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
 	}
@@ -1166,7 +1168,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
 		}
 	})
@@ -1202,6 +1204,9 @@
 		})
 	}
 
+	var transitiveAndroidMkSharedLibs []*android.DepSet[string]
+	var directAndroidMkSharedLibs []string
+
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
@@ -1209,6 +1214,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)
@@ -1222,6 +1232,8 @@
 				}
 				directDylibDeps = append(directDylibDeps, rustDep)
 				mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, makeLibName)
+				mod.Properties.SnapshotDylibs = append(mod.Properties.SnapshotDylibs, cc.BaseLibName(depName))
+
 			case rlibDepTag:
 
 				rlib, ok := rustDep.compiler.(libraryInterface)
@@ -1231,11 +1243,20 @@
 				}
 				directRlibDeps = append(directRlibDeps, rustDep)
 				mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, makeLibName)
+				mod.Properties.SnapshotRlibs = append(mod.Properties.SnapshotRlibs, cc.BaseLibName(depName))
+
 			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.
@@ -1258,11 +1279,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 {
@@ -1272,7 +1292,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)
@@ -1287,12 +1314,17 @@
 				}
 			}
 			linkObject := ccDep.OutputFile()
-			linkPath := linkPathFromFilePath(linkObject.Path())
-
 			if !linkObject.Valid() {
-				ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+				if !ctx.Config().AllowMissingDependencies() {
+					ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+				} else {
+					ctx.AddMissingDependencies([]string{depName})
+				}
+				return
 			}
 
+			linkPath := linkPathFromFilePath(linkObject.Path())
+
 			exportDep := false
 			switch {
 			case cc.IsStaticDepTag(depTag):
@@ -1306,7 +1338,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())
 					}
@@ -1314,10 +1345,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...)
@@ -1337,10 +1368,18 @@
 				// Re-get linkObject as ChooseStubOrImpl actually tells us which
 				// object (either from stub or non-stub) to use.
 				linkObject = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary)
+				if !linkObject.Valid() {
+					if !ctx.Config().AllowMissingDependencies() {
+						ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+					} else {
+						ctx.AddMissingDependencies([]string{depName})
+					}
+					return
+				}
 				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...)
@@ -1350,10 +1389,10 @@
 				// 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...)
@@ -1366,9 +1405,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 {
@@ -1387,6 +1424,8 @@
 		}
 	})
 
+	mod.transitiveAndroidMkSharedLibs = android.NewDepSet[string](android.PREORDER, directAndroidMkSharedLibs, transitiveAndroidMkSharedLibs)
+
 	var rlibDepFiles RustLibraries
 	for _, dep := range directRlibDeps {
 		rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
@@ -1400,16 +1439,19 @@
 		procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.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)
 		}
 	}
 
@@ -1425,13 +1467,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)
@@ -1515,47 +1559,61 @@
 	}
 
 	// dylibs
-	actx.AddVariationDependencies(
-		append(commonDepVariations, []blueprint.Variation{
-			{Mutator: "rust_libraries", Variation: dylibVariation}}...),
-		dylibDepTag, deps.Dylibs...)
+	dylibDepVariations := append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: dylibVariation})
+	for _, lib := range deps.Dylibs {
+		addDylibDependency(actx, lib, mod, &snapshotInfo, dylibDepVariations, dylibDepTag)
+	}
 
 	// 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 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.
+	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
 					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})
+
+					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)
+					}
+				}
+			}
+		} else if _, ok := mod.sourceProvider.(*protobufDecorator); ok {
+			for _, lib := range deps.Rustlibs {
+				replacementLib := cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Dylibs)
+				srcProviderVariations := append(commonDepVariations,
+					blueprint.Variation{Mutator: "rust_libraries", Variation: "source"})
+
+				if actx.OtherModuleDependencyVariantExists(srcProviderVariations, replacementLib) {
+					actx.AddVariationDependencies(srcProviderVariations, sourceDepTag, lib)
 				}
 			}
 		}
 	}
+
 	// stdlibs
 	if deps.Stdlibs != nil {
 		if mod.compiler.stdLinkage(ctx) == RlibLinkage {
 			for _, lib := range deps.Stdlibs {
-				depTag := rlibDepTag
 				lib = cc.GetReplaceModuleName(lib, cc.GetSnapshot(mod, &snapshotInfo, actx).Rlibs)
-
 				actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}...),
-					depTag, lib)
+					rlibDepTag, lib)
 			}
 		} else {
-			actx.AddVariationDependencies(
-				append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: "dylib"}),
-				dylibDepTag, deps.Stdlibs...)
+			for _, lib := range deps.Stdlibs {
+				addDylibDependency(actx, lib, mod, &snapshotInfo, dylibDepVariations, dylibDepTag)
+			}
 		}
 	}
 
@@ -1633,6 +1691,11 @@
 	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)
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 2a38b89..d609c2f 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -40,7 +40,6 @@
 	PrepareForTestWithRustIncludeVndk,
 	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 		variables.DeviceVndkVersion = StringPtr("current")
-		variables.ProductVndkVersion = StringPtr("current")
 		variables.Platform_vndk_version = StringPtr("29")
 	}),
 )
@@ -79,14 +78,18 @@
 }
 
 const (
-	sharedVendorVariant   = "android_vendor.29_arm64_armv8-a_shared"
-	rlibVendorVariant     = "android_vendor.29_arm64_armv8-a_rlib_rlib-std"
-	sharedRecoveryVariant = "android_recovery_arm64_armv8-a_shared"
-	rlibRecoveryVariant   = "android_recovery_arm64_armv8-a_rlib_rlib-std"
-	binaryCoreVariant     = "android_arm64_armv8-a"
-	binaryVendorVariant   = "android_vendor.29_arm64_armv8-a"
-	binaryProductVariant  = "android_product.29_arm64_armv8-a"
-	binaryRecoveryVariant = "android_recovery_arm64_armv8-a"
+	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"
+	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"
+	binaryRecoveryVariant      = "android_recovery_arm64_armv8-a"
 )
 
 func testRustVndkFs(t *testing.T, bp string, fs android.MockFS) *android.TestContext {
@@ -101,7 +104,6 @@
 		android.FixtureModifyProductVariables(
 			func(variables android.FixtureProductVariables) {
 				variables.DeviceVndkVersion = StringPtr(device_version)
-				variables.ProductVndkVersion = StringPtr(product_version)
 				variables.Platform_vndk_version = StringPtr(vndk_version)
 			},
 		),
@@ -169,7 +171,6 @@
 		android.FixtureModifyProductVariables(
 			func(variables android.FixtureProductVariables) {
 				variables.DeviceVndkVersion = StringPtr("current")
-				variables.ProductVndkVersion = StringPtr("current")
 				variables.Platform_vndk_version = StringPtr("VER")
 			},
 		),
@@ -228,11 +229,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"],
@@ -248,7 +244,6 @@
 		}
 		rust_binary_host {
 			name: "fizz-buzz",
-			dylibs: ["libdylib"],
 			rlibs: ["librlib"],
 			proc_macros: ["libpm"],
 			static_libs: ["libstatic"],
@@ -258,13 +253,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)")
 	}
@@ -273,7 +263,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)")
 	}
 
@@ -285,16 +275,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())
 	}
 }
 
@@ -377,11 +367,11 @@
 
 	// Check that our bindings are picked up as crate dependencies as well
 	libfooMod := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
-	if !android.InList("libbindings.dylib-std", libfooMod.Properties.AndroidMkRlibs) {
+	if !android.InList("libbindings", libfooMod.Properties.AndroidMkRlibs) {
 		t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
 	}
 	fizzBuzzMod := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Module().(*Module)
-	if !android.InList("libbindings.dylib-std", fizzBuzzMod.Properties.AndroidMkRlibs) {
+	if !android.InList("libbindings", fizzBuzzMod.Properties.AndroidMkRlibs) {
 		t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
 	}
 	libprocmacroMod := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Module().(*Module)
diff --git a/rust/sanitize.go b/rust/sanitize.go
index c68137e..9dda43f 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -62,8 +62,7 @@
 	"-C llvm-args=-sanitizer-coverage-level=3",
 	"-C llvm-args=-sanitizer-coverage-trace-compares",
 	"-C llvm-args=-sanitizer-coverage-inline-8bit-counters",
-	"-C llvm-args=-sanitizer-coverage-trace-geps",
-	"-C llvm-args=-sanitizer-coverage-prune-blocks=0",
+	"-C llvm-args=-sanitizer-coverage-pc-table",
 
 	// See https://github.com/rust-fuzz/cargo-fuzz/pull/193
 	"-C link-dead-code",
@@ -204,14 +203,24 @@
 		s.Address = nil
 	}
 
+	// TODO: Remove once b/304507701 is resolved
+	if Bool(s.Address) && ctx.Host() {
+		s.Address = nil
+	}
+
 	// Memtag_heap is only implemented on AArch64.
 	if ctx.Arch().ArchType != android.Arm64 || !ctx.Os().Bionic() {
 		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
 	}
 }
@@ -224,17 +233,22 @@
 	if !sanitize.Properties.SanitizerEnabled {
 		return flags, deps
 	}
+
 	if Bool(sanitize.Properties.Sanitize.Fuzzer) {
 		flags.RustFlags = append(flags.RustFlags, fuzzerFlags...)
-		if ctx.Arch().ArchType == android.Arm64 && ctx.Os().Bionic() {
-			flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
-		} else {
-			flags.RustFlags = append(flags.RustFlags, asanFlags...)
-		}
-	} else if Bool(sanitize.Properties.Sanitize.Hwaddress) {
+	}
+
+	if Bool(sanitize.Properties.Sanitize.Hwaddress) {
 		flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
-	} else if Bool(sanitize.Properties.Sanitize.Address) {
+	}
+
+	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
 }
@@ -256,7 +270,7 @@
 			}
 			// If we're using snapshots, redirect to snapshot whenever possible
 			// TODO(b/178470649): clean manual snapshot redirections
-			snapshot := mctx.Provider(cc.SnapshotInfoProvider).(cc.SnapshotInfo)
+			snapshot, _ := android.ModuleProvider(mctx, cc.SnapshotInfoProvider)
 			if lib, ok := snapshot.StaticLibs[noteDep]; ok {
 				noteDep = lib
 			}
@@ -273,14 +287,19 @@
 		var depTag blueprint.DependencyTag
 		var deps []string
 
-		if mod.IsSanitizerEnabled(cc.Asan) ||
-			(mod.IsSanitizerEnabled(cc.Fuzzer) && (mctx.Arch().ArchType != android.Arm64 || !mctx.Os().Bionic())) {
-			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) ||
-			(mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64 && mctx.Os().Bionic()) {
+		if mod.IsSanitizerEnabled(cc.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 {
 				if binary.staticallyLinked() {
@@ -394,7 +413,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 {
@@ -420,18 +440,11 @@
 }
 
 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
 	}
 
-	// TODO(b/178365482): Rust/CC interop doesn't work just yet; don't sanitize rust_ffi modules until
-	// linkage issues are resolved.
-	if lib, ok := mod.compiler.(libraryInterface); ok {
-		if lib.shared() || lib.static() {
-			return true
-		}
-	}
-
 	return mod.sanitize.isSanitizerExplicitlyDisabled(t)
 }
 
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
index 2f79cc5..42e3cef 100644
--- a/rust/snapshot_prebuilt.go
+++ b/rust/snapshot_prebuilt.go
@@ -15,35 +15,98 @@
 package rust
 
 import (
+	"fmt"
+
 	"android/soong/android"
 	"android/soong/cc"
 
 	"github.com/google/blueprint/proptools"
 )
 
-const (
-	snapshotRlibSuffix = "_rlib."
-)
-
 type snapshotLibraryDecorator struct {
 	cc.BaseSnapshotDecorator
 	*libraryDecorator
 	properties          cc.SnapshotLibraryProperties
 	sanitizerProperties struct {
-		CfiEnabled bool `blueprint:"mutated"`
+		SanitizerVariation cc.SanitizerType `blueprint:"mutated"`
 
-		// Library flags for cfi variant.
-		Cfi cc.SnapshotLibraryProperties `android:"arch_variant"`
+		//TODO: Library flags for cfi variant when CFI is supported.
+		//Cfi cc.SnapshotLibraryProperties `android:"arch_variant"`
+
+		// Library flags for hwasan variant.
+		Hwasan cc.SnapshotLibraryProperties `android:"arch_variant"`
 	}
 }
 
+var _ cc.SnapshotSanitizer = (*snapshotLibraryDecorator)(nil)
+
+func (library *snapshotLibraryDecorator) IsSanitizerAvailable(t cc.SanitizerType) bool {
+	switch t {
+	//TODO: When CFI is supported, add a check here as well
+	case cc.Hwasan:
+		return library.sanitizerProperties.Hwasan.Src != nil
+	default:
+		return false
+	}
+}
+
+func (library *snapshotLibraryDecorator) SetSanitizerVariation(t cc.SanitizerType, enabled bool) {
+	if !enabled || library.IsSanitizerEnabled(t) {
+		return
+	}
+	if !library.IsUnsanitizedVariant() {
+		panic(fmt.Errorf("snapshot Sanitizer must be one of Cfi or Hwasan but not both"))
+	}
+	library.sanitizerProperties.SanitizerVariation = t
+}
+
+func (library *snapshotLibraryDecorator) IsSanitizerEnabled(t cc.SanitizerType) bool {
+	return library.sanitizerProperties.SanitizerVariation == t
+}
+
+func (library *snapshotLibraryDecorator) IsUnsanitizedVariant() bool {
+	//TODO: When CFI is supported, add a check here as well
+	return !library.IsSanitizerEnabled(cc.Hwasan)
+}
+
 func init() {
 	registerRustSnapshotModules(android.InitRegistrationContext)
 }
 
+func (mod *Module) IsSnapshotSanitizerAvailable(t cc.SanitizerType) bool {
+	if ss, ok := mod.compiler.(cc.SnapshotSanitizer); ok {
+		return ss.IsSanitizerAvailable(t)
+	}
+	return false
+}
+
+func (mod *Module) SetSnapshotSanitizerVariation(t cc.SanitizerType, enabled bool) {
+	if ss, ok := mod.compiler.(cc.SnapshotSanitizer); ok {
+		ss.SetSanitizerVariation(t, enabled)
+	} else {
+		panic(fmt.Errorf("Calling SetSnapshotSanitizerVariation on a non-snapshotLibraryDecorator: %s", mod.Name()))
+	}
+}
+
+func (mod *Module) IsSnapshotUnsanitizedVariant() bool {
+	if ss, ok := mod.compiler.(cc.SnapshotSanitizer); ok {
+		return ss.IsUnsanitizedVariant()
+	}
+	return false
+}
+
+func (mod *Module) IsSnapshotSanitizer() bool {
+	if _, ok := mod.compiler.(cc.SnapshotSanitizer); ok {
+		return true
+	}
+	return false
+}
+
 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)
 }
@@ -77,13 +140,15 @@
 		variant = cc.SnapshotSharedSuffix
 	} else if library.rlib() {
 		variant = cc.SnapshotRlibSuffix
+	} else if library.dylib() {
+		variant = cc.SnapshotDylibSuffix
 	}
 
-	if !library.dylib() {
-		// TODO(184042776): Remove this check when dylibs are supported in snapshots.
-		library.SetSnapshotAndroidMkSuffix(ctx, variant)
-	}
+	library.SetSnapshotAndroidMkSuffix(ctx, variant)
 
+	if library.IsSanitizerEnabled(cc.Hwasan) {
+		library.properties = library.sanitizerProperties.Hwasan
+	}
 	if !library.MatchesWithDevice(ctx.DeviceConfig()) {
 		return buildOutput{}
 	}
@@ -107,6 +172,17 @@
 	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()
diff --git a/rust/snapshot_utils.go b/rust/snapshot_utils.go
index 8dabd9b..55c85e6 100644
--- a/rust/snapshot_utils.go
+++ b/rust/snapshot_utils.go
@@ -42,8 +42,7 @@
 
 func (mod *Module) IsSnapshotLibrary() bool {
 	if lib, ok := mod.compiler.(libraryInterface); ok {
-		// Rust-native dylibs are not snapshot supported yet. Only snapshot the rlib-std variants of rlibs.
-		return lib.shared() || lib.static() || (lib.rlib() && lib.rlibStd())
+		return lib.shared() || lib.static() || lib.rlib() || lib.dylib()
 	}
 	return false
 }
@@ -61,6 +60,14 @@
 	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
diff --git a/rust/test.go b/rust/test.go
index 7ffc367..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)
 }
 
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 a33d948..0b34c97 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -127,7 +127,7 @@
 			min_sdk_version: "29",
 		}
 		rust_library {
-			name: "libprotobuf_deprecated",
+			name: "libprotobuf",
 			crate_name: "protobuf",
 			srcs: ["foo.rs"],
 			host_supported: true,
@@ -176,6 +176,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)
@@ -194,8 +195,8 @@
 		ctx.BottomUp("rust_stdlinkage", LibstdMutator).Parallel()
 		ctx.BottomUp("rust_begin", BeginMutator).Parallel()
 	})
-	ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
-	ctx.RegisterSingletonType("kythe_rust_extract", kytheExtractRustFactory)
+	ctx.RegisterParallelSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
+	ctx.RegisterParallelSingletonType("kythe_rust_extract", kytheExtractRustFactory)
 	ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("rust_sanitizers", rustSanitizerRuntimeMutator).Parallel()
 	})
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
index 2e7a330..4f45799 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -48,15 +48,13 @@
 		crate_name: "rustvendor_available",
 		srcs: ["lib.rs"],
 		vendor_available: true,
-		include_dirs: ["rust_headers/"],
 	}
 
-	rust_library_rlib {
+	rust_library {
 		name: "librustvendor",
 		crate_name: "rustvendor",
 		srcs: ["lib.rs"],
 		vendor: true,
-		include_dirs: ["rust_headers/"],
 	}
 
 	rust_binary {
@@ -116,7 +114,7 @@
 			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_rlib-std", archType, archVariant)
+		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)
@@ -125,6 +123,25 @@
 		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)
@@ -209,21 +226,32 @@
 		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_rlib-std", 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"))
 	}
 
@@ -274,7 +302,7 @@
 			vendor_available: true,
 		}
 
-		rust_library_rlib {
+		rust_library {
 			name: "librust_exclude",
 			crate_name: "rust_exclude",
 			srcs: ["exclude.rs"],
@@ -308,6 +336,14 @@
 	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"
@@ -327,14 +363,22 @@
 
 		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_rlib-std", 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)
 		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)
@@ -345,6 +389,12 @@
 		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.
@@ -525,7 +575,7 @@
 		srcs: ["client.rs"],
 	}
 
-	rust_library_rlib {
+	rust_library {
 		name: "libclient_rust",
 		crate_name: "client_rust",
 		vendor: true,
@@ -572,6 +622,11 @@
 				rlibs: [
 					"libstd",
 					"librust_vendor_available",
+					"librust_vendor_available.rlib-std"
+				],
+				dylibs: [
+					"libstd",
+					"librust_vendor_available",
 				],
 				binaries: [
 					"bin",
@@ -600,6 +655,10 @@
 					"libstd",
 					"librust_vendor_available",
 				],
+				dylibs: [
+					"libstd",
+					"librust_vendor_available",
+				],
 				binaries: [
 					"bin32",
 				],
@@ -679,6 +738,52 @@
 		},
 	}
 
+	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",
@@ -921,6 +1026,9 @@
 		"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,
@@ -931,7 +1039,9 @@
 	}
 
 	sharedVariant := "android_vendor.30_arm64_armv8-a_shared"
-	rlibVariant := "android_vendor.30_arm64_armv8-a_rlib_rlib-std"
+	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"
 
@@ -941,7 +1051,7 @@
 	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"]
+	libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustc").Args["linkFlags"]
 	for _, input := range [][]string{
 		[]string{sharedVariant, "libvndk.vndk.30.arm64"},
 		[]string{staticVariant, "libvendor.vendor_static.30.arm64"},
@@ -953,7 +1063,7 @@
 		}
 	}
 
-	libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkSharedLibs
+	libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).transitiveAndroidMkSharedLibs.ToList()
 	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)
 	}
@@ -963,41 +1073,53 @@
 		t.Errorf("wanted libclient AndroidMkStaticLibs %q, got %q", w, g)
 	}
 
-	libclientAndroidMkRlibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkRlibs
-	if g, w := libclientAndroidMkRlibs, []string{"librust_vendor_available.vendor.rlib-std", "libstd.vendor"}; !reflect.DeepEqual(g, w) {
-		t.Errorf("wanted libclient libclientAndroidMkRlibs %q, got %q", w, g)
-	}
-
 	libclientAndroidMkDylibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkDylibs
-	if len(libclientAndroidMkDylibs) > 0 {
-		t.Errorf("wanted libclient libclientAndroidMkDylibs [], got %q", libclientAndroidMkDylibs)
+	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
+	libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).transitiveAndroidMkSharedLibs.ToList()
 	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.rlib-std", "libstd.vendor"}; !reflect.DeepEqual(g, w) {
-		t.Errorf("wanted libclient libclientAndroidMkRlibs %q, got %q", w, g)
+	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.rlib-std"
+	expectedRustVendorSnapshotName := "librust_vendor_available.vendor"
 	if librustVendorSnapshotMkName != expectedRustVendorSnapshotName {
 		t.Errorf("Unexpected rust vendor snapshot name in AndroidMk: %q, expected: %q\n", librustVendorSnapshotMkName, expectedRustVendorSnapshotName)
 	}
 
-	rustVendorBinModule := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Module()
-	rustVendorBinMkRlibName := android.AndroidMkEntriesForTest(t, ctx, rustVendorBinModule)[0].EntryMap["LOCAL_RLIB_LIBRARIES"][0]
-	if rustVendorBinMkRlibName != expectedRustVendorSnapshotName {
-		t.Errorf("Unexpected rust rlib name in AndroidMk: %q, expected: %q\n", rustVendorBinMkRlibName, 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)
 	}
 
-	binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustLink").Args["linkFlags"]
+	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("rustc").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",
@@ -1051,18 +1173,18 @@
 		crate_name: "recovery_available",
 	}
 
-	rust_library_rlib {
-		name: "librecovery_rlib",
+	rust_library {
+		name: "librecovery_rustlib",
 		recovery: true,
 		srcs: ["foo.rs"],
-		crate_name: "recovery_rlib",
+		crate_name: "recovery_rustlib",
 	}
 
-	rust_library_rlib {
-		name: "librecovery_available_rlib",
+	rust_library {
+		name: "librecovery_available_rustlib",
 		recovery_available: true,
 		srcs: ["foo.rs"],
-		crate_name: "recovery_available_rlib",
+		crate_name: "recovery_available_rustlib",
 	}
 
 	rust_binary {
@@ -1113,13 +1235,29 @@
 			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_rlib-std", archType, archVariant)
+		rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_dylib-std", archType, archVariant)
 		rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib")
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant)
-		cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available_rlib", "librecovery_available_rlib.rlib", rlibDir, rlibVariant)
+		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_rlib.rlib.json"),
-			filepath.Join(rlibDir, "librecovery_available_rlib.rlib.json"))
+			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" {
@@ -1169,25 +1307,25 @@
 			exclude_from_recovery_snapshot: true,
 			crate_name: "available_exclude",
 		}
-		rust_library_rlib {
-			name: "libinclude_rlib",
+		rust_library {
+			name: "libinclude_rustlib",
 			srcs: ["src/include.rs"],
 			recovery_available: true,
-			crate_name: "include_rlib",
+			crate_name: "include_rustlib",
 		}
-		rust_library_rlib {
-			name: "libexclude_rlib",
+		rust_library {
+			name: "libexclude_rustlib",
 			srcs: ["src/exclude.rs"],
 			recovery: true,
 			exclude_from_recovery_snapshot: true,
-			crate_name: "exclude_rlib",
+			crate_name: "exclude_rustlib",
 		}
-		rust_library_rlib {
-			name: "libavailable_exclude_rlib",
+		rust_library {
+			name: "libavailable_exclude_rustlib",
 			srcs: ["src/exclude.rs"],
 			recovery_available: true,
 			exclude_from_recovery_snapshot: true,
-			crate_name: "available_exclude_rlib",
+			crate_name: "available_exclude_rustlib",
 		}
 	`
 
@@ -1198,11 +1336,11 @@
 			recovery: true,
 			crate_name: "recovery",
 		}
-		rust_library_rlib {
-			name: "librecovery_rlib",
+		rust_library {
+			name: "librecovery_rustlib",
 			srcs: ["recovery.rs"],
 			recovery: true,
-			crate_name: "recovery_rlib",
+			crate_name: "recovery_rustlib",
 		}
 	`
 
@@ -1220,14 +1358,25 @@
 	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_rlib", false, rlibRecoveryVariant)
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude_rlib", true, rlibRecoveryVariant)
-	cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude_rlib", true, rlibRecoveryVariant)
+
+	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_rlib", false, rlibRecoveryVariant)
+	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.
 
@@ -1246,15 +1395,21 @@
 		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_rlib-std", 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_rlib", "libinclude_rlib.rlib", rlibDir, rlibVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "libinclude_rlib.rlib.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)
@@ -1263,12 +1418,27 @@
 		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_rlib", "libexclude_rlib.rlib", rlibDir, rlibVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libexclude_rlib.rlib.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librecovery_rlib.rlib.json"))
-		cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude_rlib", "libavailable_exclude_rlib.rlib", rlibDir, rlibVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libavailable_exclude_rlib.rlib.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.
@@ -1302,15 +1472,15 @@
 		srcs: ["foo.rs"],
 	}
 
-	rust_library_rlib {
-		name: "librecovery_rlib",
+	rust_library {
+		name: "librecovery_rustlib",
 		recovery: true,
 		crate_name: "recovery",
 		srcs: ["foo.rs"],
 	}
 
-	rust_library_rlib {
-		name: "librecovery_available_rlib",
+	rust_library {
+		name: "librecovery_available_rustlib",
 		recovery_available: true,
 		crate_name: "recovery_available",
 		srcs: ["foo.rs"],
@@ -1335,7 +1505,7 @@
 	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_rlib"] = true
+	ctx.Config().TestProductVariables.RecoverySnapshotModules["librecovery_rustlib"] = true
 	ctx.Config().TestProductVariables.DirectedRecoverySnapshot = true
 
 	// Check recovery snapshot output.
@@ -1353,15 +1523,22 @@
 		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_rlib-std", 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_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_rlib.rlib.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.
 		/*
@@ -1374,8 +1551,12 @@
 		// 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_rlib", "librecovery_available_rlib.rlib", rlibDir, rlibVariant)
-		includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_available_rlib.rlib.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.
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 97f6ab4..7baaadb 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -254,3 +254,8 @@
         "modify_permissions_allowlist.py",
     ],
 }
+
+sh_binary_host {
+    name: "keep-flagged-apis",
+    src: "keep-flagged-apis.sh",
+}
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/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt
index 869fd3f..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
@@ -72,14 +73,17 @@
 javax\.xml\.validation
 javax\.xml\.xpath
 jdk\.internal
+jdk\.internal\.access
 jdk\.internal\.math
 jdk\.internal\.misc
 jdk\.internal\.ref
 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_context.py b/scripts/construct_context.py
index 3f601c3..fc3a89e 100755
--- a/scripts/construct_context.py
+++ b/scripts/construct_context.py
@@ -19,6 +19,7 @@
 from __future__ import print_function
 
 import argparse
+import json
 import sys
 
 from manifest import compare_version_gt
@@ -33,20 +34,14 @@
         dest='sdk',
         help='specify target SDK version (as it appears in the manifest)')
     parser.add_argument(
-        '--host-context-for-sdk',
-        dest='host_contexts',
-        action='append',
-        nargs=2,
-        metavar=('sdk', 'context'),
-        help='specify context on host for a given SDK version or "any" version')
+        '--context-json',
+        default='',
+        dest='context_json',
+    )
     parser.add_argument(
-        '--target-context-for-sdk',
-        dest='target_contexts',
-        action='append',
-        nargs=2,
-        metavar=('sdk', 'context'),
-        help='specify context on target for a given SDK version or "any" '
-        'version'
+        '--product-packages',
+        default='',
+        dest='product_packages_file',
     )
     return parser.parse_args(args)
 
@@ -55,28 +50,69 @@
 # context regardless of the target SDK version.
 any_sdk = 'any'
 
-
-# We assume that the order of context arguments passed to this script is
-# correct (matches the order computed by package manager). It is possible to
-# sort them here, but Soong needs to use deterministic order anyway, so it can
-# as well use the correct order.
-def construct_context(versioned_contexts, target_sdk):
-    context = []
-    for [sdk, ctx] in versioned_contexts:
-        if sdk == any_sdk or compare_version_gt(sdk, target_sdk):
-            context.append(ctx)
-    return context
+context_sep = '#'
 
 
-def construct_contexts(args):
-    host_context = construct_context(args.host_contexts, args.sdk)
-    target_context = construct_context(args.target_contexts, args.sdk)
-    context_sep = '#'
+def encode_class_loader(context, product_packages):
+    host_sub_contexts, target_sub_contexts = encode_class_loaders(
+            context['Subcontexts'], product_packages)
+
+    return ('PCL[%s]%s' % (context['Host'], host_sub_contexts),
+            'PCL[%s]%s' % (context['Device'], target_sub_contexts))
+
+
+def encode_class_loaders(contexts, product_packages):
+    host_contexts = []
+    target_contexts = []
+
+    for context in contexts:
+        if not context['Optional'] or context['Name'] in product_packages:
+            host_context, target_context = encode_class_loader(
+                    context, product_packages)
+            host_contexts.append(host_context)
+            target_contexts.append(target_context)
+
+    if host_contexts:
+        return ('{%s}' % context_sep.join(host_contexts),
+                '{%s}' % context_sep.join(target_contexts))
+    else:
+        return '', ''
+
+
+def construct_context_args(target_sdk, context_json, product_packages):
+    all_contexts = []
+
+    # CLC for different SDK versions should come in specific order that agrees
+    # with PackageManager. Since PackageManager processes SDK versions in
+    # ascending order and prepends compatibility libraries at the front, the
+    # required order is descending, except for any_sdk that has numerically
+    # the largest order, but must be the last one. Example of correct order:
+    # [30, 29, 28, any_sdk]. There are Python tests to ensure that someone
+    # doesn't change this by accident, but there is no way to guard against
+    # changes in the PackageManager, except for grepping logcat on the first
+    # boot for absence of the following messages:
+    #
+    #   `logcat | grep -E 'ClassLoaderContext [a-z ]+ mismatch`
+
+    for sdk, contexts in sorted(
+            ((sdk, contexts)
+             for sdk, contexts in context_json.items()
+             if sdk != any_sdk and compare_version_gt(sdk, target_sdk)),
+            key=lambda item: int(item[0]), reverse=True):
+        all_contexts += contexts
+
+    if any_sdk in context_json:
+        all_contexts += context_json[any_sdk]
+
+    host_contexts, target_contexts = encode_class_loaders(
+            all_contexts, product_packages)
+
     return (
-        'class_loader_context_arg=--class-loader-context=PCL[]{%s} ; ' %
-        context_sep.join(host_context) +
-        'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{%s}' #pylint: disable=line-too-long
-        % context_sep.join(target_context))
+        'class_loader_context_arg=--class-loader-context=PCL[]%s ; ' %
+        host_contexts +
+        'stored_class_loader_context_arg='
+        '--stored-class-loader-context=PCL[]%s'
+        % target_contexts)
 
 
 def main():
@@ -85,12 +121,12 @@
         args = parse_args(sys.argv[1:])
         if not args.sdk:
             raise SystemExit('target sdk version is not set')
-        if not args.host_contexts:
-            args.host_contexts = []
-        if not args.target_contexts:
-            args.target_contexts = []
 
-        print(construct_contexts(args))
+        context_json = json.loads(args.context_json)
+        with open(args.product_packages_file, 'r') as f:
+            product_packages = set(line.strip() for line in f if line.strip())
+
+        print(construct_context_args(args.sdk, context_json, product_packages))
 
     # pylint: disable=broad-except
     except Exception as err:
diff --git a/scripts/construct_context_test.py b/scripts/construct_context_test.py
index 2ff5ac5..34a0e16 100755
--- a/scripts/construct_context_test.py
+++ b/scripts/construct_context_test.py
@@ -24,62 +24,249 @@
 sys.dont_write_bytecode = True
 
 
-def construct_contexts(arglist):
-    args = cc.parse_args(arglist)
-    return cc.construct_contexts(args)
+CONTEXT_JSON = {
+    '28': [
+        {
+            'Name': 'z',
+            'Optional': False,
+            'Host': 'out/zdir/z.jar',
+            'Device': '/system/z.jar',
+            'Subcontexts': [],
+        },
+    ],
+    '29': [
+        {
+            'Name': 'x',
+            'Optional': False,
+            'Host': 'out/xdir/x.jar',
+            'Device': '/system/x.jar',
+            'Subcontexts': [],
+        },
+        {
+            'Name': 'y',
+            'Optional': False,
+            'Host': 'out/ydir/y.jar',
+            'Device': '/product/y.jar',
+            'Subcontexts': [],
+        },
+    ],
+    'any': [
+        {
+            'Name': 'a',
+            'Optional': False,
+            'Host': 'out/adir/a.jar',
+            'Device': '/system/a.jar',
+            'Subcontexts': [
+                {  # Not installed optional, being the only child.
+                    'Name': 'a1',
+                    'Optional': True,
+                    'Host': 'out/a1dir/a1.jar',
+                    'Device': '/product/a1.jar',
+                    'Subcontexts': [],
+                },
+            ],
+        },
+        {
+            'Name': 'b',
+            'Optional': True,
+            'Host': 'out/bdir/b.jar',
+            'Device': '/product/b.jar',
+            'Subcontexts': [
+                {  # Not installed but required.
+                    'Name': 'b1',
+                    'Optional': False,
+                    'Host': 'out/b1dir/b1.jar',
+                    'Device': '/product/b1.jar',
+                    'Subcontexts': [],
+                },
+                {  # Installed optional.
+                    'Name': 'b2',
+                    'Optional': True,
+                    'Host': 'out/b2dir/b2.jar',
+                    'Device': '/product/b2.jar',
+                    'Subcontexts': [],
+                },
+                {  # Not installed optional.
+                    'Name': 'b3',
+                    'Optional': True,
+                    'Host': 'out/b3dir/b3.jar',
+                    'Device': '/product/b3.jar',
+                    'Subcontexts': [],
+                },
+                {  # Installed optional with one more level of nested deps.
+                    'Name': 'b4',
+                    'Optional': True,
+                    'Host': 'out/b4dir/b4.jar',
+                    'Device': '/product/b4.jar',
+                    'Subcontexts': [
+                        {
+                            'Name': 'b41',
+                            'Optional': True,
+                            'Host': 'out/b41dir/b41.jar',
+                            'Device': '/product/b41.jar',
+                            'Subcontexts': [],
+                        },
+                        {
+                            'Name': 'b42',
+                            'Optional': True,
+                            'Host': 'out/b42dir/b42.jar',
+                            'Device': '/product/b42.jar',
+                            'Subcontexts': [],
+                        },
+                    ],
+                },
+            ],
+        },
+        {  # Not installed optional, at the top-level.
+            'Name': 'c',
+            'Optional': True,
+            'Host': 'out/cdir/c.jar',
+            'Device': '/product/c.jar',
+            'Subcontexts': [],
+        },
+    ],
+}
 
 
-contexts = [
-    '--host-context-for-sdk',
-    '28',
-    'PCL[out/zdir/z.jar]',
-    '--target-context-for-sdk',
-    '28',
-    'PCL[/system/z.jar]',
-    '--host-context-for-sdk',
-    '29',
-    'PCL[out/xdir/x.jar]#PCL[out/ydir/y.jar]',
-    '--target-context-for-sdk',
-    '29',
-    'PCL[/system/x.jar]#PCL[/product/y.jar]',
-    '--host-context-for-sdk',
-    'any',
-    'PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]',
-    '--target-context-for-sdk',
-    'any',
-    'PCL[/system/a.jar]#PCL[/product/b.jar]',
-]
+PRODUCT_PACKAGES = ['a', 'b', 'b2', 'b4', 'b41', 'b42', 'x', 'y', 'z']
 
-#pylint: disable=line-too-long
+
+def construct_context_args(target_sdk):
+    return cc.construct_context_args(target_sdk, CONTEXT_JSON, PRODUCT_PACKAGES)
+
+
 class ConstructContextTest(unittest.TestCase):
+    def test_construct_context_27(self):
+        actual = construct_context_args('27')
+        # The order matters.
+        expected = (
+            'class_loader_context_arg='
+            '--class-loader-context=PCL[]{'
+            'PCL[out/xdir/x.jar]#'
+            'PCL[out/ydir/y.jar]#'
+            'PCL[out/zdir/z.jar]#'
+            'PCL[out/adir/a.jar]#'
+            'PCL[out/bdir/b.jar]{'
+            'PCL[out/b1dir/b1.jar]#'
+            'PCL[out/b2dir/b2.jar]#'
+            'PCL[out/b4dir/b4.jar]{'
+            'PCL[out/b41dir/b41.jar]#'
+            'PCL[out/b42dir/b42.jar]'
+            '}'
+            '}'
+            '}'
+            ' ; '
+            'stored_class_loader_context_arg='
+            '--stored-class-loader-context=PCL[]{'
+            'PCL[/system/x.jar]#'
+            'PCL[/product/y.jar]#'
+            'PCL[/system/z.jar]#'
+            'PCL[/system/a.jar]#'
+            'PCL[/product/b.jar]{'
+            'PCL[/product/b1.jar]#'
+            'PCL[/product/b2.jar]#'
+            'PCL[/product/b4.jar]{'
+            'PCL[/product/b41.jar]#'
+            'PCL[/product/b42.jar]'
+            '}'
+            '}'
+            '}')
+        self.assertEqual(actual, expected)
 
     def test_construct_context_28(self):
-        args = ['--target-sdk-version', '28'] + contexts
-        result = construct_contexts(args)
-        expect = (
-            'class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/xdir/x.jar]#PCL[out/ydir/y.jar]#PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]}'
+        actual = construct_context_args('28')
+        expected = (
+            'class_loader_context_arg='
+            '--class-loader-context=PCL[]{'
+            'PCL[out/xdir/x.jar]#'
+            'PCL[out/ydir/y.jar]#'
+            'PCL[out/adir/a.jar]#'
+            'PCL[out/bdir/b.jar]{'
+            'PCL[out/b1dir/b1.jar]#'
+            'PCL[out/b2dir/b2.jar]#'
+            'PCL[out/b4dir/b4.jar]{'
+            'PCL[out/b41dir/b41.jar]#'
+            'PCL[out/b42dir/b42.jar]'
+            '}'
+            '}'
+            '}'
             ' ; '
-            'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/x.jar]#PCL[/product/y.jar]#PCL[/system/a.jar]#PCL[/product/b.jar]}')
-        self.assertEqual(result, expect)
+            'stored_class_loader_context_arg='
+            '--stored-class-loader-context=PCL[]{'
+            'PCL[/system/x.jar]#'
+            'PCL[/product/y.jar]#'
+            'PCL[/system/a.jar]#'
+            'PCL[/product/b.jar]{'
+            'PCL[/product/b1.jar]#'
+            'PCL[/product/b2.jar]#'
+            'PCL[/product/b4.jar]{'
+            'PCL[/product/b41.jar]#'
+            'PCL[/product/b42.jar]'
+            '}'
+            '}'
+            '}')
+        self.assertEqual(actual, expected)
 
     def test_construct_context_29(self):
-        args = ['--target-sdk-version', '29'] + contexts
-        result = construct_contexts(args)
-        expect = (
-            'class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]}'
+        actual = construct_context_args('29')
+        expected = (
+            'class_loader_context_arg='
+            '--class-loader-context=PCL[]{'
+            'PCL[out/adir/a.jar]#'
+            'PCL[out/bdir/b.jar]{'
+            'PCL[out/b1dir/b1.jar]#'
+            'PCL[out/b2dir/b2.jar]#'
+            'PCL[out/b4dir/b4.jar]{'
+            'PCL[out/b41dir/b41.jar]#'
+            'PCL[out/b42dir/b42.jar]'
+            '}'
+            '}'
+            '}'
             ' ; '
-            'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]#PCL[/product/b.jar]}')
-        self.assertEqual(result, expect)
+            'stored_class_loader_context_arg='
+            '--stored-class-loader-context=PCL[]{'
+            'PCL[/system/a.jar]#'
+            'PCL[/product/b.jar]{'
+            'PCL[/product/b1.jar]#'
+            'PCL[/product/b2.jar]#'
+            'PCL[/product/b4.jar]{'
+            'PCL[/product/b41.jar]#'
+            'PCL[/product/b42.jar]'
+            '}'
+            '}'
+            '}')
+        self.assertEqual(actual, expected)
 
     def test_construct_context_S(self):
-        args = ['--target-sdk-version', 'S'] + contexts
-        result = construct_contexts(args)
-        expect = (
-            'class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]}'
+        actual = construct_context_args('S')
+        expected = (
+            'class_loader_context_arg='
+            '--class-loader-context=PCL[]{'
+            'PCL[out/adir/a.jar]#'
+            'PCL[out/bdir/b.jar]{'
+            'PCL[out/b1dir/b1.jar]#'
+            'PCL[out/b2dir/b2.jar]#'
+            'PCL[out/b4dir/b4.jar]{'
+            'PCL[out/b41dir/b41.jar]#'
+            'PCL[out/b42dir/b42.jar]'
+            '}'
+            '}'
+            '}'
             ' ; '
-            'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]#PCL[/product/b.jar]}')
-        self.assertEqual(result, expect)
-#pylint: enable=line-too-long
+            'stored_class_loader_context_arg='
+            '--stored-class-loader-context=PCL[]{'
+            'PCL[/system/a.jar]#'
+            'PCL[/product/b.jar]{'
+            'PCL[/product/b1.jar]#'
+            'PCL[/product/b2.jar]#'
+            'PCL[/product/b4.jar]{'
+            'PCL[/product/b41.jar]#'
+            'PCL[/product/b42.jar]'
+            '}'
+            '}'
+            '}')
+        self.assertEqual(actual, expected)
+
 
 if __name__ == '__main__':
     unittest.main(verbosity=2)
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..c33b104 100755
--- a/scripts/manifest_check.py
+++ b/scripts/manifest_check.py
@@ -187,18 +187,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')
 
diff --git a/scripts/mkcratersp.py b/scripts/mkcratersp.py
deleted file mode 100755
index 86b4aa3..0000000
--- a/scripts/mkcratersp.py
+++ /dev/null
@@ -1,79 +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 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:
-  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/rbc-run b/scripts/rbc-run
deleted file mode 100755
index 8d93f0e..0000000
--- a/scripts/rbc-run
+++ /dev/null
@@ -1,18 +0,0 @@
-#! /bin/bash
-# Convert and run one configuration
-# Args: a product/board makefile optionally followed by additional arguments
-#       that will be passed to rbcrun.
-[[ $# -gt 1 && -f "$1" && -f "$2" ]] || { echo "Usage: ${0##*/} product.mk input_variables.mk [Additional rbcrun arguments]" >&2; exit 1; }
-set -eu
-
-declare -r output_root="${OUT_DIR:-out}"
-declare -r runner="${output_root}/rbcrun"
-declare -r converter="${output_root}/mk2rbc"
-declare -r launcher="${output_root}/rbc/launcher.rbc"
-declare -r makefile_list="${output_root}/.module_paths/configuration.list"
-declare -r makefile="$1"
-declare -r input_variables="$2"
-shift 2
-"${converter}" -mode=write -r --outdir "${output_root}/rbc" --input_variables "${input_variables}" --launcher="${launcher}" --makefile_list="${makefile_list}" "${makefile}"
-"${runner}" RBC_OUT="make,global" RBC_DEBUG="${RBC_DEBUG:-}" $@ "${launcher}"
-
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/unpack-prebuilt-apex.sh b/scripts/unpack-prebuilt-apex.sh
index b244f79..18f4da2 100755
--- a/scripts/unpack-prebuilt-apex.sh
+++ b/scripts/unpack-prebuilt-apex.sh
@@ -17,18 +17,17 @@
 # limitations under the License.
 
 # Tool to unpack an apex file and verify that the required files were extracted.
-if [ $# -lt 7 ]; then
-  echo "usage: $0 <deapaxer_path> <debugfs_path> <blkid_path> <fsck.erofs_path> <apex file> <output_dir> <required_files>+" >&2
+if [ $# -lt 6 ]; then
+  echo "usage: $0 <deapaxer_path> <debugfs_path> <fsck.erofs_path> <apex file> <output_dir> <required_files>+" >&2
   exit 1
 fi
 
 DEAPEXER_PATH=$1
 DEBUGFS_PATH=$2
-BLKID_PATH=$3
-FSCK_EROFS_PATH=$4
-APEX_FILE=$5
-OUTPUT_DIR=$6
-shift 6
+FSCK_EROFS_PATH=$3
+APEX_FILE=$4
+OUTPUT_DIR=$5
+shift 5
 REQUIRED_PATHS=$@
 
 rm -fr $OUTPUT_DIR
@@ -36,7 +35,6 @@
 
 # Unpack the apex file contents.
 $DEAPEXER_PATH --debugfs_path $DEBUGFS_PATH \
-               --blkid_path $BLKID_PATH \
                --fsckerofs_path $FSCK_EROFS_PATH \
                extract $APEX_FILE $OUTPUT_DIR
 
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index b6611e0..5d41958 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -86,27 +86,27 @@
 
 		// Add a platform_bootclasspath that depends on the fragment.
 		fixtureAddPlatformBootclasspathForBootclasspathFragmentWithExtra(
-			"com.android.art", "mybootclasspathfragment", java.ApexBootJarFragmentsForPlatformBootclasspath),
+			"com.android.art", "art-bootclasspath-fragment", java.ApexBootJarFragmentsForPlatformBootclasspath),
 
 		java.PrepareForBootImageConfigTest,
 		java.PrepareApexBootJarConfigsAndModules,
 		android.FixtureWithRootAndroidBp(`
 			sdk {
 				name: "mysdk",
-				bootclasspath_fragments: ["mybootclasspathfragment"],
+				bootclasspath_fragments: ["art-bootclasspath-fragment"],
 			}
 
 			apex {
 				name: "com.android.art",
 				key: "com.android.art.key",
 				bootclasspath_fragments: [
-					"mybootclasspathfragment",
+					"art-bootclasspath-fragment",
 				],
 				updatable: false,
 			}
 
 			bootclasspath_fragment {
-				name: "mybootclasspathfragment",
+				name: "art-bootclasspath-fragment",
 				image_name: "art",
 				contents: ["core1", "core2"],
 				apex_available: ["com.android.art"],
@@ -142,18 +142,18 @@
 	).RunTest(t)
 
 	// A preparer to update the test fixture used when processing an unpackage snapshot.
-	preparerForSnapshot := fixtureAddPrebuiltApexForBootclasspathFragment("com.android.art", "mybootclasspathfragment")
+	preparerForSnapshot := fixtureAddPrebuiltApexForBootclasspathFragment("com.android.art", "art-bootclasspath-fragment")
 
 	// Check that source on its own configures the bootImageConfig correctly.
-	java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/meta_lic")
-	java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic")
+	java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
+	java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
 
 	CheckSnapshot(t, result, "mysdk", "",
 		checkAndroidBpContents(`
 // This is auto-generated. DO NOT EDIT.
 
 prebuilt_bootclasspath_fragment {
-    name: "mybootclasspathfragment",
+    name: "art-bootclasspath-fragment",
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["com.android.art"],
@@ -189,12 +189,12 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
-.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
-.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/art-bootclasspath-fragment/android_common/modular-hiddenapi/annotation-flags.csv -> hiddenapi/annotation-flags.csv
+.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/metadata.csv -> hiddenapi/metadata.csv
+.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/index.csv -> hiddenapi/index.csv
+.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/signature-patterns.csv -> hiddenapi/signature-patterns.csv
+.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/filtered-stub-flags.csv -> hiddenapi/filtered-stub-flags.csv
+.intermediates/art-bootclasspath-fragment/android_common/modular-hiddenapi/filtered-flags.csv -> hiddenapi/filtered-flags.csv
 .intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/core1.jar
 .intermediates/mysdk/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/core2.jar
 		`),
@@ -206,31 +206,31 @@
 			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...,
 				)...,
 			)
-			java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/snapshot/mybootclasspathfragment/android_common_com.android.art/meta_lic")
-			java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic")
+			java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
+			java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
 		}),
 
 		snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot),
 
 		// Check the behavior of the snapshot when the source is preferred.
 		snapshotTestChecker(checkSnapshotWithSourcePreferred, func(t *testing.T, result *android.TestResult) {
-			java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/meta_lic")
-			java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic")
+			java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
+			java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
 		}),
 
 		snapshotTestPreparer(checkSnapshotPreferredWithSource, preparerForSnapshot),
 
 		// Check the behavior of the snapshot when it is preferred.
 		snapshotTestChecker(checkSnapshotPreferredWithSource, func(t *testing.T, result *android.TestResult) {
-			java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/snapshot/prebuilt_mybootclasspathfragment/android_common_com.android.art/meta_lic")
-			java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/meta_lic")
+			java.CheckMutatedArtBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
+			java.CheckMutatedFrameworkBootImageConfig(t, result, "out/soong/.intermediates/default/java/dex_bootjars/android_common/meta_lic")
 		}),
 	)
 
@@ -270,6 +270,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",
@@ -489,15 +495,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/javac/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/javac/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/javac/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 +515,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/javac/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/javac/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/javac/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, `
@@ -760,6 +766,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,
@@ -963,12 +975,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/javac/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/javac/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),
@@ -997,6 +1009,12 @@
 			"SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": targetBuildRelease,
 		}),
 
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+			}
+		}),
+
 		android.FixtureWithRootAndroidBp(`
 			sdk {
 				name: "mysdk",
@@ -1095,15 +1113,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/javac/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 +1191,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/javac/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/javac/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",
 		}
 
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 6159ea9..1b2b0f1 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.
@@ -160,7 +165,7 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/myjavalib.jar
+.intermediates/myjavalib/linux_glibc_common/javac-header/myjavalib.jar -> java/myjavalib.jar
 aidl/foo/bar/Test.aidl -> aidl/aidl/foo/bar/Test.aidl
 `),
 	)
@@ -206,7 +211,7 @@
 `),
 		checkAllCopyRules(`
 .intermediates/myjavalib/android_common/turbine-combined/myjavalib.jar -> java/android/myjavalib.jar
-.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
+.intermediates/myjavalib/linux_glibc_common/javac-header/myjavalib.jar -> java/linux_glibc/myjavalib.jar
 `),
 	)
 }
@@ -608,6 +613,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",
@@ -696,9 +706,9 @@
 		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/javac/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
 `),
 		checkInfoContents(result.Config, `
 [
@@ -799,7 +809,7 @@
     libs: ["mysdk_system-module"],
 }
 `),
-		checkAllCopyRules(".intermediates/system-module/linux_glibc_common/javac/system-module.jar -> java/system-module.jar"),
+		checkAllCopyRules(".intermediates/system-module/linux_glibc_common/javac-header/system-module.jar -> java/system-module.jar"),
 	)
 }
 
@@ -879,7 +889,7 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/hostjavalib/linux_glibc_common/javac/hostjavalib.jar -> java/hostjavalib.jar
+.intermediates/hostjavalib/linux_glibc_common/javac-header/hostjavalib.jar -> java/hostjavalib.jar
 .intermediates/androidjavalib/android_common/turbine-combined/androidjavalib.jar -> java/androidjavalib.jar
 .intermediates/myjavalib/android_common/javac/myjavalib.jar -> java/android/myjavalib.jar
 .intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
@@ -941,15 +951,15 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/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/javac/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/javac/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",
@@ -999,9 +1009,9 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib-foo.stubs/android_common/javac/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",
@@ -1052,10 +1062,10 @@
 }
 		`),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/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
 		`),
 	)
 }
@@ -1100,10 +1110,10 @@
 }
 		`),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/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"),
 	)
@@ -1153,16 +1163,23 @@
 }
 		`),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/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"],
@@ -1214,21 +1231,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)
 		}),
@@ -1270,9 +1288,9 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/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",
@@ -1318,9 +1336,9 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/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",
@@ -1376,12 +1394,12 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/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/javac/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",
@@ -1448,15 +1466,15 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/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/javac/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/javac/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",
@@ -1514,12 +1532,12 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/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/javac/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",
@@ -1568,9 +1586,9 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/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",
@@ -1625,9 +1643,9 @@
 }
 `),
 		checkAllCopyRules(`
-.intermediates/myjavalib.stubs/android_common/javac/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/sdk_test.go b/sdk/sdk_test.go
index 108a664..c4df146 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -442,6 +442,11 @@
 			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", "",
@@ -487,9 +492,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/javac/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..3c0b8ae 100644
--- a/sdk/systemserverclasspath_fragment_sdk_test.go
+++ b/sdk/systemserverclasspath_fragment_sdk_test.go
@@ -86,6 +86,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 {
diff --git a/sdk/update.go b/sdk/update.go
index 4aacd06..095e0c2 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -166,10 +166,7 @@
 			// 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() {
@@ -607,7 +604,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
@@ -1171,7 +1168,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())
 	}
@@ -1417,7 +1414,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 {
@@ -1987,6 +1984,10 @@
 	requiredTraits android.SdkMemberTraitSet
 }
 
+func (m *memberContext) ModuleErrorf(fmt string, args ...interface{}) {
+	m.sdkMemberContext.ModuleErrorf(fmt, args...)
+}
+
 func (m *memberContext) SdkModuleContext() android.ModuleContext {
 	return m.sdkMemberContext
 }
diff --git a/sh/Android.bp b/sh/Android.bp
index 2341a12..930fcf5 100644
--- a/sh/Android.bp
+++ b/sh/Android.bp
@@ -10,6 +10,7 @@
         "soong",
         "soong-android",
         "soong-cc",
+        "soong-java",
         "soong-testing",
         "soong-tradefed",
     ],
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index d5e9d42..97adeed 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -17,7 +17,6 @@
 import (
 	"fmt"
 	"path/filepath"
-	"sort"
 	"strings"
 
 	"android/soong/testing"
@@ -25,7 +24,6 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/cc"
 	"android/soong/snapshot"
 	"android/soong/tradefed"
@@ -144,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
 
@@ -153,7 +154,6 @@
 
 type ShBinary struct {
 	android.ModuleBase
-	android.BazelModuleBase
 
 	properties shBinaryProperties
 
@@ -171,7 +171,7 @@
 
 	installDir android.InstallPath
 
-	data       android.Paths
+	data       []android.DataPath
 	testConfig android.Path
 
 	dataModules map[string]android.Path
@@ -188,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)
 }
@@ -261,7 +270,7 @@
 		Output: s.outputFilePath,
 		Input:  s.sourceFilePath,
 	})
-	ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: []string{s.sourceFilePath.String()}})
+	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: []string{s.sourceFilePath.String()}})
 }
 
 func (s *ShBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -309,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"}}
@@ -324,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")
@@ -331,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")
+		}
 	}
 }
 
@@ -341,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"
@@ -361,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) {
@@ -412,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(),
@@ -428,7 +453,11 @@
 			ctx.PropertyErrorf(property, "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
 		}
 	})
-	ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
+
+	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 {
@@ -448,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...)
 				}
@@ -477,16 +488,15 @@
 	}}
 }
 
-func InitShBinaryModule(s *ShBinary) {
+func initShBinaryModule(s *ShBinary) {
 	s.AddProperties(&s.properties)
-	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)
+	initShBinaryModule(module)
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst)
 	return module
 }
@@ -495,7 +505,7 @@
 // to $(HOST_OUT)/bin.
 func ShBinaryHostFactory() android.Module {
 	module := &ShBinary{}
-	InitShBinaryModule(module)
+	initShBinaryModule(module)
 	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
 	return module
 }
@@ -503,7 +513,7 @@
 // sh_test defines a shell script based test module.
 func ShTestFactory() android.Module {
 	module := &ShTest{}
-	InitShBinaryModule(&module.ShBinary)
+	initShBinaryModule(&module.ShBinary)
 	module.AddProperties(&module.testProperties)
 
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst)
@@ -513,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)
+	initShBinaryModule(&module.ShBinary)
 	module.AddProperties(&module.testProperties)
 	// Default sh_test_host to unit_tests = true
 	if module.testProperties.Test_options.Unit_test == nil {
@@ -524,59 +534,6 @@
 	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/shared/env.go b/shared/env.go
index b7d3baf..75190cc 100644
--- a/shared/env.go
+++ b/shared/env.go
@@ -55,20 +55,23 @@
 	return data, nil
 }
 
-// Reads and deserializes a Soong environment file located at the given file path to determine its
-// staleness. If any environment variable values have changed, it prints them out and returns true.
+// Reads and deserializes a Soong environment file located at the given file
+// path to determine its staleness. If any environment variable values have
+// changed, it prints and returns changed environment variable values and
+// returns true.
 // Failing to read or parse the file also causes it to return true.
-func StaleEnvFile(filepath string, getenv func(string) string) (bool, error) {
+func StaleEnvFile(filepath string, getenv func(string) string) (isStale bool,
+	changedEnvironmentVariable []string, err error) {
 	data, err := ioutil.ReadFile(filepath)
 	if err != nil {
-		return true, err
+		return true, nil, err
 	}
 
 	var contents envFileData
 
 	err = json.Unmarshal(data, &contents)
 	if err != nil {
-		return true, err
+		return true, nil, err
 	}
 
 	var changed []string
@@ -78,6 +81,7 @@
 		cur := getenv(key)
 		if old != cur {
 			changed = append(changed, fmt.Sprintf("%s (%q -> %q)", key, old, cur))
+			changedEnvironmentVariable = append(changedEnvironmentVariable, key)
 		}
 	}
 
@@ -86,10 +90,10 @@
 		for _, s := range changed {
 			fmt.Printf("   %s\n", s)
 		}
-		return true, nil
+		return true, changedEnvironmentVariable, nil
 	}
 
-	return false, nil
+	return false, nil, nil
 }
 
 // Deserializes and environment serialized by EnvFileContents() and returns it
diff --git a/snapshot/host_fake_snapshot.go b/snapshot/host_fake_snapshot.go
index b04657d..63cd4e1 100644
--- a/snapshot/host_fake_snapshot.go
+++ b/snapshot/host_fake_snapshot.go
@@ -75,7 +75,7 @@
 }
 
 func registerHostSnapshotComponents(ctx android.RegistrationContext) {
-	ctx.RegisterSingletonType("host-fake-snapshot", HostToolsFakeAndroidSingleton)
+	ctx.RegisterParallelSingletonType("host-fake-snapshot", HostToolsFakeAndroidSingleton)
 }
 
 type hostFakeSingleton struct {
@@ -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
index ac002be..ab114b4 100644
--- a/snapshot/recovery_snapshot.go
+++ b/snapshot/recovery_snapshot.go
@@ -22,16 +22,14 @@
 	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
+	return &SnapshotSingleton{
+		"recovery",                     // name
+		"SOONG_RECOVERY_SNAPSHOT_ZIP",  // makeVar
+		android.OptionalPath{},         // snapshotZipFile
+		RecoverySnapshotImageSingleton, // Image
+		false,                          // Fake
+	}
 }
 
 // Determine if a dir under source tree is an SoC-owned proprietary directory based
@@ -68,7 +66,7 @@
 type RecoverySnapshotImage struct{}
 
 func (RecoverySnapshotImage) Init(ctx android.RegistrationContext) {
-	ctx.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton)
+	ctx.RegisterParallelSingletonType("recovery-snapshot", RecoverySnapshotSingleton)
 }
 
 func (RecoverySnapshotImage) RegisterAdditionalModule(ctx android.RegistrationContext, name string, factory android.ModuleFactory) {
diff --git a/snapshot/vendor_snapshot.go b/snapshot/vendor_snapshot.go
index 8f7b8c2..3e5f546 100644
--- a/snapshot/vendor_snapshot.go
+++ b/snapshot/vendor_snapshot.go
@@ -22,28 +22,24 @@
 	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
+	return &SnapshotSingleton{
+		"vendor",                     // name
+		"SOONG_VENDOR_SNAPSHOT_ZIP",  // makeVar
+		android.OptionalPath{},       // snapshotZipFile
+		VendorSnapshotImageSingleton, // Image
+		false,                        // Fake
+	}
 }
 
 func VendorFakeSnapshotSingleton() android.Singleton {
-	return &vendorFakeSnapshotSingleton
+	return &SnapshotSingleton{
+		"vendor",                         // name
+		"SOONG_VENDOR_FAKE_SNAPSHOT_ZIP", // makeVar
+		android.OptionalPath{},           // snapshotZipFile
+		VendorSnapshotImageSingleton,     // Image
+		true,                             // Fake
+	}
 }
 
 // Determine if a dir under source tree is an SoC-owned proprietary directory based
@@ -78,8 +74,8 @@
 type VendorSnapshotImage struct{}
 
 func (VendorSnapshotImage) Init(ctx android.RegistrationContext) {
-	ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
-	ctx.RegisterSingletonType("vendor-fake-snapshot", VendorFakeSnapshotSingleton)
+	ctx.RegisterParallelSingletonType("vendor-snapshot", VendorSnapshotSingleton)
+	ctx.RegisterParallelSingletonType("vendor-fake-snapshot", VendorFakeSnapshotSingleton)
 }
 
 func (VendorSnapshotImage) RegisterAdditionalModule(ctx android.RegistrationContext, name string, factory android.ModuleFactory) {
diff --git a/starlark_fmt/format.go b/starlark_fmt/format.go
index a97f71b..0224bcf 100644
--- a/starlark_fmt/format.go
+++ b/starlark_fmt/format.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"reflect"
 	"sort"
 	"strconv"
 	"strings"
@@ -33,6 +34,72 @@
 	return strings.Repeat(" ", level*indent)
 }
 
+func PrintAny(value any, indentLevel int) string {
+	return printAnyRecursive(reflect.ValueOf(value), indentLevel)
+}
+
+func printAnyRecursive(value reflect.Value, indentLevel int) string {
+	switch value.Type().Kind() {
+	case reflect.String:
+		val := value.String()
+		if strings.Contains(val, "\"") || strings.Contains(val, "\n") {
+			return `'''` + val + `'''`
+		}
+		return `"` + val + `"`
+	case reflect.Bool:
+		if value.Bool() {
+			return "True"
+		} else {
+			return "False"
+		}
+	case reflect.Int:
+		return fmt.Sprintf("%d", value.Int())
+	case reflect.Slice:
+		if value.Len() == 0 {
+			return "[]"
+		} else if value.Len() == 1 {
+			return "[" + printAnyRecursive(value.Index(0), indentLevel) + "]"
+		}
+		list := make([]string, 0, value.Len()+2)
+		list = append(list, "[")
+		innerIndent := Indention(indentLevel + 1)
+		for i := 0; i < value.Len(); i++ {
+			list = append(list, innerIndent+printAnyRecursive(value.Index(i), indentLevel+1)+`,`)
+		}
+		list = append(list, Indention(indentLevel)+"]")
+		return strings.Join(list, "\n")
+	case reflect.Map:
+		if value.Len() == 0 {
+			return "{}"
+		}
+		items := make([]string, 0, value.Len())
+		for _, key := range value.MapKeys() {
+			items = append(items, fmt.Sprintf(`%s%s: %s,`, Indention(indentLevel+1), printAnyRecursive(key, indentLevel+1), printAnyRecursive(value.MapIndex(key), indentLevel+1)))
+		}
+		sort.Strings(items)
+		return fmt.Sprintf(`{
+%s
+%s}`, strings.Join(items, "\n"), Indention(indentLevel))
+	case reflect.Struct:
+		if value.NumField() == 0 {
+			return "struct()"
+		}
+		items := make([]string, 0, value.NumField()+2)
+		items = append(items, "struct(")
+		for i := 0; i < value.NumField(); i++ {
+			if value.Type().Field(i).Anonymous {
+				panic("anonymous fields aren't supported")
+			}
+			name := value.Type().Field(i).Name
+			items = append(items, fmt.Sprintf(`%s%s = %s,`, Indention(indentLevel+1), name, printAnyRecursive(value.Field(i), indentLevel+1)))
+		}
+		items = append(items, Indention(indentLevel)+")")
+		return strings.Join(items, "\n")
+	default:
+		panic("Unhandled kind: " + value.Kind().String())
+	}
+}
+
 // PrintBool returns a Starlark compatible bool string.
 func PrintBool(item bool) string {
 	if item {
@@ -99,6 +166,16 @@
 	return PrintDict(valDict, indentLevel)
 }
 
+// PrintStringStringDict returns a Starlark-compatible string formatted as dictionary with
+// string keys and string values.
+func PrintStringStringDict(dict map[string]string, indentLevel int) string {
+	valDict := make(map[string]string, len(dict))
+	for k, v := range dict {
+		valDict[k] = fmt.Sprintf(`"%s"`, v)
+	}
+	return PrintDict(valDict, indentLevel)
+}
+
 // PrintDict returns a starlark-compatible string containing a dictionary with string keys and
 // values printed with no additional formatting.
 func PrintDict(dict map[string]string, indentLevel int) string {
diff --git a/starlark_import/Android.bp b/starlark_import/Android.bp
new file mode 100644
index 0000000..b43217b
--- /dev/null
+++ b/starlark_import/Android.bp
@@ -0,0 +1,36 @@
+// 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+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",
+    ],
+    deps: [
+        "go-starlark-starlark",
+        "go-starlark-starlarkstruct",
+        "go-starlark-starlarkjson",
+        "go-starlark-starlarktest",
+    ],
+}
diff --git a/starlark_import/README.md b/starlark_import/README.md
new file mode 100644
index 0000000..e444759
--- /dev/null
+++ b/starlark_import/README.md
@@ -0,0 +1,14 @@
+# 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
new file mode 100644
index 0000000..ebe4247
--- /dev/null
+++ b/starlark_import/starlark_import.go
@@ -0,0 +1,306 @@
+// 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
new file mode 100644
index 0000000..8a58e3b
--- /dev/null
+++ b/starlark_import/starlark_import_test.go
@@ -0,0 +1,122 @@
+// 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
new file mode 100644
index 0000000..b243471
--- /dev/null
+++ b/starlark_import/unmarshal.go
@@ -0,0 +1,304 @@
+// 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
new file mode 100644
index 0000000..bc0ea4c
--- /dev/null
+++ b/starlark_import/unmarshal_test.go
@@ -0,0 +1,148 @@
+// 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..1d5eb31 100644
--- a/sysprop/Android.bp
+++ b/sysprop/Android.bp
@@ -9,7 +9,6 @@
         "blueprint",
         "soong",
         "soong-android",
-        "soong-bp2build",
         "soong-cc",
         "soong-java",
     ],
@@ -19,7 +18,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 61fabae..766f3e7 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -23,7 +23,6 @@
 	"path"
 	"sync"
 
-	"android/soong/bazel"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -126,7 +125,6 @@
 type syspropLibrary struct {
 	android.ModuleBase
 	android.ApexModuleBase
-	android.BazelModuleBase
 
 	properties syspropLibraryProperties
 
@@ -169,6 +167,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 {
@@ -247,7 +251,7 @@
 			ctx.PropertyErrorf("srcs", "srcs contains non-sysprop file %q", syspropFile.String())
 		}
 	}
-	ctx.SetProvider(blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
+	android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
 
 	if ctx.Failed() {
 		return
@@ -339,9 +343,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")
@@ -378,7 +385,6 @@
 	)
 	android.InitAndroidModule(m)
 	android.InitApexModule(m)
-	android.InitBazelModule(m)
 	android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
 	return m
 }
@@ -410,9 +416,8 @@
 	Host_supported     *bool
 	Apex_available     []string
 	Min_sdk_version    *string
-	Bazel_module       struct {
-		Bp2build_available *bool
-	}
+	Cflags             []string
+	Ldflags            []string
 }
 
 type javaLibraryProperties struct {
@@ -493,11 +498,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"
@@ -572,16 +574,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..e5b3dea 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -42,6 +42,7 @@
 		cc_library_headers {
 			name: "libbase_headers",
 			vendor_available: true,
+			product_available: true,
 			recovery_available: true,
 		}
 
@@ -124,6 +125,12 @@
 			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),
@@ -250,6 +257,16 @@
 		result.ModuleForTests("libsysprop-odm", variant)
 	}
 
+	// product variant of vendor-owned sysprop_library
+	for _, variant := range []string{
+		"android_product.29_arm_armv7-a-neon_shared",
+		"android_product.29_arm_armv7-a-neon_static",
+		"android_product.29_arm64_armv8-a_shared",
+		"android_product.29_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 +276,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")
@@ -272,15 +286,15 @@
 	// Check for exported includes
 	coreVariant := "android_arm64_armv8-a_static"
 	vendorVariant := "android_vendor.29_arm64_armv8-a_static"
+	productVariant := "android_product.29_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"
 
-	platformOnProductPath := "libsysprop-platform-on-product/android_arm64_armv8-a_static/gen/sysprop/public/include"
+	platformOnProductPath := "libsysprop-platform-on-product/android_product.29_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"
+	vendorOnProductPath := "libsysprop-vendor-on-product/android_product.29_arm64_armv8-a_static/gen/sysprop/public/include"
 
 	platformClient := result.ModuleForTests("cc-client-platform", coreVariant)
 	platformFlags := platformClient.Rule("cc").Args["cFlags"]
@@ -294,14 +308,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)
diff --git a/testing/all_code_metadata.go b/testing/all_code_metadata.go
index 16d7aae..12aa7b5 100644
--- a/testing/all_code_metadata.go
+++ b/testing/all_code_metadata.go
@@ -21,14 +21,9 @@
 
 	ctx.VisitAllModules(
 		func(module android.Module) {
-			if !ctx.ModuleHasProvider(module, CodeMetadataProviderKey) {
-				return
+			if metadata, ok := android.SingletonModuleProvider(ctx, module, CodeMetadataProviderKey); ok {
+				intermediateMetadataPaths = append(intermediateMetadataPaths, metadata.IntermediatePath)
 			}
-			intermediateMetadataPaths = append(
-				intermediateMetadataPaths, ctx.ModuleProvider(
-					module, CodeMetadataProviderKey,
-				).(CodeMetadataProviderData).IntermediatePath,
-			)
 		},
 	)
 
diff --git a/testing/all_test_specs.go b/testing/all_test_specs.go
index 9d4645b..b035435 100644
--- a/testing/all_test_specs.go
+++ b/testing/all_test_specs.go
@@ -21,10 +21,9 @@
 	var intermediateMetadataPaths android.Paths
 
 	ctx.VisitAllModules(func(module android.Module) {
-		if !ctx.ModuleHasProvider(module, TestSpecProviderKey) {
-			return
+		if metadata, ok := android.SingletonModuleProvider(ctx, module, TestSpecProviderKey); ok {
+			intermediateMetadataPaths = append(intermediateMetadataPaths, metadata.IntermediatePath)
 		}
-		intermediateMetadataPaths = append(intermediateMetadataPaths, ctx.ModuleProvider(module, TestSpecProviderKey).(TestSpecProviderData).IntermediatePath)
 	})
 
 	rspFile := android.PathForOutput(ctx, fileContainingFilePaths)
diff --git a/testing/code_metadata.go b/testing/code_metadata.go
index 4550283..11ba430 100644
--- a/testing/code_metadata.go
+++ b/testing/code_metadata.go
@@ -20,6 +20,7 @@
 	"android/soong/android"
 	"android/soong/testing/code_metadata_internal_proto"
 	"github.com/google/blueprint"
+
 	"google.golang.org/protobuf/proto"
 )
 
@@ -36,7 +37,6 @@
 type CodeMetadataModule struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
-	android.BazelModuleBase
 
 	// Properties for "code_metadata"
 	properties struct {
@@ -84,7 +84,7 @@
 	IntermediatePath android.WritablePath
 }
 
-var CodeMetadataProviderKey = blueprint.NewProvider(CodeMetadataProviderData{})
+var CodeMetadataProviderKey = blueprint.NewProvider[CodeMetadataProviderData]()
 
 func (module *CodeMetadataModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	metadataList := make(
@@ -96,10 +96,8 @@
 	for _, m := range ctx.GetDirectDepsWithTag(codeDepTag) {
 		targetName := m.Name()
 		var moduleSrcs []string
-		if ctx.OtherModuleHasProvider(m, blueprint.SrcsFileProviderKey) {
-			moduleSrcs = ctx.OtherModuleProvider(
-				m, blueprint.SrcsFileProviderKey,
-			).(blueprint.SrcsFileProviderData).SrcPaths
+		if srcsFileInfo, ok := android.OtherModuleProvider(ctx, m, blueprint.SrcsFileProviderKey); ok {
+			moduleSrcs = srcsFileInfo.SrcPaths
 		}
 		if module.properties.MultiOwnership {
 			metadata := &code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership{
@@ -130,9 +128,9 @@
 	intermediatePath := android.PathForModuleOut(
 		ctx, "intermediateCodeMetadata.pb",
 	)
-	android.WriteFileRule(ctx, intermediatePath, string(protoData))
+	android.WriteFileRuleVerbatim(ctx, intermediatePath, string(protoData))
 
-	ctx.SetProvider(
+	android.SetProvider(ctx,
 		CodeMetadataProviderKey,
 		CodeMetadataProviderData{IntermediatePath: intermediatePath},
 	)
diff --git a/testing/code_metadata_proto/Android.bp b/testing/code_metadata_proto/Android.bp
index 8fcca19..f07efff 100644
--- a/testing/code_metadata_proto/Android.bp
+++ b/testing/code_metadata_proto/Android.bp
@@ -20,10 +20,24 @@
     name: "soong-testing-code_metadata_proto",
     pkgPath: "android/soong/testing/code_metadata_proto",
     deps: [
-            "golang-protobuf-reflect-protoreflect",
-            "golang-protobuf-runtime-protoimpl",
-        ],
+        "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/init.go b/testing/init.go
index 290efc6..edcbf59 100644
--- a/testing/init.go
+++ b/testing/init.go
@@ -30,6 +30,6 @@
 func RegisterBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("code_metadata", CodeMetadataFactory)
 	ctx.RegisterModuleType("test_spec", TestSpecFactory)
-	ctx.RegisterSingletonType("all_test_specs", AllTestSpecsFactory)
-	ctx.RegisterSingletonType("all_code_metadata", AllCodeMetadataFactory)
+	ctx.RegisterParallelSingletonType("all_code_metadata", AllCodeMetadataFactory)
+	ctx.RegisterParallelSingletonType("all_test_specs", AllTestSpecsFactory)
 }
diff --git a/testing/test_spec.go b/testing/test_spec.go
index c370f71..4d885c6 100644
--- a/testing/test_spec.go
+++ b/testing/test_spec.go
@@ -20,8 +20,9 @@
 
 	"android/soong/android"
 	"android/soong/testing/test_spec_proto"
-	"github.com/google/blueprint"
 	"google.golang.org/protobuf/proto"
+
+	"github.com/google/blueprint"
 )
 
 // ErrTestModuleDataNotFound is the error message for missing test module provider data.
@@ -40,7 +41,6 @@
 type TestSpecModule struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
-	android.BazelModuleBase
 
 	// Properties for "test_spec"
 	properties struct {
@@ -82,16 +82,16 @@
 	IntermediatePath android.WritablePath
 }
 
-var TestSpecProviderKey = blueprint.NewProvider(TestSpecProviderData{})
+var TestSpecProviderKey = blueprint.NewProvider[TestSpecProviderData]()
 
 type TestModuleProviderData struct {
 }
 
-var TestModuleProviderKey = blueprint.NewProvider(TestModuleProviderData{})
+var TestModuleProviderKey = blueprint.NewProvider[TestModuleProviderData]()
 
 func (module *TestSpecModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	for _, m := range ctx.GetDirectDepsWithTag(testsDepTag) {
-		if !ctx.OtherModuleHasProvider(m, TestModuleProviderKey) {
+		if _, ok := android.OtherModuleProvider(ctx, m, TestModuleProviderKey); !ok {
 			ctx.ModuleErrorf(ErrTestModuleDataNotFound, m.Name())
 		}
 	}
@@ -117,9 +117,9 @@
 	if err != nil {
 		ctx.ModuleErrorf("Error: %s", err.Error())
 	}
-	android.WriteFileRule(ctx, intermediatePath, string(protoData))
+	android.WriteFileRuleVerbatim(ctx, intermediatePath, string(protoData))
 
-	ctx.SetProvider(
+	android.SetProvider(ctx,
 		TestSpecProviderKey, TestSpecProviderData{
 			IntermediatePath: intermediatePath,
 		},
diff --git a/testing/test_spec_proto/Android.bp b/testing/test_spec_proto/Android.bp
index 1cac492..d5ad70b 100644
--- a/testing/test_spec_proto/Android.bp
+++ b/testing/test_spec_proto/Android.bp
@@ -20,10 +20,24 @@
     name: "soong-testing-test_spec_proto",
     pkgPath: "android/soong/testing/test_spec_proto",
     deps: [
-            "golang-protobuf-reflect-protoreflect",
-            "golang-protobuf-runtime-protoimpl",
-        ],
+        "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/tests/apex_comparison_tests.sh b/tests/apex_comparison_tests.sh
index e350323..8893060 100755
--- a/tests/apex_comparison_tests.sh
+++ b/tests/apex_comparison_tests.sh
@@ -29,7 +29,7 @@
 # Test Setup
 ############
 
-OUTPUT_DIR="$(mktemp -d tmp.XXXXXX)"
+OUTPUT_DIR="$(mktemp -d $(pwd)/tmp.XXXXXX)"
 SOONG_OUTPUT_DIR="$OUTPUT_DIR/soong"
 BAZEL_OUTPUT_DIR="$OUTPUT_DIR/bazel"
 
@@ -45,6 +45,12 @@
   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
 
 ###########
@@ -72,10 +78,7 @@
 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 //system/apex/tools:deapexer
-DEBUGFS_PATH="$(realpath $(call_bazel cquery --config=bp2build --config=linux_x86_64 --config=ci --output=files //external/e2fsprogs/debugfs))"
-DEAPEXER="bazel-bin/system/apex/tools/deapexer"
-DEAPEXER="$DEAPEXER --debugfs_path=$DEBUGFS_PATH"
+call_bazel build --config=bp2build --config=linux_x86_64 //external/e2fsprogs/debugfs
 
 #######
 # Tests
@@ -91,8 +94,8 @@
   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"
+  deapexer list "$SOONG_APEX" > "$SOONG_LIST"
+  deapexer list "$BAZEL_APEX" > "$BAZEL_LIST"
 
   if cmp -s "$SOONG_LIST" "$BAZEL_LIST"
   then
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 5935247..5fc05f8 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -207,8 +207,8 @@
 function test_soong_build_rerun_iff_environment_changes() {
   setup
 
-  mkdir -p cherry
-  cat > cherry/Android.bp <<'EOF'
+  mkdir -p build/soong/cherry
+  cat > build/soong/cherry/Android.bp <<'EOF'
 bootstrap_go_package {
   name: "cherry",
   pkgPath: "android/soong/cherry",
@@ -224,7 +224,7 @@
 }
 EOF
 
-  cat > cherry/cherry.go <<'EOF'
+  cat > build/soong/cherry/cherry.go <<'EOF'
 package cherry
 
 import (
@@ -317,8 +317,8 @@
   run_soong
   local -r mtime1=$(stat -c "%y" out/soong/build.ninja)
 
-  mkdir -p a
-  cat > a/Android.bp <<'EOF'
+  mkdir -p vendor/foo/picard
+  cat > vendor/foo/picard/Android.bp <<'EOF'
 bootstrap_go_package {
   name: "picard-soong-rules",
   pkgPath: "android/soong/picard",
@@ -334,7 +334,7 @@
 }
 EOF
 
-  cat > a/picard.go <<'EOF'
+  cat > vendor/foo/picard/picard.go <<'EOF'
 package picard
 
 import (
@@ -390,11 +390,11 @@
 function test_glob_during_bootstrapping() {
   setup
 
-  mkdir -p a
-  cat > a/Android.bp <<'EOF'
+  mkdir -p build/soong/picard
+  cat > build/soong/picard/Android.bp <<'EOF'
 build=["foo*.bp"]
 EOF
-  cat > a/fooa.bp <<'EOF'
+  cat > build/soong/picard/fooa.bp <<'EOF'
 bootstrap_go_package {
   name: "picard-soong-rules",
   pkgPath: "android/soong/picard",
@@ -410,7 +410,7 @@
 }
 EOF
 
-  cat > a/picard.go <<'EOF'
+  cat > build/soong/picard/picard.go <<'EOF'
 package picard
 
 import (
@@ -459,7 +459,7 @@
 
   grep -q "Make it so" out/soong/build.ninja || fail "Original action not present"
 
-  cat > a/foob.bp <<'EOF'
+  cat > build/soong/picard/foob.bp <<'EOF'
 bootstrap_go_package {
   name: "worf-soong-rules",
   pkgPath: "android/soong/worf",
@@ -476,7 +476,7 @@
 }
 EOF
 
-  cat > a/worf.go <<'EOF'
+  cat > build/soong/picard/worf.go <<'EOF'
 package worf
 
 import "android/soong/picard"
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 68d7f8d..8a64a56 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -53,6 +53,20 @@
   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
@@ -218,6 +232,63 @@
   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
@@ -336,36 +407,39 @@
   fi
 }
 
-# Smoke test to verify api_bp2build worksapce does not contain any errors
-function test_api_bp2build_empty_build() {
+function test_bazel_standalone_output_paths_contain_product_name {
   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",
+  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
-  # Child dir Android.bp
-  mkdir -p foo/api
-  cat > foo/api/Android.bp << 'EOF'
-package{}
+
+  cat > a/qq.cc <<EOF
+#include "qq.h"
+int qq() {
+  return QQ;
+}
 EOF
-  touch foo/api/libfoo.map.txt
-  # Run test
-  run_soong api_bp2build
-  run_bazel build --config=android --config=api_bp2build //foo:libfoo.contribution
+
+  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
index 97ae97e..e3c189f 100755
--- a/tests/dcla_apex_comparison_test.sh
+++ b/tests/dcla_apex_comparison_test.sh
@@ -45,11 +45,18 @@
   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
@@ -76,6 +83,10 @@
 ############
 OUTPUT_DIR="$(mktemp -d tmp.XXXXXX)"
 
+function call_bazel() {
+  build/bazel/bin/bazel $@
+}
+
 function cleanup {
   rm -rf "${OUTPUT_DIR}"
 }
@@ -87,7 +98,9 @@
 
 function extract_dcla_libs() {
   local product=$1; shift
-  for module in "${MODULES[@]}"; do
+  local modules=("$@"); shift
+
+  for module in "${modules[@]}"; do
     local apex="${OUTPUT_DIR}/${product}/${module}.apex"
     local extract_dir="${OUTPUT_DIR}/${product}/${module}/extract"
 
@@ -97,11 +110,12 @@
 
 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
+      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
@@ -112,7 +126,7 @@
         sha="${sha% *}"
         if [ "${prev_sha}" == "" ]; then
           prev_sha="${sha}"
-        elif [ "${sha}" != "${prev_sha}" ] && { [ "${lib}" != "libcrypto.so" ] || [ "${module}" != "com.android.tethering" ]; }; then
+        elif [ "${sha}" != "${prev_sha}" ] && { [ "${lib}" != "libcrypto.so" ] || [[ "${module}" != *"com.android.tethering" ]]; }; then
           echo "Test failed, ${lib} has different hash value"
           exit 1
         fi
@@ -131,8 +145,22 @@
     --product "${product}" \
     --dist_dir "${OUTPUT_DIR}/${product}"
 
-  extract_dcla_libs "${product}"
-  compare_dcla_libs "${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
new file mode 100755
index 0000000..3799e92
--- /dev/null
+++ b/tests/genrule_sandbox_test.py
@@ -0,0 +1,207 @@
+#!/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.
+
+import argparse
+import asyncio
+import collections
+import json
+import os
+import socket
+import subprocess
+import sys
+import textwrap
+
+def get_top() -> str:
+  path = '.'
+  while not os.path.isfile(os.path.join(path, 'build/soong/tests/genrule_sandbox_test.py')):
+    if os.path.abspath(path) == '/':
+      sys.exit('Could not find android source tree root.')
+    path = os.path.join(path, '..')
+  return os.path.abspath(path)
+
+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",
+  ]
+  args.extend(targets)
+  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)
+
+
+async def _find_outputs_for_modules(modules):
+  module_path = "out/soong/module-actions.json"
+
+  if not os.path.exists(module_path):
+    await _build_with_soong('out', ["json-module-graph"])
+
+  with open(module_path) as f:
+    action_graph = json.load(f)
+
+  module_to_outs = collections.defaultdict(set)
+  for mod in action_graph:
+    name = mod["Name"]
+    if name in modules:
+      for act in (mod["Module"]["Actions"] or []):
+        if "}generate" in act["Desc"]:
+          module_to_outs[name].update(act["Outputs"])
+  return module_to_outs
+
+
+def _compare_outputs(module_to_outs, tempdir) -> dict[str, list[str]]:
+  different_modules = collections.defaultdict(list)
+  for module, outs in module_to_outs.items():
+    for out in outs:
+      try:
+        subprocess.check_output(["diff", os.path.join(tempdir, out), out])
+      except subprocess.CalledProcessError as e:
+        different_modules[module].append(e.stdout)
+
+  return different_modules
+
+
+async def main():
+  parser = argparse.ArgumentParser()
+  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",
+      help="whether to display differing files",
+  )
+  parser.add_argument(
+      "--output-paths-only",
+      "-o",
+      action="store_true",
+      help="Whether to only return the output paths per module",
+  )
+  args = parser.parse_args()
+  os.chdir(get_top())
+
+  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 = await _find_outputs_for_modules(set(args.modules))
+  if not module_to_outs:
+    sys.exit("No outputs found")
+
+  if args.output_paths_only:
+    for m, o in module_to_outs.items():
+      print(f"{m} outputs: {o}")
+    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)
+
+  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 = {}
+
+  # nsjail will complain if the out dir doesn't exist
+  os.makedirs("out", exist_ok=True)
+  os.makedirs(other_out_dir, exist_ok=True)
+
+  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__":
+  asyncio.run(main())
diff --git a/tests/lib.sh b/tests/lib.sh
index 715eac1..e0b319e 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
 
@@ -52,6 +57,10 @@
   cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
 }
 
+function delete_directory {
+  rm -rf "$MOCK_TOP/$1"
+}
+
 function symlink_file {
   local file="$1"
 
@@ -99,6 +108,20 @@
   symlink_directory external/python
   symlink_directory external/sqlite
   symlink_directory external/spdx-tools
+  symlink_directory libcore
+
+  # TODO: b/286872909 - Remove these when the blocking bug is completed
+  symlink_directory external/libavc
+  symlink_directory external/libaom
+  symlink_directory external/libvpx
+  symlink_directory frameworks/base/libs/androidfw
+  symlink_directory external/libhevc
+  symlink_directory external/libexif
+  symlink_directory external/libopus
+  symlink_directory external/libmpeg2
+  symlink_directory external/expat
+  symlink_directory external/flac
+  symlink_directory system/extras/toolchain-extras
 
   touch "$MOCK_TOP/Android.bp"
 }
@@ -124,14 +147,24 @@
   copy_directory build/bazel
   copy_directory build/bazel_common_rules
 
+  # This requires pulling more tools into the mock top to build partitions
+  delete_directory build/bazel/examples/partitions
+
   symlink_directory packages/modules/common/build
   symlink_directory prebuilts/bazel
   symlink_directory prebuilts/clang
   symlink_directory prebuilts/jdk
   symlink_directory external/bazel-skylib
   symlink_directory external/bazelbuild-rules_android
+  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
@@ -170,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
index 05d3a66..ca63fdf 100755
--- a/tests/mixed_mode_test.sh
+++ b/tests/mixed_mode_test.sh
@@ -1,4 +1,4 @@
-#!/bin/bash -eu
+#!/bin/bash
 
 set -o pipefail
 
@@ -88,12 +88,12 @@
     fail "Bazel actions not found for force-enabled module"
   fi
 
-  local exit_code=`run_soong --bazel-force-enabled-modules=unenabled-touch-file nothing`
+  unused=`run_soong --bazel-force-enabled-modules=unenabled-touch-file --ensure-allowlist-integrity nothing >/dev/null`
 
-  if [[ $exit_code -ne 1 ]]; then
+  if [[ $? -ne 1 ]]; then
     fail "Expected failure due to force-enabling an unenabled module "
   fi
 }
 
 
-scan_and_run_tests
\ No newline at end of file
+scan_and_run_tests
diff --git a/tests/persistent_bazel_test.sh b/tests/persistent_bazel_test.sh
index 4e2982a..9b7b58f 100755
--- a/tests/persistent_bazel_test.sh
+++ b/tests/persistent_bazel_test.sh
@@ -73,8 +73,8 @@
 
   USE_PERSISTENT_BAZEL=1 run_soong nothing 1>out/failurelog.txt 2>&1 && fail "Expected build failure" || true
 
-  if ! grep -sq "'build/bazel/rules' is not a package" out/failurelog.txt ; then
-    fail "Expected error to contain 'build/bazel/rules' is not a package, instead got:\n$(cat out/failurelog.txt)"
+  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
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index e1aa70c..231e18b 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -4,21 +4,25 @@
 
 TOP="$(readlink -f "$(dirname "$0")"/../../..)"
 "$TOP/build/soong/tests/androidmk_test.sh"
+"$TOP/build/soong/tests/b_args_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/bazel/ci/rbc_regression_test.sh" aosp_arm64-userdebug
+"$TOP/build/soong/tests/stale_metrics_files_test.sh"
+"$TOP/build/soong/tests/symlink_forest_rerun_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"
-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"
+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/soong/tests/sbom_test.sh"
+"$TOP/build/bazel/ci/b_test.sh"
+"$TOP/build/soong/tests/symlinks_path_test.sh"
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index 30a1d37..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,55 +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 /bin \
-    -I /bugreports \
-    -I /cache \
-    -I /d \
-    -I /etc \
-    -I /init \
-    -I /odm/app \
-    -I /odm/bin \
-    -I /odm_dlkm/etc \
-    -I /odm/etc \
-    -I /odm/firmware \
-    -I /odm/framework \
-    -I /odm/lib \
-    -I /odm/lib64 \
-    -I /odm/overlay \
-    -I /odm/priv-app \
-    -I /odm/usr \
-    -I /sdcard \
-    -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/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 \
-    -I /vendor_dlkm/etc"
-
   # 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.
@@ -198,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"
@@ -216,19 +171,54 @@
     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"
+
   # Teardown
   cleanup "${out_dir}"
 }
 
+function verify_package_verification_code {
+  local sbom_file="$1"; shift
+
+  local -a file_checksums
+  local package_product_found=
+  while read -r line;
+  do
+    if grep -q 'PackageVerificationCode' <<<"$line"
+    then
+      package_product_found=true
+    fi
+    if [ -n "$package_product_found" ]
+    then
+      if grep -q 'FileChecksum' <<< "$line"
+      then
+        checksum=$(echo $line | sed 's/^.*: //')
+        file_checksums+=("$checksum")
+      fi
+    fi
+  done <<< "$(grep -E 'PackageVerificationCode|FileChecksum' $sbom_file)"
+  IFS=$'\n' file_checksums=($(sort <<<"${file_checksums[*]}")); unset IFS
+  IFS= expected_package_verification_code=$(printf "${file_checksums[*]}" | sha1sum | sed 's/[[:space:]]*-//'); unset IFS
+
+  actual_package_verification_code=$(grep PackageVerificationCode $sbom_file | sed 's/PackageVerificationCode: //g')
+  if [ $actual_package_verification_code = $expected_package_verification_code ]
+  then
+    echo "Package verification code is correct."
+  else
+    echo "Unexpected package verification code."
+    exit 1
+  fi
+}
+
 function test_sbom_unbundled_apex {
   # Setup
   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
@@ -260,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"
@@ -282,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/soong_test.sh b/tests/soong_test.sh
index f7bee40..6779d8a 100755
--- a/tests/soong_test.sh
+++ b/tests/soong_test.sh
@@ -9,12 +9,8 @@
 function test_m_clean_works {
   setup
 
-  # Create a directory with files that cannot be removed
-  mkdir -p out/bad_directory_permissions
-  touch out/bad_directory_permissions/unremovable_file
-  # File permissions are fine but directory permissions are bad
-  chmod a+rwx out/bad_directory_permissions/unremovable_file
-  chmod a-rwx out/bad_directory_permissions
+  mkdir -p out/some_directory
+  touch out/some_directory/some_file
 
   run_soong clean
 }
diff --git a/tests/stale_metrics_files_test.sh b/tests/stale_metrics_files_test.sh
new file mode 100755
index 0000000..0da89c3
--- /dev/null
+++ b/tests/stale_metrics_files_test.sh
@@ -0,0 +1,47 @@
+#!/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/tests/symlink_forest_rerun_test.sh b/tests/symlink_forest_rerun_test.sh
new file mode 100755
index 0000000..74e779e
--- /dev/null
+++ b/tests/symlink_forest_rerun_test.sh
@@ -0,0 +1,43 @@
+#!/bin/bash -eu
+
+set -o pipefail
+
+# Tests that symlink forest will replant if soong_build has changed
+# Any change to the build system should trigger a rerun
+
+source "$(dirname "$0")/lib.sh"
+
+function test_symlink_forest_reruns {
+  setup
+
+  mkdir -p a
+  touch a/g.txt
+  cat > a/Android.bp <<'EOF'
+filegroup {
+    name: "g",
+    srcs: ["g.txt"],
+  }
+EOF
+
+  run_soong g
+
+  mtime=`cat out/soong/workspace/soong_build_mtime`
+  # rerun with no changes - ensure that it hasn't changed
+  run_soong g
+  newmtime=`cat out/soong/workspace/soong_build_mtime`
+  if [[ ! "$mtime" == "$mtime" ]]; then
+     fail "symlink forest reran when it shouldn't have"
+  fi
+
+  # change exit codes to force a soong_build rebuild.
+  sed -i 's/os.Exit(1)/os.Exit(2)/g' build/soong/bp2build/symlink_forest.go
+
+  run_soong g
+  newmtime=`cat out/soong/workspace/soong_build_mtime`
+  if [[ "$mtime" == "$newmtime" ]]; then
+     fail "symlink forest did not rerun when it should have"
+  fi
+
+}
+
+scan_and_run_tests
diff --git a/tests/symlinks_path_test.sh b/tests/symlinks_path_test.sh
new file mode 100755
index 0000000..ed42911
--- /dev/null
+++ b/tests/symlinks_path_test.sh
@@ -0,0 +1,51 @@
+#!/bin/bash -eu
+
+set -o pipefail
+
+# Test that relative symlinks work by recreating the bug in b/259191764
+# In some cases, developers prefer to move their checkouts. This causes
+# issues in that symlinked files (namely, the bazel wrapper script)
+# cannot be found. As such, we implemented relative symlinks so that a
+# moved checkout doesn't need a full clean before rebuilding.
+# The bazel output base will still need to be removed, as Starlark
+# doesn't seem to support relative symlinks yet.
+
+source "$(dirname "$0")/lib.sh"
+
+function check_link_has_mock_top_prefix {
+  input_link=$1
+  link_target=`readlink $input_link`
+  if [[ $link_target != "$MOCK_TOP"* ]]; then
+    echo "Symlink for file $input_link -> $link_target doesn't start with $MOCK_TOP"
+    exit 1
+  fi
+}
+
+function test_symlinks_updated_when_top_dir_changed {
+  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
+
+  # Modify OUT_DIR in a subshell so it doesn't affect the top level one.
+  (export OUT_DIR=$MOCK_TOP/$outdir; run_soong bp2build && run_bazel build --config=bp2build --config=ci //a:g)
+
+  g_txt="out2/soong/workspace/a/g.txt"
+  check_link_has_mock_top_prefix "$g_txt"
+
+  move_mock_top
+
+  (export OUT_DIR=$MOCK_TOP/$outdir; run_soong bp2build && run_bazel build --config=bp2build --config=ci //a:g)
+  check_link_has_mock_top_prefix "$g_txt"
+}
+
+scan_and_run_tests
\ No newline at end of file
diff --git a/third_party/zip/android.go b/third_party/zip/android.go
index f8e45c5..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
@@ -170,7 +175,7 @@
 func (w *Writer) CreateHeaderAndroid(fh *FileHeader) (io.Writer, error) {
 	writeDataDescriptor := fh.Method != Store
 	if writeDataDescriptor {
-		fh.Flags &= DataDescriptorFlag
+		fh.Flags |= DataDescriptorFlag
 	} else {
 		fh.Flags &= ^uint16(DataDescriptorFlag)
 	}
diff --git a/third_party/zip/android_test.go b/third_party/zip/android_test.go
index 46588d4..3911dd4 100644
--- a/third_party/zip/android_test.go
+++ b/third_party/zip/android_test.go
@@ -190,7 +190,9 @@
 		t.Errorf("wanted directoryRecords %d, got %d", w, g)
 	}
 
-	if g, w := d.directorySize, uint64(uint32max); g != w {
+	zip64ExtraBuf := 48                                                  // 4x uint16 + 5x uint64
+	expectedDirSize := directoryHeaderLen + zip64ExtraBuf + len("large") // name of header
+	if g, w := d.directorySize, uint64(expectedDirSize); g != w {
 		t.Errorf("wanted directorySize %d, got %d", w, g)
 	}
 
diff --git a/tradefed/Android.bp b/tradefed/Android.bp
index a161108..f0336a3 100644
--- a/tradefed/Android.bp
+++ b/tradefed/Android.bp
@@ -11,7 +11,6 @@
     ],
     srcs: [
         "autogen.go",
-        "autogen_bazel.go",
         "config.go",
         "makevars.go",
     ],
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 3c55c51..ddd0a80 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -167,7 +167,6 @@
 	for _, c := range options.OptionsForAutogenerated {
 		configs = append(configs, c)
 	}
-	testRunnerConfigs := append([]Option{}, options.TestRunnerOptions...)
 	name := options.Name
 	if name == "" {
 		name = ctx.ModuleName()
@@ -176,15 +175,15 @@
 	if autogenPath != nil {
 		templatePath := getTestConfigTemplate(ctx, options.TestConfigTemplateProp)
 		if templatePath.Valid() {
-			autogenTemplate(ctx, name, autogenPath, templatePath.String(), configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
+			autogenTemplate(ctx, name, autogenPath, templatePath.String(), configs, options.TestRunnerOptions, options.OutputFileName, options.TestInstallBase)
 		} else {
 			if ctx.Device() {
-				autogenTemplate(ctx, name, autogenPath, options.DeviceTemplate, configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
+				autogenTemplate(ctx, name, autogenPath, options.DeviceTemplate, configs, options.TestRunnerOptions, options.OutputFileName, options.TestInstallBase)
 			} else {
 				if Bool(options.UnitTest) {
-					autogenTemplate(ctx, name, autogenPath, options.HostUnitTestTemplate, configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
+					autogenTemplate(ctx, name, autogenPath, options.HostUnitTestTemplate, configs, options.TestRunnerOptions, options.OutputFileName, options.TestInstallBase)
 				} else {
-					autogenTemplate(ctx, name, autogenPath, options.HostTemplate, configs, testRunnerConfigs, options.OutputFileName, options.TestInstallBase)
+					autogenTemplate(ctx, name, autogenPath, options.HostTemplate, configs, options.TestRunnerOptions, options.OutputFileName, options.TestInstallBase)
 				}
 			}
 		}
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/suite_harness/tradefed_binary.go b/tradefed/suite_harness/tradefed_binary.go
index a421d8b..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,
 			})
 
@@ -78,7 +80,6 @@
 		// Add dependencies required by all tradefed_binary modules.
 		props.Libs = []string{
 			"tradefed",
-			"tradefed-test-framework",
 			"loganalysis",
 			"compatibility-host-util",
 		}
@@ -96,6 +97,7 @@
 	Short_name string
 	Full_name  string
 	Version    string
+	Suite_arch string
 }
 
 type tradefedBinaryGen struct {
@@ -128,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/ui/build/Android.bp b/ui/build/Android.bp
index b79754c..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,6 +47,7 @@
         "soong-ui-tracer",
     ],
     srcs: [
+        "androidmk_denylist.go",
         "build.go",
         "cleanbuild.go",
         "config.go",
@@ -74,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..e004cdc
--- /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"
+
+	"android/soong/android"
+)
+
+var androidmk_denylist []string = []string{
+	"chained_build_config/",
+	"cts/",
+	"dalvik/",
+	"developers/",
+	// Do not block other directories in kernel/, see b/319658303.
+	"kernel/configs/",
+	"kernel/prebuilts/",
+	"kernel/tests/",
+	"libcore/",
+	"libnativehelper/",
+	"pdk/",
+	"toolchain/",
+}
+
+func blockAndroidMks(androidMks []string) []string {
+	return android.FilterListPred(androidMks, func(s string) bool {
+		for _, d := range androidmk_denylist {
+			if strings.HasPrefix(s, d) {
+				return false
+			}
+		}
+		return true
+	})
+}
diff --git a/ui/build/build.go b/ui/build/build.go
index 6874ef7..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,25 +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.bazelDevMode {
-		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-dev 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"}
@@ -237,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)
 
@@ -249,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)
@@ -260,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 {
@@ -322,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/cleanbuild.go b/ui/build/cleanbuild.go
index fd60177..41cb5ab 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -17,7 +17,6 @@
 import (
 	"bytes"
 	"fmt"
-	"io/fs"
 	"io/ioutil"
 	"os"
 	"path/filepath"
@@ -59,37 +58,9 @@
 	FILEMODE_USER_EXECUTE = FILEMODE_EXECUTE << FILEMODE_USER_SHIFT
 )
 
-// Ensures that files and directories in the out dir can be deleted.
-// For example, Bazen can generate output directories where the write bit isn't set, causing 'm' clean' to fail.
-func ensureOutDirRemovable(ctx Context, config Config) {
-	err := filepath.WalkDir(config.OutDir(), func(path string, d fs.DirEntry, err error) error {
-		if err != nil {
-			return err
-		}
-		if d.IsDir() {
-			info, err := d.Info()
-			if err != nil {
-				return err
-			}
-			// Equivalent to running chmod u+rwx on each directory
-			newMode := info.Mode() | FILEMODE_USER_READ | FILEMODE_USER_WRITE | FILEMODE_USER_EXECUTE
-			if err := os.Chmod(path, newMode); err != nil {
-				return err
-			}
-		}
-		// Continue walking the out dir...
-		return nil
-	})
-	if err != nil && !os.IsNotExist(err) {
-		// Display the error, but don't crash.
-		ctx.Println(err.Error())
-	}
-}
-
 // Remove everything under the out directory. Don't remove the out directory
 // itself in case it's a symlink.
 func clean(ctx Context, config Config) {
-	ensureOutDirRemovable(ctx, config)
 	removeGlobs(ctx, filepath.Join(config.OutDir(), "*"))
 	ctx.Println("Entire build directory removed.")
 }
@@ -164,6 +135,7 @@
 		productOut("obj/NOTICE_FILES"),
 		productOut("obj/PACKAGING"),
 		productOut("ramdisk"),
+		productOut("ramdisk_16k"),
 		productOut("debug_ramdisk"),
 		productOut("vendor_ramdisk"),
 		productOut("vendor_debug_ramdisk"),
diff --git a/ui/build/config.go b/ui/build/config.go
index 31031eb..5085c68 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -15,13 +15,14 @@
 package build
 
 import (
-	"context"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"io/ioutil"
 	"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"
 
@@ -39,9 +41,6 @@
 const (
 	envConfigDir = "vendor/google/tools/soong_config"
 	jsonSuffix   = "json"
-
-	configFetcher         = "vendor/google/tools/soong/expconfigfetcher"
-	envConfigFetchTimeout = 10 * time.Second
 )
 
 var (
@@ -67,28 +66,27 @@
 	logsPrefix    string
 
 	// From the arguments
-	parallel          int
-	keepGoing         int
-	verbose           bool
-	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
-	skipSoong         bool
-	skipNinja         bool
-	skipSoongTests    bool
-	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
+	parallel                 int
+	keepGoing                int
+	verbose                  bool
+	checkbuild               bool
+	dist                     bool
+	jsonModuleGraph          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
+	skipSoong                bool
+	skipNinja                bool
+	skipSoongTests           bool
+	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
+	buildFromSourceStub      bool
+	ensureAllowlistIntegrity bool // For CI builds - make sure modules are mixed-built
 
 	// From the product config
 	katiArgs        []string
@@ -107,17 +105,11 @@
 
 	pathReplaced bool
 
-	bazelProdMode    bool
-	bazelDevMode     bool
-	bazelStagingMode bool
-
 	// Set by multiproduct_kati
 	emptyNinjaFile bool
 
 	metricsUploader string
 
-	bazelForceEnabledModules string
-
 	includeTags    []string
 	sourceRootDirs []string
 
@@ -138,6 +130,9 @@
 	EXTERNAL_FILE
 	// ninja uses a prioritized module list from Soong
 	HINT_FROM_SOONG
+	// If ninja log exists, use NINJA_LOG, if not, use HINT_FROM_SOONG instead.
+	// We can assume it is an incremental build if ninja log exists.
+	DEFAULT
 )
 const srcDirFileCheck = "build/soong/root.bp"
 
@@ -168,87 +163,6 @@
 	}
 }
 
-// fetchEnvConfig optionally fetches a configuration file that can then subsequently be
-// loaded into Soong environment to control certain aspects of build behavior (e.g., enabling RBE).
-// If a configuration file already exists on disk, the fetch is run in the background
-// so as to NOT block the rest of the build execution.
-func fetchEnvConfig(ctx Context, config *configImpl, envConfigName string) error {
-	configName := envConfigName + "." + jsonSuffix
-	expConfigFetcher := &smpb.ExpConfigFetcher{Filename: &configName}
-	defer func() {
-		ctx.Metrics.ExpConfigFetcher(expConfigFetcher)
-	}()
-	if !config.GoogleProdCredsExist() {
-		status := smpb.ExpConfigFetcher_MISSING_GCERT
-		expConfigFetcher.Status = &status
-		return nil
-	}
-
-	s, err := os.Stat(configFetcher)
-	if err != nil {
-		if os.IsNotExist(err) {
-			return nil
-		}
-		return err
-	}
-	if s.Mode()&0111 == 0 {
-		status := smpb.ExpConfigFetcher_ERROR
-		expConfigFetcher.Status = &status
-		return fmt.Errorf("configuration fetcher binary %v is not executable: %v", configFetcher, s.Mode())
-	}
-
-	configExists := false
-	outConfigFilePath := filepath.Join(config.OutDir(), configName)
-	if _, err := os.Stat(outConfigFilePath); err == nil {
-		configExists = true
-	}
-
-	tCtx, cancel := context.WithTimeout(ctx, envConfigFetchTimeout)
-	fetchStart := time.Now()
-	cmd := exec.CommandContext(tCtx, configFetcher, "-output_config_dir", config.OutDir(),
-		"-output_config_name", configName)
-	if err := cmd.Start(); err != nil {
-		status := smpb.ExpConfigFetcher_ERROR
-		expConfigFetcher.Status = &status
-		return err
-	}
-
-	fetchCfg := func() error {
-		if err := cmd.Wait(); err != nil {
-			status := smpb.ExpConfigFetcher_ERROR
-			expConfigFetcher.Status = &status
-			return err
-		}
-		fetchEnd := time.Now()
-		expConfigFetcher.Micros = proto.Uint64(uint64(fetchEnd.Sub(fetchStart).Microseconds()))
-		expConfigFetcher.Filename = proto.String(outConfigFilePath)
-
-		if _, err := os.Stat(outConfigFilePath); err != nil {
-			status := smpb.ExpConfigFetcher_NO_CONFIG
-			expConfigFetcher.Status = &status
-			return err
-		}
-		status := smpb.ExpConfigFetcher_CONFIG
-		expConfigFetcher.Status = &status
-		return nil
-	}
-
-	// If a config file does not exist, wait for the config file to be fetched. Otherwise
-	// fetch the config file in the background and return immediately.
-	if !configExists {
-		defer cancel()
-		return fetchCfg()
-	}
-
-	go func() {
-		defer cancel()
-		if err := fetchCfg(); err != nil {
-			ctx.Verbosef("Failed to fetch config file %v: %v\n", configName, err)
-		}
-	}()
-	return nil
-}
-
 func loadEnvConfig(ctx Context, config *configImpl, bc string) error {
 	if bc == "" {
 		return nil
@@ -284,37 +198,16 @@
 	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, _ ...string) Config {
-	ret := &configImpl{
-		environ:       OsEnvironment(),
-		sandboxConfig: &SandboxConfig{},
-	}
-	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(),
-		sandboxConfig: &SandboxConfig{},
+		environ:               OsEnvironment(),
+		sandboxConfig:         &SandboxConfig{},
+		ninjaWeightListSource: DEFAULT,
+	}
+
+	// Skip soong tests by default on Linux
+	if runtime.GOOS == "linux" {
+		ret.skipSoongTests = true
 	}
 
 	// Default matching ninja
@@ -325,8 +218,21 @@
 	ret.parseArgs(ctx, args)
 
 	if ret.ninjaWeightListSource == HINT_FROM_SOONG {
-		ret.environ.Set("SOONG_GENERATES_NINJA_HINT", "true")
+		ret.environ.Set("SOONG_GENERATES_NINJA_HINT", "always")
+	} else if ret.ninjaWeightListSource == DEFAULT {
+		defaultNinjaWeightListSource := NINJA_LOG
+		if _, err := os.Stat(filepath.Join(ret.OutDir(), ninjaLogFileName)); errors.Is(err, os.ErrNotExist) {
+			ctx.Verboseln("$OUT/.ninja_log doesn't exist, use HINT_FROM_SOONG instead")
+			defaultNinjaWeightListSource = HINT_FROM_SOONG
+		} else {
+			ctx.Verboseln("$OUT/.ninja_log exist, use NINJA_LOG")
+		}
+		ret.ninjaWeightListSource = defaultNinjaWeightListSource
+		// soong_build generates ninja hint depending on ninja log existence.
+		// Set it "depend" to avoid soong re-run due to env variable change.
+		ret.environ.Set("SOONG_GENERATES_NINJA_HINT", "depend")
 	}
+
 	// Make sure OUT_DIR is set appropriately
 	if outDir, ok := ret.environ.Get("OUT_DIR"); ok {
 		ret.environ.Set("OUT_DIR", filepath.Clean(outDir))
@@ -347,12 +253,14 @@
 	bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
 
 	if bc != "" {
-		if err := fetchEnvConfig(ctx, ret, bc); err != nil {
-			ctx.Verbosef("Failed to fetch config file: %v\n", err)
-		}
 		if err := loadEnvConfig(ctx, ret, bc); err != nil {
 			ctx.Fatalln("Failed to parse env config files: %v", err)
 		}
+		if !ret.canSupportRBE() {
+			// Explicitly set USE_RBE env variable to false when we cannot run
+			// an RBE build to avoid ninja local execution pool issues.
+			ret.environ.Set("USE_RBE", "false")
+		}
 	}
 
 	if distDir, ok := ret.environ.Get("DIST_DIR"); ok {
@@ -467,13 +375,15 @@
 
 	// 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 ret.environ.IsEnvTrue("EXPERIMENTAL_USE_OPENJDK21_TOOLCHAIN") {
+			return java21Home
+		}
 		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.")
 		}
@@ -495,10 +405,13 @@
 	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
+	// to unzip to enable zipbomb detection that incorrectly handle zip64 and data descriptors and fail on large
+	// 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")
 	}
@@ -513,22 +426,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
@@ -540,6 +453,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) {
@@ -573,12 +522,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...)
 
@@ -813,9 +760,6 @@
 			//   by a previous build.
 			c.skipConfig = true
 			c.skipKati = true
-		} else if arg == "--skip-kati" {
-			// TODO: remove --skip-kati once module builds have been migrated to --song-only
-			c.skipKati = true
 		} else if arg == "--soong-only" {
 			c.skipKati = true
 			c.skipKatiNinja = true
@@ -827,18 +771,14 @@
 			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-dev" {
-			c.bazelDevMode = 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=") {
@@ -865,16 +805,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)
@@ -883,6 +821,8 @@
 			} else {
 				ctx.Fatalf("Error parsing build-time-started-unix-millis", err)
 			}
+		} else if arg == "--ensure-allowlist-integrity" {
+			c.ensureAllowlistIntegrity = true
 		} else if len(arg) > 0 && arg[0] == '-' {
 			parseArgNum := func(def int) int {
 				if len(arg) > 2 {
@@ -917,10 +857,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" {
@@ -932,9 +868,6 @@
 			c.arguments = append(c.arguments, arg)
 		}
 	}
-	if (!c.bazelProdMode) && (!c.bazelDevMode) && (!c.bazelStagingMode) {
-		c.bazelProdMode = defaultBazelProdMode(c)
-	}
 }
 
 func validateNinjaWeightList(weightListFilePath string) (err error) {
@@ -1020,13 +953,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
 	}
 
@@ -1056,14 +988,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")
 }
@@ -1096,17 +1020,12 @@
 }
 
 func (c *configImpl) UsedEnvFile(tag string) string {
+	if v, ok := c.environ.Get("TARGET_PRODUCT"); ok {
+		return shared.JoinPath(c.SoongOutDir(), usedEnvFile+"."+v+"."+tag)
+	}
 	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")
 }
@@ -1115,10 +1034,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")
 }
@@ -1156,14 +1071,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
 }
@@ -1209,7 +1116,7 @@
 }
 
 func (c *configImpl) BuildFromTextStub() bool {
-	return c.buildFromTextStub
+	return !c.buildFromSourceStub
 }
 
 func (c *configImpl) TargetProduct() string {
@@ -1219,6 +1126,13 @@
 	panic("TARGET_PRODUCT is not defined")
 }
 
+func (c *configImpl) TargetProductOrErr() (string, error) {
+	if v, ok := c.environ.Get("TARGET_PRODUCT"); ok {
+		return v, nil
+	}
+	return "", fmt.Errorf("TARGET_PRODUCT is not defined")
+}
+
 func (c *configImpl) TargetDevice() string {
 	return c.targetDevice
 }
@@ -1336,7 +1250,26 @@
 	return true
 }
 
+func (c *configImpl) canSupportRBE() bool {
+	// Do not use RBE with prod credentials in scenarios when stubby doesn't exist, since
+	// its unlikely that we will be able to obtain necessary creds without stubby.
+	authType, _ := c.rbeAuth()
+	if !c.StubbyExists() && strings.Contains(authType, "use_google_prod_creds") {
+		return false
+	}
+	return true
+}
+
 func (c *configImpl) UseRBE() bool {
+	// These alternate modes of running Soong do not use RBE / reclient.
+	if c.Queryview() || c.JsonModuleGraph() {
+		return false
+	}
+
+	if !c.canSupportRBE() {
+		return false
+	}
+
 	if v, ok := c.Environment().Get("USE_RBE"); ok {
 		v = strings.TrimSpace(v)
 		if v != "" && v != "false" {
@@ -1346,10 +1279,6 @@
 	return false
 }
 
-func (c *configImpl) BazelBuildEnabled() bool {
-	return c.bazelProdMode || c.bazelDevMode || c.bazelStagingMode
-}
-
 func (c *configImpl) StartRBE() bool {
 	if !c.UseRBE() {
 		return false
@@ -1374,7 +1303,7 @@
 }
 
 func (c *configImpl) rbeDownloadTmpDir() string {
-    for _, f := range []string{"RBE_download_tmp_dir", "FLAG_download_tmp_dir"} {
+	for _, f := range []string{"RBE_download_tmp_dir", "FLAG_download_tmp_dir"} {
 		if v, ok := c.environ.Get(f); ok {
 			return v
 		}
@@ -1489,7 +1418,7 @@
 	if googleProdCredsExistCache {
 		return googleProdCredsExistCache
 	}
-	if _, err := exec.Command("/usr/bin/prodcertstatus", "--simple_output", "--nocheck_loas").Output(); err != nil {
+	if _, err := exec.Command("/usr/bin/gcertstatus", "-nocheck_ssh").Output(); err != nil {
 		return false
 	}
 	googleProdCredsExistCache = true
@@ -1557,11 +1486,21 @@
 }
 
 func (c *configImpl) SoongVarsFile() string {
-	return filepath.Join(c.SoongOutDir(), "soong.variables")
+	targetProduct, err := c.TargetProductOrErr()
+	if err != nil {
+		return filepath.Join(c.SoongOutDir(), "soong.variables")
+	} else {
+		return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+".variables")
+	}
 }
 
 func (c *configImpl) SoongNinjaFile() string {
-	return filepath.Join(c.SoongOutDir(), "build.ninja")
+	targetProduct, err := c.TargetProductOrErr()
+	if err != nil {
+		return filepath.Join(c.SoongOutDir(), "build.ninja")
+	} else {
+		return filepath.Join(c.SoongOutDir(), "build."+targetProduct+".ninja")
+	}
 }
 
 func (c *configImpl) CombinedNinjaFile() string {
@@ -1579,6 +1518,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())
 }
@@ -1688,12 +1631,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")
@@ -1707,22 +1644,14 @@
 	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")
-}
-
-func (c *configImpl) BazelModulesForceEnabledByFlag() string {
-	return c.bazelForceEnabledModules
-}
-
 func (c *configImpl) SkipMetricsUpload() bool {
 	return c.skipMetricsUpload
 }
 
+func (c *configImpl) EnsureAllowlistIntegrity() bool {
+	return c.ensureAllowlistIntegrity
+}
+
 // Returns a Time object if one was passed via a command-line flag.
 // Otherwise returns the passed default.
 func (c *configImpl) BuildStartedTimeOrDefault(defaultTime time.Time) time.Time {
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index a1eccf0..5182b12 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -1017,172 +1017,57 @@
 		name                string
 		environ             Environment
 		arguments           []string
-		useBazel            bool
-		bazelDevMode        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 dev mode",
-			environ:      Environment{},
-			bazelDevMode: 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 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,
-			bazelDevMode: 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,
-				bazelDevMode:     tc.bazelDevMode,
-				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..d364542 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",
diff --git a/ui/build/finder.go b/ui/build/finder.go
index 62079fe..a114079 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")
+	androidMks = blockAndroidMks(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 dad68fa..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,9 +24,6 @@
 	"os/user"
 	"path/filepath"
 	"strings"
-
-	"android/soong/ui/metrics"
-	"android/soong/ui/status"
 )
 
 var spaceSlashReplacer = strings.NewReplacer("/", "_", " ", "_")
@@ -66,6 +65,21 @@
 	}
 }
 
+func writeValueIfChanged(ctx Context, config Config, dir string, filename string, value string) {
+	filePath := filepath.Join(dir, filename)
+	previousValue := ""
+	rawPreviousValue, err := ioutil.ReadFile(filePath)
+	if err == nil {
+		previousValue = string(rawPreviousValue)
+	}
+
+	if previousValue != value {
+		if err = ioutil.WriteFile(filePath, []byte(value), 0666); err != nil {
+			ctx.Fatalf("Failed to write: %v", err)
+		}
+	}
+}
+
 // Base function to construct and run the Kati command line with additional
 // arguments, and a custom function closure to mutate the environment Kati runs
 // in.
@@ -86,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.
@@ -157,28 +169,42 @@
 	}
 	cmd.Stderr = cmd.Stdout
 
-	// Apply the caller's function closure to mutate the environment variables.
-	envFunc(cmd.Environment)
-
+	var username string
 	// Pass on various build environment metadata to Kati.
-	if _, ok := cmd.Environment.Get("BUILD_USERNAME"); !ok {
-		username := "unknown"
+	if usernameFromEnv, ok := cmd.Environment.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)
 		}
 		cmd.Environment.Set("BUILD_USERNAME", username)
+	} else {
+		username = usernameFromEnv
 	}
 
-	if _, ok := cmd.Environment.Get("BUILD_HOSTNAME"); !ok {
-		hostname, err := os.Hostname()
+	hostname, ok := cmd.Environment.Get("BUILD_HOSTNAME")
+	// Unset BUILD_HOSTNAME during kati run to avoid kati rerun, kati will use BUILD_HOSTNAME from a file.
+	cmd.Environment.Unset("BUILD_HOSTNAME")
+	if !ok {
+		hostname, err = os.Hostname()
 		if err != nil {
 			ctx.Println("Failed to read hostname:", err)
 			hostname = "unknown"
 		}
-		cmd.Environment.Set("BUILD_HOSTNAME", hostname)
 	}
+	writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_hostname.txt", hostname)
+	_, 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")
+	} else {
+		cmd.Environment.Set("HAS_BUILD_NUMBER", "false")
+	}
+
+	// Apply the caller's function closure to mutate the environment variables.
+	envFunc(cmd.Environment)
 
 	cmd.StartOrFatal()
 	// Set up the ToolStatus command line reader for Kati for a consistent UI
@@ -336,6 +362,7 @@
 			"ANDROID_BUILD_SHELL",
 			"DIST_DIR",
 			"OUT_DIR",
+			"FILE_NAME_TAG",
 		}...)
 
 		if config.Dist() {
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 5d56531..551b8ab 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -35,48 +35,6 @@
 	ninjaWeightListFileName = ".ninja_weight_list"
 )
 
-func useNinjaBuildLog(ctx Context, config Config, cmd *Cmd) {
-	ninjaLogFile := filepath.Join(config.OutDir(), ninjaLogFileName)
-	data, err := os.ReadFile(ninjaLogFile)
-	var outputBuilder strings.Builder
-	if err == nil {
-		lines := strings.Split(strings.TrimSpace(string(data)), "\n")
-		// ninja log: <start>	<end>	<restat>	<name>	<cmdhash>
-		// ninja weight list: <name>,<end-start+1>
-		for _, line := range lines {
-			if strings.HasPrefix(line, "#") {
-				continue
-			}
-			fields := strings.Split(line, "\t")
-			path := fields[3]
-			start, err := strconv.Atoi(fields[0])
-			if err != nil {
-				continue
-			}
-			end, err := strconv.Atoi(fields[1])
-			if err != nil {
-				continue
-			}
-			outputBuilder.WriteString(path)
-			outputBuilder.WriteString(",")
-			outputBuilder.WriteString(strconv.Itoa(end-start+1) + "\n")
-		}
-	} else {
-		// If there is no ninja log file, just pass empty ninja weight list.
-		// Because it is still efficient with critical path calculation logic even without weight.
-		ctx.Verbosef("There is an error during reading ninja log, so ninja will use empty weight list: %s", err)
-	}
-
-	weightListFile := filepath.Join(config.OutDir(), ninjaWeightListFileName)
-
-	err = os.WriteFile(weightListFile, []byte(outputBuilder.String()), 0644)
-	if err == nil {
-		cmd.Args = append(cmd.Args, "-o", "usesweightlist="+weightListFile)
-	} else {
-		ctx.Panicf("Could not write ninja weight list file %s", err)
-	}
-}
-
 // Constructs and runs the Ninja command line with a restricted set of
 // environment variables. It's important to restrict the environment Ninja runs
 // for hermeticity reasons, and to avoid spurious rebuilds.
@@ -131,7 +89,7 @@
 
 	switch config.NinjaWeightListSource() {
 	case NINJA_LOG:
-		useNinjaBuildLog(ctx, config, cmd)
+		cmd.Args = append(cmd.Args, "-o", "usesninjalogasweightlist=yes")
 	case EVENLY_DISTRIBUTED:
 		// pass empty weight list means ninja considers every tasks's weight as 1(default value).
 		cmd.Args = append(cmd.Args, "-o", "usesweightlist=/dev/null")
@@ -236,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()...)...)
 	}
 
@@ -309,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 b3092ea..65e2c8e 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -86,27 +86,29 @@
 // This list specifies whether a particular binary from $PATH is allowed to be
 // 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,
-	"getopt":  Allowed,
-	"git":     Allowed,
-	"hexdump": Allowed,
-	"jar":     Allowed,
-	"java":    Allowed,
-	"javap":   Allowed,
-	"lsof":    Allowed,
-	"openssl": Allowed,
-	"pstree":  Allowed,
-	"rsync":   Allowed,
-	"sh":      Allowed,
-	"stubby":  Allowed,
-	"tr":      Allowed,
-	"unzip":   Allowed,
-	"zip":     Allowed,
+	"bash":           Allowed,
+	"diff":           Allowed,
+	"dlv":            Allowed,
+	"expr":           Allowed,
+	"fuser":          Allowed,
+	"gcert":          Allowed,
+	"gcertstatus":    Allowed,
+	"getopt":         Allowed,
+	"git":            Allowed,
+	"hexdump":        Allowed,
+	"jar":            Allowed,
+	"java":           Allowed,
+	"javap":          Allowed,
+	"lsof":           Allowed,
+	"openssl":        Allowed,
+	"prodcertstatus": Allowed,
+	"pstree":         Allowed,
+	"rsync":          Allowed,
+	"sh":             Allowed,
+	"stubby":         Allowed,
+	"tr":             Allowed,
+	"unzip":          Allowed,
+	"zip":            Allowed,
 
 	// Host toolchain is removed. In-tree toolchain should be used instead.
 	// GCC also can't find cc1 with this implementation.
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 58c6930..fa04207 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -95,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)
@@ -115,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))
 
@@ -184,8 +187,6 @@
 		return
 	}
 
-	ctx.Status.Status("Dumping rbe metrics...")
-
 	outputDir := config.rbeProxyLogsDir()
 	if outputDir == "" {
 		ctx.Fatal("RBE output dir variable not defined. Aborting metrics dumping.")
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 8ead4c9..90c3bfc 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,7 +174,23 @@
 	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 {
@@ -171,8 +200,8 @@
 	if pb.config.multitreeBuild {
 		commonArgs = append(commonArgs, "--multitree-build")
 	}
-	if pb.config.buildFromTextStub {
-		commonArgs = append(commonArgs, "--build-from-text-stub")
+	if pb.config.buildFromSourceStub {
+		commonArgs = append(commonArgs, "--build-from-source-stub")
 	}
 
 	commonArgs = append(commonArgs, "-l", filepath.Join(pb.config.FileListDir(), "Android.bp.list"))
@@ -195,9 +224,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 +239,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,
@@ -235,7 +268,7 @@
 	} else if !exists {
 		// The tree is out of date for the current epoch, delete files used by bootstrap
 		// and force the primary builder to rerun.
-		os.Remove(filepath.Join(config.SoongOutDir(), "build.ninja"))
+		os.Remove(config.SoongNinjaFile())
 		for _, globFile := range bootstrapGlobFileList(config) {
 			os.Remove(globFile)
 		}
@@ -247,11 +280,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),
 	}
 }
@@ -263,36 +294,23 @@
 	// Clean up some files for incremental builds across incompatible changes.
 	bootstrapEpochCleanup(ctx, config)
 
-	mainSoongBuildExtraArgs := []string{"-o", config.SoongNinjaFile()}
+	baseArgs := []string{"--soong_variables", config.SoongVarsFile()}
+
+	mainSoongBuildExtraArgs := append(baseArgs, "-o", config.SoongNinjaFile())
 	if config.EmptyNinjaFile() {
 		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--empty-ninja-file")
 	}
-	if config.bazelProdMode {
-		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode")
-	}
-	if config.bazelDevMode {
-		mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--bazel-mode-dev")
-	}
-	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{
 		{
@@ -303,49 +321,32 @@
 			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: []string{"--bp2build_marker", config.Bp2BuildFilesMarkerFile()},
-		},
-		{
-			name:         bp2buildWorkspaceTag,
-			description:  "Creating Bazel symlink forest",
-			config:       config,
-			output:       config.Bp2BuildWorkspaceMarkerFile(),
-			specificArgs: []string{"--symlink_forest_marker", config.Bp2BuildWorkspaceMarkerFile()},
-		},
-		{
 			name:        jsonModuleGraphTag,
 			description: fmt.Sprintf("generating the Soong module graph at %s", config.ModuleGraphFile()),
 			config:      config,
 			output:      config.ModuleGraphFile(),
-			specificArgs: []string{
+			specificArgs: append(baseArgs,
 				"--module_graph_file", config.ModuleGraphFile(),
 				"--module_actions_file", config.ModuleActionsFile(),
-			},
+			),
 		},
 		{
-			name:         queryviewTag,
-			description:  fmt.Sprintf("generating the Soong module graph as a Bazel workspace at %s", queryviewDir),
-			config:       config,
-			output:       config.QueryviewMarkerFile(),
-			specificArgs: []string{"--bazel_queryview_dir", queryviewDir},
+			name:        queryviewTag,
+			description: fmt.Sprintf("generating the Soong module graph as a Bazel workspace at %s", queryviewDir),
+			config:      config,
+			output:      config.QueryviewMarkerFile(),
+			specificArgs: append(baseArgs,
+				"--bazel_queryview_dir", queryviewDir,
+			),
 		},
 		{
-			name:         apiBp2buildTag,
-			description:  fmt.Sprintf("generating BUILD files for API contributions at %s", apiBp2buildDir),
-			config:       config,
-			output:       config.ApiBp2buildMarkerFile(),
-			specificArgs: []string{"--bazel_api_bp2build_dir", apiBp2buildDir},
-		},
-		{
-			name:         soongDocsTag,
-			description:  fmt.Sprintf("generating Soong docs at %s", config.SoongDocsHtml()),
-			config:       config,
-			output:       config.SoongDocsHtml(),
-			specificArgs: []string{"--soong_docs", config.SoongDocsHtml()},
+			name:        soongDocsTag,
+			description: fmt.Sprintf("generating Soong docs at %s", config.SoongDocsHtml()),
+			config:      config,
+			output:      config.SoongDocsHtml(),
+			specificArgs: append(baseArgs,
+				"--soong_docs", config.SoongDocsHtml(),
+			),
 		},
 	}
 
@@ -383,33 +384,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"),
@@ -431,26 +409,163 @@
 		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
-	_ = bootstrap.RunBlueprint(blueprintArgs, bootstrap.DoEverything, blueprintCtx, blueprintConfig)
+	_, err := bootstrap.RunBlueprint(blueprintArgs, bootstrap.DoEverything, blueprintCtx, blueprintConfig)
+	if err != nil {
+		ctx.Fatal(err)
+	}
 }
 
-func checkEnvironmentFile(currentEnv *Environment, envFile string) {
+func checkEnvironmentFile(ctx Context, currentEnv *Environment, envFile string) {
 	getenv := func(k string) string {
 		v, _ := currentEnv.Get(k)
 		return v
 	}
 
-	if stale, _ := shared.StaleEnvFile(envFile, getenv); stale {
+	// Log the changed environment variables to ChangedEnvironmentVariable field
+	if stale, changedEnvironmentVariableList, _ := shared.StaleEnvFile(envFile, getenv); stale {
+		for _, changedEnvironmentVariable := range changedEnvironmentVariableList {
+			ctx.Metrics.AddChangedEnvironmentVariable(changedEnvironmentVariable)
+		}
 		os.Remove(envFile)
 	}
 }
 
+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
@@ -462,16 +577,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" {
@@ -487,42 +593,32 @@
 		ctx.BeginTrace(metrics.RunSoong, "environment check")
 		defer ctx.EndTrace()
 
-		checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(soongBuildTag))
+		checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(soongBuildTag))
 
-		if config.BazelBuildEnabled() || config.Bp2Build() {
-			checkEnvironmentFile(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(soongBuildEnv, config.UsedEnvFile(jsonModuleGraphTag))
+			checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(jsonModuleGraphTag))
 		}
 
 		if config.Queryview() {
-			checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(queryviewTag))
-		}
-
-		if config.ApiBp2build() {
-			checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(apiBp2buildTag))
+			checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(queryviewTag))
 		}
 
 		if config.SoongDocs() {
-			checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(soongDocsTag))
+			checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(soongDocsTag))
 		}
 	}()
 
 	runMicrofactory(ctx, config, "bpglob", "github.com/google/blueprint/bootstrap/bpglob",
 		map[string]string{"github.com/google/blueprint": "build/blueprint"})
 
-	ninja := func(name, ninjaFile string, targets ...string) {
-		ctx.BeginTrace(metrics.RunSoong, name)
+	ninja := func(targets ...string) {
+		ctx.BeginTrace(metrics.RunSoong, "bootstrap")
 		defer ctx.EndTrace()
 
-		if config.IsPersistentBazelEnabled() {
-			bazelProxy := bazel.NewProxyServer(ctx.Logger, config.OutDir(), filepath.Join(config.SoongOutDir(), "workspace"))
-			bazelProxy.Start()
-			defer bazelProxy.Close()
-		}
-
 		fifo := filepath.Join(config.OutDir(), ".ninja_fifo")
 		nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo)
 		defer nr.Close()
@@ -537,7 +633,7 @@
 			"-w", "missingoutfile=err",
 			"-j", strconv.Itoa(config.Parallel()),
 			"--frontend_file", fifo,
-			"-f", filepath.Join(config.SoongOutDir(), ninjaFile),
+			"-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"),
 		}
 
 		if extra, ok := config.Environment().Get("SOONG_UI_NINJA_ARGS"); ok {
@@ -546,7 +642,7 @@
 		}
 
 		ninjaArgs = append(ninjaArgs, targets...)
-		cmd := Command(ctx, config, "soong "+name,
+		cmd := Command(ctx, config, "soong bootstrap",
 			config.PrebuiltBuildTool("ninja"), ninjaArgs...)
 
 		var ninjaEnv Environment
@@ -566,18 +662,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())
 	}
@@ -587,7 +675,11 @@
 		targets = append(targets, config.SoongNinjaFile())
 	}
 
-	ninja("bootstrap", "bootstrap.ninja", targets...)
+	beforeSoongTimestamp := time.Now()
+
+	ninja(targets...)
+
+	loadSoongBuildMetrics(ctx, config, beforeSoongTimestamp)
 
 	distGzipFile(ctx, config, config.SoongNinjaFile(), "soong")
 	distFile(ctx, config, config.SoongVarsFile(), "soong")
@@ -602,6 +694,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.go b/ui/build/upload.go
index 9959e6f..9f14bdd 100644
--- a/ui/build/upload.go
+++ b/ui/build/upload.go
@@ -18,21 +18,16 @@
 // another.
 
 import (
-	"bufio"
 	"fmt"
 	"io/ioutil"
 	"os"
 	"path/filepath"
-	"strconv"
-	"strings"
 	"time"
 
-	"android/soong/shared"
 	"android/soong/ui/metrics"
 
 	"google.golang.org/protobuf/proto"
 
-	bazel_metrics_proto "android/soong/ui/metrics/bazel_metrics_proto"
 	upload_proto "android/soong/ui/metrics/upload_proto"
 )
 
@@ -78,113 +73,12 @@
 	return metricsFiles
 }
 
-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
-}
-
-func processBazelMetrics(bazelProfileFile string, bazelMetricsFile string, ctx Context) {
-	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
-
-		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)
-	shared.Save(&bazelProto, bazelMetricsFile)
-}
-
 // UploadMetrics uploads a set of metrics files to a server for analysis.
 // The metrics files are first copied to a temporary directory
 // and the uploader is then executed in the background to allow the user/system
 // to continue working. Soong communicates to the uploader through the
 // upload_proto raw protobuf file.
-func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, bazelProfileFile string, bazelMetricsFile string, paths ...string) {
+func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, paths ...string) {
 	ctx.BeginTrace(metrics.RunSetupTool, "upload_metrics")
 	defer ctx.EndTrace()
 
@@ -194,7 +88,6 @@
 		return
 	}
 
-	processBazelMetrics(bazelProfileFile, bazelMetricsFile, ctx)
 	// Several of the files might be directories.
 	metricsFiles := pruneMetricsFiles(paths)
 	if len(metricsFiles) == 0 {
diff --git a/ui/build/upload_test.go b/ui/build/upload_test.go
deleted file mode 100644
index 58d9237..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(), "out/bazel_metrics.txt", "out/bazel_metrics.pb", 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/BUILD.bazel b/ui/metrics/BUILD.bazel
index 15ebb88..ca39c59 100644
--- a/ui/metrics/BUILD.bazel
+++ b/ui/metrics/BUILD.bazel
@@ -16,13 +16,14 @@
 
 py_proto_library(
     name = "metrics-py-proto",
-    visibility = ["//build/bazel/scripts/incremental_build:__pkg__"],
+    visibility = ["//build/bazel/scripts:__subpackages__"],
     deps = [":metrics-proto"],
 )
 
 proto_library(
     name = "metrics-proto",
     srcs = [
+        "bazel_metrics_proto/bazel_metrics.proto",
         "bp2build_metrics_proto/bp2build_metrics.proto",
         "metrics_proto/metrics.proto",
     ],
diff --git a/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go b/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
index f8b8fd6..8b97b83 100644
--- a/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
+++ b/ui/metrics/bazel_metrics_proto/bazel_metrics.pb.go
@@ -14,8 +14,8 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.28.0
-// 	protoc        v3.21.7
+// 	protoc-gen-go v1.30.0
+// 	protoc        v3.21.12
 // source: bazel_metrics.proto
 
 package bazel_metrics_proto
@@ -41,6 +41,8 @@
 
 	PhaseTimings []*PhaseTiming `protobuf:"bytes,1,rep,name=phase_timings,json=phaseTimings,proto3" json:"phase_timings,omitempty"`
 	Total        *int64         `protobuf:"varint,2,opt,name=total,proto3,oneof" json:"total,omitempty"`
+	ExitCode     *int32         `protobuf:"varint,3,opt,name=exit_code,json=exitCode,proto3,oneof" json:"exit_code,omitempty"`
+	BesId        *string        `protobuf:"bytes,4,opt,name=bes_id,json=besId,proto3,oneof" json:"bes_id,omitempty"`
 }
 
 func (x *BazelMetrics) Reset() {
@@ -89,6 +91,20 @@
 	return 0
 }
 
+func (x *BazelMetrics) GetExitCode() int32 {
+	if x != nil && x.ExitCode != nil {
+		return *x.ExitCode
+	}
+	return 0
+}
+
+func (x *BazelMetrics) GetBesId() string {
+	if x != nil && x.BesId != nil {
+		return *x.BesId
+	}
+	return ""
+}
+
 type PhaseTiming struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -161,31 +177,37 @@
 	0x0a, 0x13, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
 	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x19, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
 	0x6c, 0x64, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x22, 0x80, 0x01, 0x0a, 0x0c, 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x22, 0xd7, 0x01, 0x0a, 0x0c, 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
 	0x73, 0x12, 0x4b, 0x0a, 0x0d, 0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x69, 0x6e,
 	0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
 	0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74,
 	0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67,
 	0x52, 0x0c, 0x70, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x19,
 	0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52,
-	0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x74, 0x6f,
-	0x74, 0x61, 0x6c, 0x22, 0xd1, 0x01, 0x0a, 0x0b, 0x50, 0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d,
-	0x69, 0x6e, 0x67, 0x12, 0x22, 0x0a, 0x0a, 0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x6e, 0x61, 0x6d,
-	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x70, 0x68, 0x61, 0x73, 0x65,
-	0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2a, 0x0a, 0x0e, 0x64, 0x75, 0x72, 0x61, 0x74,
-	0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48,
-	0x01, 0x52, 0x0d, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73,
-	0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x15, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f,
-	0x66, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01,
-	0x28, 0x05, 0x48, 0x02, 0x52, 0x12, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x66, 0x42,
-	0x75, 0x69, 0x6c, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f,
-	0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x64,
-	0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73, 0x42, 0x18, 0x0a,
-	0x16, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x66, 0x5f, 0x62, 0x75, 0x69,
-	0x6c, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x42, 0x2e, 0x5a, 0x2c, 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, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
-	0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x65, 0x78, 0x69,
+	0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x08,
+	0x65, 0x78, 0x69, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1a, 0x0a, 0x06, 0x62,
+	0x65, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x05, 0x62,
+	0x65, 0x73, 0x49, 0x64, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x74, 0x6f, 0x74, 0x61,
+	0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x42,
+	0x09, 0x0a, 0x07, 0x5f, 0x62, 0x65, 0x73, 0x5f, 0x69, 0x64, 0x22, 0xd1, 0x01, 0x0a, 0x0b, 0x50,
+	0x68, 0x61, 0x73, 0x65, 0x54, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x12, 0x22, 0x0a, 0x0a, 0x70, 0x68,
+	0x61, 0x73, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00,
+	0x52, 0x09, 0x70, 0x68, 0x61, 0x73, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2a,
+	0x0a, 0x0e, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, 0x6e, 0x6f, 0x73,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x0d, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x15, 0x70, 0x6f,
+	0x72, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x66, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x74,
+	0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x48, 0x02, 0x52, 0x12, 0x70, 0x6f, 0x72,
+	0x74, 0x69, 0x6f, 0x6e, 0x4f, 0x66, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x88,
+	0x01, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x70, 0x68, 0x61, 0x73, 0x65, 0x5f, 0x6e, 0x61, 0x6d,
+	0x65, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e,
+	0x61, 0x6e, 0x6f, 0x73, 0x42, 0x18, 0x0a, 0x16, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6f, 0x6e,
+	0x5f, 0x6f, 0x66, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x42, 0x2e,
+	0x5a, 0x2c, 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, 0x62, 0x61, 0x7a, 0x65, 0x6c,
+	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
diff --git a/ui/metrics/bazel_metrics_proto/bazel_metrics.proto b/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
index 57eed4c..e45d2bf 100644
--- a/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
+++ b/ui/metrics/bazel_metrics_proto/bazel_metrics.proto
@@ -20,6 +20,8 @@
 message BazelMetrics {
   repeated PhaseTiming phase_timings = 1;
   optional int64 total = 2;
+  optional int32 exit_code = 3;
+  optional string bes_id = 4;
 }
 
 message PhaseTiming {
diff --git a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go
index 4821043..b34c2b6 100644
--- a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go
+++ b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.pb.go
@@ -14,8 +14,8 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.28.0
-// 	protoc        v3.21.7
+// 	protoc-gen-go v1.30.0
+// 	protoc        v3.21.12
 // source: bp2build_metrics.proto
 
 package bp2build_metrics_proto
@@ -34,6 +34,78 @@
 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
 )
 
+type UnconvertedReasonType int32
+
+const (
+	// Bp2build does not know how to convert this specific module for some reason
+	// not covered by other reason types. The reason detail should explain the
+	// specific issue.
+	UnconvertedReasonType_UNSUPPORTED UnconvertedReasonType = 0
+	// The module was already defined in a BUILD file available in the source tree.
+	UnconvertedReasonType_DEFINED_IN_BUILD_FILE UnconvertedReasonType = 1
+	// The module was explicitly denylisted by name.
+	UnconvertedReasonType_DENYLISTED UnconvertedReasonType = 2
+	// The module's type has no bp2build implementation.
+	UnconvertedReasonType_TYPE_UNSUPPORTED UnconvertedReasonType = 3
+	// The module has a property not yet supported. The detail field should
+	// name the unsupported property name.
+	UnconvertedReasonType_PROPERTY_UNSUPPORTED UnconvertedReasonType = 4
+	// The module has an unconverted dependency. The detail should consist of
+	// the name of the unconverted module.
+	UnconvertedReasonType_UNCONVERTED_DEP UnconvertedReasonType = 5
+	// The module has a source file with the same name as the module itself.
+	UnconvertedReasonType_SRC_NAME_COLLISION UnconvertedReasonType = 6
+)
+
+// Enum value maps for UnconvertedReasonType.
+var (
+	UnconvertedReasonType_name = map[int32]string{
+		0: "UNSUPPORTED",
+		1: "DEFINED_IN_BUILD_FILE",
+		2: "DENYLISTED",
+		3: "TYPE_UNSUPPORTED",
+		4: "PROPERTY_UNSUPPORTED",
+		5: "UNCONVERTED_DEP",
+		6: "SRC_NAME_COLLISION",
+	}
+	UnconvertedReasonType_value = map[string]int32{
+		"UNSUPPORTED":           0,
+		"DEFINED_IN_BUILD_FILE": 1,
+		"DENYLISTED":            2,
+		"TYPE_UNSUPPORTED":      3,
+		"PROPERTY_UNSUPPORTED":  4,
+		"UNCONVERTED_DEP":       5,
+		"SRC_NAME_COLLISION":    6,
+	}
+)
+
+func (x UnconvertedReasonType) Enum() *UnconvertedReasonType {
+	p := new(UnconvertedReasonType)
+	*p = x
+	return p
+}
+
+func (x UnconvertedReasonType) String() string {
+	return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
+}
+
+func (UnconvertedReasonType) Descriptor() protoreflect.EnumDescriptor {
+	return file_bp2build_metrics_proto_enumTypes[0].Descriptor()
+}
+
+func (UnconvertedReasonType) Type() protoreflect.EnumType {
+	return &file_bp2build_metrics_proto_enumTypes[0]
+}
+
+func (x UnconvertedReasonType) Number() protoreflect.EnumNumber {
+	return protoreflect.EnumNumber(x)
+}
+
+// Deprecated: Use UnconvertedReasonType.Descriptor instead.
+func (UnconvertedReasonType) EnumDescriptor() ([]byte, []int) {
+	return file_bp2build_metrics_proto_rawDescGZIP(), []int{0}
+}
+
 type Bp2BuildMetrics struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -53,6 +125,8 @@
 	RuleClassCount map[string]uint64 `protobuf:"bytes,4,rep,name=ruleClassCount,proto3" json:"ruleClassCount,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
 	// List of converted modules
 	ConvertedModules []string `protobuf:"bytes,5,rep,name=convertedModules,proto3" json:"convertedModules,omitempty"`
+	// Unconverted modules, mapped to the reason the module was not converted.
+	UnconvertedModules map[string]*UnconvertedReason `protobuf:"bytes,11,rep,name=unconvertedModules,proto3" json:"unconvertedModules,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
 	// Counts of converted modules by module type.
 	ConvertedModuleTypeCount map[string]uint64 `protobuf:"bytes,6,rep,name=convertedModuleTypeCount,proto3" json:"convertedModuleTypeCount,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
 	// Counts of total modules by module type.
@@ -143,6 +217,13 @@
 	return nil
 }
 
+func (x *Bp2BuildMetrics) GetUnconvertedModules() map[string]*UnconvertedReason {
+	if x != nil {
+		return x.UnconvertedModules
+	}
+	return nil
+}
+
 func (x *Bp2BuildMetrics) GetConvertedModuleTypeCount() map[string]uint64 {
 	if x != nil {
 		return x.ConvertedModuleTypeCount
@@ -233,13 +314,72 @@
 	return 0
 }
 
+type UnconvertedReason struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The type of reason that the module could not be converted.
+	Type UnconvertedReasonType `protobuf:"varint,1,opt,name=type,proto3,enum=soong_build_bp2build_metrics.UnconvertedReasonType" json:"type,omitempty"`
+	// Descriptive details describing why the module could not be converted.
+	// This detail should be kept very short and should be in the context of
+	// the type. (Otherwise, this would significantly bloat metrics.)
+	Detail string `protobuf:"bytes,2,opt,name=detail,proto3" json:"detail,omitempty"`
+}
+
+func (x *UnconvertedReason) Reset() {
+	*x = UnconvertedReason{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_bp2build_metrics_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *UnconvertedReason) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UnconvertedReason) ProtoMessage() {}
+
+func (x *UnconvertedReason) ProtoReflect() protoreflect.Message {
+	mi := &file_bp2build_metrics_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 UnconvertedReason.ProtoReflect.Descriptor instead.
+func (*UnconvertedReason) Descriptor() ([]byte, []int) {
+	return file_bp2build_metrics_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *UnconvertedReason) GetType() UnconvertedReasonType {
+	if x != nil {
+		return x.Type
+	}
+	return UnconvertedReasonType_UNSUPPORTED
+}
+
+func (x *UnconvertedReason) GetDetail() string {
+	if x != nil {
+		return x.Detail
+	}
+	return ""
+}
+
 var File_bp2build_metrics_proto protoreflect.FileDescriptor
 
 var file_bp2build_metrics_proto_rawDesc = []byte{
 	0x0a, 0x16, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
 	0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
 	0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
-	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0xd1, 0x07, 0x0a, 0x0f, 0x42, 0x70, 0x32, 0x42, 0x75,
+	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0xc0, 0x09, 0x0a, 0x0f, 0x42, 0x70, 0x32, 0x42, 0x75,
 	0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x32, 0x0a, 0x14, 0x67, 0x65,
 	0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x43, 0x6f, 0x75,
 	0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x14, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61,
@@ -266,50 +406,84 @@
 	0x79, 0x52, 0x0e, 0x72, 0x75, 0x6c, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e,
 	0x74, 0x12, 0x2a, 0x0a, 0x10, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f,
 	0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x63, 0x6f, 0x6e,
-	0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x87, 0x01,
-	0x0a, 0x18, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c,
-	0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b,
-	0x32, 0x4b, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62,
-	0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
-	0x42, 0x70, 0x32, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e,
-	0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54,
-	0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x18, 0x63,
-	0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79,
-	0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x7b, 0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c,
-	0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18,
-	0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x47, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
+	0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x75, 0x0a,
+	0x12, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75,
+	0x6c, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x45, 0x2e, 0x73, 0x6f, 0x6f, 0x6e,
+	0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64,
+	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x70, 0x32, 0x42, 0x75, 0x69, 0x6c,
+	0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65,
+	0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x52, 0x12, 0x75, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64,
+	0x75, 0x6c, 0x65, 0x73, 0x12, 0x87, 0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74,
+	0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e,
+	0x74, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4b, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
+	0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
+	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x70, 0x32, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d,
+	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64,
+	0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45,
+	0x6e, 0x74, 0x72, 0x79, 0x52, 0x18, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d,
+	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x7b,
+	0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70,
+	0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x47, 0x2e, 0x73,
+	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75,
+	0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x70, 0x32, 0x42,
+	0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x54, 0x6f, 0x74, 0x61,
+	0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74,
+	0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75,
+	0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x06, 0x65,
+	0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x6f,
+	0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69,
+	0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74,
+	0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x1a, 0x41, 0x0a, 0x13, 0x52, 0x75, 0x6c, 0x65,
+	0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
+	0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
+	0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x76, 0x0a, 0x17, 0x55,
+	0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
+	0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x45, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
+	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
+	0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d,
+	0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74,
+	0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
+	0x02, 0x38, 0x01, 0x1a, 0x4b, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64,
+	0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45,
+	0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
+	0x1a, 0x47, 0x0a, 0x19, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54,
+	0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
+	0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
+	0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x57, 0x0a, 0x05, 0x45, 0x76, 0x65,
+	0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f,
+	0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72,
+	0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69,
+	0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69,
+	0x6d, 0x65, 0x22, 0x74, 0x0a, 0x11, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65,
+	0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x47, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x33, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
 	0x69, 0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
-	0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x70, 0x32, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74,
-	0x72, 0x69, 0x63, 0x73, 0x2e, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
-	0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14,
-	0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43,
-	0x6f, 0x75, 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x08,
-	0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
-	0x6c, 0x64, 0x5f, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72,
-	0x69, 0x63, 0x73, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74,
-	0x73, 0x1a, 0x41, 0x0a, 0x13, 0x52, 0x75, 0x6c, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x6f,
-	0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
-	0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
-	0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4b, 0x0a, 0x1d, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65,
-	0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74,
-	0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
-	0x01, 0x1a, 0x47, 0x0a, 0x19, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
-	0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
-	0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
-	0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52,
-	0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x57, 0x0a, 0x05, 0x45, 0x76,
-	0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74,
-	0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61,
-	0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74,
-	0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54,
-	0x69, 0x6d, 0x65, 0x42, 0x31, 0x5a, 0x2f, 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,
-	0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x72, 0x69, 0x63, 0x73, 0x2e, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64,
+	0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
+	0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x2a, 0xb0, 0x01, 0x0a, 0x15, 0x55, 0x6e, 0x63,
+	0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x54, 0x79,
+	0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45,
+	0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x5f, 0x49,
+	0x4e, 0x5f, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x0e,
+	0x0a, 0x0a, 0x44, 0x45, 0x4e, 0x59, 0x4c, 0x49, 0x53, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x14,
+	0x0a, 0x10, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54,
+	0x45, 0x44, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, 0x50, 0x52, 0x4f, 0x50, 0x45, 0x52, 0x54, 0x59,
+	0x5f, 0x55, 0x4e, 0x53, 0x55, 0x50, 0x50, 0x4f, 0x52, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x13,
+	0x0a, 0x0f, 0x55, 0x4e, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x54, 0x45, 0x44, 0x5f, 0x44, 0x45,
+	0x50, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x52, 0x43, 0x5f, 0x4e, 0x41, 0x4d, 0x45, 0x5f,
+	0x43, 0x4f, 0x4c, 0x4c, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x10, 0x06, 0x42, 0x31, 0x5a, 0x2f, 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, 0x62, 0x70, 0x32, 0x62, 0x75, 0x69, 0x6c, 0x64,
+	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -324,24 +498,31 @@
 	return file_bp2build_metrics_proto_rawDescData
 }
 
-var file_bp2build_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
+var file_bp2build_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
+var file_bp2build_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
 var file_bp2build_metrics_proto_goTypes = []interface{}{
-	(*Bp2BuildMetrics)(nil), // 0: soong_build_bp2build_metrics.Bp2BuildMetrics
-	(*Event)(nil),           // 1: soong_build_bp2build_metrics.Event
-	nil,                     // 2: soong_build_bp2build_metrics.Bp2BuildMetrics.RuleClassCountEntry
-	nil,                     // 3: soong_build_bp2build_metrics.Bp2BuildMetrics.ConvertedModuleTypeCountEntry
-	nil,                     // 4: soong_build_bp2build_metrics.Bp2BuildMetrics.TotalModuleTypeCountEntry
+	(UnconvertedReasonType)(0), // 0: soong_build_bp2build_metrics.UnconvertedReasonType
+	(*Bp2BuildMetrics)(nil),    // 1: soong_build_bp2build_metrics.Bp2BuildMetrics
+	(*Event)(nil),              // 2: soong_build_bp2build_metrics.Event
+	(*UnconvertedReason)(nil),  // 3: soong_build_bp2build_metrics.UnconvertedReason
+	nil,                        // 4: soong_build_bp2build_metrics.Bp2BuildMetrics.RuleClassCountEntry
+	nil,                        // 5: soong_build_bp2build_metrics.Bp2BuildMetrics.UnconvertedModulesEntry
+	nil,                        // 6: soong_build_bp2build_metrics.Bp2BuildMetrics.ConvertedModuleTypeCountEntry
+	nil,                        // 7: soong_build_bp2build_metrics.Bp2BuildMetrics.TotalModuleTypeCountEntry
 }
 var file_bp2build_metrics_proto_depIdxs = []int32{
-	2, // 0: soong_build_bp2build_metrics.Bp2BuildMetrics.ruleClassCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.RuleClassCountEntry
-	3, // 1: soong_build_bp2build_metrics.Bp2BuildMetrics.convertedModuleTypeCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.ConvertedModuleTypeCountEntry
-	4, // 2: soong_build_bp2build_metrics.Bp2BuildMetrics.totalModuleTypeCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.TotalModuleTypeCountEntry
-	1, // 3: soong_build_bp2build_metrics.Bp2BuildMetrics.events:type_name -> soong_build_bp2build_metrics.Event
-	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
+	4, // 0: soong_build_bp2build_metrics.Bp2BuildMetrics.ruleClassCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.RuleClassCountEntry
+	5, // 1: soong_build_bp2build_metrics.Bp2BuildMetrics.unconvertedModules:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.UnconvertedModulesEntry
+	6, // 2: soong_build_bp2build_metrics.Bp2BuildMetrics.convertedModuleTypeCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.ConvertedModuleTypeCountEntry
+	7, // 3: soong_build_bp2build_metrics.Bp2BuildMetrics.totalModuleTypeCount:type_name -> soong_build_bp2build_metrics.Bp2BuildMetrics.TotalModuleTypeCountEntry
+	2, // 4: soong_build_bp2build_metrics.Bp2BuildMetrics.events:type_name -> soong_build_bp2build_metrics.Event
+	0, // 5: soong_build_bp2build_metrics.UnconvertedReason.type:type_name -> soong_build_bp2build_metrics.UnconvertedReasonType
+	3, // 6: soong_build_bp2build_metrics.Bp2BuildMetrics.UnconvertedModulesEntry.value:type_name -> soong_build_bp2build_metrics.UnconvertedReason
+	7, // [7:7] is the sub-list for method output_type
+	7, // [7:7] is the sub-list for method input_type
+	7, // [7:7] is the sub-list for extension type_name
+	7, // [7:7] is the sub-list for extension extendee
+	0, // [0:7] is the sub-list for field type_name
 }
 
 func init() { file_bp2build_metrics_proto_init() }
@@ -374,19 +555,32 @@
 				return nil
 			}
 		}
+		file_bp2build_metrics_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*UnconvertedReason); 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_bp2build_metrics_proto_rawDesc,
-			NumEnums:      0,
-			NumMessages:   5,
+			NumEnums:      1,
+			NumMessages:   7,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
 		GoTypes:           file_bp2build_metrics_proto_goTypes,
 		DependencyIndexes: file_bp2build_metrics_proto_depIdxs,
+		EnumInfos:         file_bp2build_metrics_proto_enumTypes,
 		MessageInfos:      file_bp2build_metrics_proto_msgTypes,
 	}.Build()
 	File_bp2build_metrics_proto = out.File
diff --git a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto
index 9ff4ae2..49cb2b4 100644
--- a/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto
+++ b/ui/metrics/bp2build_metrics_proto/bp2build_metrics.proto
@@ -39,6 +39,9 @@
   // List of converted modules
   repeated string convertedModules = 5;
 
+  // Unconverted modules, mapped to the reason the module was not converted.
+  map<string, UnconvertedReason> unconvertedModules = 11;
+
   // Counts of converted modules by module type.
   map<string, uint64> convertedModuleTypeCount = 6;
 
@@ -63,3 +66,40 @@
   // The number of nanoseconds elapsed since start_time.
   uint64 real_time = 3;
 }
+
+message UnconvertedReason {
+  // The type of reason that the module could not be converted.
+  UnconvertedReasonType type = 1;
+
+  // Descriptive details describing why the module could not be converted.
+  // This detail should be kept very short and should be in the context of
+  // the type. (Otherwise, this would significantly bloat metrics.)
+  string detail = 2;
+}
+
+enum UnconvertedReasonType {
+  // Bp2build does not know how to convert this specific module for some reason
+  // not covered by other reason types. The reason detail should explain the
+  // specific issue.
+  UNSUPPORTED = 0;
+
+  // The module was already defined in a BUILD file available in the source tree.
+  DEFINED_IN_BUILD_FILE = 1;
+
+  // The module was explicitly denylisted by name.
+  DENYLISTED = 2;
+
+  // The module's type has no bp2build implementation.
+  TYPE_UNSUPPORTED = 3;
+
+  // The module has a property not yet supported. The detail field should
+  // name the unsupported property name.
+  PROPERTY_UNSUPPORTED = 4;
+
+  // The module has an unconverted dependency. The detail should consist of
+  // the name of the unconverted module.
+  UNCONVERTED_DEP = 5;
+
+  // The module has a source file with the same name as the module itself.
+  SRC_NAME_COLLISION = 6;
+}
\ No newline at end of file
diff --git a/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto b/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto
index 4aee88b..5b44002 100644
--- a/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto
+++ b/ui/metrics/bp2build_progress_metrics_proto/bp2build.proto
@@ -38,6 +38,9 @@
 
     // Total number of transitive dependencies.
     int32 num_deps = 5;
+
+    // Unconverted reasons from heuristics
+    repeated string unconverted_reasons_from_heuristics = 6;
   }
 
   // Modules that the transitive dependencies were identified for.
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index 82d11ed..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,23 +227,19 @@
 	m.metrics.BuildDateTimestamp = proto.Int64(buildTimestamp.UnixNano() / int64(time.Second))
 }
 
-func (m *Metrics) UpdateTotalRealTime(data []byte) error {
-	if err := proto.Unmarshal(data, &m.metrics); err != nil {
-		return fmt.Errorf("Failed to unmarshal proto", err)
-	}
-	startTime := *m.metrics.Total.StartTime
-	endTime := uint64(time.Now().UnixNano())
-
-	*m.metrics.Total.RealTime = *proto.Uint64(endTime - startTime)
-	return nil
-}
-
 // SetBuildCommand adds the build command specified by the user to the
 // list of collected metrics.
 func (m *Metrics) SetBuildCommand(cmd []string) {
 	m.metrics.BuildCommand = proto.String(strings.Join(cmd, " "))
 }
 
+// AddChangedEnvironmentVariable adds the changed environment variable to
+// ChangedEnvironmentVariable field.
+func (m *Metrics) AddChangedEnvironmentVariable(ChangedEnvironmentVariable string) {
+	m.metrics.ChangedEnvironmentVariable = append(m.metrics.ChangedEnvironmentVariable,
+		ChangedEnvironmentVariable)
+}
+
 // Dump exports the collected metrics from the executed build to the file at
 // out path.
 func (m *Metrics) Dump(out string) error {
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index 32d4dc0..b75f572 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -15,7 +15,7 @@
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
 // 	protoc-gen-go v1.30.0
-// 	protoc        v3.21.7
+// 	protoc        v3.21.12
 // source: metrics.proto
 
 package metrics_proto
@@ -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 {
@@ -420,6 +420,11 @@
 	Branch *string `protobuf:"bytes,32,opt,name=branch" json:"branch,omitempty"`
 	// The metric of critical path in build
 	CriticalPathInfo *CriticalPathInfo `protobuf:"bytes,33,opt,name=critical_path_info,json=criticalPathInfo" json:"critical_path_info,omitempty"`
+	// Environment variables that have changed value since the previous build,
+	// which were responsible for retriggering build analysis.
+	// Note that not all changed environment variables result in analysis retriggering.
+	// If there was no previous build, this list will be empty.
+	ChangedEnvironmentVariable []string `protobuf:"bytes,34,rep,name=changed_environment_variable,json=changedEnvironmentVariable" json:"changed_environment_variable,omitempty"`
 }
 
 // Default values for MetricsBase fields.
@@ -694,6 +699,13 @@
 	return nil
 }
 
+func (x *MetricsBase) GetChangedEnvironmentVariable() []string {
+	if x != nil {
+		return x.ChangedEnvironmentVariable
+	}
+	return nil
+}
+
 type BuildConfig struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -987,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
@@ -1017,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)
 	}
@@ -1030,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 {
@@ -1043,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 {
@@ -1137,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)
 	}
@@ -1150,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 {
@@ -1163,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 {
@@ -1201,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)
 	}
@@ -1214,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 {
@@ -1227,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 {
@@ -1256,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)
 	}
@@ -1269,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 {
@@ -1282,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 {
@@ -1311,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)
 	}
@@ -1329,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 {
@@ -1342,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 {
@@ -1394,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
@@ -1413,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)
 	}
@@ -1426,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 {
@@ -1439,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 {
@@ -1477,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)
 	}
@@ -1490,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 {
@@ -1503,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 {
@@ -1540,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)
 	}
@@ -1553,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 {
@@ -1566,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 {
@@ -1611,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)
 	}
@@ -1624,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 {
@@ -1637,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 {
@@ -1659,7 +1851,7 @@
 var file_metrics_proto_rawDesc = []byte{
 	0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
 	0x13, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
-	0x72, 0x69, 0x63, 0x73, 0x22, 0x8a, 0x0f, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
+	0x72, 0x69, 0x63, 0x73, 0x22, 0xcc, 0x0f, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
 	0x42, 0x61, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x61,
 	0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01,
 	0x28, 0x03, 0x52, 0x12, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d,
@@ -1773,199 +1965,224 @@
 	0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43,
 	0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52,
 	0x10, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66,
-	0x6f, 0x22, 0x30, 0x0a, 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x56, 0x61, 0x72, 0x69, 0x61, 0x6e,
-	0x74, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x53, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x55,
-	0x53, 0x45, 0x52, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x45, 0x4e,
-	0x47, 0x10, 0x02, 0x22, 0x3c, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, 0x0b, 0x0a, 0x07, 0x55,
-	0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x52, 0x4d, 0x10,
-	0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x4d, 0x36, 0x34, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03,
-	0x58, 0x38, 0x36, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x58, 0x38, 0x36, 0x5f, 0x36, 0x34, 0x10,
-	0x04, 0x22, 0x8a, 0x04, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69,
-	0x67, 0x12, 0x19, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x08, 0x52, 0x07, 0x75, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x17, 0x0a, 0x07,
-	0x75, 0x73, 0x65, 0x5f, 0x72, 0x62, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x75,
-	0x73, 0x65, 0x52, 0x62, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x75,
-	0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x66,
-	0x6f, 0x72, 0x63, 0x65, 0x55, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x62,
-	0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x61, 0x73, 0x5f, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x18, 0x04, 0x20,
-	0x01, 0x28, 0x08, 0x52, 0x0c, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x41, 0x73, 0x4e, 0x69, 0x6e, 0x6a,
-	0x61, 0x12, 0x2a, 0x0a, 0x11, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x69, 0x78, 0x65, 0x64,
-	0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x62, 0x61,
-	0x7a, 0x65, 0x6c, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x18, 0x0a,
-	0x07, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07,
-	0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x12, 0x44, 0x0a, 0x1f, 0x66, 0x6f, 0x72, 0x63, 0x65,
-	0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d,
-	0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08,
-	0x52, 0x1b, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61,
-	0x7a, 0x65, 0x6c, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x79, 0x0a,
-	0x18, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x6c, 0x69,
-	0x73, 0x74, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32,
-	0x36, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
-	0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69,
-	0x67, 0x2e, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73,
-	0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53, 0x45,
-	0x44, 0x52, 0x15, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69,
-	0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x74, 0x0a, 0x15, 0x4e, 0x69, 0x6e, 0x6a,
-	0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63,
-	0x65, 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53, 0x45, 0x44, 0x10, 0x00, 0x12,
-	0x0d, 0x0a, 0x09, 0x4e, 0x49, 0x4e, 0x4a, 0x41, 0x5f, 0x4c, 0x4f, 0x47, 0x10, 0x01, 0x12, 0x16,
-	0x0a, 0x12, 0x45, 0x56, 0x45, 0x4e, 0x4c, 0x59, 0x5f, 0x44, 0x49, 0x53, 0x54, 0x52, 0x49, 0x42,
-	0x55, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x58, 0x54, 0x45, 0x52, 0x4e,
-	0x41, 0x4c, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x12, 0x13, 0x0a, 0x0f, 0x48, 0x49, 0x4e,
-	0x54, 0x5f, 0x46, 0x52, 0x4f, 0x4d, 0x5f, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x04, 0x22, 0x6f,
-	0x0a, 0x12, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
-	0x49, 0x6e, 0x66, 0x6f, 0x12, 0x32, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x68,
-	0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x04, 0x52, 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63,
-	0x61, 0x6c, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x76, 0x61, 0x69,
-	0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x70, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
-	0x52, 0x0d, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x70, 0x75, 0x73, 0x22,
-	0xca, 0x02, 0x0a, 0x08, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b,
-	0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12,
-	0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
-	0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65,
-	0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d,
-	0x65, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04,
-	0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21,
-	0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01,
-	0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x73,
-	0x65, 0x12, 0x60, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x5f, 0x72,
-	0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x03,
-	0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
-	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
-	0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x15, 0x70, 0x72,
-	0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49,
-	0x6e, 0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x5f, 0x7a, 0x65, 0x72, 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, 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, 0x12, 0x40, 0x0a, 0x1c, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x5f, 0x65, 0x6e, 0x76,
+	0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c,
+	0x65, 0x18, 0x22, 0x20, 0x03, 0x28, 0x09, 0x52, 0x1a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64,
+	0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61,
+	0x62, 0x6c, 0x65, 0x22, 0x30, 0x0a, 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x56, 0x61, 0x72, 0x69,
+	0x61, 0x6e, 0x74, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x53, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0d, 0x0a,
+	0x09, 0x55, 0x53, 0x45, 0x52, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03,
+	0x45, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x3c, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, 0x0b, 0x0a,
+	0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x52,
+	0x4d, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x4d, 0x36, 0x34, 0x10, 0x02, 0x12, 0x07,
+	0x0a, 0x03, 0x58, 0x38, 0x36, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x58, 0x38, 0x36, 0x5f, 0x36,
+	0x34, 0x10, 0x04, 0x22, 0x8a, 0x04, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x75, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x17,
+	0x0a, 0x07, 0x75, 0x73, 0x65, 0x5f, 0x72, 0x62, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52,
+	0x06, 0x75, 0x73, 0x65, 0x52, 0x62, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x66, 0x6f, 0x72, 0x63, 0x65,
+	0x5f, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,
+	0x0c, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x55, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x24, 0x0a,
+	0x0e, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x61, 0x73, 0x5f, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x18,
+	0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x41, 0x73, 0x4e, 0x69,
+	0x6e, 0x6a, 0x61, 0x12, 0x2a, 0x0a, 0x11, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x69, 0x78,
+	0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f,
+	0x62, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12,
+	0x18, 0x0a, 0x07, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09,
+	0x52, 0x07, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x12, 0x44, 0x0a, 0x1f, 0x66, 0x6f, 0x72,
+	0x63, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c,
+	0x5f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x07, 0x20, 0x01,
+	0x28, 0x08, 0x52, 0x1b, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
+	0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12,
+	0x79, 0x0a, 0x18, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f,
+	0x6c, 0x69, 0x73, 0x74, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28,
+	0x0e, 0x32, 0x36, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f,
+	0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x2e, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c,
+	0x69, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55,
+	0x53, 0x45, 0x44, 0x52, 0x15, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74,
+	0x4c, 0x69, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x74, 0x0a, 0x15, 0x4e, 0x69,
+	0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6f, 0x75,
+	0x72, 0x63, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53, 0x45, 0x44, 0x10,
+	0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x49, 0x4e, 0x4a, 0x41, 0x5f, 0x4c, 0x4f, 0x47, 0x10, 0x01,
+	0x12, 0x16, 0x0a, 0x12, 0x45, 0x56, 0x45, 0x4e, 0x4c, 0x59, 0x5f, 0x44, 0x49, 0x53, 0x54, 0x52,
+	0x49, 0x42, 0x55, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x45, 0x58, 0x54, 0x45,
+	0x52, 0x4e, 0x41, 0x4c, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x12, 0x13, 0x0a, 0x0f, 0x48,
+	0x49, 0x4e, 0x54, 0x5f, 0x46, 0x52, 0x4f, 0x4d, 0x5f, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x04,
+	0x22, 0x6f, 0x0a, 0x12, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
+	0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x32, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f,
+	0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x68, 0x79, 0x73,
+	0x69, 0x63, 0x61, 0x6c, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x76,
+	0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x70, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x05, 0x52, 0x0d, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x70, 0x75,
+	0x73, 0x22, 0xca, 0x02, 0x0a, 0x08, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20,
+	0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+	0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
+	0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69,
+	0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54,
+	0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65,
+	0x12, 0x21, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x18, 0x05,
+	0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79,
+	0x55, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73,
+	0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69,
+	0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65,
+	0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x15,
+	0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
+	0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x5f, 0x7a, 0x65, 0x72,
+	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, 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, 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,
+	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,
+	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, 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 (
@@ -1981,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
@@ -1992,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
@@ -2012,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() }
@@ -2090,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:
@@ -2102,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:
@@ -2114,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:
@@ -2126,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:
@@ -2138,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:
@@ -2150,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:
@@ -2162,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:
@@ -2174,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:
@@ -2186,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
@@ -2204,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 6db83e9..11fcba7 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -131,6 +131,12 @@
 
   // The metric of critical path in build
   optional CriticalPathInfo critical_path_info = 33;
+
+  // Environment variables that have changed value since the previous build,
+  // which were responsible for retriggering build analysis.
+  // Note that not all changed environment variables result in analysis retriggering.
+  // If there was no previous build, this list will be empty.
+  repeated string changed_environment_variable = 34;
 }
 
 message BuildConfig {
@@ -207,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;
@@ -289,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/kati.go b/ui/status/kati.go
index 1485c8d..dbb0ce3 100644
--- a/ui/status/kati.go
+++ b/ui/status/kati.go
@@ -24,7 +24,7 @@
 )
 
 var katiError = regexp.MustCompile(`^(\033\[1m)?[^ ]+:[0-9]+: (\033\[31m)?error:`)
-var katiIncludeRe = regexp.MustCompile(`^(\[(\d+)/(\d+)] )?((including [^ ]+|initializing (build|packaging) system|finishing (build|packaging) rules|writing (build|packaging) rules) ...)$`)
+var katiIncludeRe = regexp.MustCompile(`^(\[(\d+)/(\d+)] )?((including [^ ]+|initializing (legacy Make module parser|packaging system)|finishing (legacy Make module parsing|packaging rules)|writing (legacy Make module|packaging) rules) ...)$`)
 var katiLogRe = regexp.MustCompile(`^\*kati\*: `)
 var katiNinjaMissing = regexp.MustCompile("^[^ ]+ is missing, regenerating...$")
 
diff --git a/ui/status/kati_test.go b/ui/status/kati_test.go
index f2cb813..fd1b4b5 100644
--- a/ui/status/kati_test.go
+++ b/ui/status/kati_test.go
@@ -65,7 +65,7 @@
 	parser.parseLine("out/build-aosp_arm.ninja is missing, regenerating...")
 	output.Expect(t, Counts{})
 
-	parser.parseLine("[1/1] initializing build system ...")
+	parser.parseLine("[1/1] initializing legacy Make module parser ...")
 	output.Expect(t, Counts{
 		TotalActions:    1,
 		RunningActions:  1,
@@ -86,14 +86,14 @@
 	parser.parseLine(msg)
 
 	// Start the next line to flush the previous result
-	parser.parseLine("[4/5] finishing build rules ...")
+	parser.parseLine("[4/5] finishing legacy Make module parsing ...")
 
 	msg += "\n"
 	if output.result.Output != msg {
 		t.Errorf("output for action did not match:\nwant: %q\n got: %q\n", msg, output.result.Output)
 	}
 
-	parser.parseLine("[5/5] writing build rules ...")
+	parser.parseLine("[5/5] writing legacy Make module rules ...")
 	parser.parseLine("*kati*: verbose msg")
 	parser.flushAction()
 
@@ -118,7 +118,7 @@
 		st: status.StartTool(),
 	}
 
-	parser.parseLine("[1/1] initializing build system ...")
+	parser.parseLine("[1/1] initializing legacy Make module parser ...")
 	parser.parseLine("[2/5] including out/soong/Android-aosp_arm.mk ...")
 	output.Expect(t, Counts{
 		TotalActions:    5,
@@ -145,7 +145,7 @@
 		FinishedActions: 3,
 	})
 
-	parser.parseLine("[3/5] finishing build rules ...")
+	parser.parseLine("[3/5] finishing legacy Make module parsing ...")
 
 	output.Expect(t, Counts{
 		TotalActions:    7,
@@ -164,7 +164,7 @@
 		st: status.StartTool(),
 	}
 
-	parser.parseLine("[1/1] initializing build system ...")
+	parser.parseLine("[1/1] initializing legacy Make module parser ...")
 	parser.parseLine("[2/5] inclduing out/soong/Android-aosp_arm.mk ...")
 	parser.parseLine("build/make/tools/Android.mk:19: error: testing")
 	parser.flushAction()
diff --git a/ui/status/ninja.go b/ui/status/ninja.go
index fc0e21a..f4e3fb8 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,34 +127,80 @@
 
 	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()))
 		}
@@ -174,6 +239,7 @@
 						IOOutputKB:                 msg.EdgeFinished.GetIoOutputKb(),
 						VoluntaryContextSwitches:   msg.EdgeFinished.GetVoluntaryContextSwitches(),
 						InvoluntaryContextSwitches: msg.EdgeFinished.GetInvoluntaryContextSwitches(),
+						Tags:                       msg.EdgeFinished.GetTags(),
 					},
 				})
 			}
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 bcadc67..d8344c8 100644
--- a/ui/status/ninja_frontend/frontend.pb.go
+++ b/ui/status/ninja_frontend/frontend.pb.go
@@ -14,8 +14,8 @@
 
 // Code generated by protoc-gen-go. DO NOT EDIT.
 // versions:
-// 	protoc-gen-go v1.26.0
-// 	protoc        v3.9.1
+// 	protoc-gen-go v1.30.0
+// 	protoc        v3.21.12
 // source: frontend.proto
 
 package ninja_frontend
@@ -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
@@ -459,6 +477,9 @@
 	VoluntaryContextSwitches *uint64 `protobuf:"varint,12,opt,name=voluntary_context_switches,json=voluntaryContextSwitches" json:"voluntary_context_switches,omitempty"`
 	// Involuntary context switches
 	InvoluntaryContextSwitches *uint64 `protobuf:"varint,13,opt,name=involuntary_context_switches,json=involuntaryContextSwitches" json:"involuntary_context_switches,omitempty"`
+	// Arbitrary tags for build system profiling (module names and types, rule
+	// names, etc). Format of the string is implementation defined.
+	Tags *string `protobuf:"bytes,14,opt,name=tags" json:"tags,omitempty"`
 }
 
 func (x *Status_EdgeFinished) Reset() {
@@ -584,6 +605,13 @@
 	return 0
 }
 
+func (x *Status_EdgeFinished) GetTags() string {
+	if x != nil && x.Tags != nil {
+		return *x.Tags
+	}
+	return ""
+}
+
 type Status_Message struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -650,7 +678,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, 0xb4, 0x0a, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74,
+	0x12, 0x05, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x22, 0xa9, 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,
@@ -677,66 +705,73 @@
 	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, 0xdf, 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, 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,
+	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,
 }
 
 var (
diff --git a/ui/status/ninja_frontend/frontend.proto b/ui/status/ninja_frontend/frontend.proto
index 5730388..42b251b 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 {
@@ -79,6 +83,9 @@
     optional uint64 voluntary_context_switches = 12;
     // Involuntary context switches
     optional uint64 involuntary_context_switches = 13;
+    // Arbitrary tags for build system profiling (module names and types, rule
+    // names, etc). Format of the string is implementation defined.
+    optional string tags = 14;
   }
 
   message Message {
diff --git a/ui/status/status.go b/ui/status/status.go
index a5b4a28..da78994 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).
@@ -85,6 +86,8 @@
 
 	// Involuntary context switches
 	InvoluntaryContextSwitches uint64
+
+	Tags string
 }
 
 // Counts describes the number of actions in each state
@@ -105,6 +108,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
@@ -116,6 +121,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.
@@ -265,6 +271,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()
@@ -327,6 +340,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/terminal/smart_status.go b/ui/terminal/smart_status.go
index 06a4064..3880b04 100644
--- a/ui/terminal/smart_status.go
+++ b/ui/terminal/smart_status.go
@@ -53,6 +53,13 @@
 	done            chan bool
 	sigwinch        chan os.Signal
 	sigwinchHandled chan bool
+
+	// Once there is a failure, we stop printing command output so the error
+	// is easier to find
+	haveFailures bool
+	// If we are dropping errors, then at the end, we report a message to go
+	// look in the verbose log if you want that command output.
+	postFailureActionCount int
 }
 
 // NewSmartStatusOutput returns a StatusOutput that represents the
@@ -165,12 +172,20 @@
 		}
 	}
 
+	s.statusLine(progress)
+
+	// Stop printing when there are failures, but don't skip actions that also have their own errors.
 	if output != "" {
-		s.statusLine(progress)
-		s.requestLine()
-		s.print(output)
-	} else {
-		s.statusLine(progress)
+		if !s.haveFailures || result.Error != nil {
+			s.requestLine()
+			s.print(output)
+		} else {
+			s.postFailureActionCount++
+		}
+	}
+
+	if result.Error != nil {
+		s.haveFailures = true
 	}
 }
 
@@ -187,6 +202,15 @@
 
 	s.stopSigwinch()
 
+	if s.postFailureActionCount > 0 {
+		s.requestLine()
+		if s.postFailureActionCount == 1 {
+			s.print(fmt.Sprintf("There was 1 action that completed after the action that failed. See verbose.log.gz for its output."))
+		} else {
+			s.print(fmt.Sprintf("There were %d actions that completed after the action that failed. See verbose.log.gz for their output.", s.postFailureActionCount))
+		}
+	}
+
 	s.requestLine()
 
 	s.runningActions = nil
diff --git a/ui/terminal/status_test.go b/ui/terminal/status_test.go
index b9057d2..8dd1809 100644
--- a/ui/terminal/status_test.go
+++ b/ui/terminal/status_test.go
@@ -295,3 +295,159 @@
 		t.Errorf("want:\n%q\ngot:\n%q", w, g)
 	}
 }
+
+func TestSmartStatusDoesntHideAfterSucecss(t *testing.T) {
+	os.Setenv(tableHeightEnVar, "")
+
+	smart := &fakeSmartTerminal{termWidth: 40}
+	stat := NewStatusOutput(smart, "", false, false, false)
+	smartStat := stat.(*smartStatusOutput)
+	smartStat.sigwinchHandled = make(chan bool)
+
+	runner := newRunner(stat, 2)
+
+	action1 := &status.Action{Description: "action1"}
+	result1 := status.ActionResult{
+		Action: action1,
+		Output: "Output1",
+	}
+
+	action2 := &status.Action{Description: "action2"}
+	result2 := status.ActionResult{
+		Action: action2,
+		Output: "Output2",
+	}
+
+	runner.startAction(action1)
+	runner.startAction(action2)
+	runner.finishAction(result1)
+	runner.finishAction(result2)
+
+	stat.Flush()
+
+	w := "\r\x1b[1m[  0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[  0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\nOutput2\n"
+
+	if g := smart.String(); g != w {
+		t.Errorf("want:\n%q\ngot:\n%q", w, g)
+	}
+}
+
+func TestSmartStatusHideAfterFailure(t *testing.T) {
+	os.Setenv(tableHeightEnVar, "")
+
+	smart := &fakeSmartTerminal{termWidth: 40}
+	stat := NewStatusOutput(smart, "", false, false, false)
+	smartStat := stat.(*smartStatusOutput)
+	smartStat.sigwinchHandled = make(chan bool)
+
+	runner := newRunner(stat, 2)
+
+	action1 := &status.Action{Description: "action1"}
+	result1 := status.ActionResult{
+		Action: action1,
+		Output: "Output1",
+		Error:  fmt.Errorf("Error1"),
+	}
+
+	action2 := &status.Action{Description: "action2"}
+	result2 := status.ActionResult{
+		Action: action2,
+		Output: "Output2",
+	}
+
+	runner.startAction(action1)
+	runner.startAction(action2)
+	runner.finishAction(result1)
+	runner.finishAction(result2)
+
+	stat.Flush()
+
+	w := "\r\x1b[1m[  0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[  0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\nFAILED: \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\nThere was 1 action that completed after the action that failed. See verbose.log.gz for its output.\n"
+
+	if g := smart.String(); g != w {
+		t.Errorf("want:\n%q\ngot:\n%q", w, g)
+	}
+}
+
+func TestSmartStatusHideAfterFailurePlural(t *testing.T) {
+	os.Setenv(tableHeightEnVar, "")
+
+	smart := &fakeSmartTerminal{termWidth: 40}
+	stat := NewStatusOutput(smart, "", false, false, false)
+	smartStat := stat.(*smartStatusOutput)
+	smartStat.sigwinchHandled = make(chan bool)
+
+	runner := newRunner(stat, 2)
+
+	action1 := &status.Action{Description: "action1"}
+	result1 := status.ActionResult{
+		Action: action1,
+		Output: "Output1",
+		Error:  fmt.Errorf("Error1"),
+	}
+
+	action2 := &status.Action{Description: "action2"}
+	result2 := status.ActionResult{
+		Action: action2,
+		Output: "Output2",
+	}
+
+	action3 := &status.Action{Description: "action3"}
+	result3 := status.ActionResult{
+		Action: action3,
+		Output: "Output3",
+	}
+
+	runner.startAction(action1)
+	runner.startAction(action2)
+	runner.startAction(action3)
+	runner.finishAction(result1)
+	runner.finishAction(result2)
+	runner.finishAction(result3)
+
+	stat.Flush()
+
+	w := "\r\x1b[1m[  0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[  0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[  0% 0/2] action3\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\nFAILED: \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\r\x1b[1m[150% 3/2] action3\x1b[0m\x1b[K\nThere were 2 actions that completed after the action that failed. See verbose.log.gz for their output.\n"
+
+	if g := smart.String(); g != w {
+		t.Errorf("want:\n%q\ngot:\n%q", w, g)
+	}
+}
+
+func TestSmartStatusDontHideErrorAfterFailure(t *testing.T) {
+	os.Setenv(tableHeightEnVar, "")
+
+	smart := &fakeSmartTerminal{termWidth: 40}
+	stat := NewStatusOutput(smart, "", false, false, false)
+	smartStat := stat.(*smartStatusOutput)
+	smartStat.sigwinchHandled = make(chan bool)
+
+	runner := newRunner(stat, 2)
+
+	action1 := &status.Action{Description: "action1"}
+	result1 := status.ActionResult{
+		Action: action1,
+		Output: "Output1",
+		Error:  fmt.Errorf("Error1"),
+	}
+
+	action2 := &status.Action{Description: "action2"}
+	result2 := status.ActionResult{
+		Action: action2,
+		Output: "Output2",
+		Error:  fmt.Errorf("Error1"),
+	}
+
+	runner.startAction(action1)
+	runner.startAction(action2)
+	runner.finishAction(result1)
+	runner.finishAction(result2)
+
+	stat.Flush()
+
+	w := "\r\x1b[1m[  0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[  0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\nFAILED: \nOutput1\n\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\nFAILED: \nOutput2\n"
+
+	if g := smart.String(); g != w {
+		t.Errorf("want:\n%q\ngot:\n%q", w, g)
+	}
+}
diff --git a/ui/tracer/status.go b/ui/tracer/status.go
index a8b4e62..f973613 100644
--- a/ui/tracer/status.go
+++ b/ui/tracer/status.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/ui/status"
+	"strings"
 	"time"
 )
 
@@ -60,6 +61,24 @@
 	}
 }
 
+func (s *statusOutput) parseTags(rawTags string) map[string]string {
+	if rawTags == "" {
+		return nil
+	}
+
+	tags := map[string]string{}
+	for _, pair := range strings.Split(rawTags, ";") {
+		if pair == "" {
+			// Ignore empty tag pairs. It's hard to generate these cleanly from
+			// make so some tag strings might be something like ";key=value".
+			continue
+		}
+		parts := strings.SplitN(pair, "=", 2)
+		tags[parts[0]] = parts[1]
+	}
+	return tags
+}
+
 func (s *statusOutput) FinishAction(result status.ActionResult, counts status.Counts) {
 	start, ok := s.running[result.Action]
 	if !ok {
@@ -90,20 +109,22 @@
 			IOOutputKB:                 result.Stats.IOOutputKB,
 			VoluntaryContextSwitches:   result.Stats.VoluntaryContextSwitches,
 			InvoluntaryContextSwitches: result.Stats.InvoluntaryContextSwitches,
+			Tags:                       s.parseTags(result.Stats.Tags),
 		},
 	})
 }
 
 type statsArg struct {
-	UserTime                   uint32 `json:"user_time"`
-	SystemTime                 uint32 `json:"system_time_ms"`
-	MaxRssKB                   uint64 `json:"max_rss_kb"`
-	MinorPageFaults            uint64 `json:"minor_page_faults"`
-	MajorPageFaults            uint64 `json:"major_page_faults"`
-	IOInputKB                  uint64 `json:"io_input_kb"`
-	IOOutputKB                 uint64 `json:"io_output_kb"`
-	VoluntaryContextSwitches   uint64 `json:"voluntary_context_switches"`
-	InvoluntaryContextSwitches uint64 `json:"involuntary_context_switches"`
+	UserTime                   uint32            `json:"user_time"`
+	SystemTime                 uint32            `json:"system_time_ms"`
+	MaxRssKB                   uint64            `json:"max_rss_kb"`
+	MinorPageFaults            uint64            `json:"minor_page_faults"`
+	MajorPageFaults            uint64            `json:"major_page_faults"`
+	IOInputKB                  uint64            `json:"io_input_kb"`
+	IOOutputKB                 uint64            `json:"io_output_kb"`
+	VoluntaryContextSwitches   uint64            `json:"voluntary_context_switches"`
+	InvoluntaryContextSwitches uint64            `json:"involuntary_context_switches"`
+	Tags                       map[string]string `json:"tags"`
 }
 
 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/BUILD.bazel b/zip/cmd/BUILD.bazel
deleted file mode 100644
index e04a1e1..0000000
--- a/zip/cmd/BUILD.bazel
+++ /dev/null
@@ -1,20 +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.
-
-# TODO(b/194644518): Switch to the source version when Bazel can build go
-# binaries.
-alias(
-    name = "soong_zip",
-    actual = "//prebuilts/build-tools:linux-x86/bin/soong_zip",
-)
diff --git a/zip/cmd/main.go b/zip/cmd/main.go
index def76aa..37537ab 100644
--- a/zip/cmd/main.go
+++ b/zip/cmd/main.go
@@ -78,6 +78,15 @@
 	return nil
 }
 
+type explicitFile struct{}
+
+func (explicitFile) String() string { return `""` }
+
+func (explicitFile) Set(s string) error {
+	fileArgsBuilder.ExplicitPathInZip(s)
+	return nil
+}
+
 type dir struct{}
 
 func (dir) String() string { return `""` }
@@ -164,6 +173,8 @@
 	cpuProfile := flags.String("cpuprofile", "", "write cpu profile to file")
 	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")
@@ -173,6 +184,7 @@
 	flags.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression")
 	flags.Var(&relativeRoot{}, "C", "path to use as relative root of files in following -f, -l, or -D arguments")
 	flags.Var(&junkPaths{}, "j", "junk paths, zip files without directory names")
+	flags.Var(&explicitFile{}, "e", "filename to use in the zip file for the next -f argument")
 
 	flags.Parse(expandedArgs[1:])
 
@@ -226,6 +238,8 @@
 		StoreSymlinks:            *symlinks,
 		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 6f1a8ad..f91a5f2 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -80,6 +80,7 @@
 
 type FileArg struct {
 	PathPrefixInZip, SourcePrefixToStrip string
+	ExplicitPathInZip                    string
 	SourceFiles                          []string
 	JunkPaths                            bool
 	GlobDir                              string
@@ -124,6 +125,10 @@
 	arg := b.state
 	arg.SourceFiles = []string{name}
 	b.fileArgs = append(b.fileArgs, arg)
+
+	if b.state.ExplicitPathInZip != "" {
+		b.state.ExplicitPathInZip = ""
+	}
 	return b
 }
 
@@ -189,6 +194,12 @@
 	return b
 }
 
+// ExplicitPathInZip sets the path in the zip file for the next File call.
+func (b *FileArgsBuilder) ExplicitPathInZip(s string) *FileArgsBuilder {
+	b.state.ExplicitPathInZip = s
+	return b
+}
+
 func (b *FileArgsBuilder) Error() error {
 	if b == nil {
 		return nil
@@ -271,6 +282,8 @@
 	StoreSymlinks            bool
 	IgnoreMissingFiles       bool
 	Sha256Checksum           bool
+	DoNotWrite               bool
+	Quiet                    bool
 
 	Stderr     io.Writer
 	Filesystem pathtools.FileSystem
@@ -328,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
 				}
@@ -345,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
 				}
@@ -356,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
 				}
@@ -389,7 +408,9 @@
 
 	var zipErr error
 
-	if !args.WriteIfChanged {
+	if args.DoNotWrite {
+		out = io.Discard
+	} else if !args.WriteIfChanged {
 		f, err := os.Create(args.OutputFilePath)
 		if err != nil {
 			return err
@@ -410,7 +431,7 @@
 		return zipErr
 	}
 
-	if args.WriteIfChanged {
+	if args.WriteIfChanged && !args.DoNotWrite {
 		err := pathtools.WriteFileIfChanged(args.OutputFilePath, buf.Bytes(), 0666)
 		if err != nil {
 			return err
@@ -425,7 +446,9 @@
 
 	var dest string
 
-	if fa.JunkPaths {
+	if fa.ExplicitPathInZip != "" {
+		dest = fa.ExplicitPathInZip
+	} else if fa.JunkPaths {
 		dest = filepath.Base(src)
 	} else {
 		var err error
diff --git a/zip/zip_test.go b/zip/zip_test.go
index e7fdea8..c64c3f4 100644
--- a/zip/zip_test.go
+++ b/zip/zip_test.go
@@ -454,6 +454,60 @@
 				fhWithSHA256("c", fileC, zip.Deflate, sha256FileC),
 			},
 		},
+		{
+			name: "explicit path",
+			args: fileArgsBuilder().
+				ExplicitPathInZip("foo").
+				File("a/a/a").
+				File("a/a/b"),
+			compressionLevel: 9,
+
+			files: []zip.FileHeader{
+				fh("foo", fileA, zip.Deflate),
+				fh("a/a/b", fileB, zip.Deflate),
+			},
+		},
+		{
+			name: "explicit path with prefix",
+			args: fileArgsBuilder().
+				PathPrefixInZip("prefix").
+				ExplicitPathInZip("foo").
+				File("a/a/a").
+				File("a/a/b"),
+			compressionLevel: 9,
+
+			files: []zip.FileHeader{
+				fh("prefix/foo", fileA, zip.Deflate),
+				fh("prefix/a/a/b", fileB, zip.Deflate),
+			},
+		},
+		{
+			name: "explicit path with glob",
+			args: fileArgsBuilder().
+				ExplicitPathInZip("foo").
+				File("a/a/a*").
+				File("a/a/b"),
+			compressionLevel: 9,
+
+			files: []zip.FileHeader{
+				fh("foo", fileA, zip.Deflate),
+				fh("a/a/b", fileB, zip.Deflate),
+			},
+		},
+		{
+			name: "explicit path with junk paths",
+			args: fileArgsBuilder().
+				JunkPaths(true).
+				ExplicitPathInZip("foo/bar").
+				File("a/a/a*").
+				File("a/a/b"),
+			compressionLevel: 9,
+
+			files: []zip.FileHeader{
+				fh("foo/bar", fileA, zip.Deflate),
+				fh("b", fileB, zip.Deflate),
+			},
+		},
 
 		// errors
 		{
@@ -490,6 +544,22 @@
 				File("d/a/a"),
 			err: ConflictingFileError{},
 		},
+		{
+			name: "error explicit path conflicting",
+			args: fileArgsBuilder().
+				ExplicitPathInZip("foo").
+				File("a/a/a").
+				ExplicitPathInZip("foo").
+				File("a/a/b"),
+			err: ConflictingFileError{},
+		},
+		{
+			name: "error explicit path conflicting glob",
+			args: fileArgsBuilder().
+				ExplicitPathInZip("foo").
+				File("a/a/*"),
+			err: ConflictingFileError{},
+		},
 	}
 
 	for _, test := range testCases {