Merge "Revert "Revert "Added new framework-pdf jar inside MediaProvider..."" into main
diff --git a/Android.bp b/Android.bp
index 63de015..b1db8e9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -130,3 +130,8 @@
     // Currently, only microdroid can refer to buildinfo.prop
     visibility: ["//packages/modules/Virtualization/microdroid"],
 }
+
+// container for apex_contributions selected using build flags
+all_apex_contributions {
+    name: "all_apex_contributions",
+}
diff --git a/OWNERS b/OWNERS
index 9221d3e..e5374ed 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,30 +1,31 @@
+# Bug component: 99142
 # This file is included by several other projects as the list of people
 # approving build related projects.
 
 # AMER
-agespino@google.com
+agespino@google.com  #{LAST_RESORT_SUGGESTION}
 ccross@android.com
 colefaust@google.com
-cparsons@google.com
-dacek@google.com
-delmerico@google.com
+cparsons@google.com  #{LAST_RESORT_SUGGESTION}
+dacek@google.com  #{LAST_RESORT_SUGGESTION}
+delmerico@google.com  #{LAST_RESORT_SUGGESTION}
 dwillemsen@google.com
-eakammer@google.com
+eakammer@google.com  #{LAST_RESORT_SUGGESTION}
 jihoonkang@google.com
-jobredeaux@google.com
+jobredeaux@google.com  #{LAST_RESORT_SUGGESTION}
 joeo@google.com
-juu@google.com
+juu@google.com  #{LAST_RESORT_SUGGESTION}
 lamontjones@google.com
 mrziwang@google.com
 spandandas@google.com
-tradical@google.com
-usta@google.com
-vinhdaitran@google.com
+tradical@google.com  #{LAST_RESORT_SUGGESTION}
+usta@google.com  #{LAST_RESORT_SUGGESTION}
+vinhdaitran@google.com  #{LAST_RESORT_SUGGESTION}
 weiwli@google.com
 yudiliu@google.com
 
 # APAC
-jingwen@google.com
+jingwen@google.com  #{LAST_RESORT_SUGGESTION}
 
 # EMEA
-lberki@google.com
+lberki@google.com  #{LAST_RESORT_SUGGESTION}
diff --git a/README.md b/README.md
index 22daa95..5e9e04a 100644
--- a/README.md
+++ b/README.md
@@ -648,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/aconfig_declarations.go b/aconfig/aconfig_declarations.go
index f19ddb8..897f892 100644
--- a/aconfig/aconfig_declarations.go
+++ b/aconfig/aconfig_declarations.go
@@ -74,8 +74,8 @@
 	// RELEASE_ACONFIG_VALUE_SETS, and add any aconfig_values that
 	// match our package.
 	valuesFromConfig := ctx.Config().ReleaseAconfigValueSets()
-	if valuesFromConfig != "" {
-		ctx.AddDependency(ctx.Module(), implicitValuesTag, valuesFromConfig)
+	if len(valuesFromConfig) > 0 {
+		ctx.AddDependency(ctx.Module(), implicitValuesTag, valuesFromConfig...)
 	}
 }
 
diff --git a/aconfig/cc_aconfig_library.go b/aconfig/cc_aconfig_library.go
index 0583bef..210a581 100644
--- a/aconfig/cc_aconfig_library.go
+++ b/aconfig/cc_aconfig_library.go
@@ -38,8 +38,11 @@
 	// name of the aconfig_declarations module to generate a library for
 	Aconfig_declarations string
 
-	// whether to generate test mode version of the library
-	Test *bool
+	// 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
+	// an error will be thrown if the mode is not supported
+	Mode *string
 }
 
 type CcAconfigLibraryCallbacks struct {
@@ -121,12 +124,11 @@
 	}
 	declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData)
 
-	var mode string
-	if proptools.Bool(this.properties.Test) {
-		mode = "test"
-	} else {
-		mode = "production"
+	mode := proptools.StringDefault(this.properties.Mode, "production")
+	if !isModeSupported(mode) {
+		ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
 	}
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:  cppRule,
 		Input: declarations.IntermediatePath,
@@ -143,6 +145,7 @@
 }
 
 type bazelCcAconfigLibraryAttributes struct {
+	cc.SdkAttributes
 	Aconfig_declarations bazel.LabelAttribute
 	Dynamic_deps         bazel.LabelListAttribute
 }
@@ -154,12 +157,13 @@
 // module type returns a cc library and the bp2build conversion is called on the
 // cc library type.
 
-func (this *CcAconfigLibraryCallbacks) GeneratorBp2build(ctx android.Bp2buildMutatorContext) bool {
+func (this *CcAconfigLibraryCallbacks) GeneratorBp2build(ctx android.Bp2buildMutatorContext, module *cc.Module) bool {
 	if ctx.ModuleType() != "cc_aconfig_library" {
 		return false
 	}
 
 	attrs := bazelCcAconfigLibraryAttributes{
+		SdkAttributes:        cc.Bp2BuildParseSdkAttributes(module),
 		Aconfig_declarations: *bazel.MakeLabelAttribute(android.BazelLabelForModuleDepSingle(ctx, this.properties.Aconfig_declarations).Label),
 		Dynamic_deps:         bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, []string{baseLibDep})),
 	}
@@ -168,6 +172,12 @@
 		Bzl_load_location: "//build/bazel/rules/cc:cc_aconfig_library.bzl",
 	}
 
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: ctx.ModuleName()}, &attrs)
+	ctx.CreateBazelTargetModule(
+		props,
+		android.CommonAttributes{
+			Name: ctx.ModuleName(),
+			Tags: android.ApexAvailableTagsWithoutTestApexes(ctx, module),
+		},
+		&attrs)
 	return true
 }
diff --git a/aconfig/cc_aconfig_library_test.go b/aconfig/cc_aconfig_library_test.go
index 6f17c75..ba27250 100644
--- a/aconfig/cc_aconfig_library_test.go
+++ b/aconfig/cc_aconfig_library_test.go
@@ -22,16 +22,17 @@
 	"android/soong/cc"
 )
 
-var codegenModeTestData = []struct {
+var ccCodegenModeTestData = []struct {
 	setting, expected string
 }{
 	{"", "production"},
-	{"test: false,", "production"},
-	{"test: true,", "test"},
+	{"mode: `production`,", "production"},
+	{"mode: `test`,", "test"},
+	{"mode: `exported`,", "exported"},
 }
 
 func TestCCCodegenMode(t *testing.T) {
-	for _, testData := range codegenModeTestData {
+	for _, testData := range ccCodegenModeTestData {
 		testCCCodegenModeHelper(t, testData.setting, testData.expected)
 	}
 }
@@ -65,3 +66,41 @@
 	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))
+}
diff --git a/aconfig/java_aconfig_library.go b/aconfig/java_aconfig_library.go
index 4db0ef7..eedb3c3 100644
--- a/aconfig/java_aconfig_library.go
+++ b/aconfig/java_aconfig_library.go
@@ -15,10 +15,13 @@
 package aconfig
 
 import (
-	"android/soong/android"
-	"android/soong/java"
 	"fmt"
+
+	"android/soong/android"
+	"android/soong/bazel"
+	"android/soong/java"
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
 type declarationsTagType struct {
@@ -27,12 +30,17 @@
 
 var declarationsTag = declarationsTagType{}
 
+var aconfigSupportedModes = []string{"production", "test", "exported"}
+
 type JavaAconfigDeclarationsLibraryProperties struct {
 	// name of the aconfig_declarations module to generate a library for
 	Aconfig_declarations string
 
-	// whether to generate test mode version of the library
-	Test bool
+	// 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
+	// an error will be thrown if the mode is not supported
+	Mode *string
 }
 
 type JavaAconfigDeclarationsLibraryCallbacks struct {
@@ -55,6 +63,8 @@
 
 	// 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 {
@@ -67,12 +77,12 @@
 
 	// Generate the action to build the srcjar
 	srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar")
-	var mode string
-	if callbacks.properties.Test {
-		mode = "test"
-	} else {
-		mode = "production"
+
+	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.IntermediatePath,
@@ -89,3 +99,60 @@
 
 	return srcJarPath
 }
+
+func isModeSupported(mode string) bool {
+	return android.InList(mode, aconfigSupportedModes)
+}
+
+type bazelJavaAconfigLibraryAttributes struct {
+	Aconfig_declarations bazel.LabelAttribute
+	Sdk_version          *string
+	Libs                 bazel.LabelListAttribute
+}
+
+func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) Bp2build(ctx android.Bp2buildMutatorContext, module *java.GeneratedJavaLibraryModule) {
+	if ctx.ModuleType() != "java_aconfig_library" {
+		return
+	}
+
+	// By default, soong builds the aconfig java library with private_current, however
+	// bazel currently doesn't support it so we default it to system_current. One reason
+	// is that the dependency of all java_aconfig_library aconfig-annotations-lib is
+	// built with system_current. For the java aconfig library itself it doesn't really
+	// matter whether it uses private API or system API because the only module it uses
+	// is DeviceConfig which is in system, and the rdeps of the java aconfig library
+	// won't change its sdk version either, so this should be fine.
+	// Ideally we should only use the default value if it is not set by the user, but
+	// bazel only supports a limited sdk versions, for example, the java_aconfig_library
+	// modules in framework/base use core_platform which is not supported by bazel yet.
+	// TODO(b/302148527): change soong to default to system_current as well.
+	sdkVersion := "system_current"
+
+	var libs bazel.LabelListAttribute
+	archVariantProps := module.GetArchVariantProperties(ctx, &java.CommonProperties{})
+	for axis, configToProps := range archVariantProps {
+		for config, p := range configToProps {
+			if archProps, ok := p.(*java.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)
+				}
+				libs.SetSelectValue(axis, config, (bazel.MakeLabelList(libLabels)))
+			}
+		}
+	}
+
+	attrs := bazelJavaAconfigLibraryAttributes{
+		Aconfig_declarations: *bazel.MakeLabelAttribute(android.BazelLabelForModuleDepSingle(ctx, callbacks.properties.Aconfig_declarations).Label),
+		Sdk_version:          &sdkVersion,
+		Libs:                 libs,
+	}
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "java_aconfig_library",
+		Bzl_load_location: "//build/bazel/rules/java:java_aconfig_library.bzl",
+	}
+
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: ctx.ModuleName()}, &attrs)
+}
diff --git a/aconfig/java_aconfig_library_test.go b/aconfig/java_aconfig_library_test.go
index af50848..a803672 100644
--- a/aconfig/java_aconfig_library_test.go
+++ b/aconfig/java_aconfig_library_test.go
@@ -178,14 +178,42 @@
 	android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode)
 }
 
+func testCodegenModeWithError(t *testing.T, bpMode string, err string) {
+	android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		java.PrepareForTestWithJavaDefaultModules).
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(err)).
+		RunTestWithBp(t, fmt.Sprintf(`
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+
+			java_aconfig_library {
+				name: "my_java_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+				%s
+			}
+		`, bpMode))
+}
+
 func TestDefaultProdMode(t *testing.T) {
 	testCodegenMode(t, "", "production")
 }
 
 func TestProdMode(t *testing.T) {
-	testCodegenMode(t, "test: false,", "production")
+	testCodegenMode(t, "mode: `production`,", "production")
 }
 
 func TestTestMode(t *testing.T) {
-	testCodegenMode(t, "test: true,", "test")
+	testCodegenMode(t, "mode: `test`,", "test")
+}
+
+func TestExportedMode(t *testing.T) {
+	testCodegenMode(t, "mode: `exported`,", "exported")
+}
+
+func TestUnsupportedMode(t *testing.T) {
+	testCodegenModeWithError(t, "mode: `unsupported`,", "mode: \"unsupported\" is not a supported mode")
 }
diff --git a/aconfig/rust_aconfig_library.go b/aconfig/rust_aconfig_library.go
index de41776..265685e 100644
--- a/aconfig/rust_aconfig_library.go
+++ b/aconfig/rust_aconfig_library.go
@@ -1,9 +1,10 @@
 package aconfig
 
 import (
+	"fmt"
+
 	"android/soong/android"
 	"android/soong/rust"
-	"fmt"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -18,7 +19,12 @@
 type RustAconfigLibraryProperties struct {
 	// name of the aconfig_declarations module to generate a library for
 	Aconfig_declarations string
-	Test                 *bool
+
+	// 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
+	// an error will be thrown if the mode is not supported
+	Mode *string
 }
 
 type aconfigDecorator struct {
@@ -60,9 +66,9 @@
 	}
 	declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData)
 
-	mode := "production"
-	if proptools.Bool(a.Properties.Test) {
-		mode = "test"
+	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{
@@ -84,6 +90,7 @@
 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/rust_aconfig_library_test.go b/aconfig/rust_aconfig_library_test.go
index 90b09c8..3aeab76 100644
--- a/aconfig/rust_aconfig_library_test.go
+++ b/aconfig/rust_aconfig_library_test.go
@@ -1,10 +1,11 @@
 package aconfig
 
 import (
-	"android/soong/android"
-	"android/soong/rust"
 	"fmt"
 	"testing"
+
+	"android/soong/android"
+	"android/soong/rust"
 )
 
 func TestRustAconfigLibrary(t *testing.T) {
@@ -22,6 +23,11 @@
 				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",
@@ -50,11 +56,104 @@
 	}
 
 	for _, variant := range variants {
-		android.AssertStringListContains(
+		android.AssertStringEquals(
 			t,
 			"dylib variant builds from generated rust code",
-			variant.Rule("rustc").Implicits.RelativeToTop().Strings(),
 			"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"},
+}
+
+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/android/Android.bp b/android/Android.bp
index f5bb785..62f534c 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -32,10 +32,12 @@
     srcs: [
         "androidmk.go",
         "apex.go",
+        "apex_contributions.go",
         "api_domain.go",
         "api_levels.go",
         "arch.go",
         "arch_list.go",
+        "base_module_context.go",
         "bazel.go",
         "bazel_handler.go",
         "bazel_paths.go",
@@ -50,6 +52,7 @@
         "defs.go",
         "depset_generic.go",
         "deptag.go",
+        "early_module_context.go",
         "expand.go",
         "filegroup.go",
         "fixture.go",
@@ -64,6 +67,7 @@
         "makevars.go",
         "metrics.go",
         "module.go",
+        "module_context.go",
         "mutator.go",
         "namespace.go",
         "neverallow.go",
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 5c8e5e3..07e1f12 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -75,14 +75,17 @@
 		"build/soong/cc/libbuildversion":     Bp2BuildDefaultTrue, // Skip tests subdir
 		"build/soong/cc/ndkstubgen":          Bp2BuildDefaultTrue,
 		"build/soong/cc/symbolfile":          Bp2BuildDefaultTrue,
+		"build/soong/jar":                    Bp2BuildDefaultTrue,
 		"build/soong/licenses":               Bp2BuildDefaultTrue,
 		"build/soong/linkerconfig":           Bp2BuildDefaultTrueRecursively,
+		"build/soong/response":               Bp2BuildDefaultTrue,
 		"build/soong/scripts":                Bp2BuildDefaultTrueRecursively,
+		"build/soong/third_party/zip":        Bp2BuildDefaultTrue,
 
 		"cts/common/device-side/nativetesthelper/jni": Bp2BuildDefaultTrueRecursively,
-		"cts/libs/json":                          Bp2BuildDefaultTrueRecursively,
-		"cts/tests/tests/gesture":                Bp2BuildDefaultTrueRecursively,
-		"platform_testing/libraries/annotations": Bp2BuildDefaultTrueRecursively,
+		"cts/flags/cc_tests":                          Bp2BuildDefaultTrueRecursively,
+		"cts/libs/json":                               Bp2BuildDefaultTrueRecursively,
+		"cts/tests/tests/gesture":                     Bp2BuildDefaultTrueRecursively,
 
 		"dalvik/tools/dexdeps": Bp2BuildDefaultTrueRecursively,
 
@@ -124,144 +127,160 @@
 		"development/samples/WiFiDirectDemo":          Bp2BuildDefaultTrue,
 		"development/sdk":                             Bp2BuildDefaultTrueRecursively,
 
-		"external/aac":                           Bp2BuildDefaultTrueRecursively,
-		"external/abseil-cpp":                    Bp2BuildDefaultTrueRecursively,
-		"external/arm-optimized-routines":        Bp2BuildDefaultTrueRecursively,
-		"external/auto":                          Bp2BuildDefaultTrue,
-		"external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively,
-		"external/auto/common":                   Bp2BuildDefaultTrueRecursively,
-		"external/auto/service":                  Bp2BuildDefaultTrueRecursively,
-		"external/auto/value":                    Bp2BuildDefaultTrueRecursively,
-		"external/boringssl":                     Bp2BuildDefaultTrueRecursively,
-		"external/bouncycastle":                  Bp2BuildDefaultTrue,
-		"external/brotli":                        Bp2BuildDefaultTrue,
-		"external/bsdiff":                        Bp2BuildDefaultTrueRecursively,
-		"external/bzip2":                         Bp2BuildDefaultTrueRecursively,
-		"external/clang/lib":                     Bp2BuildDefaultTrue,
-		"external/conscrypt":                     Bp2BuildDefaultTrue,
-		"external/e2fsprogs":                     Bp2BuildDefaultTrueRecursively,
-		"external/eigen":                         Bp2BuildDefaultTrueRecursively,
-		"external/erofs-utils":                   Bp2BuildDefaultTrueRecursively,
-		"external/error_prone":                   Bp2BuildDefaultTrueRecursively,
-		"external/escapevelocity":                Bp2BuildDefaultTrueRecursively,
-		"external/expat":                         Bp2BuildDefaultTrueRecursively,
-		"external/f2fs-tools":                    Bp2BuildDefaultTrue,
-		"external/flac":                          Bp2BuildDefaultTrueRecursively,
-		"external/flatbuffers":                   Bp2BuildDefaultTrueRecursively,
-		"external/fmtlib":                        Bp2BuildDefaultTrueRecursively,
-		"external/fsverity-utils":                Bp2BuildDefaultTrueRecursively,
-		"external/gflags":                        Bp2BuildDefaultTrueRecursively,
-		"external/google-benchmark":              Bp2BuildDefaultTrueRecursively,
-		"external/googletest":                    Bp2BuildDefaultTrueRecursively,
-		"external/guava":                         Bp2BuildDefaultTrueRecursively,
-		"external/gwp_asan":                      Bp2BuildDefaultTrueRecursively,
-		"external/hamcrest":                      Bp2BuildDefaultTrueRecursively,
-		"external/icu":                           Bp2BuildDefaultTrueRecursively,
-		"external/icu/android_icu4j":             Bp2BuildDefaultFalse, // java rules incomplete
-		"external/icu/icu4j":                     Bp2BuildDefaultFalse, // java rules incomplete
-		"external/jacoco":                        Bp2BuildDefaultTrueRecursively,
-		"external/jarjar":                        Bp2BuildDefaultTrueRecursively,
-		"external/javaparser":                    Bp2BuildDefaultTrueRecursively,
-		"external/javapoet":                      Bp2BuildDefaultTrueRecursively,
-		"external/javassist":                     Bp2BuildDefaultTrueRecursively,
-		"external/jemalloc_new":                  Bp2BuildDefaultTrueRecursively,
-		"external/jsoncpp":                       Bp2BuildDefaultTrueRecursively,
-		"external/jsr305":                        Bp2BuildDefaultTrueRecursively,
-		"external/jsr330":                        Bp2BuildDefaultTrueRecursively,
-		"external/junit":                         Bp2BuildDefaultTrueRecursively,
-		"external/kotlinc":                       Bp2BuildDefaultTrueRecursively,
-		"external/libaom":                        Bp2BuildDefaultTrueRecursively,
-		"external/libavc":                        Bp2BuildDefaultTrueRecursively,
-		"external/libcap":                        Bp2BuildDefaultTrueRecursively,
-		"external/libcxx":                        Bp2BuildDefaultTrueRecursively,
-		"external/libcxxabi":                     Bp2BuildDefaultTrueRecursively,
-		"external/libdivsufsort":                 Bp2BuildDefaultTrueRecursively,
-		"external/libdrm":                        Bp2BuildDefaultTrue,
-		"external/libevent":                      Bp2BuildDefaultTrueRecursively,
-		"external/libgav1":                       Bp2BuildDefaultTrueRecursively,
-		"external/libhevc":                       Bp2BuildDefaultTrueRecursively,
-		"external/libjpeg-turbo":                 Bp2BuildDefaultTrueRecursively,
-		"external/libmpeg2":                      Bp2BuildDefaultTrueRecursively,
-		"external/libpng":                        Bp2BuildDefaultTrueRecursively,
-		"external/libphonenumber":                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/perfmark/api":                  Bp2BuildDefaultTrueRecursively,
-		"external/protobuf":                      Bp2BuildDefaultTrueRecursively,
-		"external/python/pyyaml/lib/yaml":        Bp2BuildDefaultTrueRecursively,
-		"external/python/six":                    Bp2BuildDefaultTrueRecursively,
-		"external/python/jinja/src":              Bp2BuildDefaultTrueRecursively,
-		"external/python/markupsafe/src":         Bp2BuildDefaultTrueRecursively,
-		"external/python/setuptools":             Bp2BuildDefaultTrueRecursively,
-		"external/rappor":                        Bp2BuildDefaultTrueRecursively,
-		"external/scudo":                         Bp2BuildDefaultTrueRecursively,
-		"external/selinux/checkpolicy":           Bp2BuildDefaultTrueRecursively,
-		"external/selinux/libselinux":            Bp2BuildDefaultTrueRecursively,
-		"external/selinux/libsepol":              Bp2BuildDefaultTrueRecursively,
-		"external/speex":                         Bp2BuildDefaultTrueRecursively,
-		"external/sqlite":                        Bp2BuildDefaultTrueRecursively,
-		"external/tinyalsa":                      Bp2BuildDefaultTrueRecursively,
-		"external/tinyalsa_new":                  Bp2BuildDefaultTrueRecursively,
-		"external/toybox":                        Bp2BuildDefaultTrueRecursively,
-		"external/zlib":                          Bp2BuildDefaultTrueRecursively,
-		"external/zopfli":                        Bp2BuildDefaultTrueRecursively,
-		"external/zstd":                          Bp2BuildDefaultTrueRecursively,
+		"external/aac":                             Bp2BuildDefaultTrueRecursively,
+		"external/abseil-cpp":                      Bp2BuildDefaultTrueRecursively,
+		"external/arm-optimized-routines":          Bp2BuildDefaultTrueRecursively,
+		"external/auto":                            Bp2BuildDefaultTrue,
+		"external/auto/android-annotation-stubs":   Bp2BuildDefaultTrueRecursively,
+		"external/auto/common":                     Bp2BuildDefaultTrueRecursively,
+		"external/auto/service":                    Bp2BuildDefaultTrueRecursively,
+		"external/auto/value":                      Bp2BuildDefaultTrueRecursively,
+		"external/boringssl":                       Bp2BuildDefaultTrueRecursively,
+		"external/bouncycastle":                    Bp2BuildDefaultTrue,
+		"external/brotli":                          Bp2BuildDefaultTrue,
+		"external/bsdiff":                          Bp2BuildDefaultTrueRecursively,
+		"external/bzip2":                           Bp2BuildDefaultTrueRecursively,
+		"external/clang/lib":                       Bp2BuildDefaultTrue,
+		"external/conscrypt":                       Bp2BuildDefaultTrue,
+		"external/dexmaker":                        Bp2BuildDefaultTrueRecursively,
+		"external/e2fsprogs":                       Bp2BuildDefaultTrueRecursively,
+		"external/eigen":                           Bp2BuildDefaultTrueRecursively,
+		"external/erofs-utils":                     Bp2BuildDefaultTrueRecursively,
+		"external/error_prone":                     Bp2BuildDefaultTrueRecursively,
+		"external/escapevelocity":                  Bp2BuildDefaultTrueRecursively,
+		"external/expat":                           Bp2BuildDefaultTrueRecursively,
+		"external/f2fs-tools":                      Bp2BuildDefaultTrue,
+		"external/flac":                            Bp2BuildDefaultTrueRecursively,
+		"external/flatbuffers":                     Bp2BuildDefaultTrueRecursively,
+		"external/fmtlib":                          Bp2BuildDefaultTrueRecursively,
+		"external/fsverity-utils":                  Bp2BuildDefaultTrueRecursively,
+		"external/gflags":                          Bp2BuildDefaultTrueRecursively,
+		"external/google-benchmark":                Bp2BuildDefaultTrueRecursively,
+		"external/googletest":                      Bp2BuildDefaultTrueRecursively,
+		"external/guava":                           Bp2BuildDefaultTrueRecursively,
+		"external/gwp_asan":                        Bp2BuildDefaultTrueRecursively,
+		"external/hamcrest":                        Bp2BuildDefaultTrueRecursively,
+		"external/icu":                             Bp2BuildDefaultTrueRecursively,
+		"external/icu/android_icu4j":               Bp2BuildDefaultFalse, // java rules incomplete
+		"external/icu/icu4j":                       Bp2BuildDefaultFalse, // java rules incomplete
+		"external/jacoco":                          Bp2BuildDefaultTrueRecursively,
+		"external/jarjar":                          Bp2BuildDefaultTrueRecursively,
+		"external/javaparser":                      Bp2BuildDefaultTrueRecursively,
+		"external/javapoet":                        Bp2BuildDefaultTrueRecursively,
+		"external/javassist":                       Bp2BuildDefaultTrueRecursively,
+		"external/jemalloc_new":                    Bp2BuildDefaultTrueRecursively,
+		"external/jsoncpp":                         Bp2BuildDefaultTrueRecursively,
+		"external/jsr305":                          Bp2BuildDefaultTrueRecursively,
+		"external/jsr330":                          Bp2BuildDefaultTrueRecursively,
+		"external/junit":                           Bp2BuildDefaultTrueRecursively,
+		"external/kotlinc":                         Bp2BuildDefaultTrueRecursively,
+		"external/kotlinx.coroutines":              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/libdav1d":                        Bp2BuildDefaultTrueRecursively,
+		"external/libhevc":                         Bp2BuildDefaultTrueRecursively,
+		"external/libjpeg-turbo":                   Bp2BuildDefaultTrueRecursively,
+		"external/libmpeg2":                        Bp2BuildDefaultTrueRecursively,
+		"external/libphonenumber":                  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/mockito":                         Bp2BuildDefaultTrueRecursively,
+		"external/musl":                            Bp2BuildDefaultTrueRecursively,
+		"external/objenesis":                       Bp2BuildDefaultTrueRecursively,
+		"external/openscreen":                      Bp2BuildDefaultTrueRecursively,
+		"external/ow2-asm":                         Bp2BuildDefaultTrueRecursively,
+		"external/pcre":                            Bp2BuildDefaultTrueRecursively,
+		"external/perfmark/api":                    Bp2BuildDefaultTrueRecursively,
+		"external/perfetto":                        Bp2BuildDefaultTrue,
+		"external/protobuf":                        Bp2BuildDefaultTrueRecursively,
+		"external/python/jinja/src":                Bp2BuildDefaultTrueRecursively,
+		"external/python/markupsafe/src":           Bp2BuildDefaultTrueRecursively,
+		"external/python/pyfakefs/pyfakefs":        Bp2BuildDefaultTrueRecursively,
+		"external/python/pyyaml/lib/yaml":          Bp2BuildDefaultTrueRecursively,
+		"external/python/setuptools":               Bp2BuildDefaultTrueRecursively,
+		"external/python/six":                      Bp2BuildDefaultTrueRecursively,
+		"external/rappor":                          Bp2BuildDefaultTrueRecursively,
+		"external/rust/crates/rustc-demangle":      Bp2BuildDefaultTrueRecursively,
+		"external/rust/crates/rustc-demangle-capi": Bp2BuildDefaultTrueRecursively,
+		"external/scudo":                           Bp2BuildDefaultTrueRecursively,
+		"external/selinux/checkpolicy":             Bp2BuildDefaultTrueRecursively,
+		"external/selinux/libselinux":              Bp2BuildDefaultTrueRecursively,
+		"external/selinux/libsepol":                Bp2BuildDefaultTrueRecursively,
+		"external/speex":                           Bp2BuildDefaultTrueRecursively,
+		"external/sqlite":                          Bp2BuildDefaultTrueRecursively,
+		"external/tinyalsa":                        Bp2BuildDefaultTrueRecursively,
+		"external/tinyalsa_new":                    Bp2BuildDefaultTrueRecursively,
+		"external/toybox":                          Bp2BuildDefaultTrueRecursively,
+		"external/truth":                           Bp2BuildDefaultTrueRecursively,
+		"external/xz-java":                         Bp2BuildDefaultTrueRecursively,
+		"external/zlib":                            Bp2BuildDefaultTrueRecursively,
+		"external/zopfli":                          Bp2BuildDefaultTrueRecursively,
+		"external/zstd":                            Bp2BuildDefaultTrueRecursively,
 
 		"frameworks/av": Bp2BuildDefaultTrue,
-		"frameworks/av/media/audioaidlconversion":            Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/codec2/components/aom":          Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/codecs":                         Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/liberror":                       Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/libmediahelper":                 Bp2BuildDefaultTrue,
-		"frameworks/av/media/libshmem":                       Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/module/codecs":                  Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/module/foundation":              Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/media/module/minijail":                Bp2BuildDefaultTrueRecursively,
-		"frameworks/av/services/minijail":                    Bp2BuildDefaultTrueRecursively,
-		"frameworks/base/apex/jobscheduler/service/jni":      Bp2BuildDefaultTrueRecursively,
-		"frameworks/base/core/java":                          Bp2BuildDefaultTrue,
-		"frameworks/base/libs/androidfw":                     Bp2BuildDefaultTrue,
-		"frameworks/base/libs/services":                      Bp2BuildDefaultTrue,
-		"frameworks/base/media/tests/MediaDump":              Bp2BuildDefaultTrue,
-		"frameworks/base/proto":                              Bp2BuildDefaultTrue,
-		"frameworks/base/services/tests/servicestests/aidl":  Bp2BuildDefaultTrue,
-		"frameworks/base/startop/apps/test":                  Bp2BuildDefaultTrue,
-		"frameworks/base/tests/appwidgets/AppWidgetHostTest": Bp2BuildDefaultTrueRecursively,
-		"frameworks/base/tools/aapt":                         Bp2BuildDefaultTrue,
-		"frameworks/base/tools/aapt2":                        Bp2BuildDefaultTrue,
-		"frameworks/base/tools/codegen":                      Bp2BuildDefaultTrueRecursively,
-		"frameworks/base/tools/locked_region_code_injection": Bp2BuildDefaultTrueRecursively,
-		"frameworks/base/tools/streaming_proto":              Bp2BuildDefaultTrueRecursively,
-		"frameworks/hardware/interfaces/stats/aidl":          Bp2BuildDefaultTrue,
-		"frameworks/libs/modules-utils/build":                Bp2BuildDefaultTrueRecursively,
-		"frameworks/libs/modules-utils/java":                 Bp2BuildDefaultTrue,
-		"frameworks/native":                                  Bp2BuildDefaultTrue,
-		"frameworks/native/libs/adbd_auth":                   Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/libs/arect":                       Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/libs/binder":                      Bp2BuildDefaultTrue,
-		"frameworks/native/libs/gui":                         Bp2BuildDefaultTrue,
-		"frameworks/native/libs/math":                        Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/libs/nativebase":                  Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/libs/permission":                  Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/libs/ui":                          Bp2BuildDefaultTrue,
-		"frameworks/native/libs/vr":                          Bp2BuildDefaultTrueRecursively,
-		"frameworks/native/opengl/tests/gl2_cameraeye":       Bp2BuildDefaultTrue,
-		"frameworks/native/opengl/tests/gl2_java":            Bp2BuildDefaultTrue,
-		"frameworks/native/opengl/tests/testLatency":         Bp2BuildDefaultTrue,
-		"frameworks/native/opengl/tests/testPauseResume":     Bp2BuildDefaultTrue,
-		"frameworks/native/opengl/tests/testViewport":        Bp2BuildDefaultTrue,
-		"frameworks/native/services/batteryservice":          Bp2BuildDefaultTrue,
-		"frameworks/proto_logging/stats":                     Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/media/audioaidlconversion":                              Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/media/codec2/components/aom":                            Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/media/codecs":                                           Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/media/liberror":                                         Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/media/libmediahelper":                                   Bp2BuildDefaultTrue,
+		"frameworks/av/media/libshmem":                                         Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/media/module/codecs":                                    Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/media/module/foundation":                                Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/media/module/minijail":                                  Bp2BuildDefaultTrueRecursively,
+		"frameworks/av/services/minijail":                                      Bp2BuildDefaultTrueRecursively,
+		"frameworks/base/apex/jobscheduler/service/jni":                        Bp2BuildDefaultTrueRecursively,
+		"frameworks/base/core/java":                                            Bp2BuildDefaultTrue,
+		"frameworks/base/core/res":                                             Bp2BuildDefaultTrueRecursively,
+		"frameworks/base/errorprone":                                           Bp2BuildDefaultTrueRecursively,
+		"frameworks/base/libs/androidfw":                                       Bp2BuildDefaultTrue,
+		"frameworks/base/libs/services":                                        Bp2BuildDefaultTrue,
+		"frameworks/base/media/tests/MediaDump":                                Bp2BuildDefaultTrue,
+		"frameworks/base/mime":                                                 Bp2BuildDefaultTrueRecursively,
+		"frameworks/base/proto":                                                Bp2BuildDefaultTrue,
+		"frameworks/base/services/tests/servicestests/aidl":                    Bp2BuildDefaultTrue,
+		"frameworks/base/startop/apps/test":                                    Bp2BuildDefaultTrue,
+		"frameworks/base/tests/appwidgets/AppWidgetHostTest":                   Bp2BuildDefaultTrueRecursively,
+		"frameworks/base/tools/aapt":                                           Bp2BuildDefaultTrue,
+		"frameworks/base/tools/aapt2":                                          Bp2BuildDefaultTrue,
+		"frameworks/base/tools/codegen":                                        Bp2BuildDefaultTrueRecursively,
+		"frameworks/base/tools/locked_region_code_injection":                   Bp2BuildDefaultTrueRecursively,
+		"frameworks/base/tools/streaming_proto":                                Bp2BuildDefaultTrueRecursively,
+		"frameworks/hardware/interfaces":                                       Bp2BuildDefaultTrue,
+		"frameworks/hardware/interfaces/displayservice":                        Bp2BuildDefaultTrueRecursively,
+		"frameworks/hardware/interfaces/stats/aidl":                            Bp2BuildDefaultTrue,
+		"frameworks/libs/modules-utils/build":                                  Bp2BuildDefaultTrueRecursively,
+		"frameworks/libs/modules-utils/java":                                   Bp2BuildDefaultTrueRecursively,
+		"frameworks/libs/modules-utils/java/com/android/modules/utils/testing": Bp2BuildDefaultFalseRecursively,
+		"frameworks/native":                                                    Bp2BuildDefaultTrue,
+		"frameworks/native/libs/adbd_auth":                                     Bp2BuildDefaultTrueRecursively,
+		"frameworks/native/libs/arect":                                         Bp2BuildDefaultTrueRecursively,
+		"frameworks/native/libs/binder":                                        Bp2BuildDefaultTrue,
+		"frameworks/native/libs/gui":                                           Bp2BuildDefaultTrue,
+		"frameworks/native/libs/math":                                          Bp2BuildDefaultTrueRecursively,
+		"frameworks/native/libs/nativebase":                                    Bp2BuildDefaultTrueRecursively,
+		"frameworks/native/libs/permission":                                    Bp2BuildDefaultTrueRecursively,
+		"frameworks/native/libs/ui":                                            Bp2BuildDefaultTrue,
+		"frameworks/native/libs/vr":                                            Bp2BuildDefaultTrueRecursively,
+		"frameworks/native/opengl/tests/gl2_cameraeye":                         Bp2BuildDefaultTrue,
+		"frameworks/native/opengl/tests/gl2_java":                              Bp2BuildDefaultTrue,
+		"frameworks/native/opengl/tests/testLatency":                           Bp2BuildDefaultTrue,
+		"frameworks/native/opengl/tests/testPauseResume":                       Bp2BuildDefaultTrue,
+		"frameworks/native/opengl/tests/testViewport":                          Bp2BuildDefaultTrue,
+		"frameworks/native/services/batteryservice":                            Bp2BuildDefaultTrue,
+		"frameworks/proto_logging/stats":                                       Bp2BuildDefaultTrueRecursively,
 
 		"hardware/interfaces":                                     Bp2BuildDefaultTrue,
 		"hardware/interfaces/audio/aidl":                          Bp2BuildDefaultTrue,
@@ -275,6 +294,7 @@
 		"hardware/interfaces/configstore/1.0":                     Bp2BuildDefaultTrue,
 		"hardware/interfaces/configstore/1.1":                     Bp2BuildDefaultTrue,
 		"hardware/interfaces/configstore/utils":                   Bp2BuildDefaultTrue,
+		"hardware/interfaces/contexthub/aidl":                     Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/2.0":              Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/3.0":              Bp2BuildDefaultTrue,
 		"hardware/interfaces/graphics/allocator/4.0":              Bp2BuildDefaultTrue,
@@ -307,51 +327,65 @@
 		"hardware/interfaces/neuralnetworks/1.2/vts":              Bp2BuildDefaultFalseRecursively,
 		"hardware/interfaces/neuralnetworks/1.3/vts":              Bp2BuildDefaultFalseRecursively,
 		"hardware/interfaces/neuralnetworks/1.4/vts":              Bp2BuildDefaultFalseRecursively,
+		"hardware/interfaces/tests":                               Bp2BuildDefaultTrueRecursively,
+		"hardware/interfaces/tests/extension":                     Bp2BuildDefaultFalseRecursively, // missing deps
+		"hardware/interfaces/tests/msgq":                          Bp2BuildDefaultFalseRecursively, // missing deps
 
 		"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/fastdeploy":                    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/Connectivity/staticlibs/native":    Bp2BuildDefaultTrueRecursively,
-		"packages/modules/Gki/libkver":                       Bp2BuildDefaultTrue,
-		"packages/modules/NetworkStack/common/captiveportal": Bp2BuildDefaultTrue,
-		"packages/modules/NeuralNetworks/apex":               Bp2BuildDefaultTrue,
-		"packages/modules/NeuralNetworks/apex/testing":       Bp2BuildDefaultTrue,
-		"packages/providers/MediaProvider/tools/dialogs":     Bp2BuildDefaultFalse, // TODO(b/242834374)
-		"packages/screensavers/Basic":                        Bp2BuildDefaultTrue,
-		"packages/services/Car/tests/SampleRearViewCamera":   Bp2BuildDefaultFalse, // TODO(b/242834321)
+		"packages/apps/DevCamera":                                    Bp2BuildDefaultTrue,
+		"packages/apps/HTMLViewer":                                   Bp2BuildDefaultTrue,
+		"packages/apps/Protips":                                      Bp2BuildDefaultTrue,
+		"packages/apps/SafetyRegulatoryInfo":                         Bp2BuildDefaultTrue,
+		"packages/apps/WallpaperPicker":                              Bp2BuildDefaultTrue,
+		"packages/modules/Connectivity/bpf_progs":                    Bp2BuildDefaultTrueRecursively,
+		"packages/modules/Connectivity/service-t":                    Bp2BuildDefaultTrueRecursively,
+		"packages/modules/Connectivity/service/native":               Bp2BuildDefaultTrueRecursively,
+		"packages/modules/Connectivity/staticlibs/native":            Bp2BuildDefaultTrueRecursively,
+		"packages/modules/Connectivity/staticlibs/netd":              Bp2BuildDefaultTrueRecursively,
+		"packages/modules/Connectivity/staticlibs/netd/libnetdutils": Bp2BuildDefaultTrueRecursively,
+		"packages/modules/Connectivity/tests/unit/jni":               Bp2BuildDefaultTrueRecursively,
+		"packages/modules/Gki/libkver":                               Bp2BuildDefaultTrue,
+		"packages/modules/NetworkStack/common/captiveportal":         Bp2BuildDefaultTrue,
+		"packages/modules/NeuralNetworks/apex":                       Bp2BuildDefaultTrue,
+		"packages/modules/NeuralNetworks/apex/testing":               Bp2BuildDefaultTrue,
+		"packages/modules/NeuralNetworks/driver/cache":               Bp2BuildDefaultTrueRecursively,
+		"packages/modules/SdkExtensions/gen_sdk":                     Bp2BuildDefaultTrue,
+		"packages/modules/StatsD/lib/libstatssocket":                 Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb":                                       Bp2BuildDefaultTrue,
+		"packages/modules/adb/apex":                                  Bp2BuildDefaultTrue,
+		"packages/modules/adb/crypto":                                Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/fastdeploy":                            Bp2BuildDefaultTrue,
+		"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/common/proto":                              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,
+		"platform_testing/libraries/annotations":              Bp2BuildDefaultTrueRecursively,
+		"platform_testing/libraries/flag-helpers/libflagtest": Bp2BuildDefaultTrueRecursively,
+		"platform_testing/tests/example":                      Bp2BuildDefaultTrueRecursively,
 
 		"prebuilts/clang/host/linux-x86":                   Bp2BuildDefaultTrueRecursively,
 		"prebuilts/gradle-plugin":                          Bp2BuildDefaultTrueRecursively,
-		"prebuilts/runtime/mainline/platform/sdk":          Bp2BuildDefaultTrueRecursively,
 		"prebuilts/module_sdk":                             Bp2BuildDefaultTrueRecursively,
+		"prebuilts/runtime/mainline/platform/sdk":          Bp2BuildDefaultTrueRecursively,
 		"prebuilts/sdk":                                    Bp2BuildDefaultTrue,
 		"prebuilts/sdk/current/androidx":                   Bp2BuildDefaultTrue,
 		"prebuilts/sdk/current/androidx-legacy":            Bp2BuildDefaultTrue,
+		"prebuilts/sdk/current/extras/app-toolkit":         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,
 		"prebuilts/r8":                                     Bp2BuildDefaultTrueRecursively,
 
+		"sdk/annotations":   Bp2BuildDefaultTrueRecursively,
 		"sdk/dumpeventlog":  Bp2BuildDefaultTrue,
 		"sdk/eventanalyzer": Bp2BuildDefaultTrue,
 
@@ -363,6 +397,7 @@
 		"system/apex/tools":                                      Bp2BuildDefaultTrueRecursively,
 		"system/core/debuggerd":                                  Bp2BuildDefaultTrueRecursively,
 		"system/core/diagnose_usb":                               Bp2BuildDefaultTrueRecursively,
+		"system/core/fs_mgr":                                     Bp2BuildDefaultTrueRecursively,
 		"system/core/healthd":                                    Bp2BuildDefaultTrue,
 		"system/core/healthd/testdata":                           Bp2BuildDefaultTrue,
 		"system/core/libasyncio":                                 Bp2BuildDefaultTrue,
@@ -373,6 +408,7 @@
 		"system/core/libprocessgroup/cgrouprc":                   Bp2BuildDefaultTrue,
 		"system/core/libprocessgroup/cgrouprc_format":            Bp2BuildDefaultTrue,
 		"system/core/libsparse":                                  Bp2BuildDefaultTrueRecursively,
+		"system/core/libstats/expresslog":                        Bp2BuildDefaultTrueRecursively,
 		"system/core/libsuspend":                                 Bp2BuildDefaultTrue,
 		"system/core/libsystem":                                  Bp2BuildDefaultTrueRecursively,
 		"system/core/libsysutils":                                Bp2BuildDefaultTrueRecursively,
@@ -398,8 +434,7 @@
 		"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/memory":                        Bp2BuildDefaultTrueRecursively,
 		"system/libhidl/transport/safe_union/1.0":                Bp2BuildDefaultTrue,
 		"system/libhidl/transport/token/1.0":                     Bp2BuildDefaultTrue,
 		"system/libhidl/transport/token/1.0/utils":               Bp2BuildDefaultTrue,
@@ -407,16 +442,18 @@
 		"system/libprocinfo":                                     Bp2BuildDefaultTrue,
 		"system/libvintf":                                        Bp2BuildDefaultTrue,
 		"system/libziparchive":                                   Bp2BuildDefaultTrueRecursively,
+		"system/linkerconfig":                                    Bp2BuildDefaultTrueRecursively,
 		"system/logging":                                         Bp2BuildDefaultTrueRecursively,
 		"system/media":                                           Bp2BuildDefaultTrue,
-		"system/media/audio":                                     Bp2BuildDefaultTrueRecursively,
 		"system/media/alsa_utils":                                Bp2BuildDefaultTrueRecursively,
+		"system/media/audio":                                     Bp2BuildDefaultTrueRecursively,
 		"system/media/audio_utils":                               Bp2BuildDefaultTrueRecursively,
 		"system/media/camera":                                    Bp2BuildDefaultTrueRecursively,
 		"system/memory/libion":                                   Bp2BuildDefaultTrueRecursively,
 		"system/memory/libmemunreachable":                        Bp2BuildDefaultTrueRecursively,
-		"system/sepolicy/apex":                                   Bp2BuildDefaultTrueRecursively,
+		"system/netd":                                            Bp2BuildDefaultTrue,
 		"system/security/fsverity":                               Bp2BuildDefaultTrueRecursively,
+		"system/sepolicy/apex":                                   Bp2BuildDefaultTrueRecursively,
 		"system/testing/gtest_extras":                            Bp2BuildDefaultTrueRecursively,
 		"system/timezone/apex":                                   Bp2BuildDefaultTrueRecursively,
 		"system/timezone/output_data":                            Bp2BuildDefaultTrueRecursively,
@@ -424,13 +461,15 @@
 		"system/timezone/testing":                                Bp2BuildDefaultTrueRecursively,
 		"system/tools/aidl/build/tests_bp2build":                 Bp2BuildDefaultTrue,
 		"system/tools/aidl/metadata":                             Bp2BuildDefaultTrue,
-		"system/tools/hidl/metadata":                             Bp2BuildDefaultTrue,
-		"system/tools/hidl/utils":                                Bp2BuildDefaultTrue,
+		"system/tools/hidl":                                      Bp2BuildDefaultTrueRecursively,
 		"system/tools/mkbootimg":                                 Bp2BuildDefaultTrueRecursively,
 		"system/tools/sysprop":                                   Bp2BuildDefaultTrue,
 		"system/tools/xsdc/utils":                                Bp2BuildDefaultTrueRecursively,
 		"system/unwinding/libunwindstack":                        Bp2BuildDefaultTrueRecursively,
 
+		"test/vts/vts_hal_hidl_target": Bp2BuildDefaultTrueRecursively,
+
+		"toolchain/pgo-profiles":                      Bp2BuildDefaultTrueRecursively,
 		"tools/apifinder":                             Bp2BuildDefaultTrue,
 		"tools/apksig":                                Bp2BuildDefaultTrue,
 		"tools/dexter/slicer":                         Bp2BuildDefaultTrueRecursively,
@@ -438,6 +477,7 @@
 		"tools/metalava":                              Bp2BuildDefaultTrueRecursively,
 		"tools/platform-compat/java/android/compat":   Bp2BuildDefaultTrueRecursively,
 		"tools/platform-compat/java/androidprocessor": Bp2BuildDefaultTrueRecursively,
+		"tools/tradefederation/core/util_apps":        Bp2BuildDefaultTrueRecursively,
 		"tools/tradefederation/prebuilts/filegroups":  Bp2BuildDefaultTrueRecursively,
 	}
 
@@ -463,6 +503,7 @@
 		"external/bazelbuild-rules_go":/* recursive = */ true,
 		"external/bazelbuild-rules_python":/* recursive = */ true,
 		"external/bazelbuild-rules_rust":/* recursive = */ true,
+		"external/bazelbuild-rules_testing":/* recursive = */ true,
 		"external/bazelbuild-kotlin-rules":/* recursive = */ true,
 		"external/bazel-skylib":/* recursive = */ true,
 		"external/protobuf":/* recursive = */ false,
@@ -484,6 +525,7 @@
 		"prebuilts/clang-tools":/* recursive = */ true,
 		"prebuilts/gcc":/* recursive = */ true,
 		"prebuilts/build-tools":/* recursive = */ true,
+		"prebuilts/jdk/jdk8":/* 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,
@@ -496,14 +538,13 @@
 		"tools/asuite/atest":/* recursive = */ false,
 		"tools/asuite/atest/bazel/reporter":/* recursive = */ true,
 
-		// TODO(b/266459895): remove this and the placeholder BUILD file after re-enabling libunwindstack
-		"external/rust/crates/rustc-demangle-capi":/* recursive = */ false,
-
 		// Used for testing purposes only. Should not actually exist in the real source tree.
 		"testpkg/keep_build_file":/* recursive = */ false,
 	}
 
 	Bp2buildModuleAlwaysConvertList = []string{
+		"aconfig.test.cpp",
+		"AconfigJavaHostTest",
 		// aconfig
 		"libonce_cell",
 		"libanyhow",
@@ -556,13 +597,9 @@
 		// ext
 		"tagsoup",
 
-		// framework-res
-		"remote-color-resources-compile-public",
-		"remote-color-resources-compile-colors",
-
 		// framework-minus-apex
+		"AndroidFrameworkLintChecker",
 		"ImmutabilityAnnotationProcessor",
-		"android.mime.types.minimized",
 		"debian.mime.types.minimized",
 		"framework-javastream-protos",
 		"libview-inspector-annotation-processor",
@@ -571,7 +608,6 @@
 		"apache-commons-math",
 		"cbor-java",
 		"icu4j_calendar_astronomer",
-		"remote-color-resources-compile-public",
 		"statslog-art-java-gen",
 
 		"AndroidCommonLint",
@@ -600,6 +636,7 @@
 		"codec2_soft_exports",
 		"compatibility_matrix_schema",
 		"framework-connectivity-protos",
+		"framework-connectivity-javastream-protos",
 		"gemmlowp_headers",
 		"gl_headers",
 		"libandroid_runtime_lazy",
@@ -619,7 +656,6 @@
 		"libneuralnetworks",
 		"libneuralnetworks_static",
 		"libgraphicsenv",
-		"libhardware",
 		"libhardware_headers",
 		"libnativeloader-headers",
 		"libnativewindow_headers",
@@ -658,12 +694,11 @@
 
 		// prebuilts
 		"prebuilt_stats-log-api-gen",
+		"prebuilt_aapt2",
 
 		// fastboot
 		"fastboot",
 		"libfastboot",
-		"liblp",
-		"libstorage_literals_headers",
 
 		"PluginCoreLib",
 		"dagger2",
@@ -719,14 +754,6 @@
 		//system/chre
 		"chre_api",
 
-		//system/core/fs_mgr/libdm
-		"libdm",
-
-		//system/core/fs_mgr/libfiemap
-		"libfiemap_headers",
-		"libfiemap_passthrough_srcs",
-		"libfiemap_srcs",
-
 		//system/gsid
 		"libgsi",
 		"libgsi_headers",
@@ -743,18 +770,10 @@
 		//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_aidl",
 		"libcodec2_hidl@1.0",
 		"libcodec2_hidl@1.1",
 		"libcodec2_hidl@1.2",
@@ -795,6 +814,7 @@
 		"libcodec2_soft_vp8dec",
 		"libcodec2_soft_vp9dec",
 		"libcodec2_soft_av1dec_gav1",
+		"libcodec2_soft_av1dec_dav1d",
 		"libcodec2_soft_vp8enc",
 		"libcodec2_soft_vp9enc",
 		"libcodec2_soft_rawdec",
@@ -831,14 +851,6 @@
 		// for api_fingerprint.txt generation
 		"api_fingerprint",
 
-		// allowlisting for kotlinx_coroutines
-		"annotations",
-		"kotlinx-coroutines-android-annotation-stubs",
-		"kotlinx-coroutines-core",
-		"kotlinx_coroutines",
-		"kotlinx_coroutines-device",
-		"kotlinx_coroutines-host",
-
 		// for building com.android.neuralnetworks
 		"libimapper_stablec",
 		"libimapper_providerutils",
@@ -869,7 +881,6 @@
 		"binderRpcWireProtocolTest",
 		"binderUnitTest",
 		"cpu_features-bit_utils_test",
-		"liblp_test",
 		"android.hardware.audio.common.test.utility_tests",
 		"HalAudioStreamWorkerTest",
 		"libjavacore-unit-tests",
@@ -894,7 +905,6 @@
 		"libRSDispatch",
 
 		// hal_unit_tests and deps
-		"android.hardware.contexthub_interface", // created implicitly by android.hardware.contexthub
 		"chre_flatbuffers",
 		"event_logger",
 		"hal_unit_tests",
@@ -922,11 +932,10 @@
 		"androidx.test.annotation-nodeps",
 
 		// jni deps of an internal android_test (b/297405812)
-		"libdexmakerjvmtiagent",
 		"libopenjdkjvmti_headers",
-		"libstaticjvmtiagent",
 
 		// tradefed deps
+		"apache-commons-compress",
 		"tradefed-protos",
 		"grpc-java",
 		"grpc-java-api",
@@ -947,6 +956,44 @@
 		"gson",
 		"GsonBuildConfig.java",
 		"gson_version_generator",
+		"lab-resource-grpc",
+		"blueprint-deptools",
+		"protoc-gen-grpc-java-plugin",
+		"tf-remote-client",
+		"tradefed-lite",
+		"tradefed-isolation-protos",
+		"snakeyaml_patched_src_files",
+		"asuite_proto_java",
+		"tradefed-service-grpc-lib",
+		"tradefed-invocation-grpc",
+		"tradefed-external-dependencies",
+		"tradefed-dynamic-sharding-grpc",
+		"tradefed-device-manager-grpc",
+		"statsd_internal_protos",
+		"snakeyaml",
+		"loganalysis",
+		"junit-params",
+		"grpc-java-testing",
+		"grpc-java-netty-shaded",
+		"aoa-helper",
+		"test-services.apk",
+		"test-composers",
+		"py3-stdlib-prebuilt-srcs",
+		"platformprotos",
+		"test-services-normalized.apk",
+		"tradefed-common-util",
+		"tradefed-clearcut-client",
+		"tradefed-result-interfaces",
+		"tradefed-device-build-interfaces",
+		"tradefed-invocation-interfaces",
+		"tradefed-lib-core",
+
+		"libandroid_net_connectivity_com_android_net_module_util_jni",
+		"libservice-connectivity",
+
+		"mainline_modules_sdks_test",
+
+		"fake_device_config",
 	}
 
 	Bp2buildModuleTypeAlwaysConvertList = []string{
@@ -963,15 +1010,17 @@
 		"cc_prebuilt_library_static",
 		"combined_apis",
 		"droiddoc_exported_dir",
+		"java_aconfig_library",
 		"java_import",
 		"java_import_host",
 		"java_sdk_library",
 		"java_sdk_library_import",
 		"license",
 		"linker_config",
-		"ndk_library",
 		"ndk_headers",
+		"ndk_library",
 		"sysprop_library",
+		"versioned_ndk_headers",
 		"xsd_config",
 		// go/keep-sorted end
 	}
@@ -984,6 +1033,7 @@
 	// the "prebuilt_" prefix to the name, so that it's differentiable from
 	// the source versions within Soong's module graph.
 	Bp2buildModuleDoNotConvertList = []string{
+
 		// rust modules that have cc deps
 		"liblogger",
 		"libbssl_ffi",
@@ -1002,14 +1052,6 @@
 		"minijail_compiler_unittest",
 		"minijail_parser_unittest",
 
-		// Depends on unconverted libandroid, libgui
-		"dvr_buffer_queue-test",
-		"dvr_display-test",
-		// Depends on unconverted libchrome
-		"pdx_benchmarks",
-		"buffer_hub_queue-test",
-		"buffer_hub_queue_producer-test",
-
 		// cc bugs
 
 		// TODO(b/198619163) module has same name as source
@@ -1027,7 +1069,7 @@
 		"versioner", // TODO(b/228313961):  depends on prebuilt shared library libclang-cpp_host as a shared library, which does not supply expected providers for a shared library
 
 		// requires host tools for apexer
-		"apexer_test", "apexer_test_host_tools", "host_apex_verifier",
+		"apexer_test", "apexer_test_host_tools", "host_apex_verifier", "host-apex-verifier",
 
 		// java bugs
 		"libbase_ndk",           // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
@@ -1050,7 +1092,8 @@
 		"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
 
-		// go deps:
+		// go deps.
+		// TODO: b/305091740 - Rely on bp2build_deps to remove these dependencies.
 		"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.
@@ -1059,87 +1102,14 @@
 		// rust support
 		"libtombstoned_client_rust_bridge_code", "libtombstoned_client_wrapper", // rust conversions are not supported
 
-		// unconverted deps
-		"CarHTMLViewer",                                              // depends on unconverted modules android.car-stubs, car-ui-lib
-		"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
-		"apexer_with_DCLA_preprocessing_test",                        // depends on unconverted modules: apexer_test_host_tools, com.android.example.apex
-		"art-script",                                                 // depends on unconverted modules: dalvikvm, dex2oat
-		"bin2c_fastdeployagent",                                      // depends on unconverted modules: deployagent
-		"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",                                             // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api, art_operator_srcs, libcpu_features, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfile, libnativebridge, libnativeloader, libsigchain, libartbase, libprofile, cpp-define-generator-asm-support
-		"libart-runtime-for-test",                                    // depends on unconverted modules: apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api, art_operator_srcs, libcpu_features, libodrstatslog, libelffile, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfile, libnativebridge, libnativeloader, libsigchain, libartbase, libprofile, cpp-define-generator-asm-support
-		"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",                                            // depends on unconverted modules: art_operator_srcs, libcpu_features, libodrstatslog, libelffiled, art_cmdlineparser_headers, cpp-define-generator-definitions, libdexfiled, libnativebridge, libnativeloader, libsigchain, libartbased, libprofiled, cpp-define-generator-asm-support, apex-info-list-tinyxml, libtinyxml2, libnativeloader-headers, heapprofd_client_api
-		"libartd-runtime-gtest",                                      // depends on unconverted modules: libgtest_isolated, libartd-compiler, libdexfiled, libprofiled, libartbased, libartbased-art-gtest
-		"libdebuggerd",                                               // depends on unconverted module: libdexfile
-		"libdebuggerd_handler",                                       // depends on unconverted module libdebuggerd_handler_core
-		"libdebuggerd_handler_core", "libdebuggerd_handler_fallback", // depends on unconverted module libdebuggerd
-		"libdexfiled",                                             // depends on unconverted modules: dexfile_operator_srcs, libartbased, libartpalette
-		"libgmock_main_ndk",                                       // depends on unconverted modules: libgtest_ndk_c++
-		"libgmock_ndk",                                            // depends on unconverted modules: libgtest_ndk_c++
-		"libnativehelper_lazy_mts_jni", "libnativehelper_mts_jni", // depends on unconverted modules: libnativetesthelper_jni, libgmock_ndk
-		"libnativetesthelper_jni",   // depends on unconverted modules: libgtest_ndk_c++
-		"libphonenumber_test",       // depends on android.test.mock
-		"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
+		// TODO: b/303474748 - aidl rules for java are incompatible with parcelable declarations
+		"modules-utils-list-slice",
+		"modules-utils-os",
+		"modules-utils-synchronous-result-receiver",
 
 		// aidl files not created
 		"overlayable_policy_aidl_interface",
 
-		//prebuilts/tools/common/m2
-		// depends on //external/okio:okio-lib, which uses kotlin
-		"wire-runtime",
-
-		// depends on adbd_system_api_recovery, which is a unconverted `phony` module type
-		"minadbd",
-
-		// depends on android.hardware.health-V2.0-java
-		"android.hardware.health-translate-java",
-
-		//system/libvintf
-		// depends on apex-info-list-tinyxml, unconverted xsd_config Soong module type.
-		"libassemblevintf",
-		"assemble_vintf",
-		"checkvintf",
-
-		// depends on audio_policy_configuration_aidl_default, xsd_config module.
-		"libaudioserviceexampleimpl",
-		"android.hardware.audio.service-aidl.example",
-
-		// depends on //system/tools/aidl/build:aidl_metadata_json, which is an aidl_interfaces_metadata custom Soong type.
-		"aidl_metadata_in_cpp",
-		"libaidlmetadata",
-		"libaidlmetadata_test",
-
-		// depends on //system/tools/hidl/build:hidl_metadata_json, which is an hidl_interfaces_metadata custom Soong type.
-		"hidl_metadata_in_cpp",
-		"libhidlmetadata",
-		"hidl_metadata_test",
-
 		// cc_test related.
 		// b/274164834 "Could not open Configuration file test.cfg"
 		"svcenc", "svcdec",
@@ -1172,40 +1142,18 @@
 
 		// cc_test with unconverted deps, or are device-only (and not verified to pass yet)
 		"AMRWBEncTest",
-		"AmrnbDecoderTest", // depends on unconverted modules: libaudioutils, libsndfile
-		"AmrnbEncoderTest", // depends on unconverted modules: libaudioutils, libsndfile
-		"AmrwbDecoderTest", // depends on unconverted modules: libsndfile, libaudioutils
-		"AmrwbEncoderTest", // depends on unconverted modules: libaudioutils, libsndfile
-		"Mp3DecoderTest",   // depends on unconverted modules: libsndfile, libaudioutils
 		"avcdec",
 		"avcenc",
-		"bionic-benchmarks-tests",
-		"bionic-fortify-runtime-asan-test",
-		"bionic-stress-tests",
-		"bionic-unit-tests",
-		"bionic-unit-tests-glibc",
-		"bionic-unit-tests-static",
-		"boringssl_crypto_test",
-		"boringssl_ssl_test",
 		"boringssl_test_support", //b/244431896
 		"cfi_test_helper",
-		"cfi_test_helper2",
 		"cintltst32",
 		"cintltst64",
 		"compare",
 		"cpuid",
-		"debuggerd_test", // depends on unconverted modules: libdebuggerd
 		"elftls_dlopen_ie_error_helper",
-		"exec_linker_helper",
-		"fastdeploy_test", // depends on unconverted modules: AdbWinApi, libadb_host, libandroidfw, libfastdeploy_host, libopenscreen-discovery, libopenscreen-platform-impl, libusb
 		"fdtrack_test",
 		"google-benchmark-test",
-		"googletest-param-test-test_ndk", // depends on unconverted modules: libgtest_ndk_c++
 		"gtest-typed-test_test",
-		"gtest-typed-test_test_ndk", // depends on unconverted modules: libgtest_ndk_c++, libgtest_main_ndk_c++
-		"gtest_ndk_tests",           // depends on unconverted modules: libgtest_ndk_c++, libgtest_main_ndk_c++
-		"gtest_ndk_tests_no_main",   // depends on unconverted modules: libgtest_ndk_c++
-		"gtest_prod_test_ndk",       // depends on unconverted modules: libgtest_ndk_c++, libgtest_main_ndk_c++
 		"gtest_tests",
 		"gtest_tests_no_main",
 		"gwp_asan_unittest",
@@ -1213,7 +1161,6 @@
 		"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",
@@ -1222,11 +1169,6 @@
 		"jemalloc5_integrationtests",
 		"jemalloc5_unittests",
 		"jemalloc5_stresstests", // run by run_jemalloc_tests.sh and will be deleted after V
-		"ld_config_test_helper",
-		"ld_preload_test_helper",
-		"libBionicCtsGtestMain", // depends on unconverted modules: libgtest_isolated
-		"libBionicLoaderTests",  // depends on unconverted modules: libmeminfo
-		"libapexutil_tests",     // depends on unconverted modules: apex-info-list-tinyxml, libapexutil
 		"libcutils_sockets_test",
 		"libhwbinder_latency",
 		"liblog-host-test", // failing tests
@@ -1234,12 +1176,9 @@
 		"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_amrwbdec_test", // error: did not report any run
 		"libstagefright_m4vh263enc_test",
-		"libstagefright_mp3dec_test", // depends on unconverted modules: libsndfile, libaudioutils
-		"libstatssocket_test",
 		"libvndksupport-tests",
 		"libyuv_unittest",
 		"linker-unit-tests",
@@ -1248,22 +1187,17 @@
 		"malloc_hooks_system_tests",
 		"mat_test",
 		"mathtest",
-		"memunreachable_binder_test", // depends on unconverted modules: libbinder
 		"memunreachable_test",
 		"metadata_tests",
 		"mpeg2dec",
 		"mvcdec",
-		"ns_hidden_child_helper",
 		"pngtest",
 		"preinit_getauxval_test_helper",
 		"preinit_syscall_test_helper",
 		"psnr",
 		"quat_test",
-		"rappor-tests", // depends on unconverted modules: jsr305, guava
 		"scudo_unit_tests",
-		"stats-log-api-gen-test", // depends on unconverted modules: libstats_proto_host
 		"thread_exit_cb_helper",
-		"tls_properties_helper",
 		"ulp",
 		"vec_test",
 		"yuvconstants",
@@ -1595,14 +1529,6 @@
 		"libtest_with_dependency_loop_c",
 		"libtestshared",
 
-		// depends on unconverted libprotobuf-java-nano
-		"dnsresolverprotosnano",
-		"launcherprotosnano",
-		"datastallprotosnano",
-		"devicepolicyprotosnano",
-		"ota_metadata_proto_java",
-		"merge_ota",
-
 		// releasetools
 		"verity_utils",
 		"check_ota_package_signature",
@@ -1650,19 +1576,12 @@
 		"CtsPkgInstallerConstants",
 		"guava-android-testlib",
 
-		"MetaDataBaseUnitTest", // depends on libstagefright
-		"AVCUtilsUnitTest",     // depends on libstagefright
-		"ColorUtilsTest",       // depends on libmediandk
-
 		// python_test_host with test data
 		"sbom_writers_test",
+		"hidl_test",
 
-		// TODO(B/283193845): tradefed and its java_test_host dependents
+		// TODO(B/283193845): Remove tradefed from this list.
 		"tradefed",
-		"permissive_mte_test",
-		"ICU4CTestRunner",
-		"DeviceLongPollingStubTest",
-		"FastDeployHostTests",
 
 		"libprotobuf-full-test", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
 		"libprotobuf-lite-test", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
@@ -1671,27 +1590,11 @@
 
 		"expresscatalogvalidator", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
 
-		// depends on other //art modules
-		"libart-for-test",
-		"libart_generated_headers",
-		"libart-runtime-gtest",
-		"libartd-runtime-gtest",
-		"libart-unstripped",
-
-		// depends on libart-unstripped and new module type llvm_prebuilt_build_tool
-		"check_cfi",
-
-		// depends on unconverted module tradefed
-		"HelloWorldPerformanceTest",
-
 		// r8 is a java_binary, which creates an implicit "r8.jar" target, but the
 		// same package contains a "r8.jar" file which gets overshadowed by the implicit target.
 		// We don't need this target as we're not using the Soong wrapper for now
 		"r8",
 
-		// Depends on the module defined in the directory not bp2build default allowed
-		"ota_from_raw_img",
-
 		// TODO(b/299924782): Fix linking error
 		"libbinder_on_trusty_mock",
 
@@ -1705,16 +1608,18 @@
 		// TODO(b/297356704) sdk_version is unset.
 		"VendorAtomCodeGenJavaTest",
 
-		// android_test from allowlisted packages, but with unconverted deps
-		"MtsLibnativehelperLazyTestCases",
+		// TODO: b/305223367 - Missing dep on android.test.base-neverlink
 		"ObjenesisTck",
-		"DevCodelabTest",
-		"MtsTimeZoneDataTestCases",
-		"NanoAndroidTest",
-		"MtsLibnativehelperTestCases",
 
-		// android_test_helper_app from allowlisted packages, but with unconverted deps
-		"SharedLibraryInfoTestApp",
+		// TODO - b/306197073: Sets different STL for host and device variants
+		"trace_processor_shell",
+
+		// TODO - b/303713102: duplicate deps added by cc_lite_proto_library
+		"perfetto_unittests",
+		"perfetto_integrationtests",
+
+		// TODO - b/306194966: Depends on an empty filegroup
+		"libperfetto_c",
 	}
 
 	// Bazel prod-mode allowlist. Modules in this list are built by Bazel
@@ -1740,10 +1645,11 @@
 		"libneuralnetworks",
 		"libneuralnetworks_static",
 		// M13: media.swcodec launch
-		"com.android.media.swcodec",
-		"test_com.android.media.swcodec",
-		"libstagefright_foundation",
-		"libcodec2_hidl@1.0",
+		// TODO(b/307389608) Relaunch swcodec after fixing rust dependencies
+		// "com.android.media.swcodec",
+		// "test_com.android.media.swcodec",
+		// "libstagefright_foundation",
+		// "libcodec2_hidl@1.0",
 	}
 
 	// Staging-mode allowlist. Modules in this list are only built
@@ -1777,18 +1683,4 @@
 		"art_":        DEFAULT_PRIORITIZED_WEIGHT,
 		"ndk_library": DEFAULT_PRIORITIZED_WEIGHT,
 	}
-
-	BazelSandwichTargets = []struct {
-		Label string
-		Host  bool
-	}{
-		{
-			Label: "//build/bazel/examples/partitions:system_image",
-			Host:  false,
-		},
-		{
-			Label: "//build/bazel/examples/partitions:run_test",
-			Host:  false,
-		},
-	}
 )
diff --git a/android/apex.go b/android/apex.go
index d84499b..c6d9940 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -482,7 +482,9 @@
 	}
 	return InList(what, apex_available) ||
 		(what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available)) ||
-		(strings.HasPrefix(what, "com.android.gki.") && InList(AvailableToGkiApex, apex_available))
+		(strings.HasPrefix(what, "com.android.gki.") && InList(AvailableToGkiApex, apex_available)) ||
+		(what == "com.google.mainline.primary.libs") || // TODO b/248601389
+		(what == "com.google.mainline.go.primary.libs") // TODO b/248601389
 }
 
 // Implements ApexModule
diff --git a/android/apex_contributions.go b/android/apex_contributions.go
new file mode 100644
index 0000000..6eaca8b
--- /dev/null
+++ b/android/apex_contributions.go
@@ -0,0 +1,175 @@
+// 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.ModuleErrorf("%s listed in apex_contributions %s does not exist\n", content, m.Name())
+			}
+			pi := &PrebuiltSelectionInfo{
+				baseModuleName:     RemoveOptionalPrebuiltPrefix(content),
+				selectedModuleName: content,
+				metadataModuleName: m.Name(),
+				apiDomain:          m.ApiDomain(),
+			}
+			p.Add(ctx, pi)
+		}
+	}
+
+	if ctx.Config().Bp2buildMode() { // Skip bp2build
+		return
+	}
+	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())
+		}
+	})
+	ctx.SetProvider(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 baseModuleName to the selected source or prebuilt
+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
+	}
+	// Do not allow dups. If the base module (without the prebuilt_) has been added before, raise an exception.
+	if old, exists := (*pm)[p.baseModuleName]; exists {
+		ctx.ModuleErrorf("Cannot use Soong module: %s from apex_contributions: %s because it has been added previously as: %s from apex_contributions: %s\n",
+			p.selectedModuleName, p.metadataModuleName, old.selectedModuleName, old.metadataModuleName,
+		)
+	}
+	(*pm)[p.baseModuleName] = *p
+}
+
+type PrebuiltSelectionInfo struct {
+	// e.g. libc
+	baseModuleName string
+	// 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(baseModuleName, name string) bool {
+	if i, exists := (*p)[baseModuleName]; exists {
+		return i.selectedModuleName == name
+	} else {
+		return false
+	}
+}
+
+// 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/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/base_module_context.go b/android/base_module_context.go
new file mode 100644
index 0000000..ec9c888
--- /dev/null
+++ b/android/base_module_context.go
@@ -0,0 +1,656 @@
+// 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 {
+	EarlyModuleContext
+
+	blueprintBaseModuleContext() blueprint.BaseModuleContext
+
+	// OtherModuleName returns the name of another Module.  See BaseModuleContext.ModuleName for more information.
+	// It is intended for use inside the visit functions of Visit* and WalkDeps.
+	OtherModuleName(m blueprint.Module) string
+
+	// OtherModuleDir returns the directory of another Module.  See BaseModuleContext.ModuleDir for more information.
+	// It is intended for use inside the visit functions of Visit* and WalkDeps.
+	OtherModuleDir(m blueprint.Module) string
+
+	// OtherModuleErrorf reports an error on another Module.  See BaseModuleContext.ModuleErrorf for more information.
+	// It is intended for use inside the visit functions of Visit* and WalkDeps.
+	OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
+
+	// OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency
+	// on the module.  When called inside a Visit* method with current module being visited, and there are multiple
+	// dependencies on the module being visited, it returns the dependency tag used for the current dependency.
+	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
+
+	// OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface
+	// passed to Context.SetNameInterface, or SimpleNameInterface if it was not called.
+	OtherModuleExists(name string) bool
+
+	// OtherModuleDependencyVariantExists returns true if a module with the
+	// specified name and variant exists. The variant must match the given
+	// variations. It must also match all the non-local variations of the current
+	// module. In other words, it checks for the module that AddVariationDependencies
+	// would add a dependency on with the same arguments.
+	OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool
+
+	// OtherModuleFarDependencyVariantExists returns true if a module with the
+	// specified name and variant exists. The variant must match the given
+	// variations, but not the non-local variations of the current module. In
+	// other words, it checks for the module that AddFarVariationDependencies
+	// would add a dependency on with the same arguments.
+	OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool
+
+	// OtherModuleReverseDependencyVariantExists returns true if a module with the
+	// specified name exists with the same variations as the current module. In
+	// other words, it checks for the module that AddReverseDependency would add a
+	// dependency on with the same argument.
+	OtherModuleReverseDependencyVariantExists(name string) bool
+
+	// OtherModuleType returns the type of another Module.  See BaseModuleContext.ModuleType for more information.
+	// It is intended for use inside the visit functions of Visit* and WalkDeps.
+	OtherModuleType(m blueprint.Module) string
+
+	// OtherModuleProvider returns the value for a provider for the given module.  If the value is
+	// not set it returns the zero value of the type of the provider, so the return value can always
+	// be type asserted to the type of the provider.  The value returned may be a deep copy of the
+	// value originally passed to SetProvider.
+	OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{}
+
+	// OtherModuleHasProvider returns true if the provider for the given module has been set.
+	OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool
+
+	// Provider returns the value for a provider for the current module.  If the value is
+	// not set it returns the zero value of the type of the provider, so the return value can always
+	// be type asserted to the type of the provider.  It panics if called before the appropriate
+	// mutator or GenerateBuildActions pass for the provider.  The value returned may be a deep
+	// copy of the value originally passed to SetProvider.
+	Provider(provider blueprint.ProviderKey) interface{}
+
+	// HasProvider returns true if the provider for the current module has been set.
+	HasProvider(provider blueprint.ProviderKey) bool
+
+	// SetProvider sets the value for a provider for the current module.  It panics if not called
+	// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value
+	// is not of the appropriate type, or if the value has already been set.  The value should not
+	// be modified after being passed to SetProvider.
+	SetProvider(provider blueprint.ProviderKey, value interface{})
+
+	GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
+
+	// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if
+	// none exists.  It panics if the dependency does not have the specified tag.  It skips any
+	// dependencies that are not an android.Module.
+	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module
+
+	// GetDirectDep returns the Module and DependencyTag for the  direct dependency with the specified
+	// name, or nil if none exists.  If there are multiple dependencies on the same module it returns
+	// the first DependencyTag.
+	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
+
+	ModuleFromName(name string) (blueprint.Module, bool)
+
+	// VisitDirectDepsBlueprint calls visit for each direct dependency.  If there are multiple
+	// direct dependencies on the same module visit will be called multiple times on that module
+	// and OtherModuleDependencyTag will return a different tag for each.
+	//
+	// The Module passed to the visit function should not be retained outside of the visit
+	// function, it may be invalidated by future mutators.
+	VisitDirectDepsBlueprint(visit func(blueprint.Module))
+
+	// VisitDirectDeps calls visit for each direct dependency.  If there are multiple
+	// direct dependencies on the same module visit will be called multiple times on that module
+	// and OtherModuleDependencyTag will return a different tag for each.  It raises an error if any of the
+	// dependencies are not an android.Module.
+	//
+	// The Module passed to the visit function should not be retained outside of the visit
+	// function, it may be invalidated by future mutators.
+	VisitDirectDeps(visit func(Module))
+
+	VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
+
+	// VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit.  If there are
+	// multiple direct dependencies on the same module pred and visit will be called multiple times on that module and
+	// OtherModuleDependencyTag will return a different tag for each.  It skips any
+	// dependencies that are not an android.Module.
+	//
+	// The Module passed to the visit function should not be retained outside of the visit function, it may be
+	// invalidated by future mutators.
+	VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
+	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
+	VisitDepsDepthFirst(visit func(Module))
+	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
+	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
+
+	// WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order.  visit may
+	// be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the
+	// child and parent with different tags.  OtherModuleDependencyTag will return the tag for the currently visited
+	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down to child.  It skips
+	// any dependencies that are not an android.Module.
+	//
+	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
+	// invalidated by future mutators.
+	WalkDeps(visit func(child, parent Module) bool)
+
+	// WalkDepsBlueprint calls visit for each transitive dependency, traversing the dependency
+	// tree in top down order.  visit may be called multiple times for the same (child, parent)
+	// pair if there are multiple direct dependencies between the child and parent with different
+	// tags.  OtherModuleDependencyTag will return the tag for the currently visited
+	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down
+	// to child.
+	//
+	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
+	// invalidated by future mutators.
+	WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool)
+
+	// GetWalkPath is supposed to be called in visit function passed in WalkDeps()
+	// and returns a top-down dependency path from a start module to current child module.
+	GetWalkPath() []Module
+
+	// PrimaryModule returns the first variant of the current module.  Variants of a module are always visited in
+	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the
+	// Module returned by PrimaryModule without data races.  This can be used to perform singleton actions that are
+	// only done once for all variants of a module.
+	PrimaryModule() Module
+
+	// FinalModule returns the last variant of the current module.  Variants of a module are always visited in
+	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all
+	// variants using VisitAllModuleVariants if the current module == FinalModule().  This can be used to perform
+	// singleton actions that are only done once for all variants of a module.
+	FinalModule() Module
+
+	// VisitAllModuleVariants calls visit for each variant of the current module.  Variants of a module are always
+	// visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read
+	// from all variants if the current module == FinalModule().  Otherwise, care must be taken to not access any
+	// data modified by the current mutator.
+	VisitAllModuleVariants(visit func(Module))
+
+	// GetTagPath is supposed to be called in visit function passed in WalkDeps()
+	// and returns a top-down dependency tags path from a start module to current child module.
+	// It has one less entry than GetWalkPath() as it contains the dependency tags that
+	// exist between each adjacent pair of modules in the GetWalkPath().
+	// GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1]
+	GetTagPath() []blueprint.DependencyTag
+
+	// GetPathString is supposed to be called in visit function passed in WalkDeps()
+	// and returns a multi-line string showing the modules and dependency tags
+	// among them along the top-down dependency path from a start module to current child module.
+	// skipFirst when set to true, the output doesn't include the start module,
+	// which is already printed when this function is used along with ModuleErrorf().
+	GetPathString(skipFirst bool) string
+
+	AddMissingDependencies(missingDeps []string)
+
+	// getMissingDependencies returns the list of missing dependencies.
+	// Calling this function prevents adding new dependencies.
+	getMissingDependencies() []string
+
+	// AddUnconvertedBp2buildDep stores module name of a direct dependency that was not converted via bp2build
+	AddUnconvertedBp2buildDep(dep string)
+
+	// AddMissingBp2buildDep stores the module name of a direct dependency that was not found.
+	AddMissingBp2buildDep(dep string)
+
+	Target() Target
+	TargetPrimary() bool
+
+	// The additional arch specific targets (e.g. 32/64 bit) that this module variant is
+	// responsible for creating.
+	MultiTargets() []Target
+	Arch() Arch
+	Os() OsType
+	Host() bool
+	Device() bool
+	Darwin() bool
+	Windows() bool
+	PrimaryArch() bool
+}
+
+type baseModuleContext struct {
+	bp blueprint.BaseModuleContext
+	earlyModuleContext
+	os            OsType
+	target        Target
+	multiTargets  []Target
+	targetPrimary 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
+}
+
+// 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)
+}
+
+func (b *baseModuleContext) AddMissingDependencies(deps []string) {
+	if deps != nil {
+		missingDeps := &b.Module().base().commonProperties.MissingDeps
+		*missingDeps = append(*missingDeps, deps...)
+		*missingDeps = FirstUniqueStrings(*missingDeps)
+	}
+}
+
+func (b *baseModuleContext) checkedMissingDeps() bool {
+	return b.Module().base().commonProperties.CheckedMissingDeps
+}
+
+func (b *baseModuleContext) getMissingDependencies() []string {
+	checked := &b.Module().base().commonProperties.CheckedMissingDeps
+	*checked = true
+	var missingDeps []string
+	missingDeps = append(missingDeps, b.Module().base().commonProperties.MissingDeps...)
+	missingDeps = append(missingDeps, b.bp.EarlyGetMissingDependencies()...)
+	missingDeps = FirstUniqueStrings(missingDeps)
+	return missingDeps
+}
+
+type AllowDisabledModuleDependency interface {
+	blueprint.DependencyTag
+	AllowDisabledModuleDependency(target Module) bool
+}
+
+func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool) Module {
+	aModule, _ := module.(Module)
+
+	if !strict {
+		return aModule
+	}
+
+	if aModule == nil {
+		b.ModuleErrorf("module %q (%#v) not an android module", b.OtherModuleName(module), tag)
+		return nil
+	}
+
+	if !aModule.Enabled() {
+		if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependency(aModule) {
+			if b.Config().AllowMissingDependencies() {
+				b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
+			} else {
+				b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
+			}
+		}
+		return nil
+	}
+	return aModule
+}
+
+type dep struct {
+	mod blueprint.Module
+	tag blueprint.DependencyTag
+}
+
+func (b *baseModuleContext) getDirectDepsInternal(name string, tag blueprint.DependencyTag) []dep {
+	var deps []dep
+	b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+		if aModule, _ := module.(Module); aModule != nil {
+			if aModule.base().BaseModuleName() == name {
+				returnedTag := b.bp.OtherModuleDependencyTag(aModule)
+				if tag == nil || returnedTag == tag {
+					deps = append(deps, dep{aModule, returnedTag})
+				}
+			}
+		} else if b.bp.OtherModuleName(module) == name {
+			returnedTag := b.bp.OtherModuleDependencyTag(module)
+			if tag == nil || returnedTag == tag {
+				deps = append(deps, dep{module, returnedTag})
+			}
+		}
+	})
+	return deps
+}
+
+func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) {
+	deps := b.getDirectDepsInternal(name, tag)
+	if len(deps) == 1 {
+		return deps[0].mod, deps[0].tag
+	} else if len(deps) >= 2 {
+		panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
+			name, b.ModuleName()))
+	} else {
+		return nil, nil
+	}
+}
+
+func (b *baseModuleContext) getDirectDepFirstTag(name string) (blueprint.Module, blueprint.DependencyTag) {
+	foundDeps := b.getDirectDepsInternal(name, nil)
+	deps := map[blueprint.Module]bool{}
+	for _, dep := range foundDeps {
+		deps[dep.mod] = true
+	}
+	if len(deps) == 1 {
+		return foundDeps[0].mod, foundDeps[0].tag
+	} else if len(deps) >= 2 {
+		// this could happen if two dependencies have the same name in different namespaces
+		// TODO(b/186554727): this should not occur if namespaces are handled within
+		// getDirectDepsInternal.
+		panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
+			name, b.ModuleName()))
+	} else {
+		return nil, nil
+	}
+}
+
+func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module {
+	var deps []Module
+	b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
+		if aModule, _ := module.(Module); aModule != nil {
+			if b.bp.OtherModuleDependencyTag(aModule) == tag {
+				deps = append(deps, aModule)
+			}
+		}
+	})
+	return deps
+}
+
+// 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")
+	}
+	var m blueprint.Module
+	var ok bool
+	if moduleName, _ := SrcIsModuleWithTag(name); moduleName != "" {
+		m, ok = b.bp.ModuleFromName(moduleName)
+	} else {
+		m, ok = b.bp.ModuleFromName(name)
+	}
+	if !ok {
+		return m, ok
+	}
+	// If this module is not preferred, tried to get the prebuilt version instead
+	if a, aOk := m.(Module); aOk && !IsModulePrebuilt(a) && !IsModulePreferred(a) {
+		return b.ModuleFromName("prebuilt_" + name)
+	}
+	return m, ok
+}
+
+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
+	} else if tag == acDepTag {
+		return true
+	}
+	return false
+}
+
+// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
+// a dependency tag.
+var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:{}\E(, )?`)
+
+// PrettyPrintTag returns string representation of the tag, but prefers
+// custom String() method if available.
+func PrettyPrintTag(tag blueprint.DependencyTag) string {
+	// Use tag's custom String() method if available.
+	if stringer, ok := tag.(fmt.Stringer); ok {
+		return stringer.String()
+	}
+
+	// Otherwise, get a default string representation of the tag's struct.
+	tagString := fmt.Sprintf("%T: %+v", tag, tag)
+
+	// Remove the boilerplate from BaseDependencyTag as it adds no value.
+	tagString = tagCleaner.ReplaceAllString(tagString, "")
+	return tagString
+}
+
+func (b *baseModuleContext) GetPathString(skipFirst bool) string {
+	sb := strings.Builder{}
+	tagPath := b.GetTagPath()
+	walkPath := b.GetWalkPath()
+	if !skipFirst {
+		sb.WriteString(walkPath[0].String())
+	}
+	for i, m := range walkPath[1:] {
+		sb.WriteString("\n")
+		sb.WriteString(fmt.Sprintf("           via tag %s\n", PrettyPrintTag(tagPath[i])))
+		sb.WriteString(fmt.Sprintf("    -> %s", m.String()))
+	}
+	return sb.String()
+}
+
+func (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) 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
+}
diff --git a/android/bazel.go b/android/bazel.go
index 8634dab..1602b9b 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -81,6 +81,11 @@
 	// If non-nil, indicates that the module could not be converted successfully
 	// with bp2build. This will describe the reason the module could not be converted.
 	UnconvertedReason *UnconvertedReason
+
+	// The Partition this module will be installed on.
+	// TODO(b/306200980) Investigate how to handle modules that are installed in multiple
+	// partitions.
+	Partition string `blueprint:"mutated"`
 }
 
 // The reason a module could not be converted to a BUILD target via bp2build.
@@ -218,6 +223,28 @@
 	module.bazelProps().Bazel_module.CanConvertToBazel = true
 }
 
+// BazelHandcraftedHook is a load hook to possibly register the current module as
+// a "handcrafted" Bazel target of a given name. If the current module should be
+// registered in this way, the hook function should return the target name. If
+// it should not be registered in this way, this function should return the empty string.
+type BazelHandcraftedHook func(ctx LoadHookContext) string
+
+// AddBazelHandcraftedHook adds a load hook to (maybe) mark the given module so that
+// it is treated by bp2build as if it has a handcrafted Bazel target.
+func AddBazelHandcraftedHook(module BazelModule, hook BazelHandcraftedHook) {
+	AddLoadHook(module, func(ctx LoadHookContext) {
+		var targetName string = hook(ctx)
+		if len(targetName) > 0 {
+			moduleDir := ctx.ModuleDir()
+			if moduleDir == Bp2BuildTopLevel {
+				moduleDir = ""
+			}
+			label := fmt.Sprintf("//%s:%s", moduleDir, targetName)
+			module.bazelProps().Bazel_module.Label = &label
+		}
+	})
+}
+
 // bazelProps returns the Bazel properties for the given BazelModuleBase.
 func (b *BazelModuleBase) bazelProps() *properties {
 	return &b.bazelProperties
@@ -522,7 +549,18 @@
 	}
 
 	moduleName := moduleNameWithPossibleOverride(ctx, module, p.moduleName)
+	// use "prebuilt_" + original module name as the java_import(_host) module name,
+	// to avoid the failure that a normal module and a prebuilt module with
+	// the same name are both allowlisted. This cannot be applied to all the *_import
+	// module types. For example, android_library_import has to use original module
+	// name here otherwise the *-nodeps targets cannot be handled correctly.
+	// TODO(b/304385140): remove this special casing
+	if p.moduleType == "java_import" || p.moduleType == "java_import_host" {
+		moduleName = module.Name()
+	}
+
 	allowlist := ctx.Config().Bp2buildPackageConfig
+
 	moduleNameAllowed := allowlist.moduleAlwaysConvert[moduleName]
 	moduleTypeAllowed := allowlist.moduleTypeAlwaysConvert[p.moduleType]
 	allowlistConvert := moduleNameAllowed || moduleTypeAllowed
@@ -600,17 +638,18 @@
 }
 
 func registerBp2buildConversionMutator(ctx RegisterMutatorsContext) {
-	ctx.TopDown("bp2build_conversion", bp2buildConversionMutator).Parallel()
+	ctx.BottomUp("bp2build_conversion", bp2buildConversionMutator).Parallel()
+	ctx.BottomUp("bp2build_deps", bp2buildDepsMutator).Parallel()
 }
 
-func bp2buildConversionMutator(ctx TopDownMutatorContext) {
-	if ctx.Config().HasBazelBuildTargetInSource(ctx) {
-		// Defer to the BUILD target. Generating an additional target would
-		// cause a BUILD file conflict.
-		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE, "")
+func bp2buildConversionMutator(ctx BottomUpMutatorContext) {
+	// If an existing BUILD file in the module directory has a target defined
+	// with this same name as this module, assume that this is an existing
+	// definition for this target.
+	if ctx.Config().HasBazelBuildTargetInSource(ctx.ModuleDir(), ctx.ModuleName()) {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE, ctx.ModuleName())
 		return
 	}
-
 	bModule, ok := ctx.Module().(Bazelable)
 	if !ok {
 		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
@@ -634,24 +673,66 @@
 		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "")
 		return
 	}
+	if ctx.Module().base().GetUnconvertedReason() != nil {
+		return
+	}
+
 	bModule.ConvertWithBp2build(ctx)
 
-	if !ctx.Module().base().IsConvertedByBp2build() && ctx.Module().base().GetUnconvertedReason() == nil {
+	installCtx := &baseModuleContextToModuleInstallPathContext{ctx}
+	ctx.Module().base().setPartitionForBp2build(modulePartition(installCtx, true))
+
+	if len(ctx.Module().base().Bp2buildTargets()) == 0 && ctx.Module().base().GetUnconvertedReason() == nil {
 		panic(fmt.Errorf("illegal bp2build invariant: module '%s' was neither converted nor marked unconvertible", ctx.ModuleName()))
 	}
-}
 
-func registerApiBp2buildConversionMutator(ctx RegisterMutatorsContext) {
-	ctx.TopDown("apiBp2build_conversion", convertWithApiBp2build).Parallel()
-}
-
-// Generate API contribution targets if the Soong module provides APIs
-func convertWithApiBp2build(ctx TopDownMutatorContext) {
-	if m, ok := ctx.Module().(ApiProvider); ok {
-		m.ConvertWithApiBp2build(ctx)
+	// If an existing BUILD file in the module directory has a target defined
+	// with the same name as any target generated by this module, assume that this
+	// is an existing definition for this target. (These generated target names
+	// may be different than the module name, as checked at the beginning of this function!)
+	for _, targetInfo := range ctx.Module().base().Bp2buildTargets() {
+		if ctx.Config().HasBazelBuildTargetInSource(targetInfo.TargetPackage(), targetInfo.TargetName()) {
+			// Defer to the BUILD target. Generating an additional target would
+			// cause a BUILD file conflict.
+			ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE, targetInfo.TargetName())
+			return
+		}
 	}
 }
 
+// TODO: b/285631638 - Add this as a new mutator to the bp2build conversion mutators.
+// Currently, this only exists to prepare test coverage for the launch of this feature.
+func bp2buildDepsMutator(ctx BottomUpMutatorContext) {
+	if ctx.Module().base().GetUnconvertedReason() != nil {
+		return
+	}
+
+	if len(ctx.Module().GetMissingBp2buildDeps()) > 0 {
+		exampleDep := ctx.Module().GetMissingBp2buildDeps()[0]
+		ctx.MarkBp2buildUnconvertible(
+			bp2build_metrics_proto.UnconvertedReasonType_UNCONVERTED_DEP, exampleDep)
+	}
+
+	// Transitively mark modules unconvertible with the following set of conditions.
+	ctx.VisitDirectDeps(func(dep Module) {
+		if dep.base().GetUnconvertedReason() == nil {
+			return
+		}
+
+		if dep.base().GetUnconvertedReason().ReasonType ==
+			int(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE) {
+			return
+		}
+
+		if ctx.OtherModuleDependencyTag(dep) != Bp2buildDepTag {
+			return
+		}
+
+		ctx.MarkBp2buildUnconvertible(
+			bp2build_metrics_proto.UnconvertedReasonType_UNCONVERTED_DEP, dep.Name())
+	})
+}
+
 // 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.
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 56ec17d..0c65415 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -33,10 +33,10 @@
 	"android/soong/shared"
 	"android/soong/starlark_import"
 
+	"android/soong/bazel"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/metrics"
-
-	"android/soong/bazel"
 )
 
 var (
@@ -245,6 +245,55 @@
 
 var _ BazelContext = noopBazelContext{}
 
+func (n noopBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
+	panic("unimplemented")
+}
+
+func (n noopBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
+	panic("unimplemented")
+}
+
+func (n noopBazelContext) GetOutputFiles(_ string, _ configKey) ([]string, error) {
+	panic("unimplemented")
+}
+
+func (n noopBazelContext) GetCcInfo(_ string, _ configKey) (cquery.CcInfo, error) {
+	panic("unimplemented")
+}
+
+func (n noopBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexInfo, error) {
+	panic("unimplemented")
+}
+
+func (n noopBazelContext) GetCcUnstrippedInfo(_ string, _ configKey) (cquery.CcUnstrippedInfo, error) {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (n noopBazelContext) GetPrebuiltFileInfo(_ string, _ configKey) (cquery.PrebuiltFileInfo, error) {
+	panic("implement me")
+}
+
+func (n noopBazelContext) InvokeBazel(_ Config, _ invokeBazelContext) error {
+	panic("unimplemented")
+}
+
+func (m noopBazelContext) OutputBase() string {
+	return ""
+}
+
+func (n noopBazelContext) IsModuleNameAllowed(_ string, _ bool) bool {
+	return false
+}
+
+func (m noopBazelContext) BuildStatementsToRegister() []*bazel.BuildStatement {
+	return []*bazel.BuildStatement{}
+}
+
+func (m noopBazelContext) AqueryDepsets() []bazel.AqueryDepset {
+	return []bazel.AqueryDepset{}
+}
+
 // A bazel context to use for tests.
 type MockBazelContext struct {
 	OutputBaseDir string
@@ -427,55 +476,6 @@
 	return cquery.PrebuiltFileInfo{}, fmt.Errorf("no bazel response for %s", key)
 }
 
-func (n noopBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
-	panic("unimplemented")
-}
-
-func (n noopBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
-	panic("unimplemented")
-}
-
-func (n noopBazelContext) GetOutputFiles(_ string, _ configKey) ([]string, error) {
-	panic("unimplemented")
-}
-
-func (n noopBazelContext) GetCcInfo(_ string, _ configKey) (cquery.CcInfo, error) {
-	panic("unimplemented")
-}
-
-func (n noopBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexInfo, error) {
-	panic("unimplemented")
-}
-
-func (n noopBazelContext) GetCcUnstrippedInfo(_ string, _ configKey) (cquery.CcUnstrippedInfo, error) {
-	//TODO implement me
-	panic("implement me")
-}
-
-func (n noopBazelContext) GetPrebuiltFileInfo(_ string, _ configKey) (cquery.PrebuiltFileInfo, error) {
-	panic("implement me")
-}
-
-func (n noopBazelContext) InvokeBazel(_ Config, _ invokeBazelContext) error {
-	panic("unimplemented")
-}
-
-func (m noopBazelContext) OutputBase() string {
-	return ""
-}
-
-func (n noopBazelContext) IsModuleNameAllowed(_ string, _ bool) bool {
-	return false
-}
-
-func (m noopBazelContext) BuildStatementsToRegister() []*bazel.BuildStatement {
-	return []*bazel.BuildStatement{}
-}
-
-func (m noopBazelContext) AqueryDepsets() []bazel.AqueryDepset {
-	return []bazel.AqueryDepset{}
-}
-
 func AddToStringSet(set map[string]bool, items []string) {
 	for _, item := range items {
 		set[item] = true
@@ -1048,39 +1048,46 @@
 	allBazelCommands = []bazelCommand{aqueryCmd, cqueryCmd, buildCmd}
 )
 
+// This can't be part of bp2build_product_config.go because it would create a circular go package dependency
+func getLabelsForBazelSandwichPartitions(variables *ProductVariables) []string {
+	targetProduct := "unknown"
+	if variables.DeviceProduct != nil {
+		targetProduct = *variables.DeviceProduct
+	}
+	currentProductFolder := fmt.Sprintf("build/bazel/products/%s", targetProduct)
+	if len(variables.PartitionVarsForBazelMigrationOnlyDoNotUse.ProductDirectory) > 0 {
+		currentProductFolder = fmt.Sprintf("%s%s", variables.PartitionVarsForBazelMigrationOnlyDoNotUse.ProductDirectory, targetProduct)
+	}
+	var ret []string
+	if variables.PartitionVarsForBazelMigrationOnlyDoNotUse.PartitionQualifiedVariables["system"].BuildingImage {
+		ret = append(ret, "@//"+currentProductFolder+":system_image")
+		ret = append(ret, "@//"+currentProductFolder+":run_system_image_test")
+	}
+	return ret
+}
+
 func GetBazelSandwichCqueryRequests(config Config) ([]cqueryKey, error) {
-	result := make([]cqueryKey, 0, len(allowlists.BazelSandwichTargets))
+	partitionLabels := getLabelsForBazelSandwichPartitions(&config.productVariables)
+	result := make([]cqueryKey, 0, len(partitionLabels))
 	labelRegex := regexp.MustCompile("^@?//([a-zA-Z0-9/_-]+):[a-zA-Z0-9_-]+$")
 	// Note that bazel "targets" are different from soong "targets", the bazel targets are
 	// synonymous with soong modules, and soong targets are a configuration a module is built in.
-	for _, target := range allowlists.BazelSandwichTargets {
-		match := labelRegex.FindStringSubmatch(target.Label)
+	for _, target := range partitionLabels {
+		match := labelRegex.FindStringSubmatch(target)
 		if match == nil {
-			return nil, fmt.Errorf("invalid label, must match `^@?//([a-zA-Z0-9/_-]+):[a-zA-Z0-9_-]+$`: %s", target.Label)
-		}
-		if _, err := os.Stat(absolutePath(match[1])); err != nil {
-			if os.IsNotExist(err) {
-				// Ignore bazel sandwich targets that don't exist.
-				continue
-			} else {
-				return nil, err
-			}
+			return nil, fmt.Errorf("invalid label, must match `^@?//([a-zA-Z0-9/_-]+):[a-zA-Z0-9_-]+$`: %s", target)
 		}
 
-		var soongTarget Target
-		if target.Host {
-			soongTarget = config.BuildOSTarget
-		} else {
-			soongTarget = config.AndroidCommonTarget
-			if soongTarget.Os.Class != Device {
-				// kernel-build-tools seems to set the AndroidCommonTarget to a linux host
-				// target for some reason, disable device builds in that case.
-				continue
-			}
+		// change this to config.BuildOSTarget if we add host targets
+		soongTarget := config.AndroidCommonTarget
+		if soongTarget.Os.Class != Device {
+			// kernel-build-tools seems to set the AndroidCommonTarget to a linux host
+			// target for some reason, disable device builds in that case.
+			continue
 		}
 
 		result = append(result, cqueryKey{
-			label:       target.Label,
+			label:       target,
 			requestType: cquery.GetOutputFiles,
 			configKey: configKey{
 				arch:   soongTarget.Arch.String(),
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index 4ac5840..f25803c 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"os"
 	"path/filepath"
 	"strings"
 
@@ -101,8 +102,8 @@
 // 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)
+func BazelLabelForModuleDeps(ctx Bp2buildMutatorContext, modules []string) bazel.LabelList {
+	return BazelLabelForModuleDepsWithFn(ctx, modules, BazelModuleLabel, true)
 }
 
 // BazelLabelForModuleWholeDepsExcludes expects two lists: modules (containing modules to include in
@@ -111,15 +112,16 @@
 // 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 {
+func BazelLabelForModuleDepsExcludes(ctx Bp2buildMutatorContext, 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 {
+func BazelLabelForModuleDepsWithFn(ctx Bp2buildMutatorContext, modules []string,
+	moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string,
+	markAsDeps bool) 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 {
@@ -133,7 +135,7 @@
 			module = ":" + module
 		}
 		if m, t := SrcIsModuleWithTag(module); m != "" {
-			l := getOtherModuleLabel(ctx, m, t, moduleToLabelFn)
+			l := getOtherModuleLabel(ctx, m, t, moduleToLabelFn, markAsDeps)
 			if l != nil {
 				l.OriginalModuleName = bpText
 				labels.Includes = append(labels.Includes, *l)
@@ -150,27 +152,27 @@
 // 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,
+func BazelLabelForModuleDepsExcludesWithFn(ctx Bp2buildMutatorContext, modules, excludes []string,
 	moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string) bazel.LabelList {
-	moduleLabels := BazelLabelForModuleDepsWithFn(ctx, RemoveListFromList(modules, excludes), moduleToLabelFn)
+	moduleLabels := BazelLabelForModuleDepsWithFn(ctx, RemoveListFromList(modules, excludes), moduleToLabelFn, true)
 	if len(excludes) == 0 {
 		return moduleLabels
 	}
-	excludeLabels := BazelLabelForModuleDepsWithFn(ctx, excludes, moduleToLabelFn)
+	excludeLabels := BazelLabelForModuleDepsWithFn(ctx, excludes, moduleToLabelFn, false)
 	return bazel.LabelList{
 		Includes: moduleLabels.Includes,
 		Excludes: excludeLabels.Includes,
 	}
 }
 
-func BazelLabelForModuleSrcSingle(ctx BazelConversionPathContext, path string) bazel.Label {
+func BazelLabelForModuleSrcSingle(ctx Bp2buildMutatorContext, 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 {
+func BazelLabelForModuleDepSingle(ctx Bp2buildMutatorContext, path string) bazel.Label {
 	if srcs := BazelLabelForModuleDepsExcludes(ctx, []string{path}, []string(nil)).Includes; len(srcs) > 0 {
 		return srcs[0]
 	}
@@ -183,7 +185,7 @@
 // relative if within the same package).
 // Properties must have been annotated with struct tag `android:"path"` so that dependencies modules
 // will have already been handled by the pathdeps mutator.
-func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) bazel.LabelList {
+func BazelLabelForModuleSrc(ctx Bp2buildMutatorContext, paths []string) bazel.LabelList {
 	return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil))
 }
 
@@ -193,13 +195,13 @@
 // (absolute if in a different package or relative if within the same package).
 // Properties must have been annotated with struct tag `android:"path"` so that dependencies modules
 // will have already been handled by the pathdeps mutator.
-func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, excludes []string) bazel.LabelList {
-	excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil))
+func BazelLabelForModuleSrcExcludes(ctx Bp2buildMutatorContext, paths, excludes []string) bazel.LabelList {
+	excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil), false)
 	excluded := make([]string, 0, len(excludeLabels.Includes))
 	for _, e := range excludeLabels.Includes {
 		excluded = append(excluded, e.Label)
 	}
-	labels := expandSrcsForBazel(ctx, paths, excluded)
+	labels := expandSrcsForBazel(ctx, paths, excluded, true)
 	labels.Excludes = excludeLabels.Includes
 	labels = TransformSubpackagePaths(ctx.Config(), ctx.ModuleDir(), labels)
 	return labels
@@ -228,10 +230,18 @@
 //  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 {
+	isSymlink := func(c Config, path string) bool {
+		f, err := c.fs.Lstat(path)
+		if err != nil {
+			// The file does not exist
+			return false
+		}
+		return f.Mode()&os.ModeSymlink == os.ModeSymlink
+	}
 	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) {
+	} else if config.Bp2buildPackageConfig.ShouldKeepExistingBuildFileForDir(prefix) || isSymlink(config, 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 {
@@ -352,6 +362,12 @@
 	return newPaths
 }
 
+var Bp2buildDepTag bp2buildDepTag
+
+type bp2buildDepTag struct {
+	blueprint.BaseDependencyTag
+}
+
 // 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
@@ -374,7 +390,7 @@
 // Properties passed as the paths or excludes argument must have been annotated with struct tag
 // `android:"path"` so that dependencies on other modules will have already been handled by the
 // pathdeps mutator.
-func expandSrcsForBazel(ctx BazelConversionPathContext, paths, expandedExcludes []string) bazel.LabelList {
+func expandSrcsForBazel(ctx Bp2buildMutatorContext, paths, expandedExcludes []string, markAsDeps bool) bazel.LabelList {
 	if paths == nil {
 		return bazel.LabelList{}
 	}
@@ -391,7 +407,7 @@
 
 	for _, p := range paths {
 		if m, tag := SrcIsModuleWithTag(p); m != "" {
-			l := getOtherModuleLabel(ctx, m, tag, BazelModuleLabel)
+			l := getOtherModuleLabel(ctx, m, tag, BazelModuleLabel, markAsDeps)
 			if l != nil && !InList(l.Label, expandedExcludes) {
 				if strings.HasPrefix(m, "//") {
 					// this is a module in a soong namespace
@@ -423,8 +439,9 @@
 // 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 {
+func getOtherModuleLabel(ctx Bp2buildMutatorContext, dep, tag string,
+	labelFromModule func(BazelConversionPathContext, blueprint.Module) string,
+	markAsDep bool) *bazel.Label {
 	m, _ := ctx.ModuleFromName(dep)
 	// The module was not found in an Android.bp file, this is often due to:
 	//		* a limited manifest
@@ -435,6 +452,35 @@
 			Label: ":" + dep + "__BP2BUILD__MISSING__DEP",
 		}
 	}
+	// Returns true if a dependency from the current module to the target module
+	// should be skipped; doing so is a hack to circumvent certain problematic
+	// scenarios that will be addressed in the future.
+	shouldSkipDep := func(dep string) bool {
+		// Don't count dependencies of "libc". This is a hack to circumvent the
+		// fact that, in a variantless build graph, "libc" has a dependency on itself.
+		if ctx.ModuleName() == "libc" {
+			return true
+		}
+
+		// TODO: b/303307672: Dependencies on this module happen to "work" because
+		// there is a source file with the same name as this module in the
+		// same directory. We should remove this hack and enforce the underlying
+		// module of this name is the actual one used.
+		if dep == "mke2fs.conf" {
+			return true
+		}
+
+		// TODO: b/303310285: Remove this special-casing once all dependencies of
+		// crtbegin_dynamic are convertible
+		if ctx.ModuleName() == "crtbegin_dynamic" {
+			return true
+		}
+
+		return false
+	}
+	if markAsDep && !shouldSkipDep(dep) {
+		ctx.AddDependency(ctx.Module(), Bp2buildDepTag, dep)
+	}
 	if !convertedToBazel(ctx, m) {
 		ctx.AddUnconvertedBp2buildDep(dep)
 	}
@@ -442,6 +488,10 @@
 	otherLabel := labelFromModule(ctx, m)
 
 	// TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets.
+	if (tag != "" && m.Name() == "framework-res") ||
+		(tag == ".generated_srcjars" && ctx.OtherModuleType(m) == "java_aconfig_library") {
+		otherLabel += tag
+	}
 
 	if samePackage(label, otherLabel) {
 		otherLabel = bazelShortLabel(otherLabel)
diff --git a/android/config.go b/android/config.go
index d7d48c3..a69adc3 100644
--- a/android/config.go
+++ b/android/config.go
@@ -99,7 +99,7 @@
 
 	UseBazelProxy bool
 
-	BuildFromTextStub bool
+	BuildFromSourceStub bool
 
 	EnsureAllowlistIntegrity bool
 }
@@ -179,6 +179,15 @@
 			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).
@@ -198,21 +207,23 @@
 }
 
 // The aconfig value set passed to aconfig, derived from RELEASE_VERSION
-func (c Config) ReleaseAconfigValueSets() string {
+func (c Config) ReleaseAconfigValueSets() []string {
 	// This logic to handle both Soong module name and bazel target is temporary in order to
 	// provide backward compatibility where aosp and internal both have the release
 	// aconfig value set but can't be updated at the same time to use bazel target
-	value := strings.Split(c.config.productVariables.ReleaseAconfigValueSets, ":")
-	value_len := len(value)
-	if value_len > 2 {
-		// This shouldn't happen as this should be either a module name or a bazel target path.
-		panic(fmt.Errorf("config file: invalid value for release aconfig value sets: %s",
-			c.config.productVariables.ReleaseAconfigValueSets))
+	var valueSets []string
+	for _, valueSet := range c.config.productVariables.ReleaseAconfigValueSets {
+		value := strings.Split(valueSet, ":")
+		valueLen := len(value)
+		if valueLen > 2 {
+			// This shouldn't happen as this should be either a module name or a bazel target path.
+			panic(fmt.Errorf("config file: invalid value for release aconfig value sets: %s", valueSet))
+		}
+		if valueLen > 0 {
+			valueSets = append(valueSets, value[valueLen-1])
+		}
 	}
-	if value_len > 0 {
-		return value[value_len-1]
-	}
-	return ""
+	return valueSets
 }
 
 // The flag default permission value passed to aconfig
@@ -221,6 +232,13 @@
 	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)
+}
+
 // 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.
@@ -326,9 +344,9 @@
 	// unix sockets, instead of spawning Bazel as a subprocess.
 	UseBazelProxy bool
 
-	// If buildFromTextStub is true then the Java API stubs are
-	// built from the signature text files, not the source Java files.
-	buildFromTextStub bool
+	// If buildFromSourceStub is true then the Java API stubs are
+	// built from the source Java files, not the signature text files.
+	buildFromSourceStub bool
 
 	// If ensureAllowlistIntegrity is true, then the presence of any allowlisted
 	// modules that aren't mixed-built for at least one variant will cause a build
@@ -545,15 +563,13 @@
 		MultitreeBuild: cmdArgs.MultitreeBuild,
 		UseBazelProxy:  cmdArgs.UseBazelProxy,
 
-		buildFromTextStub: cmdArgs.BuildFromTextStub,
+		buildFromSourceStub: cmdArgs.BuildFromSourceStub,
 	}
 
 	config.deviceConfig = &deviceConfig{
 		config: config,
 	}
 
-	config.productVariables.Build_from_text_stub = boolPtr(config.buildFromTextStub)
-
 	// Soundness check of the build and source directories. This won't catch strange
 	// configurations with symlinks, but at least checks the obvious case.
 	absBuildDir, err := filepath.Abs(cmdArgs.SoongOutDir)
@@ -672,6 +688,7 @@
 		"framework-connectivity":            {},
 		"framework-connectivity-t":          {},
 		"framework-graphics":                {},
+		"framework-location":                {},
 		"framework-media":                   {},
 		"framework-mediaprovider":           {},
 		"framework-ondevicepersonalization": {},
@@ -689,6 +706,8 @@
 		"i18n.module.public.api":            {},
 	}
 
+	config.productVariables.Build_from_text_stub = boolPtr(config.BuildFromTextStub())
+
 	return Config{config}, err
 }
 
@@ -779,7 +798,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
 }
 
@@ -788,12 +807,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
 }
 
@@ -802,7 +821,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.
@@ -890,6 +909,10 @@
 	return c.katiEnabled
 }
 
+func (c *config) ProductVariables() ProductVariables {
+	return c.productVariables
+}
+
 func (c *config) BuildId() string {
 	return String(c.productVariables.BuildId)
 }
@@ -1000,12 +1023,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
 }
@@ -1435,16 +1464,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 {
@@ -2023,10 +2048,9 @@
 	}
 }
 
-func (c *config) HasBazelBuildTargetInSource(ctx BaseModuleContext) bool {
-	moduleName := ctx.Module().Name()
-	for _, buildTarget := range c.bazelTargetsByDir[ctx.ModuleDir()] {
-		if moduleName == buildTarget {
+func (c *config) HasBazelBuildTargetInSource(dir string, target string) bool {
+	for _, existingTarget := range c.bazelTargetsByDir[dir] {
+		if target == existingTarget {
 			return true
 		}
 	}
@@ -2048,12 +2072,25 @@
 		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)
 }
 
@@ -2082,3 +2119,58 @@
 func (c *deviceConfig) CheckVendorSeappViolations() bool {
 	return Bool(c.config.productVariables.CheckVendorSeappViolations)
 }
+
+func (c *deviceConfig) NextReleaseHideFlaggedApi() bool {
+	return Bool(c.config.productVariables.NextReleaseHideFlaggedApi)
+}
+
+func (c *deviceConfig) ReleaseExposeFlaggedApi() bool {
+	return Bool(c.config.productVariables.Release_expose_flagged_api)
+}
+
+func (c *deviceConfig) HideFlaggedApis() bool {
+	return c.NextReleaseHideFlaggedApi() && !c.ReleaseExposeFlaggedApi()
+}
+
+func (c *config) GetBuildFlag(name string) (string, bool) {
+	val, ok := c.productVariables.BuildFlags[name]
+	return val, ok
+}
+
+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 2beeb51..b632e33 100644
--- a/android/config_bp2build.go
+++ b/android/config_bp2build.go
@@ -201,7 +201,7 @@
 			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))
+			panic(fmt.Errorf("%q expands to more than one string value: %q", variableValue, expandedVar))
 		}
 		ret = append(ret, bazelConstant{
 			variableName:       k,
diff --git a/android/depset_generic.go b/android/depset_generic.go
index 9f07596..45c1937 100644
--- a/android/depset_generic.go
+++ b/android/depset_generic.go
@@ -95,12 +95,6 @@
 	}
 }
 
-// AddDirectToDepSet returns a new DepSet with additional elements added to its direct set.
-// The transitive sets remain untouched.
-func AddDirectToDepSet[T depSettableType](d *DepSet[T], direct ...T) *DepSet[T] {
-	return NewDepSet[T](d.order, Concat(d.direct, direct), d.transitive)
-}
-
 // DepSetBuilder is used to create an immutable DepSet.
 type DepSetBuilder[T depSettableType] struct {
 	order      DepSetOrder
@@ -194,14 +188,3 @@
 	}
 	return list
 }
-
-// ToListDirect returns the direct elements of a DepSet flattened to a list.
-func (d *DepSet[T]) ToListDirect() []T {
-	if d == nil {
-		return nil
-	}
-	list := make([]T, len(d.direct))
-	copy(list, d.direct)
-	list = firstUniqueInPlace(list)
-	return list
-}
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 a4bbcae..856c50e 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -22,7 +22,6 @@
 	"android/soong/bazel"
 	"android/soong/bazel/cquery"
 	"android/soong/ui/metrics/bp2build_metrics_proto"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -51,7 +50,7 @@
 	// 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]|$)")
+	filegroupLikelyAidlPattern  = regexp.MustCompile("(?i)(^|[^a-z])aidl(s)?([^a-z]|$)")
 
 	ProtoSrcLabelPartition = bazel.LabelPartition{
 		Extensions:  []string{".proto"},
@@ -86,12 +85,6 @@
 	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 Bp2buildMutatorContext) {
 	srcs := bazel.MakeLabelListAttribute(
@@ -112,8 +105,10 @@
 		if f.Label == fg.Name() {
 			if len(srcs.Value.Includes) > 1 {
 				ctx.ModuleErrorf("filegroup '%s' cannot contain a file with the same name", fg.Name())
+				ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_SRC_NAME_COLLISION, "")
+			} else {
+				panic("This situation should have been handled by FileGroupFactory's call to InitBazelModuleAsHandcrafted")
 			}
-			ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_SRC_NAME_COLLISION, "")
 			return
 		}
 	}
@@ -259,6 +254,16 @@
 	module.AddProperties(&module.properties)
 	InitAndroidModule(module)
 	InitBazelModule(module)
+	AddBazelHandcraftedHook(module, func(ctx LoadHookContext) string {
+		// If there is a single src with the same name as the filegroup module name,
+		// then don't generate this filegroup. It will be OK for other targets
+		// to depend on this source file by name directly.
+		fg := ctx.Module().(*fileGroup)
+		if len(fg.properties.Srcs) == 1 && fg.Name() == fg.properties.Srcs[0] {
+			return fg.Name()
+		}
+		return ""
+	})
 	InitDefaultableModule(module)
 	return module
 }
diff --git a/android/metrics.go b/android/metrics.go
index 63c72cd..3571272 100644
--- a/android/metrics.go
+++ b/android/metrics.go
@@ -15,9 +15,13 @@
 package android
 
 import (
+	"bytes"
 	"io/ioutil"
+	"os"
 	"runtime"
 	"sort"
+	"strconv"
+	"time"
 
 	"github.com/google/blueprint/metrics"
 	"google.golang.org/protobuf/proto"
@@ -27,18 +31,21 @@
 
 var soongMetricsOnceKey = NewOnceKey("soong metrics")
 
-type SoongMetrics struct {
-	Modules  int
-	Variants int
+type soongMetrics struct {
+	modules       int
+	variants      int
+	perfCollector perfCollector
 }
 
-func readSoongMetrics(config Config) (SoongMetrics, bool) {
-	soongMetrics, ok := config.Peek(soongMetricsOnceKey)
-	if ok {
-		return soongMetrics.(SoongMetrics), true
-	} else {
-		return SoongMetrics{}, false
-	}
+type perfCollector struct {
+	events []*soong_metrics_proto.PerfCounters
+	stop   chan<- bool
+}
+
+func getSoongMetrics(config Config) *soongMetrics {
+	return config.Once(soongMetricsOnceKey, func() interface{} {
+		return &soongMetrics{}
+	}).(*soongMetrics)
 }
 
 func init() {
@@ -50,27 +57,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)
@@ -107,6 +114,113 @@
 	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 f48af4a..af69a1b 100644
--- a/android/module.go
+++ b/android/module.go
@@ -15,22 +15,17 @@
 package android
 
 import (
+	"android/soong/bazel"
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 	"crypto/md5"
 	"encoding/hex"
 	"encoding/json"
 	"fmt"
 	"net/url"
-	"os"
-	"path"
 	"path/filepath"
 	"reflect"
-	"regexp"
 	"sort"
 	"strings"
-	"text/scanner"
-
-	"android/soong/bazel"
-	"android/soong/ui/metrics/bp2build_metrics_proto"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -41,470 +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)
-
-	// getMissingDependencies returns the list of missing dependencies.
-	// Calling this function prevents adding new dependencies.
-	getMissingDependencies() []string
-
-	// AddUnconvertedBp2buildDep stores module name of a direct dependency that was not converted via bp2build
-	AddUnconvertedBp2buildDep(dep string)
-
-	// AddMissingBp2buildDep stores the module name of a direct dependency that was not found.
-	AddMissingBp2buildDep(dep string)
-
-	Target() Target
-	TargetPrimary() bool
-
-	// The additional arch specific targets (e.g. 32/64 bit) that this module variant is
-	// responsible for creating.
-	MultiTargets() []Target
-	Arch() Arch
-	Os() OsType
-	Host() bool
-	Device() bool
-	Darwin() bool
-	Windows() bool
-	Debug() bool
-	PrimaryArch() bool
-}
-
-// Deprecated: use EarlyModuleContext instead
-type BaseContext interface {
-	EarlyModuleContext
-}
-
-type ModuleContext interface {
-	BaseModuleContext
-
-	blueprintModuleContext() blueprint.ModuleContext
-
-	// Deprecated: use ModuleContext.Build instead.
-	ModuleBuild(pctx PackageContext, params ModuleBuildParams)
-
-	// Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must
-	// be tagged with `android:"path" to support automatic source module dependency resolution.
-	//
-	// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
-	ExpandSources(srcFiles, excludes []string) Paths
-
-	// Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must
-	// be tagged with `android:"path" to support automatic source module dependency resolution.
-	//
-	// Deprecated: use PathForModuleSrc instead.
-	ExpandSource(srcFile, prop string) Path
-
-	ExpandOptionalSource(srcFile *string, prop string) OptionalPath
-
-	// InstallExecutable creates a rule to copy srcPath to name in the installPath directory,
-	// with the given additional dependencies.  The file is marked executable after copying.
-	//
-	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
-	// installed file will be returned by PackagingSpecs() on this module or by
-	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
-	// for which IsInstallDepNeeded returns true.
-	InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
-
-	// InstallFile creates a rule to copy srcPath to name in the installPath directory,
-	// with the given additional dependencies.
-	//
-	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
-	// installed file will be returned by PackagingSpecs() on this module or by
-	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
-	// for which IsInstallDepNeeded returns true.
-	InstallFile(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
-
-	// InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath
-	// directory, and also unzip a zip file containing extra files to install into the same
-	// directory.
-	//
-	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
-	// installed file will be returned by PackagingSpecs() on this module or by
-	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
-	// for which IsInstallDepNeeded returns true.
-	InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...Path) InstallPath
-
-	// InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath
-	// directory.
-	//
-	// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
-	// installed file will be returned by PackagingSpecs() on this module or by
-	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
-	// for which IsInstallDepNeeded returns true.
-	InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath
-
-	// InstallAbsoluteSymlink creates a rule to create an absolute symlink from src srcPath to name
-	// in the installPath directory.
-	//
-	// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
-	// installed file will be returned by PackagingSpecs() on this module or by
-	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
-	// for which IsInstallDepNeeded returns true.
-	InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath
-
-	// PackageFile creates a PackagingSpec as if InstallFile was called, but without creating
-	// the rule to copy the file.  This is useful to define how a module would be packaged
-	// without installing it into the global installation directories.
-	//
-	// The created PackagingSpec for the will be returned by PackagingSpecs() on this module or by
-	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
-	// for which IsInstallDepNeeded returns true.
-	PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec
-
-	CheckbuildFile(srcPath Path)
-
-	InstallInData() bool
-	InstallInTestcases() bool
-	InstallInSanitizerDir() bool
-	InstallInRamdisk() bool
-	InstallInVendorRamdisk() bool
-	InstallInDebugRamdisk() bool
-	InstallInRecovery() bool
-	InstallInRoot() bool
-	InstallInVendor() bool
-	InstallForceOS() (*OsType, *ArchType)
-
-	RequiredModuleNames() []string
-	HostRequiredModuleNames() []string
-	TargetRequiredModuleNames() []string
-
-	ModuleSubDir() string
-	SoongConfigTraceHash() string
-
-	Variable(pctx PackageContext, name, value string)
-	Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
-	// Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string,
-	// and performs more verification.
-	Build(pctx PackageContext, params BuildParams)
-	// Phony creates a Make-style phony rule, a rule with no commands that can depend on other
-	// phony rules or real files.  Phony can be called on the same name multiple times to add
-	// additional dependencies.
-	Phony(phony string, deps ...Path)
-
-	// GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods,
-	// but do not exist.
-	GetMissingDependencies() []string
-
-	// LicenseMetadataFile returns the path where the license metadata for this module will be
-	// generated.
-	LicenseMetadataFile() Path
-}
-
 type Module interface {
 	blueprint.Module
 
@@ -565,14 +96,15 @@
 	AddProperties(props ...interface{})
 	GetProperties() []interface{}
 
-	// IsConvertedByBp2build returns whether this module was converted via bp2build
-	IsConvertedByBp2build() bool
+	// If this module should not have bazel BUILD definitions generated by bp2build,
+	// GetUnconvertedReason returns a reason this is the case.
 	GetUnconvertedReason() *UnconvertedReason
 
 	// Bp2buildTargets returns the target(s) generated for Bazel via bp2build for this module
 	Bp2buildTargets() []bp2buildInfo
 	GetUnconvertedBp2buildDeps() []string
 	GetMissingBp2buildDeps() []string
+	GetPartitionForBp2build() string
 
 	BuildParamsForTests() []BuildParams
 	RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams
@@ -1272,7 +804,23 @@
 	m.base().commonProperties.CreateCommonOSVariant = true
 }
 
-func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutatorContext,
+func (attrs *CommonAttributes) getRequiredWithoutCycles(ctx *bottomUpMutatorContext, props *commonProperties) []string {
+	// Treat `required` as if it's empty if data should be skipped for this target,
+	// as `required` is only used for the `data` attribute at this time, and we want
+	// to avoid lookups of labels that won't actually be dependencies of this target.
+	// TODO: b/202299295 - Refactor this to use `required` dependencies, once they
+	// are handled other than passing to `data`.
+	if proptools.Bool(attrs.SkipData) {
+		return []string{}
+	}
+	// 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(), props.Required)
+	return FirstUniqueStrings(requiredWithoutCycles)
+}
+
+func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *bottomUpMutatorContext,
 	enabledPropertyOverrides bazel.BoolAttribute) constraintAttributes {
 
 	mod := ctx.Module().base()
@@ -1340,18 +888,13 @@
 
 	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)
+	requiredWithoutCycles := attrs.getRequiredWithoutCycles(ctx, &mod.commonProperties)
 	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)
+				requiredWithoutCycles := attrs.getRequiredWithoutCycles(ctx, archProps)
 				required.SetSelectValue(axis, config, depsToLabelList(requiredWithoutCycles).Value)
 				if !neitherHostNorDevice {
 					if archProps.Enabled != nil {
@@ -1408,9 +951,8 @@
 		platformEnabledAttribute.Add(&l)
 	}
 
-	if !proptools.Bool(attrs.SkipData) {
-		attrs.Data.Append(required)
-	}
+	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
@@ -1430,7 +972,7 @@
 // If compile_mulitilib is set to
 // 1. 32: Add an incompatibility constraint for non-32 arches
 // 1. 64: Add an incompatibility constraint for non-64 arches
-func addCompatibilityConstraintForCompileMultilib(ctx *topDownMutatorContext, enabled *bazel.LabelListAttribute) {
+func addCompatibilityConstraintForCompileMultilib(ctx *bottomUpMutatorContext, enabled *bazel.LabelListAttribute) {
 	mod := ctx.Module().base()
 	multilib, _ := decodeMultilib(mod, mod.commonProperties.CompileOS, ctx.Config().IgnorePrefer32OnDevice())
 
@@ -1456,7 +998,7 @@
 
 // Check product variables for `enabled: true` flag override.
 // Returns a list of the constraint_value targets who enable this override.
-func productVariableConfigEnableAttribute(ctx *topDownMutatorContext) bazel.LabelListAttribute {
+func productVariableConfigEnableAttribute(ctx *bottomUpMutatorContext) bazel.LabelListAttribute {
 	result := bazel.LabelListAttribute{}
 	productVariableProps, errs := ProductVariableProperties(ctx, ctx.Module())
 	for _, err := range errs {
@@ -1639,35 +1181,20 @@
 }
 
 func (m *ModuleBase) addBp2buildInfo(info bp2buildInfo) {
-	reason := m.commonProperties.BazelConversionStatus.UnconvertedReason
-	if reason != nil {
-		panic(fmt.Errorf("bp2build: internal error trying to convert module '%s' marked unconvertible. Reason type %d: %s",
-			m.Name(),
-			reason.ReasonType,
-			reason.Detail))
-	}
 	m.commonProperties.BazelConversionStatus.Bp2buildInfo = append(m.commonProperties.BazelConversionStatus.Bp2buildInfo, info)
 }
 
+func (m *ModuleBase) setPartitionForBp2build(partition string) {
+	m.commonProperties.BazelConversionStatus.Partition = partition
+}
+
 func (m *ModuleBase) setBp2buildUnconvertible(reasonType bp2build_metrics_proto.UnconvertedReasonType, detail string) {
-	if len(m.commonProperties.BazelConversionStatus.Bp2buildInfo) > 0 {
-		fmt.Println(m.commonProperties.BazelConversionStatus.Bp2buildInfo)
-		panic(fmt.Errorf("bp2build: internal error trying to mark converted module '%s' as unconvertible. Reason type %d: %s",
-			m.Name(),
-			reasonType,
-			detail))
-	}
 	m.commonProperties.BazelConversionStatus.UnconvertedReason = &UnconvertedReason{
 		ReasonType: int(reasonType),
 		Detail:     detail,
 	}
 }
 
-// IsConvertedByBp2build returns whether this module was converted via bp2build.
-func (m *ModuleBase) IsConvertedByBp2build() bool {
-	return len(m.commonProperties.BazelConversionStatus.Bp2buildInfo) > 0
-}
-
 func (m *ModuleBase) GetUnconvertedReason() *UnconvertedReason {
 	return m.commonProperties.BazelConversionStatus.UnconvertedReason
 }
@@ -1677,16 +1204,9 @@
 	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)
+// Bp2buildTargets returns the Bazel targets bp2build generated for this module.
+func (m *ModuleBase) GetPartitionForBp2build() string {
+	return m.commonProperties.BazelConversionStatus.Partition
 }
 
 // GetUnconvertedBp2buildDeps returns the list of module names of this module's direct dependencies that
@@ -2605,163 +2125,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
@@ -2805,527 +2168,6 @@
 	return paths
 }
 
-func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContext, BuildParams) {
-	return pctx, BuildParams{
-		Rule:            ErrorRule,
-		Description:     params.Description,
-		Output:          params.Output,
-		Outputs:         params.Outputs,
-		ImplicitOutput:  params.ImplicitOutput,
-		ImplicitOutputs: params.ImplicitOutputs,
-		Args: map[string]string{
-			"error": err.Error(),
-		},
-	}
-}
-
-func (m *moduleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) {
-	m.Build(pctx, BuildParams(params))
-}
-
-func validateBuildParams(params blueprint.BuildParams) error {
-	// Validate that the symlink outputs are declared outputs or implicit outputs
-	allOutputs := map[string]bool{}
-	for _, output := range params.Outputs {
-		allOutputs[output] = true
-	}
-	for _, output := range params.ImplicitOutputs {
-		allOutputs[output] = true
-	}
-	for _, symlinkOutput := range params.SymlinkOutputs {
-		if !allOutputs[symlinkOutput] {
-			return fmt.Errorf(
-				"Symlink output %s is not a declared output or implicit output",
-				symlinkOutput)
-		}
-	}
-	return nil
-}
-
-// Convert build parameters from their concrete Android types into their string representations,
-// and combine the singular and plural fields of the same type (e.g. Output and Outputs).
-func convertBuildParams(params BuildParams) blueprint.BuildParams {
-	bparams := blueprint.BuildParams{
-		Rule:            params.Rule,
-		Description:     params.Description,
-		Deps:            params.Deps,
-		Outputs:         params.Outputs.Strings(),
-		ImplicitOutputs: params.ImplicitOutputs.Strings(),
-		SymlinkOutputs:  params.SymlinkOutputs.Strings(),
-		Inputs:          params.Inputs.Strings(),
-		Implicits:       params.Implicits.Strings(),
-		OrderOnly:       params.OrderOnly.Strings(),
-		Validations:     params.Validations.Strings(),
-		Args:            params.Args,
-		Optional:        !params.Default,
-	}
-
-	if params.Depfile != nil {
-		bparams.Depfile = params.Depfile.String()
-	}
-	if params.Output != nil {
-		bparams.Outputs = append(bparams.Outputs, params.Output.String())
-	}
-	if params.SymlinkOutput != nil {
-		bparams.SymlinkOutputs = append(bparams.SymlinkOutputs, params.SymlinkOutput.String())
-	}
-	if params.ImplicitOutput != nil {
-		bparams.ImplicitOutputs = append(bparams.ImplicitOutputs, params.ImplicitOutput.String())
-	}
-	if params.Input != nil {
-		bparams.Inputs = append(bparams.Inputs, params.Input.String())
-	}
-	if params.Implicit != nil {
-		bparams.Implicits = append(bparams.Implicits, params.Implicit.String())
-	}
-	if params.Validation != nil {
-		bparams.Validations = append(bparams.Validations, params.Validation.String())
-	}
-
-	bparams.Outputs = proptools.NinjaEscapeList(bparams.Outputs)
-	bparams.ImplicitOutputs = proptools.NinjaEscapeList(bparams.ImplicitOutputs)
-	bparams.SymlinkOutputs = proptools.NinjaEscapeList(bparams.SymlinkOutputs)
-	bparams.Inputs = proptools.NinjaEscapeList(bparams.Inputs)
-	bparams.Implicits = proptools.NinjaEscapeList(bparams.Implicits)
-	bparams.OrderOnly = proptools.NinjaEscapeList(bparams.OrderOnly)
-	bparams.Validations = proptools.NinjaEscapeList(bparams.Validations)
-	bparams.Depfile = proptools.NinjaEscape(bparams.Depfile)
-
-	return bparams
-}
-
-func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
-	if m.config.captureBuild {
-		m.variables[name] = value
-	}
-
-	m.bp.Variable(pctx.PackageContext, name, value)
-}
-
-func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
-	argNames ...string) blueprint.Rule {
-
-	if m.config.UseRemoteBuild() {
-		if params.Pool == nil {
-			// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
-			// jobs to the local parallelism value
-			params.Pool = localPool
-		} else if params.Pool == remotePool {
-			// remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
-			// pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
-			// parallelism.
-			params.Pool = nil
-		}
-	}
-
-	rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...)
-
-	if m.config.captureBuild {
-		m.ruleParams[rule] = params
-	}
-
-	return rule
-}
-
-func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
-	if params.Description != "" {
-		params.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}"
-	}
-
-	if missingDeps := m.GetMissingDependencies(); len(missingDeps) > 0 {
-		pctx, params = m.ninjaError(params, fmt.Errorf("module %s missing dependencies: %s\n",
-			m.ModuleName(), strings.Join(missingDeps, ", ")))
-	}
-
-	if m.config.captureBuild {
-		m.buildParams = append(m.buildParams, params)
-	}
-
-	bparams := convertBuildParams(params)
-	err := validateBuildParams(bparams)
-	if err != nil {
-		m.ModuleErrorf(
-			"%s: build parameter validation failed: %s",
-			m.ModuleName(),
-			err.Error())
-	}
-	m.bp.Build(pctx.PackageContext, bparams)
-}
-
-func (m *moduleContext) Phony(name string, deps ...Path) {
-	addPhony(m.config, name, deps...)
-}
-
-func (m *moduleContext) GetMissingDependencies() []string {
-	var missingDeps []string
-	missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...)
-	missingDeps = append(missingDeps, m.bp.GetMissingDependencies()...)
-	missingDeps = FirstUniqueStrings(missingDeps)
-	return missingDeps
-}
-
-func (b *baseModuleContext) AddMissingDependencies(deps []string) {
-	if deps != nil {
-		missingDeps := &b.Module().base().commonProperties.MissingDeps
-		*missingDeps = append(*missingDeps, deps...)
-		*missingDeps = FirstUniqueStrings(*missingDeps)
-	}
-}
-
-func (b *baseModuleContext) checkedMissingDeps() bool {
-	return b.Module().base().commonProperties.CheckedMissingDeps
-}
-
-func (b *baseModuleContext) getMissingDependencies() []string {
-	checked := &b.Module().base().commonProperties.CheckedMissingDeps
-	*checked = true
-	var missingDeps []string
-	missingDeps = append(missingDeps, b.Module().base().commonProperties.MissingDeps...)
-	missingDeps = append(missingDeps, b.bp.EarlyGetMissingDependencies()...)
-	missingDeps = FirstUniqueStrings(missingDeps)
-	return missingDeps
-}
-
-type AllowDisabledModuleDependency interface {
-	blueprint.DependencyTag
-	AllowDisabledModuleDependency(target Module) bool
-}
-
-func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool) Module {
-	aModule, _ := module.(Module)
-
-	if !strict {
-		return aModule
-	}
-
-	if aModule == nil {
-		b.ModuleErrorf("module %q (%#v) not an android module", b.OtherModuleName(module), tag)
-		return nil
-	}
-
-	if !aModule.Enabled() {
-		if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependency(aModule) {
-			if b.Config().AllowMissingDependencies() {
-				b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
-			} else {
-				b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
-			}
-		}
-		return nil
-	}
-	return aModule
-}
-
-type dep struct {
-	mod blueprint.Module
-	tag blueprint.DependencyTag
-}
-
-func (b *baseModuleContext) getDirectDepsInternal(name string, tag blueprint.DependencyTag) []dep {
-	var deps []dep
-	b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
-		if aModule, _ := module.(Module); aModule != nil {
-			if aModule.base().BaseModuleName() == name {
-				returnedTag := b.bp.OtherModuleDependencyTag(aModule)
-				if tag == nil || returnedTag == tag {
-					deps = append(deps, dep{aModule, returnedTag})
-				}
-			}
-		} else if b.bp.OtherModuleName(module) == name {
-			returnedTag := b.bp.OtherModuleDependencyTag(module)
-			if tag == nil || returnedTag == tag {
-				deps = append(deps, dep{module, returnedTag})
-			}
-		}
-	})
-	return deps
-}
-
-func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) {
-	deps := b.getDirectDepsInternal(name, tag)
-	if len(deps) == 1 {
-		return deps[0].mod, deps[0].tag
-	} else if len(deps) >= 2 {
-		panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
-			name, b.ModuleName()))
-	} else {
-		return nil, nil
-	}
-}
-
-func (b *baseModuleContext) getDirectDepFirstTag(name string) (blueprint.Module, blueprint.DependencyTag) {
-	foundDeps := b.getDirectDepsInternal(name, nil)
-	deps := map[blueprint.Module]bool{}
-	for _, dep := range foundDeps {
-		deps[dep.mod] = true
-	}
-	if len(deps) == 1 {
-		return foundDeps[0].mod, foundDeps[0].tag
-	} else if len(deps) >= 2 {
-		// this could happen if two dependencies have the same name in different namespaces
-		// TODO(b/186554727): this should not occur if namespaces are handled within
-		// getDirectDepsInternal.
-		panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
-			name, b.ModuleName()))
-	} else {
-		return nil, nil
-	}
-}
-
-func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module {
-	var deps []Module
-	b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
-		if aModule, _ := module.(Module); aModule != nil {
-			if b.bp.OtherModuleDependencyTag(aModule) == tag {
-				deps = append(deps, aModule)
-			}
-		}
-	})
-	return deps
-}
-
-func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
-	module, _ := m.getDirectDepInternal(name, tag)
-	return module
-}
-
-// GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified
-// name, or nil if none exists. If there are multiple dependencies on the same module it returns the
-// first DependencyTag.
-func (b *baseModuleContext) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) {
-	return b.getDirectDepFirstTag(name)
-}
-
-func (b *baseModuleContext) ModuleFromName(name string) (blueprint.Module, bool) {
-	if !b.isBazelConversionMode() {
-		panic("cannot call ModuleFromName if not in bazel conversion mode")
-	}
-	var m blueprint.Module
-	var ok bool
-	if moduleName, _ := SrcIsModuleWithTag(name); moduleName != "" {
-		m, ok = b.bp.ModuleFromName(moduleName)
-	} else {
-		m, ok = b.bp.ModuleFromName(name)
-	}
-	if !ok {
-		return m, ok
-	}
-	// If this module is not preferred, tried to get the prebuilt version instead
-	if a, aOk := m.(Module); aOk && !IsModulePrebuilt(a) && !IsModulePreferred(a) {
-		return b.ModuleFromName("prebuilt_" + name)
-	}
-	return m, ok
-}
-
-func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) {
-	b.bp.VisitDirectDeps(visit)
-}
-
-func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) {
-	b.bp.VisitDirectDeps(func(module blueprint.Module) {
-		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
-			visit(aModule)
-		}
-	})
-}
-
-func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
-	b.bp.VisitDirectDeps(func(module blueprint.Module) {
-		if b.bp.OtherModuleDependencyTag(module) == tag {
-			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
-				visit(aModule)
-			}
-		}
-	})
-}
-
-func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
-	b.bp.VisitDirectDepsIf(
-		// pred
-		func(module blueprint.Module) bool {
-			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
-				return pred(aModule)
-			} else {
-				return false
-			}
-		},
-		// visit
-		func(module blueprint.Module) {
-			visit(module.(Module))
-		})
-}
-
-func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
-	b.bp.VisitDepsDepthFirst(func(module blueprint.Module) {
-		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
-			visit(aModule)
-		}
-	})
-}
-
-func (b *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) {
-	b.bp.VisitDepsDepthFirstIf(
-		// pred
-		func(module blueprint.Module) bool {
-			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
-				return pred(aModule)
-			} else {
-				return false
-			}
-		},
-		// visit
-		func(module blueprint.Module) {
-			visit(module.(Module))
-		})
-}
-
-func (b *baseModuleContext) WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) {
-	b.bp.WalkDeps(visit)
-}
-
-func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
-	b.walkPath = []Module{b.Module()}
-	b.tagPath = []blueprint.DependencyTag{}
-	b.bp.WalkDeps(func(child, parent blueprint.Module) bool {
-		childAndroidModule, _ := child.(Module)
-		parentAndroidModule, _ := parent.(Module)
-		if childAndroidModule != nil && parentAndroidModule != nil {
-			// record walkPath before visit
-			for b.walkPath[len(b.walkPath)-1] != parentAndroidModule {
-				b.walkPath = b.walkPath[0 : len(b.walkPath)-1]
-				b.tagPath = b.tagPath[0 : len(b.tagPath)-1]
-			}
-			b.walkPath = append(b.walkPath, childAndroidModule)
-			b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule))
-			return visit(childAndroidModule, parentAndroidModule)
-		} else {
-			return false
-		}
-	})
-}
-
-func (b *baseModuleContext) GetWalkPath() []Module {
-	return b.walkPath
-}
-
-func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag {
-	return b.tagPath
-}
-
-func (b *baseModuleContext) VisitAllModuleVariants(visit func(Module)) {
-	b.bp.VisitAllModuleVariants(func(module blueprint.Module) {
-		visit(module.(Module))
-	})
-}
-
-func (b *baseModuleContext) PrimaryModule() Module {
-	return b.bp.PrimaryModule().(Module)
-}
-
-func (b *baseModuleContext) FinalModule() Module {
-	return b.bp.FinalModule().(Module)
-}
-
-// IsMetaDependencyTag returns true for cross-cutting metadata dependencies.
-func IsMetaDependencyTag(tag blueprint.DependencyTag) bool {
-	if tag == licenseKindTag {
-		return true
-	} else if tag == licensesTag {
-		return true
-	}
-	return false
-}
-
-// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
-// a dependency tag.
-var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:{}\E(, )?`)
-
-// PrettyPrintTag returns string representation of the tag, but prefers
-// custom String() method if available.
-func PrettyPrintTag(tag blueprint.DependencyTag) string {
-	// Use tag's custom String() method if available.
-	if stringer, ok := tag.(fmt.Stringer); ok {
-		return stringer.String()
-	}
-
-	// Otherwise, get a default string representation of the tag's struct.
-	tagString := fmt.Sprintf("%T: %+v", tag, tag)
-
-	// Remove the boilerplate from BaseDependencyTag as it adds no value.
-	tagString = tagCleaner.ReplaceAllString(tagString, "")
-	return tagString
-}
-
-func (b *baseModuleContext) GetPathString(skipFirst bool) string {
-	sb := strings.Builder{}
-	tagPath := b.GetTagPath()
-	walkPath := b.GetWalkPath()
-	if !skipFirst {
-		sb.WriteString(walkPath[0].String())
-	}
-	for i, m := range walkPath[1:] {
-		sb.WriteString("\n")
-		sb.WriteString(fmt.Sprintf("           via tag %s\n", PrettyPrintTag(tagPath[i])))
-		sb.WriteString(fmt.Sprintf("    -> %s", m.String()))
-	}
-	return sb.String()
-}
-
-func (m *moduleContext) ModuleSubDir() string {
-	return m.bp.ModuleSubDir()
-}
-
-func (m *moduleContext) SoongConfigTraceHash() string {
-	return m.module.base().commonProperties.SoongConfigTraceHash
-}
-
-func (b *baseModuleContext) Target() Target {
-	return b.target
-}
-
-func (b *baseModuleContext) TargetPrimary() bool {
-	return b.targetPrimary
-}
-
-func (b *baseModuleContext) MultiTargets() []Target {
-	return b.multiTargets
-}
-
-func (b *baseModuleContext) Arch() Arch {
-	return b.target.Arch
-}
-
-func (b *baseModuleContext) Os() OsType {
-	return b.os
-}
-
-func (b *baseModuleContext) Host() bool {
-	return b.os.Class == Host
-}
-
-func (b *baseModuleContext) Device() bool {
-	return b.os.Class == Device
-}
-
-func (b *baseModuleContext) Darwin() bool {
-	return b.os == Darwin
-}
-
-func (b *baseModuleContext) Windows() bool {
-	return b.os == Windows
-}
-
-func (b *baseModuleContext) Debug() bool {
-	return b.debug
-}
-
-func (b *baseModuleContext) PrimaryArch() bool {
-	if len(b.config.Targets[b.target.Os]) <= 1 {
-		return true
-	}
-	return b.target.Arch.ArchType == b.config.Targets[b.target.Os][0].Arch.ArchType
-}
-
 // Makes this module a platform module, i.e. not specific to soc, device,
 // product, or system_ext.
 func (m *ModuleBase) MakeAsPlatform() {
@@ -3349,274 +2191,6 @@
 	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, InstallPaths(m.module.base().installFilesDepSet.ToList()).Paths()...)
-
-		var implicitDeps, orderOnlyDeps Paths
-
-		if m.Host() {
-			// Installed host modules might be used during the build, depend directly on their
-			// dependencies so their timestamp is updated whenever their dependency is updated
-			implicitDeps = deps
-		} else {
-			orderOnlyDeps = deps
-		}
-
-		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
-}
-
 // SrcIsModule decodes module references in the format ":unqualified-name" or "//namespace:name"
 // into the module name, or empty string if the input was not a module reference.
 func SrcIsModule(s string) (module string) {
@@ -3823,44 +2397,6 @@
 	HostToolPath() OptionalPath
 }
 
-// Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must
-// be tagged with `android:"path" to support automatic source module dependency resolution.
-//
-// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
-func (m *moduleContext) ExpandSources(srcFiles, excludes []string) Paths {
-	return PathsForModuleSrcExcludes(m, srcFiles, excludes)
-}
-
-// Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must
-// be tagged with `android:"path" to support automatic source module dependency resolution.
-//
-// Deprecated: use PathForModuleSrc instead.
-func (m *moduleContext) ExpandSource(srcFile, _ string) Path {
-	return PathForModuleSrc(m, srcFile)
-}
-
-// Returns an optional single path expanded from globs and modules referenced using ":module" syntax if
-// the srcFile is non-nil.  The property must be tagged with `android:"path" to support automatic source module
-// dependency resolution.
-func (m *moduleContext) ExpandOptionalSource(srcFile *string, _ string) OptionalPath {
-	if srcFile != nil {
-		return OptionalPathForPath(PathForModuleSrc(m, *srcFile))
-	}
-	return OptionalPath{}
-}
-
-func (m *moduleContext) RequiredModuleNames() []string {
-	return m.module.RequiredModuleNames()
-}
-
-func (m *moduleContext) HostRequiredModuleNames() []string {
-	return m.module.HostRequiredModuleNames()
-}
-
-func (m *moduleContext) TargetRequiredModuleNames() []string {
-	return m.module.TargetRequiredModuleNames()
-}
-
 func init() {
 	RegisterParallelSingletonType("buildtarget", BuildTargetSingleton)
 	RegisterParallelSingletonType("soongconfigtrace", soongConfigTraceSingletonFunc)
diff --git a/android/module_context.go b/android/module_context.go
new file mode 100644
index 0000000..0b4d28c
--- /dev/null
+++ b/android/module_context.go
@@ -0,0 +1,698 @@
+// 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"
+	"github.com/google/blueprint/proptools"
+	"path"
+	"path/filepath"
+	"strings"
+)
+
+// 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
+
+type ModuleContext interface {
+	BaseModuleContext
+
+	blueprintModuleContext() blueprint.ModuleContext
+
+	// Deprecated: use ModuleContext.Build instead.
+	ModuleBuild(pctx PackageContext, params ModuleBuildParams)
+
+	// Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must
+	// be tagged with `android:"path" to support automatic source module dependency resolution.
+	//
+	// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
+	ExpandSources(srcFiles, excludes []string) Paths
+
+	// Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must
+	// be tagged with `android:"path" to support automatic source module dependency resolution.
+	//
+	// Deprecated: use PathForModuleSrc instead.
+	ExpandSource(srcFile, prop string) Path
+
+	ExpandOptionalSource(srcFile *string, prop string) OptionalPath
+
+	// InstallExecutable creates a rule to copy srcPath to name in the installPath directory,
+	// with the given additional dependencies.  The file is marked executable after copying.
+	//
+	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
+
+	// InstallFile creates a rule to copy srcPath to name in the installPath directory,
+	// with the given additional dependencies.
+	//
+	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	InstallFile(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath
+
+	// InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath
+	// directory, and also unzip a zip file containing extra files to install into the same
+	// directory.
+	//
+	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...Path) InstallPath
+
+	// InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath
+	// directory.
+	//
+	// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath
+
+	// InstallAbsoluteSymlink creates a rule to create an absolute symlink from src srcPath to name
+	// in the installPath directory.
+	//
+	// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
+	// installed file will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath
+
+	// PackageFile creates a PackagingSpec as if InstallFile was called, but without creating
+	// the rule to copy the file.  This is useful to define how a module would be packaged
+	// without installing it into the global installation directories.
+	//
+	// The created PackagingSpec for the will be returned by PackagingSpecs() on this module or by
+	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
+	// for which IsInstallDepNeeded returns true.
+	PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec
+
+	CheckbuildFile(srcPath Path)
+
+	InstallInData() bool
+	InstallInTestcases() bool
+	InstallInSanitizerDir() bool
+	InstallInRamdisk() bool
+	InstallInVendorRamdisk() bool
+	InstallInDebugRamdisk() bool
+	InstallInRecovery() bool
+	InstallInRoot() bool
+	InstallInVendor() bool
+	InstallForceOS() (*OsType, *ArchType)
+
+	RequiredModuleNames() []string
+	HostRequiredModuleNames() []string
+	TargetRequiredModuleNames() []string
+
+	ModuleSubDir() string
+	SoongConfigTraceHash() string
+
+	Variable(pctx PackageContext, name, value string)
+	Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
+	// Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string,
+	// and performs more verification.
+	Build(pctx PackageContext, params BuildParams)
+	// Phony creates a Make-style phony rule, a rule with no commands that can depend on other
+	// phony rules or real files.  Phony can be called on the same name multiple times to add
+	// additional dependencies.
+	Phony(phony string, deps ...Path)
+
+	// GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods,
+	// but do not exist.
+	GetMissingDependencies() []string
+
+	// LicenseMetadataFile returns the path where the license metadata for this module will be
+	// generated.
+	LicenseMetadataFile() Path
+}
+
+type 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
+}
+
+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 (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) 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, InstallPaths(m.module.base().installFilesDepSet.ToList()).Paths()...)
+
+		var implicitDeps, orderOnlyDeps Paths
+
+		if m.Host() {
+			// Installed host modules might be used during the build, depend directly on their
+			// dependencies so their timestamp is updated whenever their dependency is updated
+			implicitDeps = deps
+		} else {
+			orderOnlyDeps = deps
+		}
+
+		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
+}
+
+// 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/mutator.go b/android/mutator.go
index 336f8f7..3ff9e61 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -38,13 +38,6 @@
 	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,
@@ -233,6 +226,15 @@
 	BazelConversionPathContext
 	BaseMutatorContext
 
+	// AddDependency adds a dependency to the given module.  It returns a slice of modules for each
+	// dependency (some entries may be nil).
+	//
+	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
+	// new dependencies have had the current mutator called on them.  If the mutator is not
+	// parallel this method does not affect the ordering of the current mutator pass, but will
+	// be ordered correctly for all future mutator passes.
+	AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module
+
 	// CreateBazelTargetModule creates a BazelTargetModule by calling the
 	// factory method, just like in CreateModule, but also requires
 	// BazelTargetModuleProperties containing additional metadata for the
@@ -284,7 +286,6 @@
 
 type TopDownMutatorContext interface {
 	BaseMutatorContext
-	Bp2buildMutatorContext
 
 	// 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.
@@ -300,15 +301,7 @@
 
 type BottomUpMutatorContext interface {
 	BaseMutatorContext
-
-	// AddDependency adds a dependency to the given module.  It returns a slice of modules for each
-	// dependency (some entries may be nil).
-	//
-	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
-	// new dependencies have had the current mutator called on them.  If the mutator is not
-	// parallel this method does not affect the ordering of the current mutator pass, but will
-	// be ordered correctly for all future mutator passes.
-	AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module
+	Bp2buildMutatorContext
 
 	// AddReverseDependency adds a dependency from the destination to the given module.
 	// Does not affect the ordering of the current mutator pass, but will be ordered
@@ -705,20 +698,14 @@
 	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(
+func (t *bottomUpMutatorContext) CreateBazelTargetModule(
 	bazelProps bazel.BazelTargetModuleProperties,
 	commonAttrs CommonAttributes,
 	attrs interface{}) {
 	t.createBazelTargetModule(bazelProps, commonAttrs, attrs, bazel.BoolAttribute{})
 }
 
-func (t *topDownMutatorContext) CreateBazelTargetModuleWithRestrictions(
+func (t *bottomUpMutatorContext) CreateBazelTargetModuleWithRestrictions(
 	bazelProps bazel.BazelTargetModuleProperties,
 	commonAttrs CommonAttributes,
 	attrs interface{},
@@ -726,7 +713,7 @@
 	t.createBazelTargetModule(bazelProps, commonAttrs, attrs, enabledProperty)
 }
 
-func (t *topDownMutatorContext) MarkBp2buildUnconvertible(
+func (t *bottomUpMutatorContext) MarkBp2buildUnconvertible(
 	reasonType bp2build_metrics_proto.UnconvertedReasonType, detail string) {
 	mod := t.Module()
 	mod.base().setBp2buildUnconvertible(reasonType, detail)
@@ -742,7 +729,7 @@
 	Actual *bazel.LabelAttribute
 }
 
-func (t *topDownMutatorContext) CreateBazelTargetAliasInDir(
+func (t *bottomUpMutatorContext) CreateBazelTargetAliasInDir(
 	dir string,
 	name string,
 	actual bazel.Label) {
@@ -763,7 +750,7 @@
 // Returns the directory in which the bazel target will be generated
 // If ca.Dir is not nil, use that
 // Otherwise default to the directory of the soong module
-func dirForBazelTargetGeneration(t *topDownMutatorContext, ca *CommonAttributes) string {
+func dirForBazelTargetGeneration(t *bottomUpMutatorContext, ca *CommonAttributes) string {
 	dir := t.OtherModuleDir(t.Module())
 	if ca.Dir != nil {
 		dir = *ca.Dir
@@ -781,7 +768,7 @@
 	return dir
 }
 
-func (t *topDownMutatorContext) CreateBazelConfigSetting(
+func (t *bottomUpMutatorContext) CreateBazelConfigSetting(
 	csa bazel.ConfigSettingAttributes,
 	ca CommonAttributes,
 	dir string) {
@@ -867,7 +854,7 @@
 	return ConvertApexAvailableToTags(noTestApexes)
 }
 
-func (t *topDownMutatorContext) createBazelTargetModule(
+func (t *bottomUpMutatorContext) createBazelTargetModule(
 	bazelProps bazel.BazelTargetModuleProperties,
 	commonAttrs CommonAttributes,
 	attrs interface{},
diff --git a/android/neverallow.go b/android/neverallow.go
index 2be6a74..f721b94 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -169,6 +169,8 @@
 		"external/kotlinx.coroutines",
 		"external/robolectric-shadows",
 		"external/robolectric",
+		"frameworks/base/ravenwood",
+		"frameworks/base/tools/hoststubgen",
 		"frameworks/layoutlib",
 	}
 
diff --git a/android/paths.go b/android/paths.go
index d4b1d6e..a6cda38 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -116,6 +116,48 @@
 
 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) 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 {
@@ -171,9 +213,6 @@
 	// Base returns the last element of the path
 	Base() string
 
-	// Dir returns a path pointing the directory containing the path
-	Dir() Path
-
 	// Rel returns the portion of the path relative to the directory it was created from.  For
 	// example, Rel on a PathsForModuleSrc would return the path relative to the module source
 	// directory, and OutputPath.Join("foo").Rel() would return "foo".
@@ -483,7 +522,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)
 }
@@ -1015,12 +1054,6 @@
 	return filepath.Base(p.path)
 }
 
-func (p basePath) Dir() Path {
-	p.path = filepath.Dir(p.path)
-	p.rel = filepath.Dir(p.rel)
-	return p
-}
-
 func (p basePath) Rel() string {
 	if p.rel != "" {
 		return p.rel
@@ -1055,11 +1088,6 @@
 	return p
 }
 
-func (p SourcePath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 // safePathForSource is for paths that we expect are safe -- only for use by go
 // code that is embedding ninja variables in paths
 func safePathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
@@ -1262,12 +1290,6 @@
 	return p
 }
 
-func (p OutputPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	p.fullPath = filepath.Dir(p.fullPath)
-	return p
-}
-
 func (p OutputPath) WithoutRel() OutputPath {
 	p.basePath.rel = filepath.Base(p.basePath.path)
 	return p
@@ -1300,11 +1322,6 @@
 	basePath
 }
 
-func (p toolDepPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 func (t toolDepPath) RelativeToTop() Path {
 	ensureTestOnly()
 	return t
@@ -1488,11 +1505,6 @@
 	OutputPath
 }
 
-func (p ModuleOutPath) Dir() Path {
-	p.OutputPath = p.OutputPath.Dir().(OutputPath)
-	return p
-}
-
 func (p ModuleOutPath) RelativeToTop() Path {
 	p.OutputPath = p.outputPathRelativeToTop()
 	return p
@@ -1537,11 +1549,6 @@
 	ModuleOutPath
 }
 
-func (p ModuleGenPath) Dir() Path {
-	p.ModuleOutPath = p.ModuleOutPath.Dir().(ModuleOutPath)
-	return p
-}
-
 func (p ModuleGenPath) RelativeToTop() Path {
 	p.OutputPath = p.outputPathRelativeToTop()
 	return p
@@ -1581,11 +1588,6 @@
 	ModuleOutPath
 }
 
-func (p ModuleObjPath) Dir() Path {
-	p.ModuleOutPath = p.ModuleOutPath.Dir().(ModuleOutPath)
-	return p
-}
-
 func (p ModuleObjPath) RelativeToTop() Path {
 	p.OutputPath = p.outputPathRelativeToTop()
 	return p
@@ -1610,11 +1612,6 @@
 	ModuleOutPath
 }
 
-func (p ModuleResPath) Dir() Path {
-	p.ModuleOutPath = p.ModuleOutPath.Dir().(ModuleOutPath)
-	return p
-}
-
 func (p ModuleResPath) RelativeToTop() Path {
 	p.OutputPath = p.outputPathRelativeToTop()
 	return p
@@ -1651,11 +1648,6 @@
 	makePath bool
 }
 
-func (p InstallPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 // Will panic if called from outside a test environment.
 func ensureTestOnly() {
 	if PrefixInList(os.Args, "-test.") {
@@ -1733,20 +1725,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) {
@@ -1762,12 +1754,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
@@ -1797,9 +1784,6 @@
 		}
 		partitionPaths = []string{"host", osName + "-" + archName, partition}
 	}
-	if debug {
-		partitionPaths = append([]string{"debug"}, partitionPaths...)
-	}
 
 	partitionPath, err := validatePath(partitionPaths...)
 	if err != nil {
@@ -1843,12 +1827,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() {
@@ -1931,7 +1915,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)
 		}
@@ -1940,11 +1926,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
@@ -1972,11 +1972,6 @@
 	basePath
 }
 
-func (p PhonyPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 func (p PhonyPath) writablePath() {}
 
 func (p PhonyPath) getSoongOutDir() string {
@@ -2002,11 +1997,6 @@
 	basePath
 }
 
-func (p testPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 func (p testPath) RelativeToTop() Path {
 	ensureTestOnly()
 	return p
diff --git a/android/paths_test.go b/android/paths_test.go
index 2f87977..bf46c34 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",
 	},
diff --git a/android/plugin.go b/android/plugin.go
index 4672453..2c7f9ff 100644
--- a/android/plugin.go
+++ b/android/plugin.go
@@ -16,8 +16,6 @@
 
 import (
 	"encoding/json"
-	"fmt"
-	"io/ioutil"
 	"os"
 	"strings"
 
@@ -72,28 +70,31 @@
 	"xsdc-soong-rules":                       true,
 }
 
-const (
-	internalPluginsPath = "vendor/google/build/soong/internal_plugins.json"
-)
+var internalPluginsPaths = []string{
+	"vendor/google/build/soong/internal_plugins.json",
+	"vendor/google_clockwork/build/internal_plugins.json",
+}
 
 type pluginProvider interface {
 	IsPluginFor(string) bool
 }
 
 func maybeAddInternalPluginsToAllowlist(ctx SingletonContext) {
-	if path := ExistentPathForSource(ctx, internalPluginsPath); path.Valid() {
-		ctx.AddNinjaFileDeps(path.String())
-		absPath := absolutePath(path.String())
-		var moreAllowed map[string]bool
-		data, err := ioutil.ReadFile(absPath)
-		if err != nil {
-			ctx.Errorf("Failed to open internal plugins path %q %q", internalPluginsPath, err)
-		}
-		if err := json.Unmarshal(data, &moreAllowed); err != nil {
-			fmt.Fprintf(os.Stderr, "Internal plugins file %q did not parse correctly: %q", data, err)
-		}
-		for k, v := range moreAllowed {
-			allowedPluginsByName[k] = v
+	for _, internalPluginsPath := range internalPluginsPaths {
+		if path := ExistentPathForSource(ctx, internalPluginsPath); path.Valid() {
+			ctx.AddNinjaFileDeps(path.String())
+			absPath := absolutePath(path.String())
+			var moreAllowed map[string]bool
+			data, err := os.ReadFile(absPath)
+			if err != nil {
+				ctx.Errorf("Failed to open internal plugins path %q %q", internalPluginsPath, err)
+			}
+			if err := json.Unmarshal(data, &moreAllowed); err != nil {
+				ctx.Errorf("Internal plugins file %q did not parse correctly: %q", data, err)
+			}
+			for k, v := range moreAllowed {
+				allowedPluginsByName[k] = v
+			}
 		}
 	}
 }
diff --git a/android/prebuilt.go b/android/prebuilt.go
index e7b7979..91c0aa1 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -387,7 +387,7 @@
 
 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()
 }
 
@@ -406,6 +406,8 @@
 
 // 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
@@ -416,6 +418,14 @@
 			ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
 			p.properties.SourceExists = true
 		}
+		// Add a dependency from the prebuilt to the `all_apex_contributions`
+		// metadata module
+		// TODO: When all branches contain this singleton module, make this strict
+		// TODO: Add this dependency only for mainline prebuilts and not every prebuilt module
+		if ctx.OtherModuleExists("all_apex_contributions") {
+			ctx.AddDependency(m, acDepTag, "all_apex_contributions")
+		}
+
 	}
 }
 
@@ -435,7 +445,11 @@
 
 // PrebuiltSelectModuleMutator marks prebuilts that are used, either overriding source modules or
 // because the source module doesn't exist.  It also disables installing overridden source modules.
-func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
+//
+// If the visited module is the metadata module `all_apex_contributions`, it sets a
+// provider containing metadata about whether source or prebuilt of mainline modules should be used.
+// This logic was added here to prevent the overhead of creating a new mutator.
+func PrebuiltSelectModuleMutator(ctx BottomUpMutatorContext) {
 	m := ctx.Module()
 	if p := GetEmbeddedPrebuilt(m); p != nil {
 		if p.srcsSupplier == nil && p.srcsPropertyName == "" {
@@ -444,6 +458,17 @@
 		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) {
+			if ctx.Config().Bp2buildMode() {
+				// This provider key is not applicable in bp2build
+				return
+			}
+			psi := ctx.OtherModuleProvider(am, PrebuiltSelectionInfoProvider).(PrebuiltSelectionInfoMap)
+			ctx.SetProvider(PrebuiltSelectionInfoProvider, psi)
+		})
+
 	} else if s, ok := ctx.Module().(Module); ok {
 		ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(prebuiltModule Module) {
 			p := GetEmbeddedPrebuilt(prebuiltModule)
@@ -455,6 +480,11 @@
 			}
 		})
 	}
+	// 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)
+	}
 }
 
 // PrebuiltPostDepsMutator replaces dependencies on the source module with dependencies on the
@@ -480,9 +510,66 @@
 	}
 }
 
+// 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(sln, PrebuiltNameFromSource(sln))
+		}
+
+		// Stub library created by java_sdk_library
+		return psi.IsSelected(sln, sln)
+	}
+	return psi.IsSelected(m.base().BaseModuleName(), 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) {
+		if ctx.OtherModuleHasProvider(am, PrebuiltSelectionInfoProvider) {
+			psi = ctx.OtherModuleProvider(am, PrebuiltSelectionInfoProvider).(PrebuiltSelectionInfoMap)
+		}
+	})
+
+	// 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 !ctx.Config().Bp2buildMode() {
 		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 c00b22b..17b3230 100644
--- a/android/prebuilt_build_tool.go
+++ b/android/prebuilt_build_tool.go
@@ -14,11 +14,7 @@
 
 package android
 
-import (
-	"path/filepath"
-
-	"github.com/google/blueprint"
-)
+import "path/filepath"
 
 func init() {
 	RegisterModuleType("prebuilt_build_tool", NewPrebuiltBuildTool)
@@ -59,13 +55,6 @@
 	}
 }
 
-type PrebuiltBuildToolInfo struct {
-	Src  Path
-	Deps Paths
-}
-
-var PrebuiltBuildToolInfoProvider = blueprint.NewProvider(PrebuiltBuildToolInfo{})
-
 func (t *prebuiltBuildTool) GenerateAndroidBuildActions(ctx ModuleContext) {
 	sourcePath := t.prebuilt.SingleSourcePath(ctx)
 	installedPath := PathForModuleOut(ctx, t.BaseModuleName())
@@ -93,11 +82,6 @@
 	}
 
 	t.toolPath = OptionalPathForPath(installedPath)
-
-	ctx.SetProvider(PrebuiltBuildToolInfoProvider, PrebuiltBuildToolInfo{
-		Src:  sourcePath,
-		Deps: deps,
-	})
 }
 
 func (t *prebuiltBuildTool) MakeVars(ctx MakeVarsModuleContext) {
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index fc47cfd..953258e 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,7 +569,7 @@
 	}
 }
 
-func testPrebuiltError(t *testing.T, expectedError, bp string) {
+func testPrebuiltErrorWithFixture(t *testing.T, expectedError, bp string, fixture FixturePreparer) {
 	t.Helper()
 	fs := MockFS{
 		"prebuilt_file": nil,
@@ -508,9 +580,15 @@
 		PrepareForTestWithOverrides,
 		fs.AddToFixture(),
 		FixtureRegisterWithContext(registerTestPrebuiltModules),
+		OptionalFixturePreparer(fixture),
 	).
 		ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(expectedError)).
 		RunTestWithBp(t, bp)
+
+}
+
+func testPrebuiltError(t *testing.T, expectedError, bp string) {
+	testPrebuiltErrorWithFixture(t, expectedError, bp, nil)
 }
 
 func TestPrebuiltShouldNotChangePartition(t *testing.T) {
@@ -559,6 +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 {
@@ -653,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, `Cannot use Soong module: prebuilt_foo from apex_contributions: my_apex_contributions because it has been added previously as: foo from apex_contributions: my_apex_contributions`, `
+		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 fc21d01..c449a87 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -289,7 +289,7 @@
 				attrs.Strip_import_prefix = proptools.StringPtr("")
 			}
 
-			tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
+			tags := ApexAvailableTagsWithoutTestApexes(ctx, ctx.Module())
 
 			moduleDir := ctx.ModuleDir()
 			if !canonicalPathFromRoot {
diff --git a/android/register.go b/android/register.go
index f1c2986..de31353 100644
--- a/android/register.go
+++ b/android/register.go
@@ -22,6 +22,7 @@
 	"regexp"
 
 	"android/soong/shared"
+
 	"github.com/google/blueprint"
 )
 
@@ -66,9 +67,6 @@
 var moduleTypeByFactory = map[reflect.Value]string{}
 
 type singleton struct {
-	// True if this should be registered as a pre-singleton, false otherwise.
-	pre bool
-
 	// True if this should be registered as a parallel singleton.
 	parallel bool
 
@@ -77,11 +75,7 @@
 }
 
 func newSingleton(name string, factory SingletonFactory, parallel bool) singleton {
-	return singleton{pre: false, parallel: parallel, name: name, factory: factory}
-}
-
-func newPreSingleton(name string, factory SingletonFactory) singleton {
-	return singleton{pre: true, parallel: false, name: name, factory: factory}
+	return singleton{parallel: parallel, name: name, factory: factory}
 }
 
 func (s singleton) componentName() string {
@@ -90,17 +84,12 @@
 
 func (s singleton) register(ctx *Context) {
 	adaptor := SingletonFactoryAdaptor(ctx, s.factory)
-	if s.pre {
-		ctx.RegisterPreSingletonType(s.name, adaptor)
-	} else {
-		ctx.RegisterSingletonType(s.name, adaptor, s.parallel)
-	}
+	ctx.RegisterSingletonType(s.name, adaptor, s.parallel)
 }
 
 var _ sortableComponent = singleton{}
 
 var singletons sortableComponents
-var preSingletons sortableComponents
 
 type mutator struct {
 	name              string
@@ -164,10 +153,6 @@
 	registerSingletonType(name, factory, true)
 }
 
-func RegisterPreSingletonType(name string, factory SingletonFactory) {
-	preSingletons = append(preSingletons, newPreSingleton(name, factory))
-}
-
 type Context struct {
 	*blueprint.Context
 	config Config
@@ -181,8 +166,7 @@
 	return ctx
 }
 
-// Helper function to register the module types used in bp2build and
-// api_bp2build.
+// Helper function to register the module types used in bp2build.
 func registerModuleTypes(ctx *Context) {
 	for _, t := range moduleTypes {
 		t.register(ctx)
@@ -254,8 +238,6 @@
 // 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)
 	}
@@ -278,17 +260,17 @@
 func collateGloballyRegisteredSingletons() sortableComponents {
 	allSingletons := append(sortableComponents(nil), singletons...)
 	allSingletons = append(allSingletons,
-		singleton{pre: false, parallel: true, name: "bazeldeps", factory: BazelSingleton},
+		singleton{parallel: true, name: "bazeldeps", factory: BazelSingleton},
 
 		// Register phony just before makevars so it can write out its phony rules as Make rules
-		singleton{pre: false, parallel: false, name: "phony", factory: phonySingletonFactory},
+		singleton{parallel: false, name: "phony", factory: phonySingletonFactory},
 
 		// Register makevars after other singletons so they can export values through makevars
-		singleton{pre: false, parallel: false, name: "makevars", factory: makeVarsSingletonFunc},
+		singleton{parallel: false, name: "makevars", factory: makeVarsSingletonFunc},
 
 		// Register env and ninjadeps last so that they can track all used environment variables and
 		// Ninja file dependencies stored in the config.
-		singleton{pre: false, parallel: false, name: "ninjadeps", factory: ninjaDepsSingletonFactory},
+		singleton{parallel: false, name: "ninjadeps", factory: ninjaDepsSingletonFactory},
 	)
 
 	return allSingletons
@@ -318,7 +300,6 @@
 	RegisterModuleType(name string, factory ModuleFactory)
 	RegisterSingletonModuleType(name string, factory SingletonModuleFactory)
 	RegisterParallelSingletonModuleType(name string, factory SingletonModuleFactory)
-	RegisterPreSingletonType(name string, factory SingletonFactory)
 	RegisterParallelSingletonType(name string, factory SingletonFactory)
 	RegisterSingletonType(name string, factory SingletonFactory)
 	PreArchMutators(f RegisterMutatorFunc)
@@ -350,9 +331,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.
@@ -361,7 +341,6 @@
 type initRegistrationContext struct {
 	moduleTypes        map[string]ModuleFactory
 	singletonTypes     map[string]SingletonFactory
-	preSingletonTypes  map[string]SingletonFactory
 	moduleTypesForDocs map[string]reflect.Value
 }
 
@@ -407,14 +386,6 @@
 	ctx.registerSingletonType(name, factory, true)
 }
 
-func (ctx *initRegistrationContext) RegisterPreSingletonType(name string, factory SingletonFactory) {
-	if _, present := ctx.preSingletonTypes[name]; present {
-		panic(fmt.Sprintf("pre singleton type %q is already registered", name))
-	}
-	ctx.preSingletonTypes[name] = factory
-	RegisterPreSingletonType(name, factory)
-}
-
 func (ctx *initRegistrationContext) PreArchMutators(f RegisterMutatorFunc) {
 	PreArchMutators(f)
 }
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 245b759..5c6dffe 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -871,7 +871,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
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 1fadda0..aafcee7 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -48,6 +48,7 @@
 	SdkPublic
 	SdkSystem
 	SdkTest
+	SdkTestFrameworksCore
 	SdkModule
 	SdkSystemServer
 	SdkPrivate
@@ -67,6 +68,8 @@
 		return "system"
 	case SdkTest:
 		return "test"
+	case SdkTestFrameworksCore:
+		return "test_frameworks_core"
 	case SdkCore:
 		return "core"
 	case SdkCorePlatform:
@@ -92,6 +95,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:
@@ -137,7 +142,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))
@@ -185,7 +190,8 @@
 		return ctx.Config().AlwaysUsePrebuiltSdks()
 	} else if !s.ApiLevel.IsPreview() {
 		// validation check
-		if s.Kind != SdkPublic && s.Kind != SdkSystem && s.Kind != SdkTest && s.Kind != SdkModule && s.Kind != SdkSystemServer {
+		if s.Kind != SdkPublic && s.Kind != SdkSystem && s.Kind != SdkTest &&
+			s.Kind != SdkTestFrameworksCore && s.Kind != SdkModule && s.Kind != SdkSystemServer {
 			panic(fmt.Errorf("prebuilt SDK is not not available for SdkKind=%q", s.Kind))
 			return false
 		}
@@ -266,6 +272,8 @@
 			kind = SdkSystem
 		case "test":
 			kind = SdkTest
+		case "test_frameworks_core":
+			kind = SdkTestFrameworksCore
 		case "module":
 			kind = SdkModule
 		case "system_server":
diff --git a/android/test_asserts.go b/android/test_asserts.go
index 3a2cb1a..c33ade5 100644
--- a/android/test_asserts.go
+++ b/android/test_asserts.go
@@ -148,7 +148,7 @@
 		return
 	}
 	if !ok {
-		t.Errorf("%s does not match regular expression %s", s, expectedRex)
+		t.Errorf("%s: %s does not match regular expression %s", message, s, expectedRex)
 	}
 }
 
diff --git a/android/test_suites.go b/android/test_suites.go
index 63a709f..9ded998 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -60,7 +60,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)
@@ -69,7 +69,7 @@
 		FlagWithArg("-P ", "host/testcases").
 		FlagWithArg("-C ", testCasesDir.String()).
 		FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths()).
-        Flag("-sha256")
+		Flag("-sha256")
 	rule.Build("robolectric_tests_zip", "robolectric-tests.zip")
 
 	return outputFile
diff --git a/android/testing.go b/android/testing.go
index 32357db..da3b75a 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -186,12 +186,12 @@
 	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) {
@@ -397,9 +397,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 +409,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 +435,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,7 +445,6 @@
 	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)
 }
@@ -503,10 +491,6 @@
 	ctx.singletons = append(ctx.singletons, newSingleton(name, factory, true))
 }
 
-func (ctx *TestContext) RegisterPreSingletonType(name string, factory SingletonFactory) {
-	ctx.preSingletons = append(ctx.preSingletons, newPreSingleton(name, factory))
-}
-
 // ModuleVariantForTests selects a specific variant of the module with the given
 // name by matching the variations map against the variations of each module
 // variant. A module variant matches the map if every variation that exists in
diff --git a/android/updatable_modules.go b/android/updatable_modules.go
index 71c76c5..6d0eeb7 100644
--- a/android/updatable_modules.go
+++ b/android/updatable_modules.go
@@ -14,9 +14,9 @@
 
 package android
 
-// This file contains branch specific constants for building updatable modules.
-// They are stored in a separate file to minimise the potential of merge
-// conflicts between branches when the code from the package is changed.
+// This file contains branch specific constants. They are stored in a separate
+// file to minimise the potential of merge conflicts between branches when
+// the code from the package is changed.
 
 // The default manifest version for all the modules on this branch.
 // This version code will be used only if there is no version field in the
@@ -33,4 +33,4 @@
 // * AOSP            - xx9990000
 // * x-mainline-prod - xx9990000
 // * master          - 990090000
-const DefaultUpdatableModuleVersion = "339990000"
+const DefaultUpdatableModuleVersion = "340090000"
diff --git a/android/util.go b/android/util.go
index 7f6af2d..f687bca 100644
--- a/android/util.go
+++ b/android/util.go
@@ -33,17 +33,12 @@
 	return append([]T{}, s...)
 }
 
-// Concat returns a new slice concatenated from the input slices. It does not change the input
+// Concat returns a new slice concatenated from the two input slices. It does not change the input
 // slices.
-func Concat[T any](slices ...[]T) []T {
-	newLength := 0
-	for _, s := range slices {
-		newLength += len(s)
-	}
-	res := make([]T, 0, newLength)
-	for _, s := range slices {
-		res = append(res, s...)
-	}
+func Concat[T any](s1, s2 []T) []T {
+	res := make([]T, 0, len(s1)+len(s2))
+	res = append(res, s1...)
+	res = append(res, s2...)
 	return res
 }
 
@@ -66,17 +61,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()
 }
diff --git a/android/util_test.go b/android/util_test.go
index 20161e5..699135b 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -811,7 +811,7 @@
 			if !reflect.DeepEqual(slice, testCase.expected) {
 				t.Errorf("expected %#v, got %#v", testCase.expected, slice)
 			}
-			if slice != nil && unsafe.SliceData(testCase.in) == unsafe.SliceData(slice) {
+			if cap(slice) > 0 && unsafe.SliceData(testCase.in) == unsafe.SliceData(slice) {
 				t.Errorf("expected slices to have different backing arrays")
 			}
 		})
diff --git a/android/variable.go b/android/variable.go
index d33294c..fe3a6d7 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -418,8 +418,6 @@
 	ProductPublicSepolicyDirs  []string `json:",omitempty"`
 	ProductPrivateSepolicyDirs []string `json:",omitempty"`
 
-	ProductVndkVersion *string `json:",omitempty"`
-
 	TargetFSConfigGen []string `json:",omitempty"`
 
 	EnforceProductPartitionInterface *bool `json:",omitempty"`
@@ -476,20 +474,86 @@
 	ProductBrand        string   `json:",omitempty"`
 	BuildVersionTags    []string `json:",omitempty"`
 
-	ReleaseVersion          string `json:",omitempty"`
-	ReleaseAconfigValueSets 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"`
 
-	// PartitionsVars are extra variables that are used to define the partition images. They should
-	// not be read from soong modules.
-	PartitionVars struct {
-		ProductDirectory string `json:",omitempty"`
-	} `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"`
+
+	NextReleaseHideFlaggedApi *bool `json:",omitempty"`
+
+	Release_expose_flagged_api *bool `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"`
+	BoardBuildGkiBootImageWithoutRamdisk bool   `json:",omitempty"`
+	ProductUseDynamicPartitionSize       bool   `json:",omitempty"`
+	CopyImagesForTargetFilesZip          bool   `json:",omitempty"`
+
+	BoardAvbEnable bool `json:",omitempty"`
+
+	ProductPackages []string `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 2f5d8d4..6136cbd 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -260,6 +260,7 @@
 				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
diff --git a/apex/apex.go b/apex/apex.go
index 090d9c4..4c02305 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -135,6 +135,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
@@ -454,6 +459,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
 
@@ -474,9 +482,6 @@
 	nativeApisUsedByModuleFile   android.ModuleOutPath
 	nativeApisBackedByModuleFile android.ModuleOutPath
 	javaApisUsedByModuleFile     android.ModuleOutPath
-
-	// Collect the module directory for IDE info in java/jdeps.go.
-	modulePaths []string
 }
 
 // apexFileClass represents a type of file that can be included in APEX.
@@ -736,7 +741,7 @@
 			vndkVersion = deviceConfig.VndkVersion()
 		} else if a.ProductSpecific() {
 			prefix = cc.ProductVariationPrefix
-			vndkVersion = deviceConfig.ProductVndkVersion()
+			vndkVersion = deviceConfig.PlatformVndkVersion()
 		}
 	}
 	if vndkVersion == "current" {
@@ -1923,6 +1928,7 @@
 
 		a.filesInfo = append(a.filesInfo, fileInfo)
 	}
+	a.apexKeysPath = writeApexKeys(ctx, a)
 }
 
 func (a *apexBundle) setCompression(ctx android.ModuleContext) {
@@ -1999,11 +2005,21 @@
 
 	// if true, raise error on duplicate apexFile
 	checkDuplicate bool
+
+	// visitor skips these from this list of module names
+	unwantedTransitiveDeps []string
 }
 
 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
@@ -2367,10 +2383,6 @@
 	if a.properties.IsCoverageVariant {
 		return false
 	}
-	// TODO(b/263308515) remove this
-	if a.testApex {
-		return false
-	}
 	if ctx.DeviceConfig().DeviceArch() == "" {
 		return false
 	}
@@ -2391,14 +2403,13 @@
 	}
 	////////////////////////////////////////////////////////////////////////////////////////////
 	// 2) traverse the dependency tree to collect apexFile structs from them.
-	// Collect the module directory for IDE info in java/jdeps.go.
-	a.modulePaths = append(a.modulePaths, ctx.ModuleDir())
 
 	// TODO(jiyong): do this using WalkPayloadDeps
 	// TODO(jiyong): make this clean!!!
 	vctx := visitorContext{
-		handleSpecialLibs: !android.Bool(a.properties.Ignore_system_library_special_case),
-		checkDuplicate:    a.shouldCheckDuplicate(ctx),
+		handleSpecialLibs:      !android.Bool(a.properties.Ignore_system_library_special_case),
+		checkDuplicate:         a.shouldCheckDuplicate(ctx),
+		unwantedTransitiveDeps: a.properties.Unwanted_transitive_deps,
 	}
 	ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool { return a.depVisitor(&vctx, ctx, child, parent) })
 	vctx.normalizeFileInfo(ctx)
@@ -2956,7 +2967,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 (
@@ -3021,59 +3031,6 @@
 	//
 	// Module separator
 	//
-	m["com.android.appsearch"] = []string{
-		"icing-java-proto-lite",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.btservices"] = []string{
-		// empty
-	}
-	//
-	// Module separator
-	//
-	m["com.android.cellbroadcast"] = []string{}
-	//
-	// Module separator
-	//
-	m["com.android.extservices"] = []string{
-		"ExtServices-core",
-		"libtextclassifier-java",
-		"textclassifier-statsd",
-		"TextClassifierNotificationLibNoManifest",
-		"TextClassifierServiceLibNoManifest",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.neuralnetworks"] = []string{
-		"android.hardware.neuralnetworks@1.0",
-		"android.hardware.neuralnetworks@1.1",
-		"android.hardware.neuralnetworks@1.2",
-		"android.hardware.neuralnetworks@1.3",
-		"android.hidl.allocator@1.0",
-		"android.hidl.memory.token@1.0",
-		"android.hidl.memory@1.0",
-		"android.hidl.safe_union@1.0",
-		"libarect",
-		"libprocpartition",
-	}
-	//
-	// Module separator
-	//
-	m["com.android.media"] = []string{
-		// empty
-	}
-	//
-	// Module separator
-	//
-	m["com.android.media.swcodec"] = []string{
-		// empty
-	}
-	//
-	// Module separator
-	//
 	m["com.android.mediaprovider"] = []string{
 		"MediaProvider",
 		"MediaProviderGoogle",
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 3a6af1e..ddb9a40 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -948,7 +948,7 @@
 	// 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("rustc").RuleParams.Command
+	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")
 
@@ -1024,7 +1024,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("rustc").RuleParams.Command
+	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")
 }
@@ -3088,10 +3088,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"])
@@ -3885,13 +3882,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 += `
@@ -5451,7 +5459,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() {
@@ -5901,8 +5909,8 @@
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
-		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/libfoo/android_common_apex10000/hiddenapi/libfoo.jar")
-		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/libbar/android_common_myapex/hiddenapi/libbar.jar")
+		checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/hiddenapi-modular/encoded/libfoo.jar")
+		checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/hiddenapi-modular/encoded/libbar.jar")
 
 		// Verify the correct module jars contribute to the hiddenapi index file.
 		checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
@@ -7701,6 +7709,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 {
@@ -9081,8 +9125,8 @@
 		}
 	`)
 
-	apexKeysText := ctx.SingletonForTests("apex_keys_text")
-	content := apexKeysText.MaybeDescription("apexkeys.txt").BuildParams.Args["content"]
+	myapex := ctx.ModuleForTests("myapex", "android_common_myapex")
+	content := myapex.Output("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" sign_tool="sign_myapex"`)
 }
 
@@ -9122,10 +9166,10 @@
 		}
 	`)
 
-	apexKeysText := ctx.SingletonForTests("apex_keys_text")
-	content := apexKeysText.MaybeDescription("apexkeys.txt").BuildParams.Args["content"]
+	content := ctx.ModuleForTests("myapex", "android_common_myapex").Output("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" sign_tool="sign_myapex"`)
+	content = ctx.ModuleForTests("myapex_set", "android_common_myapex_set").Output("apexkeys.txt").BuildParams.Args["content"]
 	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) {
@@ -10521,6 +10565,7 @@
 			min_sdk_version: "29",
 			recovery_available: true,
 			vendor_available: true,
+			product_available: true,
 		}
 		api_imports {
 			name: "api_imports",
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 89ea004..43be310 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -832,7 +832,7 @@
 // TestBootclasspathFragment_AndroidNonUpdatable checks to make sure that setting
 // additional_stubs: ["android-non-updatable"] causes the source android-non-updatable modules to be
 // added to the hiddenapi list tool.
-func TestBootclasspathFragment_AndroidNonUpdatable(t *testing.T) {
+func TestBootclasspathFragment_AndroidNonUpdatable_FromSource(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForTestWithBootclasspathFragment,
 		prepareForTestWithArtApex,
@@ -843,6 +843,9 @@
 		// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
 		// is disabled.
 		android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.SetBuildFromTextStub(false)
+		}),
 
 		java.PrepareForTestWithJavaSdkLibraryFiles,
 		java.FixtureWithLastReleaseApis("foo", "android-non-updatable"),
@@ -1000,6 +1003,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/builder.go b/apex/builder.go
index 729917f..ba4df5f 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -75,9 +75,11 @@
 	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")
 }
 
 var (
@@ -237,6 +239,12 @@
 		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
@@ -364,12 +372,12 @@
 	output := android.PathForModuleOut(ctx, "file_contexts")
 	rule := android.NewRuleBuilder(pctx, ctx)
 
-	forceLabel := "u:object_r:system_file:s0"
+	labelForRoot := "u:object_r:system_file:s0"
+	labelForManifest := "u:object_r:system_file:s0"
 	if a.SocSpecific() && !a.vndkApex {
-		// APEX on /vendor should label ./ and ./apex_manifest.pb as vendor_apex_metadata_file.
-		// The reason why we skip VNDK APEX is that aosp_{pixel device} targets install VNDK APEX on /vendor
-		// even though VNDK APEX is supposed to be installed on /system. (See com.android.vndk.current.on_vendor)
-		forceLabel = "u:object_r:vendor_apex_metadata_file:s0"
+		// APEX on /vendor should label ./ and ./apex_manifest.pb as vendor file.
+		labelForRoot = "u:object_r:vendor_file:s0"
+		labelForManifest = "u:object_r:vendor_apex_metadata_file:s0"
 	}
 	// remove old file
 	rule.Command().Text("rm").FlagWithOutput("-f ", output)
@@ -379,8 +387,8 @@
 	rule.Command().Text("echo").Text(">>").Output(output)
 	if !useFileContextsAsIs {
 		// force-label /apex_manifest.pb and /
-		rule.Command().Text("echo").Text("/apex_manifest\\\\.pb").Text(forceLabel).Text(">>").Output(output)
-		rule.Command().Text("echo").Text("/").Text(forceLabel).Text(">>").Output(output)
+		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")
@@ -886,6 +894,10 @@
 	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",
@@ -948,6 +960,8 @@
 
 	// installed-files.txt is dist'ed
 	a.installedFilesFile = a.buildInstalledFilesFile(ctx, a.outputFile, imageDir)
+
+	a.apexKeysPath = writeApexKeys(ctx, a)
 }
 
 // getCertificateAndPrivateKey retrieves the cert and the private key that will be used to sign
@@ -1162,3 +1176,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/key.go b/apex/key.go
index fc1456b..2405e98 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -16,8 +16,6 @@
 
 import (
 	"fmt"
-	"sort"
-	"strings"
 
 	"android/soong/android"
 	"android/soong/bazel"
@@ -33,7 +31,6 @@
 
 func registerApexKeyBuildComponents(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("apex_key", ApexKeyFactory)
-	ctx.RegisterParallelSingletonType("apex_keys_text", apexKeysTextFactory)
 }
 
 type apexKey struct {
@@ -102,99 +99,65 @@
 	}
 }
 
-// //////////////////////////////////////////////////////////////////////
-// 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)
-		}
+	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)
 	}
-
-	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())
 }
 
-func apexKeysTextFactory() android.Singleton {
-	return &apexKeysText{}
+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),
+		}
+	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()),
+		}
+	}
+	panic(fmt.Errorf("unknown type(%t) for apexKeyEntry", module))
 }
 
-func (s *apexKeysText) MakeVars(ctx android.MakeVarsContext) {
-	ctx.Strict("SOONG_APEX_KEYS_FILE", s.output.String())
+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
 }
 
 // For Bazel / bp2build
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 1a90c3a..7a9d23e 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -60,6 +60,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
@@ -238,6 +241,7 @@
 					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)
 				},
 			},
@@ -759,6 +763,7 @@
 }
 
 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")
@@ -975,6 +980,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)
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 2b86e53..e2aee96 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -115,12 +115,7 @@
 	})
 
 	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")
 		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
diff --git a/bazel/aquery.go b/bazel/aquery.go
index c355712..35942bc 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -18,14 +18,16 @@
 	"crypto/sha256"
 	"encoding/base64"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"path/filepath"
-	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
 	"reflect"
 	"sort"
 	"strings"
 	"sync"
 
+	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
+
 	"github.com/google/blueprint/metrics"
 	"github.com/google/blueprint/proptools"
 	"google.golang.org/protobuf/proto"
@@ -35,19 +37,6 @@
 type depsetId int
 type pathFragmentId int
 
-// artifact contains relevant portions of Bazel's aquery proto, Artifact.
-// Represents a single artifact, whether it's a source file or a derived output file.
-type artifact struct {
-	Id             artifactId
-	PathFragmentId pathFragmentId
-}
-
-type pathFragment struct {
-	Id       pathFragmentId
-	Label    string
-	ParentId pathFragmentId
-}
-
 // KeyValuePair represents Bazel's aquery proto, KeyValuePair.
 type KeyValuePair struct {
 	Key   string
@@ -68,37 +57,6 @@
 	TransitiveDepSetHashes []string
 }
 
-// depSetOfFiles contains relevant portions of Bazel's aquery proto, DepSetOfFiles.
-// Represents a data structure containing one or more files. Depsets in Bazel are an efficient
-// data structure for storing large numbers of file paths.
-type depSetOfFiles struct {
-	Id                  depsetId
-	DirectArtifactIds   []artifactId
-	TransitiveDepSetIds []depsetId
-}
-
-// action contains relevant portions of Bazel's aquery proto, Action.
-// Represents a single command line invocation in the Bazel build graph.
-type action struct {
-	Arguments            []string
-	EnvironmentVariables []KeyValuePair
-	InputDepSetIds       []depsetId
-	Mnemonic             string
-	OutputIds            []artifactId
-	TemplateContent      string
-	Substitutions        []KeyValuePair
-	FileContents         string
-}
-
-// actionGraphContainer contains relevant portions of Bazel's aquery proto, ActionGraphContainer.
-// An aquery response from Bazel contains a single ActionGraphContainer proto.
-type actionGraphContainer struct {
-	Artifacts     []artifact
-	Actions       []action
-	DepSetOfFiles []depSetOfFiles
-	PathFragments []pathFragment
-}
-
 // BuildStatement contains information to register a build statement corresponding (one to one)
 // with a Bazel action from Bazel's action graph.
 type BuildStatement struct {
@@ -370,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 {
@@ -478,26 +443,21 @@
 
 // escapes the args received from aquery and creates a command string
 func commandString(actionEntry *analysis_v2_proto.Action) string {
-	switch actionEntry.Mnemonic {
-	case "GoCompilePkg", "GoStdlib":
-		argsEscaped := []string{}
-		for _, arg := range actionEntry.Arguments {
-			if arg == "" {
-				// If this is an empty string, add ''
-				// And not
-				// 1. (literal empty)
-				// 2. `''\'''\'''` (escaped version of '')
-				//
-				// If we had used (1), then this would appear as a whitespace when we strings.Join
-				argsEscaped = append(argsEscaped, "''")
-			} else {
-				argsEscaped = append(argsEscaped, proptools.ShellEscapeIncludingSpaces(arg))
-			}
+	argsEscaped := make([]string, len(actionEntry.Arguments))
+	for i, arg := range actionEntry.Arguments {
+		if arg == "" {
+			// If this is an empty string, add ''
+			// And not
+			// 1. (literal empty)
+			// 2. `''\'''\'''` (escaped version of '')
+			//
+			// If we had used (1), then this would appear as a whitespace when we strings.Join
+			argsEscaped[i] = "''"
+		} else {
+			argsEscaped[i] = proptools.ShellEscapeIncludingSpaces(arg)
 		}
-		return strings.Join(argsEscaped, " ")
-	default:
-		return strings.Join(proptools.ShellEscapeListIncludingSpaces(actionEntry.Arguments), " ")
 	}
+	return strings.Join(argsEscaped, " ")
 }
 
 func (a *aqueryArtifactHandler) normalActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
@@ -782,7 +742,7 @@
 	}
 
 	if len(actionEntry.Arguments) < 1 {
-		return nil, fmt.Errorf("received action with no command: [%s]", actionEntry.Mnemonic)
+		return nil, errors.New("received action with no command")
 	}
 	return a.normalActionBuildStatement(actionEntry)
 
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 32c87a0..cbd2791 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -178,8 +178,8 @@
    { "id": 2, "path_fragment_id": 2 }],
  "actions": [{
    "target_id": 1,
-   "action_key": "x",
-   "mnemonic": "x",
+   "action_key": "action_x",
+   "mnemonic": "X",
    "arguments": ["touch", "foo"],
    "input_dep_set_ids": [1],
    "output_ids": [3],
@@ -198,7 +198,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, "undefined outputId 3")
+	assertError(t, err, "undefined outputId 3: [X] []")
 }
 
 func TestInvalidInputDepsetIdFromAction(t *testing.T) {
@@ -209,13 +209,17 @@
    { "id": 2, "path_fragment_id": 2 }],
  "actions": [{
    "target_id": 1,
-   "action_key": "x",
-   "mnemonic": "x",
+   "action_key": "action_x",
+   "mnemonic": "X",
    "arguments": ["touch", "foo"],
    "input_dep_set_ids": [2],
    "output_ids": [1],
    "primary_output_id": 1
  }],
+ "targets": [{
+   "id": 1,
+   "label": "target_x"
+ }],
  "dep_set_of_files": [
    { "id": 1, "direct_artifact_ids": [1, 2] }],
  "path_fragments": [
@@ -229,7 +233,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, "undefined (not even empty) input depsetId 2")
+	assertError(t, err, "undefined (not even empty) input depsetId 2: [X] [target_x]")
 }
 
 func TestInvalidInputDepsetIdFromDepset(t *testing.T) {
@@ -383,8 +387,8 @@
    { "id": 4, "path_fragment_id": 4 }],
  "actions": [{
    "target_id": 1,
-   "action_key": "x",
-   "mnemonic": "x",
+   "action_key": "action_x",
+   "mnemonic": "X",
    "arguments": ["touch", "foo"],
    "input_dep_set_ids": [1],
    "output_ids": [2,3,4],
@@ -407,7 +411,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, `found multiple potential depfiles "two.d", "other.d"`)
+	assertError(t, err, `found multiple potential depfiles "two.d", "other.d": [X] []`)
 }
 
 func TestTransitiveInputDepsets(t *testing.T) {
@@ -559,7 +563,7 @@
 	}, actual)
 }
 
-func TestBazelOutRemovalFromInputDepsets(t *testing.T) {
+func TestBazelToolsRemovalFromInputDepsets(t *testing.T) {
 	const inputString = `{
  "artifacts": [
    { "id": 1, "path_fragment_id": 10 },
@@ -637,7 +641,55 @@
 	}
 }
 
-func TestBazelOutRemovalFromTransitiveInputDepsets(t *testing.T) {
+func TestBazelToolsRemovalFromTargets(t *testing.T) {
+	const inputString = `{
+ "artifacts": [{ "id": 1, "path_fragment_id": 10 }],
+ "targets": [
+   { "id": 100, "label": "targetX" },
+   { "id": 200, "label": "@bazel_tools//tool_y" }
+],
+ "actions": [{
+   "target_id": 100,
+   "action_key": "actionX",
+   "arguments": ["bogus", "command"],
+   "mnemonic" : "x",
+   "output_ids": [1]
+ }, {
+   "target_id": 200,
+   "action_key": "y"
+ }],
+ "path_fragments": [{ "id": 10, "label": "outputX"}]
+}`
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actualBuildStatements, actualDepsets, _ := AqueryBuildStatements(data, &metrics.EventHandler{})
+	if len(actualDepsets) != 0 {
+		t.Errorf("expected 0 depset but found %#v", actualDepsets)
+		return
+	}
+	expectedBuildStatement := &BuildStatement{
+		Command:      "bogus command",
+		OutputPaths:  []string{"outputX"},
+		Mnemonic:     "x",
+		SymlinkPaths: []string{},
+	}
+	buildStatementFound := false
+	for _, actualBuildStatement := range actualBuildStatements {
+		if buildStatementEquals(actualBuildStatement, expectedBuildStatement) == "" {
+			buildStatementFound = true
+			break
+		}
+	}
+	if !buildStatementFound {
+		t.Errorf("expected but missing %#v in %#v build statements", expectedBuildStatement, len(actualBuildStatements))
+		return
+	}
+}
+
+func TestBazelToolsRemovalFromTransitiveInputDepsets(t *testing.T) {
 	const inputString = `{
  "artifacts": [
    { "id": 1, "path_fragment_id": 10 },
@@ -939,7 +991,7 @@
    { "id": 3, "path_fragment_id": 3 }],
  "actions": [{
    "target_id": 1,
-   "action_key": "x",
+   "action_key": "action_x",
    "mnemonic": "Symlink",
    "input_dep_set_ids": [1],
    "output_ids": [3],
@@ -958,7 +1010,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]`)
+	assertError(t, err, `Expect 1 input and 1 output to symlink action, got: input ["file" "other_file"], output ["symlink"]: [Symlink] []`)
 }
 
 func TestSymlinkMultipleOutputs(t *testing.T) {
@@ -989,7 +1041,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, "undefined outputId 2")
+	assertError(t, err, "undefined outputId 2: [Symlink] []")
 }
 
 func TestTemplateExpandActionSubstitutions(t *testing.T) {
@@ -1066,7 +1118,7 @@
 		return
 	}
 	_, _, err = AqueryBuildStatements(data, &metrics.EventHandler{})
-	assertError(t, err, `Expect 1 output to template expand action, got: output []`)
+	assertError(t, err, `Expect 1 output to template expand action, got: output []: [TemplateExpand] []`)
 }
 
 func TestFileWrite(t *testing.T) {
diff --git a/bazel/configurability.go b/bazel/configurability.go
index a28432c..2c9a536 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -133,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
@@ -160,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.
 	}
 
@@ -209,11 +209,11 @@
 		AndroidAndInApex:           "//build/bazel/rules/apex:android-in_apex",
 		AndroidPlatform:            "//build/bazel/rules/apex:system",
 		Unbundled_app:              "//build/bazel/rules/apex:unbundled_app",
-		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",
+		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,
 	}
 
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index e30e53d..14e32ed 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -77,6 +77,7 @@
         "java_proto_conversion_test.go",
         "java_sdk_library_conversion_test.go",
         "java_sdk_library_import_conversion_test.go",
+        "java_test_host_conversion_test.go",
         "license_conversion_test.go",
         "license_kind_conversion_test.go",
         "linker_config_conversion_test.go",
@@ -88,6 +89,7 @@
         "python_library_conversion_test.go",
         "python_test_conversion_test.go",
         "rust_binary_conversion_test.go",
+        "rust_ffi_conversion_test.go",
         "rust_library_conversion_test.go",
         "rust_proc_macro_conversion_test.go",
         "rust_protobuf_conversion_test.go",
diff --git a/bp2build/aar_conversion_test.go b/bp2build/aar_conversion_test.go
index 59aacbb..bdad1f4 100644
--- a/bp2build/aar_conversion_test.go
+++ b/bp2build/aar_conversion_test.go
@@ -21,6 +21,17 @@
 	"android/soong/java"
 )
 
+func runAndroidLibraryImportTestWithRegistrationCtxFunc(t *testing.T, registrationCtxFunc func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
+	t.Helper()
+	(&tc).ModuleTypeUnderTest = "android_library_import"
+	(&tc).ModuleTypeUnderTestFactory = java.AARImportFactory
+	RunBp2BuildTestCase(t, registrationCtxFunc, tc)
+}
+
+func runAndroidLibraryImportTest(t *testing.T, tc Bp2buildTestCase) {
+	runAndroidLibraryImportTestWithRegistrationCtxFunc(t, func(ctx android.RegistrationContext) {}, tc)
+}
+
 func TestConvertAndroidLibrary(t *testing.T) {
 	t.Helper()
 	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
@@ -58,8 +69,8 @@
 				"TestLib",
 				AttrNameToString{
 					"srcs": `["lib.java"] + select({
-        "//build/bazel/platforms/arch:arm": ["arm.java"],
-        "//build/bazel/platforms/arch:x86": ["x86.java"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["arm.java"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["x86.java"],
         "//conditions:default": [],
     })`,
 					"manifest":       `"manifest/AndroidManifest.xml"`,
@@ -75,7 +86,7 @@
 func TestConvertAndroidLibraryWithNoSources(t *testing.T) {
 	t.Helper()
 	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
-		Description:                "Android Library - modules with deps must have sources",
+		Description:                "Android Library - modules will deps when there are no sources",
 		ModuleTypeUnderTest:        "android_library",
 		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
 		Filesystem: map[string]string{
@@ -91,26 +102,30 @@
 	sdk_version: "current",
 }
 `,
-		ExpectedBazelTargets: []string{},
+		StubbedBuildDefinitions: []string{"lib_dep"},
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget(
+				"android_library",
+				"TestLib",
+				AttrNameToString{
+					"manifest":       `"AndroidManifest.xml"`,
+					"resource_files": `["res/res.png"]`,
+					"sdk_version":    `"current"`, // use as default
+				},
+			),
+			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
+		},
 	})
 }
 
 func TestConvertAndroidLibraryImport(t *testing.T) {
-	t.Helper()
-	RunBp2BuildTestCase(
-		t,
+	runAndroidLibraryImportTestWithRegistrationCtxFunc(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": "",
-				"dep.aar":    "",
-			},
-			StubbedBuildDefinitions: []string{"static_lib_dep", "prebuilt_static_import_dep"},
+			Description:             "Android Library Import",
+			StubbedBuildDefinitions: []string{"static_lib_dep", "static_import_dep", "static_import_dep-neverlink"},
 			// 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
@@ -122,9 +137,9 @@
     sdk_version: "current",
 }
 
-// TODO: b/301007952 - This dep is needed because android_library_import must have aars set.
 android_library_import {
         name: "static_import_dep",
+        aars: ["import.aar"],
 }
 `,
 			ExpectedBazelTargets: []string{
@@ -219,3 +234,16 @@
 			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
 		}})
 }
+
+func TestAarImportFailsToConvertNoAars(t *testing.T) {
+	runAndroidLibraryImportTest(t,
+		Bp2buildTestCase{
+			Description: "Android Library Import with no aars does not convert.",
+			Blueprint: `
+android_library_import {
+        name: "no_aar_import",
+}
+`,
+			ExpectedBazelTargets: []string{},
+		})
+}
diff --git a/bp2build/aconfig_conversion_test.go b/bp2build/aconfig_conversion_test.go
index cbf42ac..ca41680 100644
--- a/bp2build/aconfig_conversion_test.go
+++ b/bp2build/aconfig_conversion_test.go
@@ -20,11 +20,13 @@
 	"android/soong/aconfig"
 	"android/soong/android"
 	"android/soong/cc"
+	"android/soong/java"
 )
 
 func registerAconfigModuleTypes(ctx android.RegistrationContext) {
 	aconfig.RegisterBuildComponents(ctx)
 	ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
+	ctx.RegisterModuleType("java_library", java.LibraryFactory)
 }
 
 func TestAconfigDeclarations(t *testing.T) {
@@ -105,7 +107,6 @@
 	cc_library {
 			name: "server_configurable_flags",
 			srcs: ["bar.cc"],
-			bazel_module: { bp2build_available: false },
 	}
 	cc_aconfig_library {
 			name: "foo",
@@ -127,10 +128,126 @@
 			AttrNameToString{
 				"aconfig_declarations":   `":foo_aconfig_declarations"`,
 				"dynamic_deps":           `[":server_configurable_flags"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 			},
 		)}
 	RunBp2BuildTestCase(t, registerAconfigModuleTypes, Bp2buildTestCase{
+		Blueprint:               bp,
+		ExpectedBazelTargets:    expectedBazelTargets,
+		StubbedBuildDefinitions: []string{"server_configurable_flags"},
+	})
+}
+
+func TestJavaAconfigLibrary(t *testing.T) {
+	bp := `
+	aconfig_declarations {
+		name: "foo_aconfig_declarations",
+		srcs: [
+			"foo1.aconfig",
+		],
+		package: "com.android.foo",
+	}
+	java_library {
+			name: "foo_java_library",
+			srcs: ["foo.java"],
+			sdk_version: "current",
+	}
+	java_aconfig_library {
+			name: "foo",
+			aconfig_declarations: "foo_aconfig_declarations",
+			libs: ["foo_java_library"],
+			test: true,
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTargetNoRestrictions(
+			"aconfig_declarations",
+			"foo_aconfig_declarations",
+			AttrNameToString{
+				"srcs":    `["foo1.aconfig"]`,
+				"package": `"com.android.foo"`,
+			},
+		),
+		MakeBazelTargetNoRestrictions(
+			"java_library",
+			"foo_java_library",
+			AttrNameToString{
+				"srcs":                   `["foo.java"]`,
+				"sdk_version":            `"current"`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
+			},
+		),
+		MakeNeverlinkDuplicateTarget("java_library", "foo_java_library"),
+		MakeBazelTargetNoRestrictions(
+			"java_aconfig_library",
+			"foo",
+			AttrNameToString{
+				"aconfig_declarations":   `":foo_aconfig_declarations"`,
+				"libs":                   `[":foo_java_library-neverlink"]`,
+				"test":                   `True`,
+				"sdk_version":            `"system_current"`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
+			},
+		)}
+	RunBp2BuildTestCase(t, registerAconfigModuleTypes, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: expectedBazelTargets,
+	})
+}
+
+func TestJavaAconfigLibraryAsTaggedOutput(t *testing.T) {
+	bp := `
+	aconfig_declarations {
+		name: "foo_aconfig_declarations",
+		srcs: [
+			"foo.aconfig",
+		],
+		package: "com.android.foo",
+	}
+	java_library {
+			name: "foo_library",
+			srcs: [":foo_aconfig_library{.generated_srcjars}"],
+			sdk_version: "current",
+			bazel_module: { bp2build_available: true },
+	}
+	java_aconfig_library {
+			name: "foo_aconfig_library",
+			aconfig_declarations: "foo_aconfig_declarations",
+			test: true,
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTargetNoRestrictions(
+			"aconfig_declarations",
+			"foo_aconfig_declarations",
+			AttrNameToString{
+				"srcs":    `["foo.aconfig"]`,
+				"package": `"com.android.foo"`,
+			},
+		),
+		MakeBazelTargetNoRestrictions(
+			"java_aconfig_library",
+			"foo_aconfig_library",
+			AttrNameToString{
+				"aconfig_declarations":   `":foo_aconfig_declarations"`,
+				"test":                   `True`,
+				"sdk_version":            `"system_current"`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
+			},
+		),
+		MakeBazelTargetNoRestrictions(
+			"java_library",
+			"foo_library",
+			AttrNameToString{
+				"srcs":                   `[":foo_aconfig_library.generated_srcjars"]`,
+				"sdk_version":            `"current"`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
+			},
+		),
+		MakeNeverlinkDuplicateTarget("java_library", "foo_library"),
+	}
+
+	RunBp2BuildTestCase(t, registerAconfigModuleTypes, Bp2buildTestCase{
 		Blueprint:            bp,
 		ExpectedBazelTargets: expectedBazelTargets,
 	})
diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go
index 8ec4b35..33d1a04 100644
--- a/bp2build/android_app_conversion_test.go
+++ b/bp2build/android_app_conversion_test.go
@@ -167,8 +167,8 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("android_binary", "TestApp", AttrNameToString{
 				"srcs": `select({
-        "//build/bazel/platforms/arch:arm": ["arm.java"],
-        "//build/bazel/platforms/arch:x86": ["x86.java"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["arm.java"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["x86.java"],
         "//conditions:default": [],
     })`,
 				"manifest":       `"AndroidManifest.xml"`,
@@ -478,3 +478,41 @@
 			}),
 		}})
 }
+
+func TestFrameworkResConversion(t *testing.T) {
+	runAndroidAppTestCase(t, Bp2buildTestCase{
+		Description:                "Framework Res custom conversion",
+		ModuleTypeUnderTest:        "android_app",
+		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
+		Filesystem: map[string]string{
+			"res/values/attrs.xml": "",
+			"resource_zip.zip":     "",
+		},
+		Blueprint: `
+android_app {
+	name: "framework-res",
+	resource_zips: [
+		"resource_zip.zip",
+	],
+	certificate: "platform",
+}
+
+filegroup {
+	name: "framework-res-package-jar",
+	srcs: [":framework-res{.export-package.apk}"],
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("framework_resources", "framework-res", AttrNameToString{
+				"certificate_name":       `"platform"`,
+				"manifest":               `"AndroidManifest.xml"`,
+				"resource_files":         `["res/values/attrs.xml"]`,
+				"resource_zips":          `["resource_zip.zip"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
+			}),
+			MakeBazelTargetNoRestrictions("filegroup", "framework-res-package-jar", AttrNameToString{
+				"srcs": `[":framework-res.export-package.apk"]`,
+			}),
+		}})
+
+}
diff --git a/bp2build/android_test_conversion_test.go b/bp2build/android_test_conversion_test.go
index 52413fa..486f154 100644
--- a/bp2build/android_test_conversion_test.go
+++ b/bp2build/android_test_conversion_test.go
@@ -47,7 +47,40 @@
 		name: "TestApp",
 		srcs: ["app.java"],
 		sdk_version: "current",
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("android_test", "TestApp", AttrNameToString{
+				"srcs":           `["app.java"]`,
+				"manifest":       `"AndroidManifest.xml"`,
+				"resource_files": `["res/res.png"]`,
+				"sdk_version":    `"current"`,
+				"assets":         `["assets/asset.png"]`,
+				"assets_dir":     `"assets"`,
+				// no need for optimize = False because it's false for
+				// android_test by default
+			}),
+		}})
+}
+
+func TestAndroidTest_OptimizationEnabled(t *testing.T) {
+	runAndroidAppTestCase(t, Bp2buildTestCase{
+		Description:                "Android test - simple example",
+		ModuleTypeUnderTest:        "android_test",
+		ModuleTypeUnderTestFactory: java.AndroidTestFactory,
+		Filesystem: map[string]string{
+			"app.java":            "",
+			"res/res.png":         "",
+			"AndroidManifest.xml": "",
+			"assets/asset.png":    "",
+		},
+		Blueprint: `
+android_test {
+		name: "TestApp",
+		srcs: ["app.java"],
+		sdk_version: "current",
 		optimize: {
+			enabled: true,
 			shrink: true,
 			optimize: true,
 			obfuscate: true,
@@ -62,6 +95,9 @@
 				"sdk_version":    `"current"`,
 				"assets":         `["assets/asset.png"]`,
 				"assets_dir":     `"assets"`,
+				// optimize = True because it's false for android_test by
+				// default
+				"optimize": `True`,
 			}),
 		}})
 }
@@ -98,6 +134,45 @@
 				"assets":         `["assets/asset.png"]`,
 				"assets_dir":     `"assets"`,
 				"testonly":       `True`,
+				// no need for optimize = True because it's true for
+				// android_test_helper_app by default
+			}),
+		}})
+}
+
+func TestAndroidTestHelperApp_OptimizationDisabled(t *testing.T) {
+	runAndroidAppTestCase(t, Bp2buildTestCase{
+		Description:                "Android test helper app - simple example",
+		ModuleTypeUnderTest:        "android_test_helper_app",
+		ModuleTypeUnderTestFactory: java.AndroidTestHelperAppFactory,
+		Filesystem: map[string]string{
+			"app.java":            "",
+			"res/res.png":         "",
+			"AndroidManifest.xml": "",
+			"assets/asset.png":    "",
+		},
+		Blueprint: `
+android_test_helper_app {
+		name: "TestApp",
+		srcs: ["app.java"],
+		sdk_version: "current",
+		optimize: {
+			enabled: false,
+		},
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("android_binary", "TestApp", AttrNameToString{
+				"srcs":           `["app.java"]`,
+				"manifest":       `"AndroidManifest.xml"`,
+				"resource_files": `["res/res.png"]`,
+				"sdk_version":    `"current"`,
+				"assets":         `["assets/asset.png"]`,
+				"assets_dir":     `"assets"`,
+				"testonly":       `True`,
+				// optimize = False because it's true for
+				// android_test_helper_app by default
+				"optimize": `False`,
 			}),
 		}})
 }
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 60de28c..bdb655b 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -112,7 +112,7 @@
 }
 
 cc_binary { name: "cc_binary_1"}
-sh_binary { name: "sh_binary_2"}
+sh_binary { name: "sh_binary_2", src: "foo.sh"}
 
 apex {
 	name: "com.android.apogee",
@@ -158,22 +158,22 @@
 				"manifest":        `"apogee_manifest.json"`,
 				"min_sdk_version": `"29"`,
 				"native_shared_libs_32": `select({
-        "//build/bazel/platforms/arch:arm": [
+        "//build/bazel_common_rules/platforms/arch:arm": [
             ":native_shared_lib_1",
             ":native_shared_lib_2",
         ],
-        "//build/bazel/platforms/arch:x86": [
+        "//build/bazel_common_rules/platforms/arch:x86": [
             ":native_shared_lib_1",
             ":native_shared_lib_2",
         ],
         "//conditions:default": [],
     })`,
 				"native_shared_libs_64": `select({
-        "//build/bazel/platforms/arch:arm64": [
+        "//build/bazel_common_rules/platforms/arch:arm64": [
             ":native_shared_lib_1",
             ":native_shared_lib_2",
         ],
-        "//build/bazel/platforms/arch:x86_64": [
+        "//build/bazel_common_rules/platforms/arch:x86_64": [
             ":native_shared_lib_1",
             ":native_shared_lib_2",
         ],
@@ -293,18 +293,18 @@
         ":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"],
+        "//build/bazel_common_rules/platforms/arch:arm": [":native_shared_lib_for_first"],
+        "//build/bazel_common_rules/platforms/arch:x86": [":native_shared_lib_for_first"],
         "//conditions:default": [],
     })`,
 				"native_shared_libs_64": `select({
-        "//build/bazel/platforms/arch:arm64": [
+        "//build/bazel_common_rules/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": [
+        "//build/bazel_common_rules/platforms/arch:x86_64": [
             ":unnested_native_shared_lib",
             ":native_shared_lib_for_both",
             ":native_shared_lib_for_lib64",
@@ -322,13 +322,13 @@
 	expectedBazelTargets := []string{
 		MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 			"native_shared_libs_32": `select({
-        "//build/bazel/platforms/arch:arm": [
+        "//build/bazel_common_rules/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": [
+        "//build/bazel_common_rules/platforms/arch:x86": [
             ":unnested_native_shared_lib",
             ":native_shared_lib_for_both",
             ":native_shared_lib_for_lib32",
@@ -337,13 +337,13 @@
         "//conditions:default": [],
     })`,
 			"native_shared_libs_64": `select({
-        "//build/bazel/platforms/arch:arm64": [
+        "//build/bazel_common_rules/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": [
+        "//build/bazel_common_rules/platforms/arch:x86_64": [
             ":unnested_native_shared_lib",
             ":native_shared_lib_for_both",
             ":native_shared_lib_for_lib64",
@@ -405,8 +405,8 @@
         ":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"],
+        "//build/bazel_common_rules/platforms/arch:arm": [":native_shared_lib_for_first"],
+        "//build/bazel_common_rules/platforms/arch:x86": [":native_shared_lib_for_first"],
         "//conditions:default": [],
     })`,
 				"file_contexts": `"//system/sepolicy/apex:com.android.apogee-file_contexts"`,
@@ -433,13 +433,13 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"native_shared_libs_64": `select({
-        "//build/bazel/platforms/arch:arm64": [
+        "//build/bazel_common_rules/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": [
+        "//build/bazel_common_rules/platforms/arch:x86_64": [
             ":unnested_native_shared_lib",
             ":native_shared_lib_for_both",
             ":native_shared_lib_for_lib64",
@@ -609,7 +609,7 @@
 }
 
 cc_binary { name: "cc_binary_1" }
-sh_binary { name: "sh_binary_2" }
+sh_binary { name: "sh_binary_2", src: "foo.sh"}
 
 apex {
 	name: "com.android.apogee",
@@ -671,22 +671,22 @@
 				"manifest":        `"apogee_manifest.json"`,
 				"min_sdk_version": `"29"`,
 				"native_shared_libs_32": `select({
-        "//build/bazel/platforms/arch:arm": [
+        "//build/bazel_common_rules/platforms/arch:arm": [
             ":native_shared_lib_1",
             ":native_shared_lib_2",
         ],
-        "//build/bazel/platforms/arch:x86": [
+        "//build/bazel_common_rules/platforms/arch:x86": [
             ":native_shared_lib_1",
             ":native_shared_lib_2",
         ],
         "//conditions:default": [],
     })`,
 				"native_shared_libs_64": `select({
-        "//build/bazel/platforms/arch:arm64": [
+        "//build/bazel_common_rules/platforms/arch:arm64": [
             ":native_shared_lib_1",
             ":native_shared_lib_2",
         ],
-        "//build/bazel/platforms/arch:x86_64": [
+        "//build/bazel_common_rules/platforms/arch:x86_64": [
             ":native_shared_lib_1",
             ":native_shared_lib_2",
         ],
@@ -736,7 +736,7 @@
 }
 
 cc_binary { name: "cc_binary_1"}
-sh_binary { name: "sh_binary_2"}
+sh_binary { name: "sh_binary_2", src: "foo.sh"}
 
 apex_test {
 	name: "com.android.apogee",
@@ -796,13 +796,13 @@
 				"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"],
+        "//build/bazel_common_rules/platforms/arch:arm": [":native_shared_lib_1"],
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/arch:arm64": [":native_shared_lib_1"],
+        "//build/bazel_common_rules/platforms/arch:x86_64": [":native_shared_lib_1"],
         "//conditions:default": [],
     })`,
 				"testonly":     "True",
@@ -1298,13 +1298,13 @@
 				"manifest":      `"myapex_manifest.json"`,
 				"binaries":      `[":bar"]`,
 				"native_shared_libs_32": `select({
-        "//build/bazel/platforms/arch:arm": [":foo"],
-        "//build/bazel/platforms/arch:x86": [":foo"],
+        "//build/bazel_common_rules/platforms/arch:arm": [":foo"],
+        "//build/bazel_common_rules/platforms/arch:x86": [":foo"],
         "//conditions:default": [],
     })`,
 				"native_shared_libs_64": `select({
-        "//build/bazel/platforms/arch:arm64": [":foo"],
-        "//build/bazel/platforms/arch:x86_64": [":foo"],
+        "//build/bazel_common_rules/platforms/arch:arm64": [":foo"],
+        "//build/bazel_common_rules/platforms/arch:x86_64": [":foo"],
         "//conditions:default": [],
     })`,
 			}),
diff --git a/bp2build/apex_key_conversion_test.go b/bp2build/apex_key_conversion_test.go
index 140afb7..05e2f25 100644
--- a/bp2build/apex_key_conversion_test.go
+++ b/bp2build/apex_key_conversion_test.go
@@ -49,7 +49,7 @@
 		ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{
 			"private_key":            `"com.android.apogee.pem"`,
 			"public_key":             `"com.android.apogee.avbpubkey"`,
-			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+			"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 		}),
 		}})
 }
@@ -72,7 +72,7 @@
 		ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{
 			"private_key_name":       `"com.android.apogee.pem"`,
 			"public_key_name":        `"com.android.apogee.avbpubkey"`,
-			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+			"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 		}),
 		}})
 }
@@ -95,7 +95,7 @@
 		ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{
 			"private_key":            `":com.android.apogee.pem"`,
 			"public_key":             `":com.android.apogee.avbpubkey"`,
-			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+			"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 		}),
 		}})
 }
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index 6c9d903..1496ca7 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -82,7 +82,7 @@
 		os.Exit(1)
 	}
 	var bp2buildFiles []BazelFile
-	productConfig, err := createProductConfigFiles(ctx, res.metrics)
+	productConfig, err := createProductConfigFiles(ctx, res.moduleNameToPartition, res.metrics.convertedModulePathMap)
 	ctx.Context().EventHandler.Do("CreateBazelFile", func() {
 		allTargets := make(map[string]BazelTargets)
 		for k, v := range res.buildFileToTargets {
diff --git a/bp2build/bp2build_product_config.go b/bp2build/bp2build_product_config.go
index 7c26262..7f26bef 100644
--- a/bp2build/bp2build_product_config.go
+++ b/bp2build/bp2build_product_config.go
@@ -3,9 +3,9 @@
 import (
 	"encoding/json"
 	"fmt"
-	"os"
 	"path/filepath"
 	"reflect"
+	"sort"
 	"strings"
 
 	"android/soong/android"
@@ -22,9 +22,38 @@
 	bp2buildTargets map[string]BazelTargets
 }
 
+type bazelLabel struct {
+	repo   string
+	pkg    string
+	target string
+}
+
+const releaseAconfigValueSetsName = "release_aconfig_value_sets"
+
+func (l *bazelLabel) Less(other *bazelLabel) bool {
+	if l.repo < other.repo {
+		return true
+	}
+	if l.repo > other.repo {
+		return false
+	}
+	if l.pkg < other.pkg {
+		return true
+	}
+	if l.pkg > other.pkg {
+		return false
+	}
+	return l.target < other.target
+}
+
+func (l *bazelLabel) String() string {
+	return fmt.Sprintf("@%s//%s:%s", l.repo, l.pkg, l.target)
+}
+
 func createProductConfigFiles(
 	ctx *CodegenContext,
-	metrics CodegenMetrics) (createProductConfigFilesResult, error) {
+	moduleNameToPartition map[string]string,
+	convertedModulePathMap map[string]string) (createProductConfigFilesResult, error) {
 	cfg := &ctx.config
 	targetProduct := "unknown"
 	if cfg.HasDeviceProduct() {
@@ -39,23 +68,18 @@
 
 	var res createProductConfigFilesResult
 
-	productVariablesFileName := cfg.ProductVariablesFileName
-	if !strings.HasPrefix(productVariablesFileName, "/") {
-		productVariablesFileName = filepath.Join(ctx.topDir, productVariablesFileName)
-	}
-	productVariablesBytes, err := os.ReadFile(productVariablesFileName)
-	if err != nil {
-		return res, err
-	}
-	productVariables := android.ProductVariables{}
-	err = json.Unmarshal(productVariablesBytes, &productVariables)
+	productVariables := ctx.Config().ProductVariables()
+	// TODO(b/306243251): For some reason, using the real value of native_coverage makes some select
+	// statements ambiguous
+	productVariables.Native_coverage = nil
+	productVariablesBytes, err := json.Marshal(productVariables)
 	if err != nil {
 		return res, err
 	}
 
 	currentProductFolder := fmt.Sprintf("build/bazel/products/%s", targetProduct)
-	if len(productVariables.PartitionVars.ProductDirectory) > 0 {
-		currentProductFolder = fmt.Sprintf("%s%s", productVariables.PartitionVars.ProductDirectory, targetProduct)
+	if len(productVariables.PartitionVarsForBazelMigrationOnlyDoNotUse.ProductDirectory) > 0 {
+		currentProductFolder = fmt.Sprintf("%s%s", productVariables.PartitionVarsForBazelMigrationOnlyDoNotUse.ProductDirectory, targetProduct)
 	}
 
 	productReplacer := strings.NewReplacer(
@@ -72,14 +96,22 @@
 		productsForTesting[i] = fmt.Sprintf("  \"@//build/bazel/tests/products:%s\",", productsForTesting[i])
 	}
 
-	productLabelsToVariables := make(map[string]*android.ProductVariables)
-	productLabelsToVariables[productReplacer.Replace("@//{PRODUCT_FOLDER}:{PRODUCT}")] = &productVariables
+	productLabelsToVariables := make(map[bazelLabel]*android.ProductVariables)
+	productLabelsToVariables[bazelLabel{
+		repo:   "",
+		pkg:    currentProductFolder,
+		target: targetProduct,
+	}] = &productVariables
 	for product, productVariablesStarlark := range productsForTestingMap {
 		productVariables, err := starlarkMapToProductVariables(productVariablesStarlark)
 		if err != nil {
 			return res, err
 		}
-		productLabelsToVariables["@//build/bazel/tests/products:"+product] = &productVariables
+		productLabelsToVariables[bazelLabel{
+			repo:   "",
+			pkg:    "build/bazel/tests/products",
+			target: product,
+		}] = &productVariables
 	}
 
 	res.bp2buildTargets = make(map[string]BazelTargets)
@@ -105,12 +137,12 @@
 			},
 		},
 	})
-	createTargets(productLabelsToVariables, res.bp2buildTargets)
+	createTargets(ctx, productLabelsToVariables, moduleNameToPartition, convertedModulePathMap, res.bp2buildTargets)
 
 	platformMappingContent, err := platformMappingContent(
 		productLabelsToVariables,
 		ctx.Config().Bp2buildSoongConfigDefinitions,
-		metrics.convertedModulePathMap)
+		convertedModulePathMap)
 	if err != nil {
 		return res, err
 	}
@@ -194,7 +226,7 @@
 }
 
 func platformMappingContent(
-	productLabelToVariables map[string]*android.ProductVariables,
+	productLabelToVariables map[bazelLabel]*android.ProductVariables,
 	soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions,
 	convertedModulePathMap map[string]string) (string, error) {
 	var result strings.Builder
@@ -211,9 +243,16 @@
 		mergedConvertedModulePathMap[k] = v
 	}
 
+	productLabels := make([]bazelLabel, 0, len(productLabelToVariables))
+	for k := range productLabelToVariables {
+		productLabels = append(productLabels, k)
+	}
+	sort.Slice(productLabels, func(i, j int) bool {
+		return productLabels[i].Less(&productLabels[j])
+	})
 	result.WriteString("platforms:\n")
-	for productLabel, productVariables := range productLabelToVariables {
-		platformMappingSingleProduct(productLabel, productVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result)
+	for _, productLabel := range productLabels {
+		platformMappingSingleProduct(productLabel, productLabelToVariables[productLabel], soongConfigDefinitions, mergedConvertedModulePathMap, &result)
 	}
 	return result.String(), nil
 }
@@ -233,7 +272,7 @@
 }
 
 func platformMappingSingleProduct(
-	label string,
+	label bazelLabel,
 	productVariables *android.ProductVariables,
 	soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions,
 	convertedModulePathMap map[string]string,
@@ -249,11 +288,22 @@
 		defaultAppCertificateFilegroup = "@//" + filepath.Dir(proptools.String(productVariables.DefaultAppCertificate)) + ":generated_android_certificate_directory"
 	}
 
+	// TODO: b/301598690 - commas can't be escaped in a string-list passed in a platform mapping,
+	// so commas are switched for ":" here, and must be back-substituted into commas
+	// wherever the AAPTCharacteristics product config variable is used.
+	AAPTConfig := []string{}
+	for _, conf := range productVariables.AAPTConfig {
+		AAPTConfig = append(AAPTConfig, strings.Replace(conf, ",", ":", -1))
+	}
+
 	for _, suffix := range bazelPlatformSuffixes {
 		result.WriteString("  ")
-		result.WriteString(label)
+		result.WriteString(label.String())
 		result.WriteString(suffix)
 		result.WriteString("\n")
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:aapt_characteristics=%s\n", proptools.String(productVariables.AAPTCharacteristics)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:aapt_config=%s\n", strings.Join(AAPTConfig, ",")))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:aapt_preferred_config=%s\n", proptools.String(productVariables.AAPTPreferredConfig)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:always_use_prebuilt_sdks=%t\n", proptools.Bool(productVariables.Always_use_prebuilt_sdks)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:arc=%t\n", proptools.Bool(productVariables.Arc)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:apex_global_min_sdk_version_override=%s\n", proptools.String(productVariables.ApexGlobalMinSdkVersionOverride)))
@@ -272,7 +322,7 @@
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_name=%s\n", proptools.String(productVariables.DeviceName)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_page_size_agnostic=%t\n", proptools.Bool(productVariables.DevicePageSizeAgnostic)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_product=%s\n", proptools.String(productVariables.DeviceProduct)))
-		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_platform=%s\n", label))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_platform=%s\n", label.String()))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:enable_cfi=%t\n", proptools.BoolDefault(productVariables.EnableCFI, true)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:enforce_vintf_manifest=%t\n", proptools.Bool(productVariables.Enforce_vintf_manifest)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:malloc_not_svelte=%t\n", proptools.Bool(productVariables.Malloc_not_svelte)))
@@ -284,14 +334,17 @@
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:manifest_package_name_overrides=%s\n", strings.Join(productVariables.ManifestPackageNameOverrides, ",")))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:native_coverage=%t\n", proptools.Bool(productVariables.Native_coverage)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:platform_sdk_final=%t\n", proptools.Bool(productVariables.Platform_sdk_final)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:platform_security_patch=%s\n", proptools.String(productVariables.Platform_security_patch)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:platform_version_last_stable=%s\n", proptools.String(productVariables.Platform_version_last_stable)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:platform_version_name=%s\n", proptools.String(productVariables.Platform_version_name)))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:product_brand=%s\n", productVariables.ProductBrand))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:product_manufacturer=%s\n", productVariables.ProductManufacturer))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:release_aconfig_flag_default_permission=%s\n", productVariables.ReleaseAconfigFlagDefaultPermission))
-		// Empty string can't be used as label_flag on the bazel side
+		releaseAconfigValueSets := "//build/bazel/product_config:empty_aconfig_value_sets"
 		if len(productVariables.ReleaseAconfigValueSets) > 0 {
-			result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:release_aconfig_value_sets=%s\n", productVariables.ReleaseAconfigValueSets))
+			releaseAconfigValueSets = "@//" + label.pkg + ":" + releaseAconfigValueSetsName + "_" + label.target
 		}
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:release_aconfig_value_sets=%s\n", releaseAconfigValueSets))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:release_version=%s\n", productVariables.ReleaseVersion))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:platform_sdk_version=%d\n", platform_sdk_version))
 		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:safestack=%t\n", proptools.Bool(productVariables.Safestack)))
@@ -310,8 +363,9 @@
 			}
 		}
 
-		for namespace, namespaceContents := range productVariables.VendorVars {
-			for variable, value := range namespaceContents {
+		for _, namespace := range android.SortedKeys(productVariables.VendorVars) {
+			for _, variable := range android.SortedKeys(productVariables.VendorVars[namespace]) {
+				value := productVariables.VendorVars[namespace][variable]
 				key := namespace + "__" + variable
 				_, hasBool := soongConfigDefinitions.BoolVars[key]
 				_, hasString := soongConfigDefinitions.StringVars[key]
@@ -422,11 +476,21 @@
 	return result, nil
 }
 
-func createTargets(productLabelsToVariables map[string]*android.ProductVariables, res map[string]BazelTargets) {
+func createTargets(
+	ctx *CodegenContext,
+	productLabelsToVariables map[bazelLabel]*android.ProductVariables,
+	moduleNameToPartition map[string]string,
+	convertedModulePathMap map[string]string,
+	res map[string]BazelTargets) {
 	createGeneratedAndroidCertificateDirectories(productLabelsToVariables, res)
+	createAvbKeyFilegroups(productLabelsToVariables, res)
+	createReleaseAconfigValueSetsFilegroup(productLabelsToVariables, res)
+	for label, variables := range productLabelsToVariables {
+		createSystemPartition(ctx, label, &variables.PartitionVarsForBazelMigrationOnlyDoNotUse, moduleNameToPartition, convertedModulePathMap, res)
+	}
 }
 
-func createGeneratedAndroidCertificateDirectories(productLabelsToVariables map[string]*android.ProductVariables, targets map[string]BazelTargets) {
+func createGeneratedAndroidCertificateDirectories(productLabelsToVariables map[bazelLabel]*android.ProductVariables, targets map[string]BazelTargets) {
 	var allDefaultAppCertificateDirs []string
 	for _, productVariables := range productLabelsToVariables {
 		if proptools.String(productVariables.DefaultAppCertificate) != "" {
@@ -454,3 +518,371 @@
 		})
 	}
 }
+
+func createReleaseAconfigValueSetsFilegroup(productLabelsToVariables map[bazelLabel]*android.ProductVariables, targets map[string]BazelTargets) {
+	for label, productVariables := range productLabelsToVariables {
+		if len(productVariables.ReleaseAconfigValueSets) > 0 {
+			key := label.target
+			dir := label.pkg
+			var value_sets strings.Builder
+			for _, value_set := range productVariables.ReleaseAconfigValueSets {
+				value_sets.WriteString("        \"" + value_set + "\",\n")
+			}
+
+			name := releaseAconfigValueSetsName + "_" + key
+			content := "aconfig_value_sets(\n" +
+				"    name = \"" + name + "\",\n" +
+				"    value_sets = [\n" +
+				value_sets.String() +
+				"    ],\n" +
+				"    visibility = [\"//visibility:public\"],\n" +
+				")"
+			targets[dir] = append(targets[dir], BazelTarget{
+				name:        name,
+				packageName: dir,
+				content:     content,
+				ruleClass:   "aconfig_value_sets",
+				loads: []BazelLoad{{
+					file: "//build/bazel/rules/aconfig:aconfig_value_sets.bzl",
+					symbols: []BazelLoadSymbol{{
+						symbol: "aconfig_value_sets",
+					}},
+				}},
+			})
+		}
+	}
+}
+
+func createAvbKeyFilegroups(productLabelsToVariables map[bazelLabel]*android.ProductVariables, targets map[string]BazelTargets) {
+	var allAvbKeys []string
+	for _, productVariables := range productLabelsToVariables {
+		for _, partitionVariables := range productVariables.PartitionVarsForBazelMigrationOnlyDoNotUse.PartitionQualifiedVariables {
+			if partitionVariables.BoardAvbKeyPath != "" {
+				if !android.InList(partitionVariables.BoardAvbKeyPath, allAvbKeys) {
+					allAvbKeys = append(allAvbKeys, partitionVariables.BoardAvbKeyPath)
+				}
+			}
+		}
+	}
+	for _, key := range allAvbKeys {
+		dir := filepath.Dir(key)
+		name := filepath.Base(key)
+		content := fmt.Sprintf(`filegroup(
+    name = "%s_filegroup",
+    srcs = ["%s"],
+    visibility = ["//visibility:public"],
+)`, name, name)
+		targets[dir] = append(targets[dir], BazelTarget{
+			name:        name + "_filegroup",
+			packageName: dir,
+			content:     content,
+			ruleClass:   "filegroup",
+		})
+	}
+}
+
+func createSystemPartition(
+	ctx *CodegenContext,
+	platformLabel bazelLabel,
+	variables *android.PartitionVariables,
+	moduleNameToPartition map[string]string,
+	convertedModulePathMap map[string]string,
+	targets map[string]BazelTargets) {
+	if !variables.PartitionQualifiedVariables["system"].BuildingImage {
+		return
+	}
+	qualifiedVariables := variables.PartitionQualifiedVariables["system"]
+
+	imageProps := generateImagePropDictionary(variables, "system")
+	imageProps["skip_fsck"] = "true"
+
+	var properties strings.Builder
+	for _, prop := range android.SortedKeys(imageProps) {
+		properties.WriteString(prop)
+		properties.WriteRune('=')
+		properties.WriteString(imageProps[prop])
+		properties.WriteRune('\n')
+	}
+
+	var extraProperties strings.Builder
+	if variables.BoardAvbEnable {
+		extraProperties.WriteString("    avb_enable = True,\n")
+		extraProperties.WriteString(fmt.Sprintf("    avb_add_hashtree_footer_args = %q,\n", qualifiedVariables.BoardAvbAddHashtreeFooterArgs))
+		keypath := qualifiedVariables.BoardAvbKeyPath
+		if keypath != "" {
+			extraProperties.WriteString(fmt.Sprintf("    avb_key = \"//%s:%s\",\n", filepath.Dir(keypath), filepath.Base(keypath)+"_filegroup"))
+			extraProperties.WriteString(fmt.Sprintf("    avb_algorithm = %q,\n", qualifiedVariables.BoardAvbAlgorithm))
+			extraProperties.WriteString(fmt.Sprintf("    avb_rollback_index = %s,\n", qualifiedVariables.BoardAvbRollbackIndex))
+			extraProperties.WriteString(fmt.Sprintf("    avb_rollback_index_location = %s,\n", qualifiedVariables.BoardAvbRollbackIndexLocation))
+		}
+	}
+
+	var deps []string
+	for _, mod := range variables.ProductPackages {
+		if path, ok := convertedModulePathMap[mod]; ok && ctx.Config().BazelContext.IsModuleNameAllowed(mod, false) {
+			if partition, ok := moduleNameToPartition[mod]; ok && partition == "system" {
+				if path == "//." {
+					path = "//"
+				}
+				deps = append(deps, fmt.Sprintf("        \"%s:%s\",\n", path, mod))
+			}
+		}
+	}
+	if len(deps) > 0 {
+		sort.Strings(deps)
+		extraProperties.WriteString("    deps = [\n")
+		for _, dep := range deps {
+			extraProperties.WriteString(dep)
+		}
+		extraProperties.WriteString("    ],\n")
+	}
+
+	targets[platformLabel.pkg] = append(targets[platformLabel.pkg], BazelTarget{
+		name:        "system_image",
+		packageName: platformLabel.pkg,
+		content: fmt.Sprintf(`partition(
+    name = "system_image",
+    base_staging_dir = "//build/bazel/bazel_sandwich:system_staging_dir",
+    base_staging_dir_file_list = "//build/bazel/bazel_sandwich:system_staging_dir_file_list",
+    root_dir = "//build/bazel/bazel_sandwich:root_staging_dir",
+    selinux_file_contexts = "//build/bazel/bazel_sandwich:selinux_file_contexts",
+    image_properties = """
+%s
+""",
+%s
+    type = "system",
+)`, properties.String(), extraProperties.String()),
+		ruleClass: "partition",
+		loads: []BazelLoad{{
+			file: "//build/bazel/rules/partitions:partition.bzl",
+			symbols: []BazelLoadSymbol{{
+				symbol: "partition",
+			}},
+		}},
+	}, BazelTarget{
+		name:        "system_image_test",
+		packageName: platformLabel.pkg,
+		content: `partition_diff_test(
+    name = "system_image_test",
+    partition1 = "//build/bazel/bazel_sandwich:make_system_image",
+    partition2 = ":system_image",
+)`,
+		ruleClass: "partition_diff_test",
+		loads: []BazelLoad{{
+			file: "//build/bazel/rules/partitions/diff:partition_diff.bzl",
+			symbols: []BazelLoadSymbol{{
+				symbol: "partition_diff_test",
+			}},
+		}},
+	}, BazelTarget{
+		name:        "run_system_image_test",
+		packageName: platformLabel.pkg,
+		content: `run_test_in_build(
+    name = "run_system_image_test",
+    test = ":system_image_test",
+)`,
+		ruleClass: "run_test_in_build",
+		loads: []BazelLoad{{
+			file: "//build/bazel/bazel_sandwich:run_test_in_build.bzl",
+			symbols: []BazelLoadSymbol{{
+				symbol: "run_test_in_build",
+			}},
+		}},
+	})
+}
+
+var allPartitionTypes = []string{
+	"system",
+	"vendor",
+	"cache",
+	"userdata",
+	"product",
+	"system_ext",
+	"oem",
+	"odm",
+	"vendor_dlkm",
+	"odm_dlkm",
+	"system_dlkm",
+}
+
+// An equivalent of make's generate-image-prop-dictionary function
+func generateImagePropDictionary(variables *android.PartitionVariables, partitionType string) map[string]string {
+	partitionQualifiedVariables, ok := variables.PartitionQualifiedVariables[partitionType]
+	if !ok {
+		panic("Unknown partitionType: " + partitionType)
+	}
+	ret := map[string]string{}
+	if partitionType == "system" {
+		if len(variables.PartitionQualifiedVariables["system_other"].BoardPartitionSize) > 0 {
+			ret["system_other_size"] = variables.PartitionQualifiedVariables["system_other"].BoardPartitionSize
+		}
+		if len(partitionQualifiedVariables.ProductHeadroom) > 0 {
+			ret["system_headroom"] = partitionQualifiedVariables.ProductHeadroom
+		}
+		addCommonRoFlagsToImageProps(variables, partitionType, ret)
+	}
+	// TODO: other partition-specific logic
+	if variables.TargetUserimagesUseExt2 {
+		ret["fs_type"] = "ext2"
+	} else if variables.TargetUserimagesUseExt3 {
+		ret["fs_type"] = "ext3"
+	} else if variables.TargetUserimagesUseExt4 {
+		ret["fs_type"] = "ext4"
+	}
+
+	if !variables.TargetUserimagesSparseExtDisabled {
+		ret["extfs_sparse_flag"] = "-s"
+	}
+	if !variables.TargetUserimagesSparseErofsDisabled {
+		ret["erofs_sparse_flag"] = "-s"
+	}
+	if !variables.TargetUserimagesSparseSquashfsDisabled {
+		ret["squashfs_sparse_flag"] = "-s"
+	}
+	if !variables.TargetUserimagesSparseF2fsDisabled {
+		ret["f2fs_sparse_flag"] = "-S"
+	}
+	erofsCompressor := variables.BoardErofsCompressor
+	if len(erofsCompressor) == 0 && hasErofsPartition(variables) {
+		if len(variables.BoardErofsUseLegacyCompression) > 0 {
+			erofsCompressor = "lz4"
+		} else {
+			erofsCompressor = "lz4hc,9"
+		}
+	}
+	if len(erofsCompressor) > 0 {
+		ret["erofs_default_compressor"] = erofsCompressor
+	}
+	if len(variables.BoardErofsCompressorHints) > 0 {
+		ret["erofs_default_compress_hints"] = variables.BoardErofsCompressorHints
+	}
+	if len(variables.BoardErofsCompressorHints) > 0 {
+		ret["erofs_default_compress_hints"] = variables.BoardErofsCompressorHints
+	}
+	if len(variables.BoardErofsPclusterSize) > 0 {
+		ret["erofs_pcluster_size"] = variables.BoardErofsPclusterSize
+	}
+	if len(variables.BoardErofsShareDupBlocks) > 0 {
+		ret["erofs_share_dup_blocks"] = variables.BoardErofsShareDupBlocks
+	}
+	if len(variables.BoardErofsUseLegacyCompression) > 0 {
+		ret["erofs_use_legacy_compression"] = variables.BoardErofsUseLegacyCompression
+	}
+	if len(variables.BoardExt4ShareDupBlocks) > 0 {
+		ret["ext4_share_dup_blocks"] = variables.BoardExt4ShareDupBlocks
+	}
+	if len(variables.BoardFlashLogicalBlockSize) > 0 {
+		ret["flash_logical_block_size"] = variables.BoardFlashLogicalBlockSize
+	}
+	if len(variables.BoardFlashEraseBlockSize) > 0 {
+		ret["flash_erase_block_size"] = variables.BoardFlashEraseBlockSize
+	}
+	if len(variables.BoardExt4ShareDupBlocks) > 0 {
+		ret["ext4_share_dup_blocks"] = variables.BoardExt4ShareDupBlocks
+	}
+	if len(variables.BoardExt4ShareDupBlocks) > 0 {
+		ret["ext4_share_dup_blocks"] = variables.BoardExt4ShareDupBlocks
+	}
+	for _, partitionType := range allPartitionTypes {
+		if qualifiedVariables, ok := variables.PartitionQualifiedVariables[partitionType]; ok && len(qualifiedVariables.ProductVerityPartition) > 0 {
+			ret[partitionType+"_verity_block_device"] = qualifiedVariables.ProductVerityPartition
+		}
+	}
+	// TODO: Vboot
+	// TODO: AVB
+	if variables.BoardUsesRecoveryAsBoot {
+		ret["recovery_as_boot"] = "true"
+	}
+	if variables.BoardBuildGkiBootImageWithoutRamdisk {
+		ret["gki_boot_image_without_ramdisk"] = "true"
+	}
+	if variables.ProductUseDynamicPartitionSize {
+		ret["use_dynamic_partition_size"] = "true"
+	}
+	if variables.CopyImagesForTargetFilesZip {
+		ret["use_fixed_timestamp"] = "true"
+	}
+	return ret
+}
+
+// Soong equivalent of make's add-common-ro-flags-to-image-props
+func addCommonRoFlagsToImageProps(variables *android.PartitionVariables, partitionType string, ret map[string]string) {
+	partitionQualifiedVariables, ok := variables.PartitionQualifiedVariables[partitionType]
+	if !ok {
+		panic("Unknown partitionType: " + partitionType)
+	}
+	if len(partitionQualifiedVariables.BoardErofsCompressor) > 0 {
+		ret[partitionType+"_erofs_compressor"] = partitionQualifiedVariables.BoardErofsCompressor
+	}
+	if len(partitionQualifiedVariables.BoardErofsCompressHints) > 0 {
+		ret[partitionType+"_erofs_compress_hints"] = partitionQualifiedVariables.BoardErofsCompressHints
+	}
+	if len(partitionQualifiedVariables.BoardErofsPclusterSize) > 0 {
+		ret[partitionType+"_erofs_pcluster_size"] = partitionQualifiedVariables.BoardErofsPclusterSize
+	}
+	if len(partitionQualifiedVariables.BoardExtfsRsvPct) > 0 {
+		ret[partitionType+"_extfs_rsv_pct"] = partitionQualifiedVariables.BoardExtfsRsvPct
+	}
+	if len(partitionQualifiedVariables.BoardF2fsSloadCompressFlags) > 0 {
+		ret[partitionType+"_f2fs_sldc_flags"] = partitionQualifiedVariables.BoardF2fsSloadCompressFlags
+	}
+	if len(partitionQualifiedVariables.BoardFileSystemCompress) > 0 {
+		ret[partitionType+"_f2fs_compress"] = partitionQualifiedVariables.BoardFileSystemCompress
+	}
+	if len(partitionQualifiedVariables.BoardFileSystemType) > 0 {
+		ret[partitionType+"_fs_type"] = partitionQualifiedVariables.BoardFileSystemType
+	}
+	if len(partitionQualifiedVariables.BoardJournalSize) > 0 {
+		ret[partitionType+"_journal_size"] = partitionQualifiedVariables.BoardJournalSize
+	}
+	if len(partitionQualifiedVariables.BoardPartitionReservedSize) > 0 {
+		ret[partitionType+"_reserved_size"] = partitionQualifiedVariables.BoardPartitionReservedSize
+	}
+	if len(partitionQualifiedVariables.BoardPartitionSize) > 0 {
+		ret[partitionType+"_size"] = partitionQualifiedVariables.BoardPartitionSize
+	}
+	if len(partitionQualifiedVariables.BoardSquashfsBlockSize) > 0 {
+		ret[partitionType+"_squashfs_block_size"] = partitionQualifiedVariables.BoardSquashfsBlockSize
+	}
+	if len(partitionQualifiedVariables.BoardSquashfsCompressor) > 0 {
+		ret[partitionType+"_squashfs_compressor"] = partitionQualifiedVariables.BoardSquashfsCompressor
+	}
+	if len(partitionQualifiedVariables.BoardSquashfsCompressorOpt) > 0 {
+		ret[partitionType+"_squashfs_compressor_opt"] = partitionQualifiedVariables.BoardSquashfsCompressorOpt
+	}
+	if len(partitionQualifiedVariables.BoardSquashfsDisable4kAlign) > 0 {
+		ret[partitionType+"_squashfs_disable_4k_align"] = partitionQualifiedVariables.BoardSquashfsDisable4kAlign
+	}
+	if len(partitionQualifiedVariables.BoardPartitionSize) == 0 && len(partitionQualifiedVariables.BoardPartitionReservedSize) == 0 && len(partitionQualifiedVariables.ProductHeadroom) == 0 {
+		ret[partitionType+"_disable_sparse"] = "true"
+	}
+	addCommonFlagsToImageProps(variables, partitionType, ret)
+}
+
+func hasErofsPartition(variables *android.PartitionVariables) bool {
+	return variables.PartitionQualifiedVariables["product"].BoardFileSystemType == "erofs" ||
+		variables.PartitionQualifiedVariables["system_ext"].BoardFileSystemType == "erofs" ||
+		variables.PartitionQualifiedVariables["odm"].BoardFileSystemType == "erofs" ||
+		variables.PartitionQualifiedVariables["vendor"].BoardFileSystemType == "erofs" ||
+		variables.PartitionQualifiedVariables["system"].BoardFileSystemType == "erofs" ||
+		variables.PartitionQualifiedVariables["vendor_dlkm"].BoardFileSystemType == "erofs" ||
+		variables.PartitionQualifiedVariables["odm_dlkm"].BoardFileSystemType == "erofs" ||
+		variables.PartitionQualifiedVariables["system_dlkm"].BoardFileSystemType == "erofs"
+}
+
+// Soong equivalent of make's add-common-flags-to-image-props
+func addCommonFlagsToImageProps(variables *android.PartitionVariables, partitionType string, ret map[string]string) {
+	// The selinux_fc will be handled separately
+	partitionQualifiedVariables, ok := variables.PartitionQualifiedVariables[partitionType]
+	if !ok {
+		panic("Unknown partitionType: " + partitionType)
+	}
+	ret["building_"+partitionType+"_image"] = boolToMakeString(partitionQualifiedVariables.BuildingImage)
+}
+
+func boolToMakeString(b bool) string {
+	if b {
+		return "true"
+	}
+	return ""
+}
diff --git a/bp2build/bp2build_product_config_test.go b/bp2build/bp2build_product_config_test.go
index 02d83b4..02a2b51 100644
--- a/bp2build/bp2build_product_config_test.go
+++ b/bp2build/bp2build_product_config_test.go
@@ -2,6 +2,7 @@
 
 import (
 	"android/soong/android"
+	"android/soong/cc"
 	"android/soong/starlark_import"
 	"encoding/json"
 	"reflect"
@@ -87,3 +88,67 @@
 		}
 	}
 }
+
+func TestSystemPartitionDeps(t *testing.T) {
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
+	}, Bp2buildTestCase{
+		ExtraFixturePreparer: android.GroupFixturePreparers(
+			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+				deviceProduct := "aosp_arm64"
+				variables.DeviceProduct = &deviceProduct
+				partitionVars := &variables.PartitionVarsForBazelMigrationOnlyDoNotUse
+				partitionVars.ProductDirectory = "build/make/target/product/"
+				partitionVars.ProductPackages = []string{"foo"}
+				var systemVars android.PartitionQualifiedVariablesType
+				systemVars.BuildingImage = true
+				partitionVars.PartitionQualifiedVariables = map[string]android.PartitionQualifiedVariablesType{
+					"system": systemVars,
+				}
+			}),
+			android.FixtureModifyConfig(func(config android.Config) {
+				// MockBazelContext will pretend everything is mixed-builds allowlisted.
+				// The default is noopBazelContext, which does the opposite.
+				config.BazelContext = android.MockBazelContext{}
+			}),
+		),
+		Blueprint: `
+cc_library {
+  name: "foo",
+}`,
+		ExpectedBazelTargets: []string{`android_product(
+    name = "aosp_arm64",
+    soong_variables = _soong_variables,
+)`, `partition(
+    name = "system_image",
+    base_staging_dir = "//build/bazel/bazel_sandwich:system_staging_dir",
+    base_staging_dir_file_list = "//build/bazel/bazel_sandwich:system_staging_dir_file_list",
+    root_dir = "//build/bazel/bazel_sandwich:root_staging_dir",
+    selinux_file_contexts = "//build/bazel/bazel_sandwich:selinux_file_contexts",
+    image_properties = """
+building_system_image=true
+erofs_sparse_flag=-s
+extfs_sparse_flag=-s
+f2fs_sparse_flag=-S
+skip_fsck=true
+squashfs_sparse_flag=-s
+system_disable_sparse=true
+
+""",
+    deps = [
+        "//:foo",
+    ],
+
+    type = "system",
+)`, `partition_diff_test(
+    name = "system_image_test",
+    partition1 = "//build/bazel/bazel_sandwich:make_system_image",
+    partition2 = ":system_image",
+)`, `run_test_in_build(
+    name = "run_system_image_test",
+    test = ":system_image_test",
+)`},
+		Dir:                      "build/make/target/product/aosp_arm64",
+		RunBp2buildProductConfig: true,
+	})
+}
diff --git a/bp2build/bpf_conversion_test.go b/bp2build/bpf_conversion_test.go
index 1259f9e..26b0bf4 100644
--- a/bp2build/bpf_conversion_test.go
+++ b/bp2build/bpf_conversion_test.go
@@ -58,7 +58,7 @@
         "bpfTestSrcOne.c",
         "bpfTestSrcTwo.c",
     ]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 			}),
 		},
 	})
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 15b7766..d2187ff 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -279,17 +279,18 @@
 }
 
 type conversionResults struct {
-	buildFileToTargets map[string]BazelTargets
-	metrics            CodegenMetrics
+	buildFileToTargets    map[string]BazelTargets
+	moduleNameToPartition map[string]string
+	metrics               CodegenMetrics
 }
 
 func (r conversionResults) BuildDirToTargets() map[string]BazelTargets {
 	return r.buildFileToTargets
 }
 
-// struct to store state of go bazel targets
+// struct to store state of b bazel targets (e.g. go targets which do not implement android.Module)
 // this implements bp2buildModule interface and is passed to generateBazelTargets
-type goBazelTarget struct {
+type bTarget struct {
 	targetName            string
 	targetPackage         string
 	bazelRuleClass        string
@@ -297,26 +298,26 @@
 	bazelAttributes       []interface{}
 }
 
-var _ bp2buildModule = (*goBazelTarget)(nil)
+var _ bp2buildModule = (*bTarget)(nil)
 
-func (g goBazelTarget) TargetName() string {
-	return g.targetName
+func (b bTarget) TargetName() string {
+	return b.targetName
 }
 
-func (g goBazelTarget) TargetPackage() string {
-	return g.targetPackage
+func (b bTarget) TargetPackage() string {
+	return b.targetPackage
 }
 
-func (g goBazelTarget) BazelRuleClass() string {
-	return g.bazelRuleClass
+func (b bTarget) BazelRuleClass() string {
+	return b.bazelRuleClass
 }
 
-func (g goBazelTarget) BazelRuleLoadLocation() string {
-	return g.bazelRuleLoadLocation
+func (b bTarget) BazelRuleLoadLocation() string {
+	return b.bazelRuleLoadLocation
 }
 
-func (g goBazelTarget) BazelAttributes() []interface{} {
-	return g.bazelAttributes
+func (b bTarget) BazelAttributes() []interface{} {
+	return b.bazelAttributes
 }
 
 // Creates a target_compatible_with entry that is *not* compatible with android
@@ -421,7 +422,7 @@
 		Target_compatible_with: targetNotCompatibleWithAndroid(),
 	}
 
-	libTest := goBazelTarget{
+	libTest := bTarget{
 		targetName:            gp.name,
 		targetPackage:         gp.dir,
 		bazelRuleClass:        "go_test",
@@ -514,7 +515,7 @@
 		Target_compatible_with: targetNotCompatibleWithAndroid(),
 	}
 
-	lib := goBazelTarget{
+	lib := bTarget{
 		targetName:            g.Name(),
 		targetPackage:         ctx.ModuleDir(g),
 		bazelRuleClass:        "go_library",
@@ -555,23 +556,35 @@
 	Deps []string
 }
 
+type buildConversionMetadata struct {
+	nameToGoLibraryModule nameToGoLibraryModule
+	ndkHeaders            []blueprint.Module
+}
+
 type nameToGoLibraryModule map[string]goLibraryModule
 
-// Visit each module in the graph
+// Visit each module in the graph, and collect metadata about the build graph
 // If a module is of type `bootstrap_go_package`, return a map containing metadata like its dir and deps
-func createGoLibraryModuleMap(ctx *android.Context) nameToGoLibraryModule {
-	ret := nameToGoLibraryModule{}
+// If a module is of type `ndk_headers`, add it to a list and return the list
+func createBuildConversionMetadata(ctx *android.Context) buildConversionMetadata {
+	goMap := nameToGoLibraryModule{}
+	ndkHeaders := []blueprint.Module{}
 	ctx.VisitAllModules(func(m blueprint.Module) {
 		moduleType := ctx.ModuleType(m)
 		// We do not need to store information about blueprint_go_binary since it does not have any rdeps
 		if moduleType == "bootstrap_go_package" {
-			ret[m.Name()] = goLibraryModule{
+			goMap[m.Name()] = goLibraryModule{
 				Dir:  ctx.ModuleDir(m),
 				Deps: m.(*bootstrap.GoPackage).Deps(),
 			}
+		} else if moduleType == "ndk_headers" || moduleType == "versioned_ndk_headers" {
+			ndkHeaders = append(ndkHeaders, m)
 		}
 	})
-	return ret
+	return buildConversionMetadata{
+		nameToGoLibraryModule: goMap,
+		ndkHeaders:            ndkHeaders,
+	}
 }
 
 // Returns the deps in the transitive closure of a go target
@@ -620,7 +633,7 @@
 			Deps:                   goDepLabels(transitiveDeps, goModulesMap),
 			Target_compatible_with: targetNotCompatibleWithAndroid(),
 		}
-		libTestSource := goBazelTarget{
+		libTestSource := bTarget{
 			targetName:            goSource,
 			targetPackage:         ctx.ModuleDir(g),
 			bazelRuleClass:        "go_source",
@@ -669,7 +682,7 @@
 		ga.Srcs = goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs())
 	}
 
-	bin := goBazelTarget{
+	bin := bTarget{
 		targetName:            g.Name(),
 		targetPackage:         ctx.ModuleDir(g),
 		bazelRuleClass:        "go_binary",
@@ -695,12 +708,15 @@
 	metrics := CreateCodegenMetrics()
 
 	dirs := make(map[string]bool)
+	moduleNameToPartition := make(map[string]string)
 
 	var errs []error
 
 	// Visit go libraries in a pre-run and store its state in a map
 	// The time complexity remains O(N), and this does not add significant wall time.
-	nameToGoLibMap := createGoLibraryModuleMap(ctx.Context())
+	meta := createBuildConversionMetadata(ctx.Context())
+	nameToGoLibMap := meta.nameToGoLibraryModule
+	ndkHeaders := meta.ndkHeaders
 
 	bpCtx := ctx.Context()
 	bpCtx.VisitAllModules(func(m blueprint.Module) {
@@ -713,27 +729,35 @@
 
 		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() {
-				if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() {
-					panic(fmt.Errorf("module %q [%s] [%s] was both converted with bp2build and has a handcrafted label", bpCtx.ModuleName(m), moduleType, dir))
-				}
-				// Handle modules converted to handcrafted targets.
-				//
-				// Since these modules are associated with some handcrafted
-				// target in a BUILD file, we don't autoconvert them.
+			if aModule, ok := m.(android.Module); ok {
+				reason := aModule.GetUnconvertedReason()
+				if reason != nil {
+					// If this module was force-enabled, cause an error.
+					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)
+					}
 
-				// Log the module.
-				metrics.AddUnconvertedModule(m, moduleType, dir,
-					android.UnconvertedReason{
-						ReasonType: int(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE),
-					})
-			} else if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() {
+					// Log the module isn't to be converted by bp2build.
+					// TODO: b/291598248 - Log handcrafted modules differently than other unconverted modules.
+					metrics.AddUnconvertedModule(m, moduleType, dir, *reason)
+					return
+				}
+				if len(aModule.Bp2buildTargets()) == 0 {
+					panic(fmt.Errorf("illegal bp2build invariant: module '%s' was neither converted nor marked unconvertible", aModule.Name()))
+				}
+
 				// Handle modules converted to generated targets.
+				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)
+				}
+
+				// record the partition
+				moduleNameToPartition[android.RemoveOptionalPrebuiltPrefix(aModule.Name())] = aModule.GetPartitionForBp2build()
 
 				// Log the module.
 				metrics.AddConvertedModule(aModule, moduleType, dir)
@@ -761,34 +785,16 @@
 						return
 					}
 				}
-				targets, targetErrs = generateBazelTargets(bpCtx, aModule)
-				errs = append(errs, targetErrs...)
-				for _, t := range targets {
-					// A module can potentially generate more than 1 Bazel
-					// target, each of a different rule class.
-					metrics.IncrementRuleClassCount(t.ruleClass)
-				}
-			} else if _, ok := ctx.Config().BazelModulesForceEnabledByFlag()[m.Name()]; ok && m.Name() != "" {
-				err := fmt.Errorf("Force Enabled Module %s not converted", m.Name())
-				errs = append(errs, err)
-			} else if aModule, ok := m.(android.Module); ok {
-				reason := aModule.GetUnconvertedReason()
-				if reason == nil {
-					panic(fmt.Errorf("module '%s' was neither converted nor marked unconvertible with bp2build", aModule.Name()))
-				} else {
-					metrics.AddUnconvertedModule(m, moduleType, dir, *reason)
-				}
-				return
 			} else if glib, ok := m.(*bootstrap.GoPackage); ok {
 				targets, targetErrs = generateBazelTargetsGoPackage(bpCtx, glib, nameToGoLibMap)
 				errs = append(errs, targetErrs...)
-				metrics.IncrementRuleClassCount("go_library")
-				metrics.AddConvertedModule(glib, "go_library", dir)
+				metrics.IncrementRuleClassCount("bootstrap_go_package")
+				metrics.AddConvertedModule(glib, "bootstrap_go_package", dir)
 			} else if gbin, ok := m.(*bootstrap.GoBinary); ok {
 				targets, targetErrs = generateBazelTargetsGoBinary(bpCtx, gbin, nameToGoLibMap)
 				errs = append(errs, targetErrs...)
-				metrics.IncrementRuleClassCount("go_binary")
-				metrics.AddConvertedModule(gbin, "go_binary", dir)
+				metrics.IncrementRuleClassCount("blueprint_go_binary")
+				metrics.AddConvertedModule(gbin, "blueprint_go_binary", dir)
 			} else {
 				metrics.AddUnconvertedModule(m, moduleType, dir, android.UnconvertedReason{
 					ReasonType: int(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED),
@@ -818,6 +824,37 @@
 		}
 	})
 
+	// Create an ndk_sysroot target that has a dependency edge on every target corresponding to Soong's ndk_headers
+	// This root target will provide headers to sdk variants of jni libraries
+	if ctx.Mode() == Bp2Build {
+		var depLabels bazel.LabelList
+		for _, ndkHeader := range ndkHeaders {
+			depLabel := bazel.Label{
+				Label: "//" + bpCtx.ModuleDir(ndkHeader) + ":" + ndkHeader.Name(),
+			}
+			depLabels.Add(&depLabel)
+		}
+		a := struct {
+			Deps bazel.LabelListAttribute
+		}{
+			Deps: bazel.MakeLabelListAttribute(bazel.UniqueSortedBazelLabelList(depLabels)),
+		}
+		ndkSysroot := bTarget{
+			targetName:            "ndk_sysroot",
+			targetPackage:         "build/bazel/rules/cc", // The location is subject to change, use build/bazel for now
+			bazelRuleClass:        "cc_library_headers",
+			bazelRuleLoadLocation: "//build/bazel/rules/cc:cc_library_headers.bzl",
+			bazelAttributes:       []interface{}{&a},
+		}
+
+		if t, err := generateBazelTarget(bpCtx, ndkSysroot); err == nil {
+			dir := ndkSysroot.targetPackage
+			buildFileToTargets[dir] = append(buildFileToTargets[dir], t)
+		} else {
+			errs = append(errs, err)
+		}
+	}
+
 	if len(errs) > 0 {
 		return conversionResults{}, errs
 	}
@@ -844,8 +881,9 @@
 	}
 
 	return conversionResults{
-		buildFileToTargets: buildFileToTargets,
-		metrics:            metrics,
+		buildFileToTargets:    buildFileToTargets,
+		moduleNameToPartition: moduleNameToPartition,
+		metrics:               metrics,
 	}, errs
 }
 
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 329c907..f809bcc 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -270,8 +270,8 @@
 			ExpectedBazelTargets: []string{
 				MakeBazelTarget("custom", "foo", AttrNameToString{
 					"string_literal_prop": `select({
-        "//build/bazel/platforms/arch:arm": "ARM",
-        "//build/bazel/platforms/arch:arm64": "ARM64",
+        "//build/bazel_common_rules/platforms/arch:arm": "ARM",
+        "//build/bazel_common_rules/platforms/arch:arm64": "ARM64",
         "//conditions:default": None,
     })`,
 				}),
@@ -349,19 +349,6 @@
 			},
 		},
 		{
-			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",
@@ -395,60 +382,60 @@
 			ExpectedBazelTargets: []string{
 				MakeBazelTarget("custom", "arch_paths", AttrNameToString{
 					"arch_paths": `select({
-        "//build/bazel/platforms/arch:arm": [
+        "//build/bazel_common_rules/platforms/arch:arm": [
             "arm.txt",
             "lib32.txt",
         ],
-        "//build/bazel/platforms/arch:arm64": [
+        "//build/bazel_common_rules/platforms/arch:arm64": [
             "arm64.txt",
             "lib64.txt",
         ],
-        "//build/bazel/platforms/arch:riscv64": [
+        "//build/bazel_common_rules/platforms/arch:riscv64": [
             "riscv64.txt",
             "lib64.txt",
         ],
-        "//build/bazel/platforms/arch:x86": [
+        "//build/bazel_common_rules/platforms/arch:x86": [
             "x86.txt",
             "lib32.txt",
         ],
-        "//build/bazel/platforms/arch:x86_64": [
+        "//build/bazel_common_rules/platforms/arch:x86_64": [
             "x86_64.txt",
             "lib64.txt",
         ],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/os:android": [
+        "//build/bazel_common_rules/platforms/os:android": [
             "linux.txt",
             "bionic.txt",
             "android.txt",
         ],
-        "//build/bazel/platforms/os:darwin": [
+        "//build/bazel_common_rules/platforms/os:darwin": [
             "host.txt",
             "darwin.txt",
             "not_windows.txt",
         ],
-        "//build/bazel/platforms/os:linux_bionic": [
+        "//build/bazel_common_rules/platforms/os:linux_bionic": [
             "host.txt",
             "linux.txt",
             "bionic.txt",
             "linux_bionic.txt",
             "not_windows.txt",
         ],
-        "//build/bazel/platforms/os:linux_glibc": [
+        "//build/bazel_common_rules/platforms/os:linux_glibc": [
             "host.txt",
             "linux.txt",
             "glibc.txt",
             "linux_glibc.txt",
             "not_windows.txt",
         ],
-        "//build/bazel/platforms/os:linux_musl": [
+        "//build/bazel_common_rules/platforms/os:linux_musl": [
             "host.txt",
             "linux.txt",
             "musl.txt",
             "linux_musl.txt",
             "not_windows.txt",
         ],
-        "//build/bazel/platforms/os:windows": [
+        "//build/bazel_common_rules/platforms/os:windows": [
             "host.txt",
             "windows.txt",
         ],
@@ -480,7 +467,7 @@
 				}),
 				MakeBazelTarget("custom", "has_dep", AttrNameToString{
 					"arch_paths": `select({
-        "//build/bazel/platforms/arch:x86": [":dep"],
+        "//build/bazel_common_rules/platforms/arch:x86": [":dep"],
         "//conditions:default": [],
     })`,
 				}),
@@ -1071,50 +1058,6 @@
 				}),
 			},
 		},
-		{
-			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 {
@@ -1825,8 +1768,8 @@
 			ExpectedBazelTargets: []string{
 				MakeBazelTarget("py_library", "fg_foo", map[string]string{
 					"data": `select({
-        "//build/bazel/platforms/arch:arm": [":reqdarm"],
-        "//build/bazel/platforms/arch:x86": [":reqdx86"],
+        "//build/bazel_common_rules/platforms/arch:arm": [":reqdarm"],
+        "//build/bazel_common_rules/platforms/arch:x86": [":reqdx86"],
         "//conditions:default": [],
     })`,
 					"srcs_version": `"PY3"`,
@@ -1994,6 +1937,41 @@
 	})
 }
 
+func TestAlreadyPresentOneToManyBuildTarget(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+    one_to_many_prop: true,
+	}
+	custom {
+		name: "bar",
+	}
+	`
+	alreadyPresentBuildFile :=
+		MakeBazelTarget(
+			"custom",
+			// one_to_many_prop ensures that foo generates "foo_proto_library_deps".
+			"foo_proto_library_deps",
+			AttrNameToString{},
+		)
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"bar",
+			AttrNameToString{},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		AlreadyExistingBuildContents: alreadyPresentBuildFile,
+		Blueprint:                    bp,
+		ExpectedBazelTargets:         expectedBazelTargets,
+		Description:                  "Not duplicating work for an already-present BUILD target (different generated name)",
+	})
+}
+
 // Verifies that if a module is defined in pkg1/Android.bp, that a target present
 // in pkg2/BUILD.bazel does not result in the module being labeled "already defined
 // in a BUILD file".
@@ -2066,3 +2044,213 @@
 	})
 
 }
+
+func TestBp2buildDepsMutator_missingTransitiveDep(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	}
+
+	custom {
+		name: "has_deps",
+	  arch_paths: [":has_missing_dep", ":foo"],
+	}
+
+	custom {
+		name: "has_missing_dep",
+	  arch_paths: [":missing"],
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"foo",
+			AttrNameToString{},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: expectedBazelTargets,
+		Description:          "Skipping conversion of a target with missing transitive dep",
+	})
+}
+
+func TestBp2buildDepsMutator_missingDirectDep(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	  arch_paths: [":exists"],
+	}
+	custom {
+		name: "exists",
+	}
+
+	custom {
+		name: "has_missing_dep",
+	  arch_paths: [":missing"],
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"foo",
+			AttrNameToString{"arch_paths": `[":exists"]`},
+		),
+		MakeBazelTarget(
+			"custom",
+			"exists",
+			AttrNameToString{},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: expectedBazelTargets,
+		Description:          "Skipping conversion of a target with missing direct dep",
+	})
+}
+
+func TestBp2buildDepsMutator_unconvertedDirectDep(t *testing.T) {
+	bp := `
+	custom {
+		name: "has_unconverted_dep",
+	  arch_paths: [":unconvertible"],
+	}
+
+	custom {
+		name: "unconvertible",
+		does_not_convert_to_bazel: true
+	}
+	`
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: []string{},
+		Description:          "Skipping conversion of a target with unconverted direct dep",
+	})
+}
+
+func TestBp2buildDepsMutator_unconvertedTransitiveDep(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	  arch_paths: [":has_unconverted_dep", ":bar"],
+	}
+
+	custom {
+		name: "bar",
+	}
+
+	custom {
+		name: "has_unconverted_dep",
+	  arch_paths: [":unconvertible"],
+	}
+
+	custom {
+		name: "unconvertible",
+		does_not_convert_to_bazel: true
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"bar",
+			AttrNameToString{},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: expectedBazelTargets,
+		Description:          "Skipping conversion of a target with unconverted transitive dep",
+	})
+}
+
+func TestBp2buildDepsMutator_alreadyExistsBuildDeps(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	  arch_paths: [":bar"],
+	}
+	custom {
+		name: "bar",
+	  arch_paths: [":checked_in"],
+	}
+	custom {
+		name: "checked_in",
+	  arch_paths: [":checked_in"],
+		does_not_convert_to_bazel: true
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"foo",
+			AttrNameToString{"arch_paths": `[":bar"]`},
+		),
+		MakeBazelTarget(
+			"custom",
+			"bar",
+			AttrNameToString{"arch_paths": `[":checked_in"]`},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		StubbedBuildDefinitions: []string{"checked_in"},
+		Blueprint:               bp,
+		ExpectedBazelTargets:    expectedBazelTargets,
+		Description:             "Convert target with already-existing build dep",
+	})
+}
+
+// Tests that deps of libc are always considered valid for libc. This circumvents
+// an issue that, in a variantless graph (such as bp2build's), libc has the
+// unique predicament that it depends on itself.
+func TestBp2buildDepsMutator_depOnLibc(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	  arch_paths: [":libc"],
+	}
+	custom {
+		name: "libc",
+	  arch_paths: [":libc_dep"],
+	}
+	custom {
+		name: "libc_dep",
+		does_not_convert_to_bazel: true
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"foo",
+			AttrNameToString{"arch_paths": `[":libc"]`},
+		),
+		MakeBazelTarget(
+			"custom",
+			"libc",
+			AttrNameToString{"arch_paths": `[":libc_dep"]`},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		StubbedBuildDefinitions: []string{"checked_in"},
+		Blueprint:               bp,
+		ExpectedBazelTargets:    expectedBazelTargets,
+		Description:             "Convert target with dep on libc",
+	})
+}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 402d4b0..645298f 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -95,6 +95,7 @@
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "dir": attr.string(),
+        "does_not_convert_to_bazel": attr.bool(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
@@ -128,6 +129,7 @@
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "dir": attr.string(),
+        "does_not_convert_to_bazel": attr.bool(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
@@ -161,6 +163,7 @@
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "dir": attr.string(),
+        "does_not_convert_to_bazel": attr.bool(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index c679703..2857a91 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -618,13 +618,13 @@
 			{"cc_library_static", "bar_bp2build_cc_library_static", AttrNameToString{
 				"local_includes":         `["."]`,
 				"srcs":                   `["b.cc"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 			},
 			},
 			{"cc_library_shared", "bar", AttrNameToString{
 				"local_includes":         `["."]`,
 				"srcs":                   `["b.cc"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 			},
 			},
 			{"cc_binary", "foo", AttrNameToString{
@@ -653,7 +653,7 @@
 		targets: []testBazelTarget{
 			{"cc_binary", "foo", AttrNameToString{
 				"features": `select({
-        "//build/bazel/platforms/arch:arm": ["arm_isa_arm"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["arm_isa_arm"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
@@ -713,8 +713,8 @@
 			{"cc_binary", "foo", AttrNameToString{
 				"local_includes": `["."]`,
 				"suffix": `select({
-        "//build/bazel/platforms/arch:arm": "-32",
-        "//build/bazel/platforms/arch:arm64": "-64",
+        "//build/bazel_common_rules/platforms/arch:arm": "-32",
+        "//build/bazel_common_rules/platforms/arch:arm64": "-64",
         "//conditions:default": None,
     })`,
 			}},
@@ -775,7 +775,7 @@
 		targets: []testBazelTarget{
 			{"sysprop_library", "foo_sysprop_library", AttrNameToString{
 				"srcs": `select({
-        "//build/bazel/platforms/os:android": ["bar.sysprop"],
+        "//build/bazel_common_rules/platforms/os:android": ["bar.sysprop"],
         "//conditions:default": [],
     })`,
 			}},
@@ -788,7 +788,7 @@
 				"local_includes":  `["."]`,
 				"min_sdk_version": `"5"`,
 				"whole_archive_deps": `select({
-        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
+        "//build/bazel_common_rules/platforms/os:android": [":foo_cc_sysprop_library_static"],
         "//conditions:default": [],
     })`,
 			}},
@@ -866,8 +866,8 @@
         "ubsan_undefined",
         "ubsan_nullability",
     ] + select({
-        "//build/bazel/platforms/os:android": ["ubsan_alignment"],
-        "//build/bazel/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
+        "//build/bazel_common_rules/platforms/os:android": ["ubsan_alignment"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
         "//conditions:default": [],
     })`,
 			}},
@@ -964,11 +964,11 @@
 			{"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"],
+        "//build/bazel_common_rules/platforms/os_arch:android_arm": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_x86": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_x86_64": ["android_thin_lto"],
         "//conditions:default": [],
     })`,
 			}},
@@ -998,7 +998,7 @@
 			{"cc_binary", "foo", AttrNameToString{
 				"local_includes": `["."]`,
 				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os:android": ["android_thin_lto"],
         "//conditions:default": ["-android_thin_lto"],
     })`,
 			}},
@@ -1062,7 +1062,7 @@
 			{"cc_binary", "foo", AttrNameToString{
 				"local_includes": `["."]`,
 				"features": `select({
-        "//build/bazel/platforms/os:android": ["visibility_hidden"],
+        "//build/bazel_common_rules/platforms/os:android": ["visibility_hidden"],
         "//conditions:default": [],
     })`,
 			}},
@@ -1106,7 +1106,7 @@
 		targets: []testBazelTarget{
 			{"cc_binary", "foo", AttrNameToString{
 				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_cfi"],
+        "//build/bazel_common_rules/platforms/os:android": ["android_cfi"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
@@ -1187,8 +1187,8 @@
 			}},
 			{"cc_binary", "foo_with_arch_variant_stem", AttrNameToString{
 				"stem": `select({
-        "//build/bazel/platforms/arch:arm": "foo-arm",
-        "//build/bazel/platforms/arch:arm64": "foo-arm64",
+        "//build/bazel_common_rules/platforms/arch:arm": "foo-arm",
+        "//build/bazel_common_rules/platforms/arch:arm64": "foo-arm64",
         "//conditions:default": None,
     })`,
 				"local_includes": `["."]`,
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 560123e..188c81b 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -137,28 +137,32 @@
 			"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"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["-Wl,--exclude-libs=baz.a"],
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["x86.cpp"],
+        "//build/bazel_common_rules/platforms/arch:x86_64": ["x86_64.cpp"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/os:android": [
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/os:darwin": ["darwin.cpp"],
+        "//build/bazel_common_rules/platforms/os:linux_bionic": ["bionic.cpp"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": ["linux.cpp"],
         "//conditions:default": [],
     })`,
 			"sdk_version":        `"current"`,
 			"min_sdk_version":    `"29"`,
 			"use_version_lib":    `True`,
 			"whole_archive_deps": `["//build/soong/cc/libbuildversion:libbuildversion"]`,
+			"deps": `select({
+        "//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
+        "//conditions:default": [],
+    })`,
 		}),
 	})
 }
@@ -224,8 +228,8 @@
         "-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"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["-Wl,--exclude-libs=libgcc_eh.a"],
+        "//build/bazel_common_rules/platforms/arch:x86_64": ["-Wl,--exclude-libs=libgcc_eh.a"],
         "//conditions:default": [],
     })`,
 		}),
@@ -274,7 +278,7 @@
 		Blueprint: soongCcLibraryPreamble,
 		ExpectedBazelTargets: makeCcLibraryTargets("fake-libarm-optimized-routines-math", AttrNameToString{
 			"copts": `select({
-        "//build/bazel/platforms/arch:arm64": ["-DHAVE_FAST_FMA=1"],
+        "//build/bazel_common_rules/platforms/arch:arm64": ["-DHAVE_FAST_FMA=1"],
         "//conditions:default": [],
     })`,
 			"local_includes": `["."]`,
@@ -555,8 +559,8 @@
 		ModuleTypeUnderTest:        "cc_library",
 		ModuleTypeUnderTestFactory: cc.LibraryFactory,
 		Dir:                        "foo/bar",
-		StubbedBuildDefinitions: []string{"//foo/bar:prebuilt_whole_static_lib_for_shared", "//foo/bar:prebuilt_whole_static_lib_for_static",
-			"//foo/bar:prebuilt_whole_static_lib_for_both"},
+		StubbedBuildDefinitions: []string{"//foo/bar:whole_static_lib_for_shared", "//foo/bar:whole_static_lib_for_static",
+			"//foo/bar:whole_static_lib_for_both"},
 		Filesystem: map[string]string{
 			"foo/bar/Android.bp": `
 cc_library {
@@ -684,14 +688,14 @@
         "bothflag",
         "staticflag",
     ] + select({
-        "//build/bazel/platforms/arch:x86": ["-DX86_STATIC"],
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/arch:x86": [":x86_dep_for_static"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
@@ -699,7 +703,7 @@
         "both.cpp",
         "staticonly.cpp",
     ] + select({
-        "//build/bazel/platforms/arch:x86": ["x86_static.cpp"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["x86_static.cpp"],
         "//conditions:default": [],
     })`,
 			}),
@@ -708,27 +712,27 @@
         "bothflag",
         "sharedflag",
     ] + select({
-        "//build/bazel/platforms/arch:arm": ["-DARM_SHARED"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["-DARM_SHARED"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/os:android": ["-DANDROID_SHARED"],
+        "//build/bazel_common_rules/platforms/os:android": ["-DANDROID_SHARED"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/os_arch:android_arm": ["-DANDROID_ARM_SHARED"],
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/arch:arm": [":arm_static_dep_for_shared"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/os:android": [":android_dep_for_shared"],
+        "//build/bazel_common_rules/platforms/os:android": [":android_dep_for_shared"],
         "//conditions:default": [],
     })`,
 				"implementation_dynamic_deps": `select({
-        "//build/bazel/platforms/arch:arm": [":arm_shared_dep_for_shared"],
+        "//build/bazel_common_rules/platforms/arch:arm": [":arm_shared_dep_for_shared"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
@@ -736,14 +740,14 @@
         "both.cpp",
         "sharedonly.cpp",
     ] + select({
-        "//build/bazel/platforms/arch:arm": ["arm_shared.cpp"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["arm_shared.cpp"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/os:android": ["android_shared.cpp"],
+        "//build/bazel_common_rules/platforms/os:android": ["android_shared.cpp"],
         "//conditions:default": [],
     })`,
 				"whole_archive_deps": `select({
-        "//build/bazel/platforms/arch:arm": [":arm_whole_static_dep_for_shared"],
+        "//build/bazel_common_rules/platforms/arch:arm": [":arm_whole_static_dep_for_shared"],
         "//conditions:default": [],
     })`,
 			}),
@@ -950,22 +954,22 @@
 		Blueprint: soongCcLibraryPreamble,
 		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
 			"additional_linker_inputs": `select({
-        "//build/bazel/platforms/arch:arm": [
+        "//build/bazel_common_rules/platforms/arch:arm": [
             "arm.map",
             "dynamic_arm.list",
         ],
-        "//build/bazel/platforms/arch:arm64": [
+        "//build/bazel_common_rules/platforms/arch:arm64": [
             "arm64.map",
             "dynamic_arm64.list",
         ],
         "//conditions:default": [],
     })`,
 			"linkopts": `select({
-        "//build/bazel/platforms/arch:arm": [
+        "//build/bazel_common_rules/platforms/arch:arm": [
             "-Wl,--version-script,$(location arm.map)",
             "-Wl,--dynamic-list,$(location dynamic_arm.list)",
         ],
-        "//build/bazel/platforms/arch:arm64": [
+        "//build/bazel_common_rules/platforms/arch:arm64": [
             "-Wl,--version-script,$(location arm64.map)",
             "-Wl,--dynamic-list,$(location dynamic_arm64.list)",
         ],
@@ -973,8 +977,8 @@
     })`,
 			"srcs": `["a.cpp"]`,
 			"features": `select({
-        "//build/bazel/platforms/arch:arm": ["android_cfi_exports_map"],
-        "//build/bazel/platforms/arch:arm64": ["android_cfi_exports_map"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["android_cfi_exports_map"],
+        "//build/bazel_common_rules/platforms/arch:arm64": ["android_cfi_exports_map"],
         "//conditions:default": [],
     })`,
 		}),
@@ -1061,7 +1065,7 @@
 	})...)
 	expected_targets = append(expected_targets, makeCcLibraryTargets("b", AttrNameToString{
 		"features": `select({
-        "//build/bazel/platforms/arch:x86_64": [
+        "//build/bazel_common_rules/platforms/arch:x86_64": [
             "disable_pack_relocations",
             "-no_undefined_symbols",
         ],
@@ -1072,7 +1076,7 @@
 	})...)
 	expected_targets = append(expected_targets, makeCcLibraryTargets("c", AttrNameToString{
 		"features": `select({
-        "//build/bazel/platforms/os:darwin": [
+        "//build/bazel_common_rules/platforms/os:darwin": [
             "disable_pack_relocations",
             "-no_undefined_symbols",
         ],
@@ -1177,10 +1181,10 @@
         "-fsigned-char",
         "-pedantic",
     ] + select({
-        "//build/bazel/platforms/arch:arm64": ["-DARM64=1"],
+        "//build/bazel_common_rules/platforms/arch:arm64": ["-DARM64=1"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/os:android": ["-DANDROID=1"],
+        "//build/bazel_common_rules/platforms/os:android": ["-DANDROID=1"],
         "//conditions:default": [],
     })`,
 			"srcs": `["a.cpp"]`,
@@ -1267,14 +1271,14 @@
 `,
 		ExpectedBazelTargets: makeCcLibraryTargets("foo_static", AttrNameToString{
 			"implementation_deps": `select({
-        "//build/bazel/platforms/arch:arm": [],
+        "//build/bazel_common_rules/platforms/arch:arm": [],
         "//conditions:default": [":arm_static_lib_excludes_bp2build_cc_library_static"],
     }) + select({
         "//build/bazel/product_config/config_settings:malloc_not_svelte": [],
         "//conditions:default": [":malloc_not_svelte_static_lib_excludes_bp2build_cc_library_static"],
     })`,
 			"implementation_dynamic_deps": `select({
-        "//build/bazel/platforms/arch:arm": [],
+        "//build/bazel_common_rules/platforms/arch:arm": [],
         "//conditions:default": [":arm_shared_lib_excludes"],
     }) + select({
         "//build/bazel/product_config/config_settings:malloc_not_svelte": [":malloc_not_svelte_shared_lib"],
@@ -1282,7 +1286,7 @@
     })`,
 			"srcs_c": `["common.c"]`,
 			"whole_archive_deps": `select({
-        "//build/bazel/platforms/arch:arm": [],
+        "//build/bazel_common_rules/platforms/arch:arm": [],
         "//conditions:default": [":arm_whole_static_lib_excludes_bp2build_cc_library_static"],
     }) + select({
         "//build/bazel/product_config/config_settings:malloc_not_svelte": [":malloc_not_svelte_whole_static_lib_bp2build_cc_library_static"],
@@ -1321,7 +1325,7 @@
         "//conditions:default": [],
     })`,
 			"srcs_c":                 `["common.c"]`,
-			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+			"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 		}),
 	},
 	)
@@ -1398,7 +1402,7 @@
 `,
 		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
 			"features": `select({
-        "//build/bazel/platforms/arch:arm": ["-link_crt"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["-link_crt"],
         "//conditions:default": [],
     })`,
 			"srcs": `["impl.cpp"]`,
@@ -1502,8 +1506,8 @@
 		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
 			"srcs": `["impl.cpp"]`,
 			"features": `select({
-        "//build/bazel/platforms/arch:arm": ["-use_libcrt"],
-        "//build/bazel/platforms/arch:x86": ["-use_libcrt"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["-use_libcrt"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["-use_libcrt"],
         "//conditions:default": [],
     })`,
 		}),
@@ -1539,11 +1543,11 @@
 `,
 		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
 			"features": `select({
-        "//build/bazel/platforms/arch:arm": ["-use_libcrt"],
-        "//build/bazel/platforms/arch:x86": ["-use_libcrt"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["-use_libcrt"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["-use_libcrt"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/os:darwin": ["-use_libcrt"],
+        "//build/bazel_common_rules/platforms/os:darwin": ["-use_libcrt"],
         "//conditions:default": [],
     })`,
 			"srcs": `["impl.cpp"]`,
@@ -1582,8 +1586,8 @@
 		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"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["-use_libcrt"],
+        "//build/bazel_common_rules/platforms/arch:x86_64": ["-use_libcrt"],
         "//conditions:default": [],
     })`,
 		}),
@@ -1701,15 +1705,15 @@
 		ExpectedBazelTargets: makeCcLibraryTargets("multi-arch", AttrNameToString{
 			"strip": `{
         "keep_symbols": select({
-            "//build/bazel/platforms/arch:arm64": True,
+            "//build/bazel_common_rules/platforms/arch:arm64": True,
             "//conditions:default": None,
         }),
         "keep_symbols_and_debug_frame": select({
-            "//build/bazel/platforms/arch:arm": True,
+            "//build/bazel_common_rules/platforms/arch:arm": True,
             "//conditions:default": None,
         }),
         "keep_symbols_list": select({
-            "//build/bazel/platforms/os:darwin": [
+            "//build/bazel_common_rules/platforms/os:darwin": [
                 "foo",
                 "bar",
             ],
@@ -1840,7 +1844,7 @@
 `,
 		ExpectedBazelTargets: makeCcLibraryTargets("target_linux_bionic_empty", AttrNameToString{
 			"system_dynamic_deps": `select({
-        "//build/bazel/platforms/os:linux_musl": [":libc_musl"],
+        "//build/bazel_common_rules/platforms/os:linux_musl": [":libc_musl"],
         "//conditions:default": [],
     })`,
 		}),
@@ -1871,7 +1875,7 @@
 `,
 		ExpectedBazelTargets: makeCcLibraryTargets("target_bionic_empty", AttrNameToString{
 			"system_dynamic_deps": `select({
-        "//build/bazel/platforms/os:linux_musl": [":libc_musl"],
+        "//build/bazel_common_rules/platforms/os:linux_musl": [":libc_musl"],
         "//conditions:default": [],
     })`,
 		}),
@@ -2007,25 +2011,25 @@
 `,
 		ExpectedBazelTargets: makeCcLibraryTargets("foo-lib", AttrNameToString{
 			"srcs": `["base.cpp"] + select({
-        "//build/bazel/platforms/os:android": [
+        "//build/bazel_common_rules/platforms/os:android": [
             "linux.cpp",
             "bionic.cpp",
             "android.cpp",
         ],
-        "//build/bazel/platforms/os:darwin": ["darwin.cpp"],
-        "//build/bazel/platforms/os:linux_bionic": [
+        "//build/bazel_common_rules/platforms/os:darwin": ["darwin.cpp"],
+        "//build/bazel_common_rules/platforms/os:linux_bionic": [
             "linux.cpp",
             "bionic.cpp",
         ],
-        "//build/bazel/platforms/os:linux_glibc": [
+        "//build/bazel_common_rules/platforms/os:linux_glibc": [
             "linux.cpp",
             "linux_glibc.cpp",
         ],
-        "//build/bazel/platforms/os:linux_musl": [
+        "//build/bazel_common_rules/platforms/os:linux_musl": [
             "linux.cpp",
             "linux_musl.cpp",
         ],
-        "//build/bazel/platforms/os:windows": ["windows.cpp"],
+        "//build/bazel_common_rules/platforms/os:windows": ["windows.cpp"],
         "//conditions:default": [],
     })`,
 		}),
@@ -2052,7 +2056,7 @@
 `,
 		ExpectedBazelTargets: makeCcLibraryTargets("libcrypto", AttrNameToString{
 			"inject_bssl_hash": `select({
-        "//build/bazel/platforms/os:android": True,
+        "//build/bazel_common_rules/platforms/os:android": True,
         "//conditions:default": None,
     })`,
 		}),
@@ -2693,11 +2697,11 @@
 		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"],
+        "//build/bazel_common_rules/platforms/os_arch:darwin_arm64": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os_arch:darwin_x86_64": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os_arch:linux_glibc_x86": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os_arch:windows_x86": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os_arch:windows_x86_64": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 		}),
@@ -2729,8 +2733,8 @@
 		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": [],
+        "//build/bazel_common_rules/platforms/os_arch:darwin_arm64": [],
+        "//build/bazel_common_rules/platforms/os_arch:darwin_x86_64": [],
         "//conditions:default": ["@platforms//:incompatible"],
     })`,
 		}),
@@ -2763,7 +2767,7 @@
 		}), MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 			"srcs": `["foo.cpp"]`,
 			"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 		}),
@@ -2800,15 +2804,15 @@
 		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"],
+        "//build/bazel_common_rules/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": [],
+        "//build/bazel_common_rules/platforms/os_arch:darwin_arm64": [],
+        "//build/bazel_common_rules/platforms/os_arch:darwin_x86_64": [],
+        "//build/bazel_common_rules/platforms/os_arch:linux_glibc_x86": [],
         "//conditions:default": ["@platforms//:incompatible"],
     })`,
 		}),
@@ -2919,22 +2923,22 @@
 }`,
 		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"],
+        "//build/bazel_common_rules/platforms/os:darwin": [":bazlib"],
+        "//build/bazel_common_rules/platforms/os:linux_bionic": [":bazlib"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": [":bazlib"],
+        "//build/bazel_common_rules/platforms/os:linux_musl": [":bazlib"],
+        "//build/bazel_common_rules/platforms/os:windows": [":bazlib"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/os:darwin": [":quxlib"],
-        "//build/bazel/platforms/os:linux_bionic": [":quxlib"],
-        "//build/bazel/platforms/os:linux_glibc": [":quxlib"],
-        "//build/bazel/platforms/os:linux_musl": [":quxlib"],
-        "//build/bazel/platforms/os:windows": [":quxlib"],
         "//build/bazel/rules/apex:foo": [
             "@api_surfaces//module-libapi/current:barlib",
             "@api_surfaces//module-libapi/current:quxlib",
         ],
+        "//build/bazel_common_rules/platforms/os:darwin": [":quxlib"],
+        "//build/bazel_common_rules/platforms/os:linux_bionic": [":quxlib"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": [":quxlib"],
+        "//build/bazel_common_rules/platforms/os:linux_musl": [":quxlib"],
+        "//build/bazel_common_rules/platforms/os:windows": [":quxlib"],
         "//conditions:default": [
             ":barlib",
             ":quxlib",
@@ -3049,7 +3053,7 @@
 `,
 		ExpectedBazelTargets: makeCcLibraryTargets("foo", AttrNameToString{
 			"features": `select({
-        "//build/bazel/platforms/arch:arm": ["arm_isa_arm"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["arm_isa_arm"],
         "//conditions:default": [],
     })`,
 			"local_includes": `["."]`,
@@ -3133,8 +3137,8 @@
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"srcs_c": `["foo.c"]`,
 				"suffix": `select({
-        "//build/bazel/platforms/arch:arm": "-32",
-        "//build/bazel/platforms/arch:arm64": "-64",
+        "//build/bazel_common_rules/platforms/arch:arm": "-32",
+        "//build/bazel_common_rules/platforms/arch:arm64": "-64",
         "//conditions:default": None,
     })`,
 			}),
@@ -3351,6 +3355,7 @@
 		Description:                "cc_library with target.apex",
 		ModuleTypeUnderTest:        "cc_library",
 		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		StubbedBuildDefinitions:    []string{"bar", "baz", "buh"},
 		Blueprint: `
 cc_library {
     name: "foo",
@@ -3362,27 +3367,29 @@
             exclude_static_libs: ["buh"],
         }
     }
-}`,
+}` + simpleModule("cc_library_static", "baz") +
+			simpleModule("cc_library_static", "buh") +
+			simpleModule("cc_library_static", "bar"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"implementation_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
+				"implementation_deps": `[":baz"] + select({
         "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":buh__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [":buh"],
     })`,
-				"implementation_dynamic_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
+				"implementation_dynamic_deps": `[":baz"] + select({
         "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":bar__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [":bar"],
     })`,
 				"local_includes": `["."]`,
 			}),
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"implementation_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
+				"implementation_deps": `[":baz"] + select({
         "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":buh__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [":buh"],
     })`,
-				"implementation_dynamic_deps": `[":baz__BP2BUILD__MISSING__DEP"] + select({
+				"implementation_dynamic_deps": `[":baz"] + select({
         "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":bar__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [":bar"],
     })`,
 				"local_includes": `["."]`,
 			}),
@@ -3408,20 +3415,23 @@
             exclude_static_libs: ["abc"],
         }
     }
-}`,
+}` + simpleModule("cc_library_static", "bar") +
+			simpleModule("cc_library_static", "baz") +
+			simpleModule("cc_library_static", "abc"),
+		StubbedBuildDefinitions: []string{"bar", "baz", "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"],
+        "//conditions:default": [":bar"],
     })`,
 				"dynamic_deps": `select({
         "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":baz__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [":baz"],
     })`,
 				"deps": `select({
         "//build/bazel/rules/apex:in_apex": [],
-        "//conditions:default": [":abc__BP2BUILD__MISSING__DEP"],
+        "//conditions:default": [":abc"],
     })`,
 				"local_includes": `["."]`,
 			}),
@@ -3493,7 +3503,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTargetNoRestrictions("sysprop_library", "foo_sysprop_library", AttrNameToString{
 				"srcs": `select({
-        "//build/bazel/platforms/os:android": ["bar.sysprop"],
+        "//build/bazel_common_rules/platforms/os:android": ["bar.sysprop"],
         "//conditions:default": [],
     })`,
 			}),
@@ -3506,7 +3516,7 @@
 				"local_includes":  `["."]`,
 				"min_sdk_version": `"5"`,
 				"whole_archive_deps": `select({
-        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
+        "//build/bazel_common_rules/platforms/os:android": [":foo_cc_sysprop_library_static"],
         "//conditions:default": [],
     })`,
 			}),
@@ -3515,7 +3525,7 @@
 				"local_includes":  `["."]`,
 				"min_sdk_version": `"5"`,
 				"whole_archive_deps": `select({
-        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
+        "//build/bazel_common_rules/platforms/os:android": [":foo_cc_sysprop_library_static"],
         "//conditions:default": [],
     })`,
 			}),
@@ -3851,39 +3861,39 @@
 `,
 		ExpectedBazelTargets: makeCcLibraryTargets("a", AttrNameToString{
 			"export_includes": `select({
-        "//build/bazel/platforms/os_arch:android_arm": [
+        "//build/bazel_common_rules/platforms/os_arch:android_arm": [
             "android_arm_eid1",
             "android_arm_eid2",
         ],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/os:android": [
+        "//build/bazel_common_rules/platforms/os:android": [
             "android_eid1",
             "android_eid2",
             "linux_eid1",
             "linux_eid2",
         ],
-        "//build/bazel/platforms/os:linux_bionic": [
+        "//build/bazel_common_rules/platforms/os:linux_bionic": [
             "linux_eid1",
             "linux_eid2",
         ],
-        "//build/bazel/platforms/os:linux_glibc": [
+        "//build/bazel_common_rules/platforms/os:linux_glibc": [
             "linux_eid1",
             "linux_eid2",
         ],
-        "//build/bazel/platforms/os:linux_musl": [
+        "//build/bazel_common_rules/platforms/os:linux_musl": [
             "linux_eid1",
             "linux_eid2",
         ],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/arch:arm": [
+        "//build/bazel_common_rules/platforms/arch:arm": [
             "lib32_eid1",
             "lib32_eid2",
             "arm_eid1",
             "arm_eid2",
         ],
-        "//build/bazel/platforms/arch:x86": [
+        "//build/bazel_common_rules/platforms/arch:x86": [
             "lib32_eid1",
             "lib32_eid2",
         ],
@@ -3893,39 +3903,39 @@
         "eid2",
     ]`,
 			"export_system_includes": `select({
-        "//build/bazel/platforms/os_arch:android_arm": [
+        "//build/bazel_common_rules/platforms/os_arch:android_arm": [
             "android_arm_esid1",
             "android_arm_esid2",
         ],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/os:android": [
+        "//build/bazel_common_rules/platforms/os:android": [
             "android_esid1",
             "android_esid2",
             "linux_esid1",
             "linux_esid2",
         ],
-        "//build/bazel/platforms/os:linux_bionic": [
+        "//build/bazel_common_rules/platforms/os:linux_bionic": [
             "linux_esid1",
             "linux_esid2",
         ],
-        "//build/bazel/platforms/os:linux_glibc": [
+        "//build/bazel_common_rules/platforms/os:linux_glibc": [
             "linux_esid1",
             "linux_esid2",
         ],
-        "//build/bazel/platforms/os:linux_musl": [
+        "//build/bazel_common_rules/platforms/os:linux_musl": [
             "linux_esid1",
             "linux_esid2",
         ],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/arch:arm": [
+        "//build/bazel_common_rules/platforms/arch:arm": [
             "lib32_esid1",
             "lib32_esid2",
             "arm_esid1",
             "arm_esid2",
         ],
-        "//build/bazel/platforms/arch:x86": [
+        "//build/bazel_common_rules/platforms/arch:x86": [
             "lib32_esid1",
             "lib32_esid2",
         ],
@@ -3936,7 +3946,7 @@
     ]`,
 			"srcs":                   `["a.cpp"]`,
 			"local_includes":         `["."]`,
-			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+			"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 		}),
 	},
 	)
@@ -4071,8 +4081,8 @@
         "ubsan_undefined",
         "ubsan_nullability",
     ] + select({
-        "//build/bazel/platforms/os:android": ["ubsan_alignment"],
-        "//build/bazel/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
+        "//build/bazel_common_rules/platforms/os:android": ["ubsan_alignment"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
@@ -4082,8 +4092,8 @@
         "ubsan_undefined",
         "ubsan_nullability",
     ] + select({
-        "//build/bazel/platforms/os:android": ["ubsan_alignment"],
-        "//build/bazel/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
+        "//build/bazel_common_rules/platforms/os:android": ["ubsan_alignment"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
@@ -4211,21 +4221,21 @@
 			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"],
+        "//build/bazel_common_rules/platforms/os_arch:android_arm": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_x86": ["android_thin_lto"],
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/os_arch:android_arm": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_x86": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_x86_64": ["android_thin_lto"],
         "//conditions:default": [],
     })`}),
 		},
@@ -4256,14 +4266,14 @@
 			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
 				"local_includes": `["."]`,
 				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_thin_lto"],
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/os:android": ["android_thin_lto"],
         "//conditions:default": ["-android_thin_lto"],
     })`,
 			}),
@@ -4391,14 +4401,14 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
 				"features": `select({
-        "//build/bazel/platforms/os:android": ["visibility_hidden"],
+        "//build/bazel_common_rules/platforms/os:android": ["visibility_hidden"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
 			}),
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"features": `select({
-        "//build/bazel/platforms/os:android": ["visibility_hidden"],
+        "//build/bazel_common_rules/platforms/os:android": ["visibility_hidden"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
@@ -4430,7 +4440,7 @@
 					"flag_values": `{
         "//build/bazel/rules/apex:api_domain": "myapex",
     }`,
-					"constraint_values": `["//build/bazel/platforms/os:android"]`,
+					"constraint_values": `["//build/bazel_common_rules/platforms/os:android"]`,
 				},
 			),
 		},
@@ -4564,12 +4574,12 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTargetNoRestrictions("cc_binary", "a", AttrNameToString{
 				"linkopts": `["-lcommon"] + select({
-        "//build/bazel/platforms/os:darwin": [
+        "//build/bazel_common_rules/platforms/os:darwin": [
             "-ldarwinadditional",
             "-ldarwin",
         ],
-        "//build/bazel/platforms/os:linux_glibc": ["-llinux"],
-        "//build/bazel/platforms/os:windows": ["-lwindows"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": ["-llinux"],
+        "//build/bazel_common_rules/platforms/os:windows": ["-lwindows"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
@@ -4622,14 +4632,14 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
 				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_cfi"],
+        "//build/bazel_common_rules/platforms/os:android": ["android_cfi"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
 			}),
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_cfi"],
+        "//build/bazel_common_rules/platforms/os:android": ["android_cfi"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
@@ -4727,8 +4737,8 @@
 			}),
 			MakeBazelTarget("cc_library_shared", "foo_with_arch_variant_stem", AttrNameToString{
 				"stem": `select({
-        "//build/bazel/platforms/arch:arm": "foo-arm",
-        "//build/bazel/platforms/arch:arm64": "foo-arm64",
+        "//build/bazel_common_rules/platforms/arch:arm": "foo-arm",
+        "//build/bazel_common_rules/platforms/arch:arm64": "foo-arm64",
         "//conditions:default": None,
     })`,
 				"local_includes": `["."]`,
@@ -5112,35 +5122,35 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTargetNoRestrictions("cc_library_shared", "lib32", AttrNameToString{
 				"local_includes": `["."]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"] + select({
-        "//build/bazel/platforms/arch:arm64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/arch:riscv64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/arch:x86_64": ["@platforms//:incompatible"],
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"] + select({
+        "//build/bazel_common_rules/platforms/arch:arm64": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/arch:riscv64": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/arch:x86_64": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
 			MakeBazelTargetNoRestrictions("cc_library_static", "lib32_bp2build_cc_library_static", AttrNameToString{
 				"local_includes": `["."]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"] + select({
-        "//build/bazel/platforms/arch:arm64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/arch:riscv64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/arch:x86_64": ["@platforms//:incompatible"],
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"] + select({
+        "//build/bazel_common_rules/platforms/arch:arm64": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/arch:riscv64": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/arch:x86_64": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
 			MakeBazelTargetNoRestrictions("cc_library_shared", "lib64", AttrNameToString{
 				"local_includes": `["."]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"] + select({
-        "//build/bazel/platforms/arch:arm": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/arch:x86": ["@platforms//:incompatible"],
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"] + select({
+        "//build/bazel_common_rules/platforms/arch:arm": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
 			MakeBazelTargetNoRestrictions("cc_library_static", "lib64_bp2build_cc_library_static", AttrNameToString{
 				"local_includes": `["."]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"] + select({
-        "//build/bazel/platforms/arch:arm": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/arch:x86": ["@platforms//:incompatible"],
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"] + select({
+        "//build/bazel_common_rules/platforms/arch:arm": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -5157,7 +5167,6 @@
 		Blueprint: `
 cc_library {
 	name: "libfoo",
-	bazel_module: { bp2build_available: false },
 }
 ndk_library {
 	name: "libfoo",
@@ -5165,9 +5174,11 @@
 	symbol_file: "libfoo.map.txt",
 }
 `,
+		StubbedBuildDefinitions: []string{"libfoo"},
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_stub_suite", "libfoo.ndk_stub_libs", AttrNameToString{
 				"api_surface":          `"publicapi"`,
+				"included_in_ndk":      `True`,
 				"soname":               `"libfoo.so"`,
 				"source_library_label": `"//:libfoo"`,
 				"symbol_file":          `"libfoo.map.txt"`,
@@ -5210,3 +5221,146 @@
 	}
 	runCcLibraryTestCase(t, tc)
 }
+
+func TestVersionedNdkHeadersConversion(t *testing.T) {
+	tc := Bp2buildTestCase{
+		Description:                "versioned_ndk_headers conversion",
+		ModuleTypeUnderTest:        "versioned_ndk_headers",
+		ModuleTypeUnderTestFactory: cc.VersionedNdkHeadersFactory,
+		Blueprint: `
+versioned_ndk_headers {
+	name: "libfoo_headers",
+	from: "from",
+	to: "to",
+}
+`,
+		Filesystem: map[string]string{
+			"from/foo.h":       "",
+			"from/foo_other.h": "",
+		},
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions("ndk_headers", "libfoo_headers", AttrNameToString{
+				"strip_import_prefix": `"from"`,
+				"import_prefix":       `"to"`,
+				"hdrs": `[
+        "from/foo.h",
+        "from/foo_other.h",
+    ]`,
+				"run_versioner": "True",
+			}),
+		},
+	}
+	runCcLibraryTestCase(t, tc)
+}
+
+// Regression test for b/303307456.
+// TODO: b/202299295 - Remove this test when cc rules have proper support
+// for the `required` property
+func TestCcModules_requiredProperty(t *testing.T) {
+	runCcLibrarySharedTestCase(t, Bp2buildTestCase{
+		Description: "cc modules do not use the required property",
+		Filesystem: map[string]string{
+			"foo.c": "",
+			"bar.c": "",
+		},
+		Blueprint: soongCcLibraryPreamble + `
+cc_library {
+    name: "foo_both",
+    srcs: ["foo.c"],
+    include_build_directory: false,
+    required: ["bar"],
+}
+cc_library_shared {
+    name: "foo_shared",
+    srcs: ["foo.c"],
+    include_build_directory: false,
+    required: ["bar"],
+}
+cc_library_static {
+    name: "foo_static",
+    srcs: ["foo.c"],
+    include_build_directory: false,
+    required: ["bar"],
+}
+cc_library_static {
+    name: "bar",
+    srcs: ["bar.c"],
+    include_build_directory: false,
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo_both_bp2build_cc_library_static", AttrNameToString{
+				"srcs_c": `["foo.c"]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "foo_both", AttrNameToString{
+				"srcs_c": `["foo.c"]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
+				"srcs_c": `["foo.c"]`,
+			}),
+			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
+				"srcs_c": `["foo.c"]`,
+			}),
+			MakeBazelTarget("cc_library_static", "bar", AttrNameToString{
+				"srcs_c": `["bar.c"]`,
+			}),
+		},
+	})
+}
+
+func TestPropertiesIfStubLibraryIsInNdk(t *testing.T) {
+	tc := Bp2buildTestCase{
+		Description:                "If an equivalent ndk_library exists, set included_in_ndk=true for module-libapi stubs",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+// libfoo is an ndk library and contributes to module-libapi
+cc_library {
+	name: "libfoo",
+	stubs: {symbol_file: "libfoo.map.txt"},
+}
+ndk_library {
+	name: "libfoo",
+	first_version: "29",
+	symbol_file: "libfoo.map.txt",
+}
+// libbar is not an ndk library, but contributes to module-libapi
+cc_library {
+	name: "libbar",
+	stubs: {symbol_file: "libbar.map.txt"},
+}
+`,
+		StubbedBuildDefinitions: []string{"libfoo.ndk"},
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "libfoo_bp2build_cc_library_static", AttrNameToString{
+				"local_includes": `["."]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "libfoo", AttrNameToString{
+				"local_includes":    `["."]`,
+				"stubs_symbol_file": `"libfoo.map.txt"`,
+			}),
+			MakeBazelTarget("cc_stub_suite", "libfoo_stub_libs", AttrNameToString{
+				"api_surface":          `"module-libapi"`,
+				"soname":               `"libfoo.so"`,
+				"source_library_label": `"//:libfoo"`,
+				"symbol_file":          `"libfoo.map.txt"`,
+				"versions":             `["current"]`,
+				"included_in_ndk":      `True`,
+			}),
+			MakeBazelTarget("cc_library_static", "libbar_bp2build_cc_library_static", AttrNameToString{
+				"local_includes": `["."]`,
+			}),
+			MakeBazelTarget("cc_library_shared", "libbar", AttrNameToString{
+				"local_includes":    `["."]`,
+				"stubs_symbol_file": `"libbar.map.txt"`,
+			}),
+			MakeBazelTarget("cc_stub_suite", "libbar_stub_libs", AttrNameToString{
+				"api_surface":          `"module-libapi"`,
+				"soname":               `"libbar.so"`,
+				"source_library_label": `"//:libbar"`,
+				"symbol_file":          `"libbar.map.txt"`,
+				"versions":             `["current"]`,
+			}),
+		},
+	}
+	runCcLibraryTestCase(t, tc)
+}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index fde4c97..7655986 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -70,10 +70,6 @@
 	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
 		Description: "cc_library_headers test",
 		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":                        "",
@@ -86,7 +82,6 @@
 cc_library_headers {
     name: "foo_headers",
     export_include_dirs: ["dir-1", "dir-2"],
-    header_libs: ["lib-1", "lib-2"],
 
     arch: {
         arm64: {
@@ -108,9 +103,9 @@
 		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"],
+        "//build/bazel_common_rules/platforms/arch:arm64": ["arch_arm64_exported_include_dir"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["arch_x86_exported_include_dir"],
+        "//build/bazel_common_rules/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir"],
         "//conditions:default": [],
     }) + [
         "dir-1",
@@ -118,6 +113,10 @@
     ]`,
 				"sdk_version":     `"current"`,
 				"min_sdk_version": `"29"`,
+				"deps": `select({
+        "//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
+        "//conditions:default": [],
+    })`,
 			}),
 		},
 	})
@@ -181,11 +180,11 @@
 		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"],
+        "//build/bazel_common_rules/platforms/os:android": [":android-lib"],
+        "//build/bazel_common_rules/platforms/os:darwin": [":darwin-lib"],
+        "//build/bazel_common_rules/platforms/os:linux_bionic": [":linux_bionic-lib"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": [":linux-lib"],
+        "//build/bazel_common_rules/platforms/os:windows": [":windows-lib"],
         "//conditions:default": [],
     }) + [":base-lib"]`,
 			}),
@@ -218,7 +217,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `select({
-        "//build/bazel/platforms/os:android": [":exported-lib"],
+        "//build/bazel_common_rules/platforms/os:android": [":exported-lib"],
         "//conditions:default": [],
     })`,
 			}),
@@ -269,13 +268,13 @@
 		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"],
+        "//build/bazel_common_rules/platforms/os:android": ["android_include_dir"],
+        "//build/bazel_common_rules/platforms/os:darwin": ["darwin_include_dir"],
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["arm_include_dir"],
+        "//build/bazel_common_rules/platforms/arch:x86_64": ["x86_64_include_dir"],
         "//conditions:default": [],
     }) + ["shared_include_dir"]`,
 			}),
@@ -318,7 +317,7 @@
 	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
 		Description:             "cc_library_headers exported_static_lib_headers is reexported",
 		Filesystem:              map[string]string{},
-		StubbedBuildDefinitions: []string{"foo_export"},
+		StubbedBuildDefinitions: []string{"foo_export", "foo_no_reexport"},
 		Blueprint: soongCcLibraryHeadersPreamble + `
 cc_library_headers {
 		name: "foo_headers",
@@ -326,7 +325,8 @@
 		static_libs: ["foo_export", "foo_no_reexport"],
     bazel_module: { bp2build_available: true },
 }
-` + simpleModule("cc_library_headers", "foo_export"),
+` + simpleModule("cc_library_headers", "foo_export") +
+			simpleModule("cc_library_headers", "foo_no_reexport"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `[":foo_export"]`,
@@ -339,7 +339,7 @@
 	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
 		Description:             "cc_library_headers exported_shared_lib_headers is reexported",
 		Filesystem:              map[string]string{},
-		StubbedBuildDefinitions: []string{"foo_export"},
+		StubbedBuildDefinitions: []string{"foo_export", "foo_no_reexport"},
 		Blueprint: soongCcLibraryHeadersPreamble + `
 cc_library_headers {
 		name: "foo_headers",
@@ -347,7 +347,8 @@
 		shared_libs: ["foo_export", "foo_no_reexport"],
     bazel_module: { bp2build_available: true },
 }
-` + simpleModule("cc_library_headers", "foo_export"),
+` + simpleModule("cc_library_headers", "foo_export") +
+			simpleModule("cc_library_headers", "foo_no_reexport"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `[":foo_export"]`,
@@ -360,7 +361,7 @@
 	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
 		Description:             "cc_library_headers exported_header_lib_headers is reexported",
 		Filesystem:              map[string]string{},
-		StubbedBuildDefinitions: []string{"foo_export"},
+		StubbedBuildDefinitions: []string{"foo_export", "foo_no_reexport"},
 		Blueprint: soongCcLibraryHeadersPreamble + `
 cc_library_headers {
 		name: "foo_headers",
@@ -368,7 +369,8 @@
 		header_libs: ["foo_export", "foo_no_reexport"],
     bazel_module: { bp2build_available: true },
 }
-` + simpleModule("cc_library_headers", "foo_export"),
+` + simpleModule("cc_library_headers", "foo_export") +
+			simpleModule("cc_library_headers", "foo_no_reexport"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `[":foo_export"]`,
@@ -422,7 +424,7 @@
 func TestPrebuiltCcLibraryHeadersPreferredRdepUpdated(t *testing.T) {
 	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
 		Description:             "cc_library_headers prebuilt preferred is used as rdep",
-		StubbedBuildDefinitions: []string{"foo_export"},
+		StubbedBuildDefinitions: []string{"foo_export", "//foo/bar:foo_headers"},
 		Filesystem: map[string]string{
 			"foo/bar/Android.bp": simpleModule("cc_library_headers", "foo_headers"),
 		},
@@ -454,7 +456,7 @@
 func TestPrebuiltCcLibraryHeadersRdepUpdated(t *testing.T) {
 	runCcLibraryHeadersTestCase(t, Bp2buildTestCase{
 		Description:             "cc_library_headers not preferred is not used for rdep",
-		StubbedBuildDefinitions: []string{"foo_export"},
+		StubbedBuildDefinitions: []string{"foo_export", "//foo/bar:foo_headers"},
 		Filesystem: map[string]string{
 			"foo/bar/Android.bp": simpleModule("cc_library_headers", "foo_headers"),
 		},
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index bdde996..9f9fcf9 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -175,6 +175,10 @@
     ]`,
 				"sdk_version":     `"current"`,
 				"min_sdk_version": `"29"`,
+				"deps": `select({
+        "//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
+        "//conditions:default": [],
+    })`,
 			}),
 		},
 	})
@@ -200,11 +204,11 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
 				"implementation_dynamic_deps": `select({
-        "//build/bazel/platforms/arch:arm64": [":shared_dep"],
+        "//build/bazel_common_rules/platforms/arch:arm64": [":shared_dep"],
         "//conditions:default": [],
     })`,
 				"whole_archive_deps": `select({
-        "//build/bazel/platforms/arch:arm64": [":static_dep"],
+        "//build/bazel_common_rules/platforms/arch:arm64": [":static_dep"],
         "//conditions:default": [],
     })`,
 			}),
@@ -229,7 +233,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
 				"implementation_dynamic_deps": `select({
-        "//build/bazel/platforms/os:android": [":shared_dep"],
+        "//build/bazel_common_rules/platforms/os:android": [":shared_dep"],
         "//conditions:default": [],
     })`,
 			}),
@@ -262,10 +266,10 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
 				"implementation_dynamic_deps": `[":shared_dep"] + select({
-        "//build/bazel/platforms/arch:arm64": [":shared_dep3"],
+        "//build/bazel_common_rules/platforms/arch:arm64": [":shared_dep3"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/os:android": [":shared_dep2"],
+        "//build/bazel_common_rules/platforms/os:android": [":shared_dep2"],
         "//conditions:default": [],
     })`,
 			}),
@@ -468,7 +472,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_shared", "foo_shared", AttrNameToString{
 				"features": `select({
-        "//build/bazel/platforms/arch:arm": ["-link_crt"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["-link_crt"],
         "//conditions:default": [],
     })`,
 				"srcs": `["impl.cpp"]`,
@@ -1002,8 +1006,8 @@
 			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",
+        "//build/bazel_common_rules/platforms/arch:arm": "-32",
+        "//build/bazel_common_rules/platforms/arch:arm64": "-64",
         "//conditions:default": None,
     })`,
 			}),
@@ -1064,7 +1068,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("sysprop_library", "foo_sysprop_library", AttrNameToString{
 				"srcs": `select({
-        "//build/bazel/platforms/os:android": ["bar.sysprop"],
+        "//build/bazel_common_rules/platforms/os:android": ["bar.sysprop"],
         "//conditions:default": [],
     })`,
 			}),
@@ -1077,7 +1081,7 @@
 				"local_includes":  `["."]`,
 				"min_sdk_version": `"5"`,
 				"whole_archive_deps": `select({
-        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
+        "//build/bazel_common_rules/platforms/os:android": [":foo_cc_sysprop_library_static"],
         "//conditions:default": [],
     })`,
 			}),
@@ -1197,8 +1201,8 @@
         "ubsan_undefined",
         "ubsan_nullability",
     ] + select({
-        "//build/bazel/platforms/os:android": ["ubsan_alignment"],
-        "//build/bazel/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
+        "//build/bazel_common_rules/platforms/os:android": ["ubsan_alignment"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
@@ -1299,11 +1303,11 @@
 			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"],
+        "//build/bazel_common_rules/platforms/os_arch:android_arm": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_x86": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_x86_64": ["android_thin_lto"],
         "//conditions:default": [],
     })`}),
 		},
@@ -1332,7 +1336,7 @@
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"local_includes": `["."]`,
 				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os:android": ["android_thin_lto"],
         "//conditions:default": ["-android_thin_lto"],
     })`,
 			}),
@@ -1396,7 +1400,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"features": `select({
-        "//build/bazel/platforms/os:android": ["visibility_hidden"],
+        "//build/bazel_common_rules/platforms/os:android": ["visibility_hidden"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
@@ -1506,7 +1510,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
 				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_cfi"],
+        "//build/bazel_common_rules/platforms/os:android": ["android_cfi"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
@@ -1595,7 +1599,7 @@
 		Description:                "cc_library_shared stubs",
 		ModuleTypeUnderTest:        "cc_library_shared",
 		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		StubbedBuildDefinitions:    []string{"libNoStubs", "libHasApexStubs", "libHasApexAndNdkStubs"},
+		StubbedBuildDefinitions:    []string{"libNoStubs", "libHasApexStubs", "libHasApexAndNdkStubs", "libHasApexAndNdkStubs.ndk_stub_libs"},
 		Blueprint: soongCcLibrarySharedPreamble + `
 cc_library_shared {
 	name: "libUsesSdk",
@@ -1621,9 +1625,7 @@
 }
 ndk_library {
 	name: "libHasApexAndNdkStubs",
-	// TODO: b/301321658 - Stub this once existing-build-file handling can deal with
-	// modules that generate targets of a different name.
-	bazel_module: { bp2build_available: false },
+	first_version: "28",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -1644,6 +1646,10 @@
     })`,
 				"local_includes": `["."]`,
 				"sdk_version":    `"current"`,
+				"deps": `select({
+        "//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
+        "//conditions:default": [],
+    })`,
 			}),
 		},
 	})
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 7b97b39..d7bbd68 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -203,6 +203,10 @@
     ]`,
 				"sdk_version":     `"current"`,
 				"min_sdk_version": `"29"`,
+				"deps": `select({
+        "//build/bazel/rules/apex:unbundled_app": ["//build/bazel/rules/cc:ndk_sysroot"],
+        "//conditions:default": [],
+    })`,
 			}),
 		},
 	})
@@ -406,11 +410,11 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"implementation_deps": `select({
-        "//build/bazel/platforms/arch:arm64": [":static_dep"],
+        "//build/bazel_common_rules/platforms/arch:arm64": [":static_dep"],
         "//conditions:default": [],
     })`,
 				"whole_archive_deps": `select({
-        "//build/bazel/platforms/arch:arm64": [":static_dep2"],
+        "//build/bazel_common_rules/platforms/arch:arm64": [":static_dep2"],
         "//conditions:default": [],
     })`,
 			}),
@@ -438,11 +442,11 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"implementation_deps": `select({
-        "//build/bazel/platforms/os:android": [":static_dep"],
+        "//build/bazel_common_rules/platforms/os:android": [":static_dep"],
         "//conditions:default": [],
     })`,
 				"whole_archive_deps": `select({
-        "//build/bazel/platforms/os:android": [":static_dep2"],
+        "//build/bazel_common_rules/platforms/os:android": [":static_dep2"],
         "//conditions:default": [],
     })`,
 			}),
@@ -480,10 +484,10 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"implementation_deps": `[":static_dep"] + select({
-        "//build/bazel/platforms/arch:arm64": [":static_dep4"],
+        "//build/bazel_common_rules/platforms/arch:arm64": [":static_dep4"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/os:android": [":static_dep3"],
+        "//build/bazel_common_rules/platforms/os:android": [":static_dep3"],
         "//conditions:default": [],
     })`,
 				"whole_archive_deps": `[":static_dep2"]`,
@@ -535,7 +539,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `["common.c"] + select({
-        "//build/bazel/platforms/arch:arm": ["foo-arm.c"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["foo-arm.c"],
         "//conditions:default": [],
     })`,
 			}),
@@ -565,7 +569,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `["common.c"] + select({
-        "//build/bazel/platforms/arch:arm": ["for-arm.c"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["for-arm.c"],
         "//conditions:default": ["not-for-arm.c"],
     })`,
 			}),
@@ -597,11 +601,11 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `["common.c"] + select({
-        "//build/bazel/platforms/arch:arm": [
+        "//build/bazel_common_rules/platforms/arch:arm": [
             "not-for-x86.c",
             "for-arm.c",
         ],
-        "//build/bazel/platforms/arch:x86": [
+        "//build/bazel_common_rules/platforms/arch:x86": [
             "not-for-arm.c",
             "for-x86.c",
         ],
@@ -646,25 +650,25 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `["common.c"] + select({
-        "//build/bazel/platforms/arch:arm": [
+        "//build/bazel_common_rules/platforms/arch:arm": [
             "not-for-arm64.c",
             "not-for-x86.c",
             "not-for-x86_64.c",
             "for-arm.c",
         ],
-        "//build/bazel/platforms/arch:arm64": [
+        "//build/bazel_common_rules/platforms/arch:arm64": [
             "not-for-arm.c",
             "not-for-x86.c",
             "not-for-x86_64.c",
             "for-arm64.c",
         ],
-        "//build/bazel/platforms/arch:x86": [
+        "//build/bazel_common_rules/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": [
+        "//build/bazel_common_rules/platforms/arch:x86_64": [
             "not-for-arm.c",
             "not-for-arm64.c",
             "not-for-x86.c",
@@ -703,7 +707,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs": `["common.cc"] + select({
-        "//build/bazel/platforms/arch:arm": [],
+        "//build/bazel_common_rules/platforms/arch:arm": [],
         "//conditions:default": ["foo-no-arm.cc"],
     })`,
 			}),
@@ -734,8 +738,8 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs": `["common.cc"] + select({
-        "//build/bazel/platforms/arch:arm": [],
-        "//build/bazel/platforms/arch:x86": [
+        "//build/bazel_common_rules/platforms/arch:arm": [],
+        "//build/bazel_common_rules/platforms/arch:x86": [
             "foo-no-arm.cc",
             "x86-only.cc",
         ],
@@ -788,8 +792,8 @@
 		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"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["for-lib32.c"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["for-lib32.c"],
         "//conditions:default": ["not-for-lib32.c"],
     })`,
 			}),
@@ -820,23 +824,23 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `["common.c"] + select({
-        "//build/bazel/platforms/arch:arm": [
+        "//build/bazel_common_rules/platforms/arch:arm": [
             "not-for-lib64.c",
             "for-lib32.c",
         ],
-        "//build/bazel/platforms/arch:arm64": [
+        "//build/bazel_common_rules/platforms/arch:arm64": [
             "not-for-lib32.c",
             "for-lib64.c",
         ],
-        "//build/bazel/platforms/arch:riscv64": [
+        "//build/bazel_common_rules/platforms/arch:riscv64": [
             "not-for-lib32.c",
             "for-lib64.c",
         ],
-        "//build/bazel/platforms/arch:x86": [
+        "//build/bazel_common_rules/platforms/arch:x86": [
             "not-for-lib64.c",
             "for-lib32.c",
         ],
-        "//build/bazel/platforms/arch:x86_64": [
+        "//build/bazel_common_rules/platforms/arch:x86_64": [
             "not-for-lib32.c",
             "for-lib64.c",
         ],
@@ -891,7 +895,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `["common.c"] + select({
-        "//build/bazel/platforms/arch:arm": [
+        "//build/bazel_common_rules/platforms/arch:arm": [
             "not-for-arm64.c",
             "not-for-lib64.c",
             "not-for-riscv64.c",
@@ -900,7 +904,7 @@
             "for-arm.c",
             "for-lib32.c",
         ],
-        "//build/bazel/platforms/arch:arm64": [
+        "//build/bazel_common_rules/platforms/arch:arm64": [
             "not-for-arm.c",
             "not-for-lib32.c",
             "not-for-riscv64.c",
@@ -909,7 +913,7 @@
             "for-arm64.c",
             "for-lib64.c",
         ],
-        "//build/bazel/platforms/arch:riscv64": [
+        "//build/bazel_common_rules/platforms/arch:riscv64": [
             "not-for-arm.c",
             "not-for-arm64.c",
             "not-for-lib32.c",
@@ -918,7 +922,7 @@
             "for-riscv64.c",
             "for-lib64.c",
         ],
-        "//build/bazel/platforms/arch:x86": [
+        "//build/bazel_common_rules/platforms/arch:x86": [
             "not-for-arm.c",
             "not-for-arm64.c",
             "not-for-lib64.c",
@@ -927,7 +931,7 @@
             "for-x86.c",
             "for-lib32.c",
         ],
-        "//build/bazel/platforms/arch:x86_64": [
+        "//build/bazel_common_rules/platforms/arch:x86_64": [
             "not-for-arm.c",
             "not-for-arm64.c",
             "not-for-lib32.c",
@@ -1085,20 +1089,20 @@
         "//dep:generated_src_other_pkg",
         ":generated_hdr",
     ] + select({
-        "//build/bazel/platforms/arch:x86": ["for-x86.cpp"],
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/os:android": [":generated_src_android"],
         "//conditions:default": [],
     })`,
 				"hdrs": `select({
-        "//build/bazel/platforms/os:android": ["//dep:generated_hdr_other_pkg_android"],
+        "//build/bazel_common_rules/platforms/os:android": ["//dep:generated_hdr_other_pkg_android"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/platforms/arch:x86": ["//dep:generated_hdr_other_pkg_x86"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["//dep:generated_hdr_other_pkg_x86"],
         "//conditions:default": [],
     }) + ["//dep:generated_hdr_other_pkg"]`,
 				"local_includes":           `["."]`,
@@ -1143,15 +1147,15 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"srcs_c": `select({
-        "//build/bazel/platforms/os:android": ["android_src.c"],
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/os_arch:android_arm": ["android_arm_src.c"],
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": ["android_arm64_src.c"],
+        "//build/bazel_common_rules/platforms/os_arch:android_x86": ["android_x86_src.c"],
+        "//build/bazel_common_rules/platforms/os_arch:android_x86_64": ["android_x86_64_src.c"],
+        "//build/bazel_common_rules/platforms/os_arch:linux_bionic_arm64": ["linux_bionic_arm64_src.c"],
+        "//build/bazel_common_rules/platforms/os_arch:linux_bionic_x86_64": ["linux_bionic_x86_64_src.c"],
         "//conditions:default": [],
     })`,
 			}),
@@ -1354,7 +1358,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "target_bionic_empty", AttrNameToString{
 				"system_dynamic_deps": `select({
-        "//build/bazel/platforms/os:linux_musl": [":libc_musl"],
+        "//build/bazel_common_rules/platforms/os:linux_musl": [":libc_musl"],
         "//conditions:default": [],
     })`,
 			}),
@@ -1388,7 +1392,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "target_linux_bionic_empty", AttrNameToString{
 				"system_dynamic_deps": `select({
-        "//build/bazel/platforms/os:linux_musl": [":libc_musl"],
+        "//build/bazel_common_rules/platforms/os:linux_musl": [":libc_musl"],
         "//conditions:default": [],
     })`,
 			}),
@@ -1473,9 +1477,9 @@
 		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"],
+        "//build/bazel_common_rules/platforms/os:android": [":libc"],
+        "//build/bazel_common_rules/platforms/os:linux_bionic": [":libc"],
+        "//build/bazel_common_rules/platforms/os:linux_musl": [":libc_musl"],
         "//conditions:default": [],
     })`,
 			}),
@@ -1508,8 +1512,8 @@
 		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"],
+        "//build/bazel_common_rules/platforms/os:linux_bionic": [":libm"],
+        "//build/bazel_common_rules/platforms/os:linux_musl": [":libc_musl"],
         "//conditions:default": [],
     })`,
 			}),
@@ -1833,7 +1837,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("sysprop_library", "foo_sysprop_library", AttrNameToString{
 				"srcs": `select({
-        "//build/bazel/platforms/os:android": ["bar.sysprop"],
+        "//build/bazel_common_rules/platforms/os:android": ["bar.sysprop"],
         "//conditions:default": [],
     })`,
 			}),
@@ -1846,7 +1850,7 @@
 				"local_includes":  `["."]`,
 				"min_sdk_version": `"5"`,
 				"whole_archive_deps": `select({
-        "//build/bazel/platforms/os:android": [":foo_cc_sysprop_library_static"],
+        "//build/bazel_common_rules/platforms/os:android": [":foo_cc_sysprop_library_static"],
         "//conditions:default": [],
     })`,
 			}),
@@ -1926,8 +1930,8 @@
         "ubsan_undefined",
         "ubsan_nullability",
     ] + select({
-        "//build/bazel/platforms/os:android": ["ubsan_alignment"],
-        "//build/bazel/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
+        "//build/bazel_common_rules/platforms/os:android": ["ubsan_alignment"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": ["ubsan_integer_overflow"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
@@ -2028,11 +2032,11 @@
 			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"],
+        "//build/bazel_common_rules/platforms/os_arch:android_arm": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_riscv64": ["-android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_x86": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os_arch:android_x86_64": ["android_thin_lto"],
         "//conditions:default": [],
     })`}),
 		},
@@ -2061,7 +2065,7 @@
 			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
 				"local_includes": `["."]`,
 				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_thin_lto"],
+        "//build/bazel_common_rules/platforms/os:android": ["android_thin_lto"],
         "//conditions:default": ["-android_thin_lto"],
     })`,
 			}),
@@ -2125,7 +2129,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
 				"features": `select({
-        "//build/bazel/platforms/os:android": ["visibility_hidden"],
+        "//build/bazel_common_rules/platforms/os:android": ["visibility_hidden"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
@@ -2170,7 +2174,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
 				"features": `select({
-        "//build/bazel/platforms/os:android": ["android_cfi"],
+        "//build/bazel_common_rules/platforms/os:android": ["android_cfi"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index e1e2f43..4d44db7 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -232,11 +232,11 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_object", "foo", AttrNameToString{
 				"copts": `["-fno-addrsig"] + select({
-        "//build/bazel/platforms/arch:x86": ["-fPIC"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["-fPIC"],
         "//conditions:default": [],
     })`,
 				"srcs": `["a.cpp"] + select({
-        "//build/bazel/platforms/arch:arm": ["arch/arm/file.cpp"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["arch/arm/file.cpp"],
         "//conditions:default": [],
     })`,
 				"system_dynamic_deps": `[]`,
@@ -276,17 +276,17 @@
 		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"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["-Wall"],
+        "//build/bazel_common_rules/platforms/arch:arm64": ["-Wall"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["-fPIC"],
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["arm.cpp"],
+        "//build/bazel_common_rules/platforms/arch:arm64": ["arm64.cpp"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["x86.cpp"],
+        "//build/bazel_common_rules/platforms/arch:x86_64": ["x86_64.cpp"],
         "//conditions:default": [],
     })`,
 				"system_dynamic_deps": `[]`,
@@ -364,15 +364,15 @@
 			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"],
+        "//build/bazel_common_rules/platforms/arch:arm": [":arm_obj"],
+        "//build/bazel_common_rules/platforms/arch:x86": [":x86_obj"],
+        "//build/bazel_common_rules/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",
+        "//build/bazel_common_rules/platforms/arch:arm": "arm.lds",
+        "//build/bazel_common_rules/platforms/arch:x86": "x86.lds",
+        "//build/bazel_common_rules/platforms/arch:x86_64": "x86_64.lds",
         "//conditions:default": None,
     })`,
 				"srcs": `["base.cpp"]`,
@@ -405,18 +405,18 @@
 			MakeBazelTarget("cc_object", "foo", AttrNameToString{
 				"copts": `["-fno-addrsig"]`,
 				"srcs": `["base.cpp"] + select({
-        "//build/bazel/platforms/os_arch:android_arm64": [
+        "//build/bazel_common_rules/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": [
+        "//build/bazel_common_rules/platforms/os_arch:android_x86": ["linux_x86.cpp"],
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/os_arch:linux_glibc_x86": ["linux_x86.cpp"],
+        "//build/bazel_common_rules/platforms/os_arch:linux_musl_arm64": ["linux_arm64.cpp"],
+        "//build/bazel_common_rules/platforms/os_arch:linux_musl_x86": ["linux_x86.cpp"],
         "//conditions:default": [],
     })`,
 			}),
diff --git a/bp2build/cc_prebuilt_binary_conversion_test.go b/bp2build/cc_prebuilt_binary_conversion_test.go
index 0e8048c..9adaf32 100644
--- a/bp2build/cc_prebuilt_binary_conversion_test.go
+++ b/bp2build/cc_prebuilt_binary_conversion_test.go
@@ -95,8 +95,8 @@
 }`, ExpectedBazelTargets: []string{
 				MakeBazelTarget("cc_prebuilt_binary", "bintest", AttrNameToString{
 					"src": `select({
-        "//build/bazel/platforms/arch:arm": "binb",
-        "//build/bazel/platforms/arch:arm64": "bina",
+        "//build/bazel_common_rules/platforms/arch:arm": "binb",
+        "//build/bazel_common_rules/platforms/arch:arm64": "bina",
         "//conditions:default": None,
     })`,
 				}),
diff --git a/bp2build/cc_prebuilt_library_conversion_test.go b/bp2build/cc_prebuilt_library_conversion_test.go
index 8c33be3..a7f0c7b 100644
--- a/bp2build/cc_prebuilt_library_conversion_test.go
+++ b/bp2build/cc_prebuilt_library_conversion_test.go
@@ -76,21 +76,21 @@
 			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",
+        "//build/bazel_common_rules/platforms/arch:arm": "libg.so",
+        "//build/bazel_common_rules/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",
+        "//build/bazel_common_rules/platforms/arch:arm": "libg.so",
+        "//build/bazel_common_rules/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",
+        "//build/bazel_common_rules/platforms/arch:arm": "libg.so",
+        "//build/bazel_common_rules/platforms/arch:arm64": "libf.so",
         "//conditions:default": None,
     })`,
 				}),
@@ -289,16 +289,16 @@
 			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/"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["testdir/1/"],
+        "//build/bazel_common_rules/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/"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["testdir/1/"],
+        "//build/bazel_common_rules/platforms/arch:arm64": ["testdir/2/"],
         "//conditions:default": [],
     })`,
 			}),
@@ -306,8 +306,8 @@
 				"alwayslink":     "True",
 				"static_library": `"libf.so"`,
 				"export_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["testdir/1/"],
+        "//build/bazel_common_rules/platforms/arch:arm64": ["testdir/2/"],
         "//conditions:default": [],
     })`,
 			}),
@@ -336,16 +336,16 @@
 			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/"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["testdir/1/"],
+        "//build/bazel_common_rules/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/"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["testdir/1/"],
+        "//build/bazel_common_rules/platforms/arch:arm64": ["testdir/2/"],
         "//conditions:default": [],
     })`,
 			}),
@@ -353,8 +353,8 @@
 				"alwayslink":     "True",
 				"static_library": `"libf.so"`,
 				"export_system_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["testdir/1/"],
+        "//build/bazel_common_rules/platforms/arch:arm64": ["testdir/2/"],
         "//conditions:default": [],
     })`,
 			}),
@@ -381,11 +381,11 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_prebuilt_library_static", "ndk_libfoo_static", AttrNameToString{
 				"static_library": `select({
-        "//build/bazel/platforms/os_arch:android_arm": "current/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libfoo_static.a",
-        "//build/bazel/platforms/os_arch:android_arm64": "current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libfoo_static.a",
-        "//build/bazel/platforms/os_arch:android_riscv64": "current/sources/cxx-stl/llvm-libc++/libs/riscv64/libfoo_static.a",
-        "//build/bazel/platforms/os_arch:android_x86": "current/sources/cxx-stl/llvm-libc++/libs/x86/libfoo_static.a",
-        "//build/bazel/platforms/os_arch:android_x86_64": "current/sources/cxx-stl/llvm-libc++/libs/x86_64/libfoo_static.a",
+        "//build/bazel_common_rules/platforms/os_arch:android_arm": "current/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libfoo_static.a",
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": "current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libfoo_static.a",
+        "//build/bazel_common_rules/platforms/os_arch:android_riscv64": "current/sources/cxx-stl/llvm-libc++/libs/riscv64/libfoo_static.a",
+        "//build/bazel_common_rules/platforms/os_arch:android_x86": "current/sources/cxx-stl/llvm-libc++/libs/x86/libfoo_static.a",
+        "//build/bazel_common_rules/platforms/os_arch:android_x86_64": "current/sources/cxx-stl/llvm-libc++/libs/x86_64/libfoo_static.a",
         "//conditions:default": None,
     })`,
 				"export_system_includes": `[
@@ -395,11 +395,11 @@
 			}),
 			MakeBazelTarget("cc_prebuilt_library_shared", "ndk_libfoo_shared", AttrNameToString{
 				"shared_library": `select({
-        "//build/bazel/platforms/os_arch:android_arm": "current/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libfoo_shared.so",
-        "//build/bazel/platforms/os_arch:android_arm64": "current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libfoo_shared.so",
-        "//build/bazel/platforms/os_arch:android_riscv64": "current/sources/cxx-stl/llvm-libc++/libs/riscv64/libfoo_shared.so",
-        "//build/bazel/platforms/os_arch:android_x86": "current/sources/cxx-stl/llvm-libc++/libs/x86/libfoo_shared.so",
-        "//build/bazel/platforms/os_arch:android_x86_64": "current/sources/cxx-stl/llvm-libc++/libs/x86_64/libfoo_shared.so",
+        "//build/bazel_common_rules/platforms/os_arch:android_arm": "current/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libfoo_shared.so",
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": "current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libfoo_shared.so",
+        "//build/bazel_common_rules/platforms/os_arch:android_riscv64": "current/sources/cxx-stl/llvm-libc++/libs/riscv64/libfoo_shared.so",
+        "//build/bazel_common_rules/platforms/os_arch:android_x86": "current/sources/cxx-stl/llvm-libc++/libs/x86/libfoo_shared.so",
+        "//build/bazel_common_rules/platforms/os_arch:android_x86_64": "current/sources/cxx-stl/llvm-libc++/libs/x86_64/libfoo_shared.so",
         "//conditions:default": None,
     })`,
 				"export_system_includes": `[
diff --git a/bp2build/cc_prebuilt_library_shared_conversion_test.go b/bp2build/cc_prebuilt_library_shared_conversion_test.go
index 9e975ae..2242758 100644
--- a/bp2build/cc_prebuilt_library_shared_conversion_test.go
+++ b/bp2build/cc_prebuilt_library_shared_conversion_test.go
@@ -68,8 +68,8 @@
 			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",
+        "//build/bazel_common_rules/platforms/arch:arm": "libg.so",
+        "//build/bazel_common_rules/platforms/arch:arm64": "libf.so",
         "//conditions:default": None,
     })`,
 				}),
@@ -125,8 +125,8 @@
 			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/"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["testdir/1/"],
+        "//build/bazel_common_rules/platforms/arch:arm64": ["testdir/2/"],
         "//conditions:default": [],
     })`,
 			}),
@@ -155,8 +155,8 @@
 			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/"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["testdir/1/"],
+        "//build/bazel_common_rules/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
index 58c0a70..1a9579a 100644
--- a/bp2build/cc_prebuilt_library_shared_test.go
+++ b/bp2build/cc_prebuilt_library_shared_test.go
@@ -52,8 +52,8 @@
 			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",
+        "//build/bazel_common_rules/platforms/arch:arm": "libg.so",
+        "//build/bazel_common_rules/platforms/arch:arm64": "libf.so",
         "//conditions:default": None,
     })`,
 				}),
diff --git a/bp2build/cc_prebuilt_library_static_conversion_test.go b/bp2build/cc_prebuilt_library_static_conversion_test.go
index 77562e7..fb408b5 100644
--- a/bp2build/cc_prebuilt_library_static_conversion_test.go
+++ b/bp2build/cc_prebuilt_library_static_conversion_test.go
@@ -72,15 +72,15 @@
 			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",
+        "//build/bazel_common_rules/platforms/arch:arm": "libg.so",
+        "//build/bazel_common_rules/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",
+        "//build/bazel_common_rules/platforms/arch:arm": "libg.so",
+        "//build/bazel_common_rules/platforms/arch:arm64": "libf.so",
         "//conditions:default": None,
     })`}),
 			},
@@ -141,8 +141,8 @@
 			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/"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["testdir/1/"],
+        "//build/bazel_common_rules/platforms/arch:arm64": ["testdir/2/"],
         "//conditions:default": [],
     })`,
 			}),
@@ -150,8 +150,8 @@
 				"alwayslink":     "True",
 				"static_library": `"libf.so"`,
 				"export_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["testdir/1/"],
+        "//build/bazel_common_rules/platforms/arch:arm64": ["testdir/2/"],
         "//conditions:default": [],
     })`,
 			}),
@@ -180,8 +180,8 @@
 			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/"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["testdir/1/"],
+        "//build/bazel_common_rules/platforms/arch:arm64": ["testdir/2/"],
         "//conditions:default": [],
     })`,
 			}),
@@ -189,8 +189,8 @@
 				"alwayslink":     "True",
 				"static_library": `"libf.so"`,
 				"export_system_includes": `select({
-        "//build/bazel/platforms/arch:arm": ["testdir/1/"],
-        "//build/bazel/platforms/arch:arm64": ["testdir/2/"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["testdir/1/"],
+        "//build/bazel_common_rules/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
index 17da813..7d0ab28 100644
--- a/bp2build/cc_prebuilt_library_static_test.go
+++ b/bp2build/cc_prebuilt_library_static_test.go
@@ -69,15 +69,15 @@
 			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",
+        "//build/bazel_common_rules/platforms/arch:arm": "libg.so",
+        "//build/bazel_common_rules/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",
+        "//build/bazel_common_rules/platforms/arch:arm": "libg.so",
+        "//build/bazel_common_rules/platforms/arch:arm64": "libf.so",
         "//conditions:default": None,
     })`}),
 			},
diff --git a/bp2build/cc_prebuilt_object_conversion_test.go b/bp2build/cc_prebuilt_object_conversion_test.go
index 903c816..068e4e2 100644
--- a/bp2build/cc_prebuilt_object_conversion_test.go
+++ b/bp2build/cc_prebuilt_object_conversion_test.go
@@ -71,8 +71,8 @@
 }`, ExpectedBazelTargets: []string{
 				MakeBazelTarget("cc_prebuilt_object", "objtest", AttrNameToString{
 					"src": `select({
-        "//build/bazel/platforms/arch:arm": "objb.o",
-        "//build/bazel/platforms/arch:arm64": "obja.o",
+        "//build/bazel_common_rules/platforms/arch:arm": "objb.o",
+        "//build/bazel_common_rules/platforms/arch:arm64": "obja.o",
         "//conditions:default": None,
     })`,
 				}),
diff --git a/bp2build/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go
index 679a364..c5f5f79 100644
--- a/bp2build/cc_test_conversion_test.go
+++ b/bp2build/cc_test_conversion_test.go
@@ -117,26 +117,26 @@
         ":libgtest_main",
         ":libgtest",
     ] + select({
-        "//build/bazel/platforms/os:darwin": [":hostlib"],
-        "//build/bazel/platforms/os:linux_bionic": [":hostlib"],
-        "//build/bazel/platforms/os:linux_glibc": [":hostlib"],
-        "//build/bazel/platforms/os:linux_musl": [":hostlib"],
-        "//build/bazel/platforms/os:windows": [":hostlib"],
+        "//build/bazel_common_rules/platforms/os:darwin": [":hostlib"],
+        "//build/bazel_common_rules/platforms/os:linux_bionic": [":hostlib"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": [":hostlib"],
+        "//build/bazel_common_rules/platforms/os:linux_musl": [":hostlib"],
+        "//build/bazel_common_rules/platforms/os:windows": [":hostlib"],
         "//conditions:default": [],
     })`,
 				"local_includes": `["."]`,
 				"dynamic_deps": `[":cc_test_lib2"] + select({
-        "//build/bazel/platforms/os:android": [":foolib"],
+        "//build/bazel_common_rules/platforms/os:android": [":foolib"],
         "//conditions:default": [],
     })`,
 				"srcs": `["test.cpp"] + select({
-        "//build/bazel/platforms/os:android": [
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/os:linux_bionic": ["linux.cpp"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": ["linux.cpp"],
+        "//build/bazel_common_rules/platforms/os:linux_musl": ["linux.cpp"],
         "//conditions:default": [],
     })`,
 				"runs_on": `[
@@ -144,7 +144,7 @@
         "device",
     ]`,
 				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm64": [
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": [
             "memtag_heap",
             "diag_memtag_heap",
         ],
@@ -178,7 +178,7 @@
         "device",
     ]`,
 				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm64": [
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": [
             "memtag_heap",
             "diag_memtag_heap",
         ],
@@ -217,7 +217,7 @@
         "device",
     ]`,
 				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm64": [
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": [
             "memtag_heap",
             "diag_memtag_heap",
         ],
@@ -248,7 +248,7 @@
 			{"cc_test", "mytest", AttrNameToString{
 				"local_includes":         `["."]`,
 				"srcs":                   `["test.cpp"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 				"test_config":            `"test_config.xml"`,
 				"deps": `[
         ":libgtest_main",
@@ -256,7 +256,7 @@
     ]`,
 				"runs_on": `["device"]`,
 				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm64": [
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": [
             "memtag_heap",
             "diag_memtag_heap",
         ],
@@ -287,7 +287,7 @@
 			{"cc_test", "mytest", AttrNameToString{
 				"local_includes":         `["."]`,
 				"srcs":                   `["test.cpp"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 				"test_config":            `"AndroidTest.xml"`,
 				"dynamic_config":         `"DynamicConfig.xml"`,
 				"deps": `[
@@ -296,7 +296,7 @@
     ]`,
 				"runs_on": `["device"]`,
 				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm64": [
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": [
             "memtag_heap",
             "diag_memtag_heap",
         ],
@@ -330,7 +330,7 @@
 				"auto_generate_test_config": "True",
 				"local_includes":            `["."]`,
 				"srcs":                      `["test.cpp"]`,
-				"target_compatible_with":    `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with":    `["//build/bazel_common_rules/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\" />'",
@@ -341,7 +341,7 @@
 				"dynamic_deps":          `[":liblog"]`,
 				"runs_on":               `["device"]`,
 				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm64": [
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": [
             "memtag_heap",
             "diag_memtag_heap",
         ],
@@ -369,14 +369,14 @@
 			{"cc_test", "mytest", AttrNameToString{
 				"local_includes":         `["."]`,
 				"srcs":                   `["test.cpp"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 				"deps": `[
         ":libgtest",
         ":libgtest_main",
     ]`,
 				"runs_on": `["device"]`,
 				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm64": [
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": [
             "memtag_heap",
             "diag_memtag_heap",
         ],
@@ -405,12 +405,12 @@
 			{"cc_test", "mytest", AttrNameToString{
 				"local_includes":         `["."]`,
 				"srcs":                   `["test.cpp"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 				"deps":                   `[":libgtest_isolated_main"]`,
 				"dynamic_deps":           `[":liblog"]`,
 				"runs_on":                `["device"]`,
 				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm64": [
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": [
             "memtag_heap",
             "diag_memtag_heap",
         ],
@@ -446,10 +446,10 @@
         ":libgtest",
     ]`,
 				"gtest":                  "True",
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 				"runs_on":                `["device"]`,
 				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm64": [
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": [
             "memtag_heap",
             "diag_memtag_heap",
         ],
@@ -460,10 +460,10 @@
 			{"cc_test", "mytest_with_no_gtest", AttrNameToString{
 				"local_includes":         `["."]`,
 				"gtest":                  "False",
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 				"runs_on":                `["device"]`,
 				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm64": [
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": [
             "memtag_heap",
             "diag_memtag_heap",
         ],
@@ -495,12 +495,12 @@
 			{"cc_test", "mytest", AttrNameToString{
 				"local_includes":         `["."]`,
 				"srcs":                   `["test.cpp"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 				"deps":                   `[":libgtest_isolated_main"]`,
 				"dynamic_deps":           `[":liblog"]`,
 				"runs_on":                `["device"]`,
 				"features": `["android_cfi"] + select({
-        "//build/bazel/platforms/os_arch:android_arm64": ["-memtag_heap"],
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": ["-memtag_heap"],
         "//conditions:default": [],
     })`,
 			},
@@ -532,12 +532,12 @@
 			{"cc_test", "mytest", AttrNameToString{
 				"local_includes":         `["."]`,
 				"srcs":                   `["test.cpp"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 				"deps":                   `[":libgtest_isolated_main"]`,
 				"dynamic_deps":           `[":liblog"]`,
 				"runs_on":                `["device"]`,
 				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm64": ["-memtag_heap"],
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": ["-memtag_heap"],
         "//conditions:default": [],
     })`,
 			},
@@ -569,12 +569,12 @@
 			{"cc_test", "mytest", AttrNameToString{
 				"local_includes":         `["."]`,
 				"srcs":                   `["test.cpp"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 				"deps":                   `[":libgtest_isolated_main"]`,
 				"dynamic_deps":           `[":liblog"]`,
 				"runs_on":                `["device"]`,
 				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm64": [
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": [
             "memtag_heap",
             "diag_memtag_heap",
         ],
@@ -615,12 +615,12 @@
 			{"cc_test", "mytest", AttrNameToString{
 				"local_includes":         `["."]`,
 				"srcs":                   `["test.cpp"]`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 				"deps":                   `[":libgtest_isolated_main"]`,
 				"dynamic_deps":           `[":liblog"]`,
 				"runs_on":                `["device"]`,
 				"features": `select({
-        "//build/bazel/platforms/os_arch:android_arm64": [
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": [
             "-memtag_heap",
             "-diag_memtag_heap",
         ],
diff --git a/bp2build/cc_yasm_conversion_test.go b/bp2build/cc_yasm_conversion_test.go
index 55d4feb..c98e1a1 100644
--- a/bp2build/cc_yasm_conversion_test.go
+++ b/bp2build/cc_yasm_conversion_test.go
@@ -126,14 +126,14 @@
 			MakeBazelTarget("yasm", "foo_yasm", map[string]string{
 				"include_dirs": `["."]`,
 				"srcs": `select({
-        "//build/bazel/platforms/arch:x86": ["myfile.asm"],
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/arch:x86": [":foo_yasm"],
         "//conditions:default": [],
     })`,
 		})...),
@@ -164,7 +164,7 @@
 			MakeBazelTarget("yasm", "foo_yasm", map[string]string{
 				"include_dirs": `["."]`,
 				"srcs": `["myfile.asm"] + select({
-        "//build/bazel/platforms/arch:x86": ["mysecondfile.asm"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["mysecondfile.asm"],
         "//conditions:default": [],
     })`,
 			}),
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index c697235..b2792e6 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -15,7 +15,6 @@
 	rust_config "android/soong/rust/config"
 	"android/soong/starlark_fmt"
 
-	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -34,19 +33,9 @@
 	files = append(files, newFile("android", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
 	files = append(files, newFile("android", "constants.bzl", android.BazelCcToolchainVars(cfg)))
 
-	// Visit all modules to determine the list of ndk libraries
-	// This list will be used to add additional flags for cc stub generation
-	ndkLibsStringFormatted := []string{}
-	ctx.Context().VisitAllModules(func(m blueprint.Module) {
-		if ctx.Context().ModuleType(m) == "ndk_library" {
-			ndkLibsStringFormatted = append(ndkLibsStringFormatted, fmt.Sprintf(`"%s"`, m.Name())) // name will be `"libc.ndk"`
-		}
-	})
-
 	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("cc_toolchain", "ndk_libs.bzl", fmt.Sprintf("ndk_libs = [%v]", strings.Join(ndkLibsStringFormatted, ", "))))
 
 	files = append(files, newFile("java_toolchain", GeneratedBuildFileName, "")) // Creates a //java_toolchain package.
 	files = append(files, newFile("java_toolchain", "constants.bzl", java_config.BazelJavaToolchainVars(cfg)))
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index 6b10077..51675ce 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -107,10 +107,6 @@
 		},
 		{
 			dir:      "cc_toolchain",
-			basename: "ndk_libs.bzl",
-		},
-		{
-			dir:      "cc_toolchain",
 			basename: "sanitizer_constants.bzl",
 		},
 		{
diff --git a/bp2build/fdo_profile_conversion_test.go b/bp2build/fdo_profile_conversion_test.go
index 4d04283..918b27c 100644
--- a/bp2build/fdo_profile_conversion_test.go
+++ b/bp2build/fdo_profile_conversion_test.go
@@ -50,8 +50,8 @@
 }`,
 			expectedBazelAttrs: AttrNameToString{
 				"profile": `select({
-        "//build/bazel/platforms/arch:arm": "foo_arm.afdo",
-        "//build/bazel/platforms/arch:arm64": "foo_arm64.afdo",
+        "//build/bazel_common_rules/platforms/arch:arm": "foo_arm.afdo",
+        "//build/bazel_common_rules/platforms/arch:arm64": "foo_arm64.afdo",
         "//conditions:default": None,
     })`,
 			},
diff --git a/bp2build/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go
index cb2e207..9c49dac 100644
--- a/bp2build/filegroup_conversion_test.go
+++ b/bp2build/filegroup_conversion_test.go
@@ -40,7 +40,9 @@
     srcs: ["foo"],
 }
 `,
-		ExpectedBazelTargets: []string{}})
+		ExpectedBazelTargets:       []string{},
+		ExpectedHandcraftedModules: []string{"foo"}},
+	)
 }
 
 func TestFilegroupSameNameAsFile_MultipleFiles(t *testing.T) {
diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go
index 7e9b17b..af03dff 100644
--- a/bp2build/genrule_conversion_test.go
+++ b/bp2build/genrule_conversion_test.go
@@ -681,11 +681,11 @@
 
 	expectedBazelAttrs := AttrNameToString{
 		"srcs": `["foo1.in"] + select({
-        "//build/bazel/platforms/arch:arm": ["foo1_arch.in"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["foo1_arch.in"],
         "//conditions:default": [],
     })`,
 		"cmd":                    `"cat $(SRCS) > $(OUTS)"`,
-		"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+		"target_compatible_with": `["//build/bazel_common_rules/platforms/os:android"]`,
 	}
 
 	expectedBazelTargets := []string{
diff --git a/bp2build/gensrcs_conversion_test.go b/bp2build/gensrcs_conversion_test.go
index e808340..e9fc61d 100644
--- a/bp2build/gensrcs_conversion_test.go
+++ b/bp2build/gensrcs_conversion_test.go
@@ -15,16 +15,22 @@
 package bp2build
 
 import (
+	"testing"
+
 	"android/soong/android"
 	"android/soong/genrule"
-	"testing"
 )
 
+func registerModulesForGensrcsTests(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+}
+
 func TestGensrcs(t *testing.T) {
 	testcases := []struct {
-		name               string
-		bp                 string
-		expectedBazelAttrs AttrNameToString
+		name                    string
+		bp                      string
+		expectedBazelAttrs      AttrNameToString
+		stubbedBuildDefinitions []string
 	}{
 		{
 			name: "gensrcs with common usage of properties",
@@ -37,18 +43,22 @@
                 data: ["foo/file.txt", ":external_files"],
                 output_extension: "out",
                 bazel_module: { bp2build_available: true },
+			}
+      filegroup {
+                name: "external_files",
 			}`,
+			stubbedBuildDefinitions: []string{"external_files"},
 			expectedBazelAttrs: AttrNameToString{
 				"srcs": `[
         "test/input.txt",
-        ":external_files__BP2BUILD__MISSING__DEP",
+        ":external_files",
     ]`,
 				"tools":            `["program.py"]`,
 				"output_extension": `"out"`,
-				"cmd":              `"$(location program.py) $(SRC) $(OUT) $(location foo/file.txt) $(location :external_files__BP2BUILD__MISSING__DEP)"`,
+				"cmd":              `"$(location program.py) $(SRC) $(OUT) $(location foo/file.txt) $(location :external_files)"`,
 				"data": `[
         "foo/file.txt",
-        ":external_files__BP2BUILD__MISSING__DEP",
+        ":external_files",
     ]`,
 			},
 		},
@@ -73,12 +83,13 @@
 			MakeBazelTargetNoRestrictions("gensrcs", "foo", test.expectedBazelAttrs),
 		}
 		t.Run(test.name, func(t *testing.T) {
-			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+			RunBp2BuildTestCase(t, registerModulesForGensrcsTests,
 				Bp2buildTestCase{
 					ModuleTypeUnderTest:        "gensrcs",
 					ModuleTypeUnderTestFactory: genrule.GenSrcsFactory,
 					Blueprint:                  test.bp,
 					ExpectedBazelTargets:       expectedBazelTargets,
+					StubbedBuildDefinitions:    test.stubbedBuildDefinitions,
 				})
 		})
 	}
diff --git a/bp2build/go_conversion_test.go b/bp2build/go_conversion_test.go
index 2387641..ebd241d 100644
--- a/bp2build/go_conversion_test.go
+++ b/bp2build/go_conversion_test.go
@@ -84,8 +84,8 @@
         "foo1.go",
         "foo2.go",
     ] + select({
-        "//build/bazel/platforms/os:darwin": ["foo_darwin.go"],
-        "//build/bazel/platforms/os:linux_glibc": ["foo_linux.go"],
+        "//build/bazel_common_rules/platforms/os:darwin": ["foo_darwin.go"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": ["foo_linux.go"],
         "//conditions:default": [],
     })`,
 			},
@@ -98,8 +98,8 @@
         "foo1_test.go",
         "foo2_test.go",
     ] + select({
-        "//build/bazel/platforms/os:darwin": ["foo_darwin_test.go"],
-        "//build/bazel/platforms/os:linux_glibc": ["foo_linux_test.go"],
+        "//build/bazel_common_rules/platforms/os:darwin": ["foo_darwin_test.go"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": ["foo_linux_test.go"],
         "//conditions:default": [],
     })`,
 				},
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
index 7d8ab63..29c0e44 100644
--- a/bp2build/java_binary_host_conversion_test.go
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -63,7 +63,7 @@
 				"java_version": `"8"`,
 				"javacopts":    `["-Xdoclint:all/protected"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -71,7 +71,7 @@
 				"main_class": `"com.android.test.MainClass"`,
 				"jvm_flags":  `["-Djava.library.path=$${RUNPATH}other/jni-lib-1"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 				"runtime_deps": `[":java-binary-host-1_lib"]`,
@@ -102,7 +102,7 @@
 				"main_class":   `"com.android.test.MainClass"`,
 				"runtime_deps": `[":java-dep-1"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -114,7 +114,7 @@
 	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
 		Description:             "java_binary_host with srcs, libs.",
 		Filesystem:              testFs,
-		StubbedBuildDefinitions: []string{"prebuilt_java-lib-dep-1"},
+		StubbedBuildDefinitions: []string{"java-lib-dep-1", "java-lib-dep-1-neverlink"},
 		Blueprint: `java_binary_host {
     name: "java-binary-host-libs",
     libs: ["java-lib-dep-1"],
@@ -132,14 +132,14 @@
 				"srcs": `["a.java"]`,
 				"deps": `[":java-lib-dep-1-neverlink"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/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"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 				"runtime_deps": `[":java-binary-host-libs_lib"]`,
@@ -165,7 +165,7 @@
         "b.kt",
     ]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -173,7 +173,7 @@
 				"main_class":   `"com.android.test.MainClass"`,
 				"runtime_deps": `[":java-binary-host_lib"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -197,7 +197,7 @@
 				"srcs":        `["a.java"]`,
 				"common_srcs": `["b.kt"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -205,7 +205,7 @@
 				"main_class":   `"com.android.test.MainClass"`,
 				"runtime_deps": `[":java-binary-host_lib"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -240,7 +240,7 @@
     ]`,
 				"resource_strip_prefix": `"res"`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -248,7 +248,7 @@
 				"main_class":   `"com.android.test.MainClass"`,
 				"runtime_deps": `[":java-binary-host_lib"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -286,7 +286,7 @@
     ]`,
 				"resource_strip_prefix": `"adir"`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -294,7 +294,7 @@
 				"main_class":   `"com.android.test.MainClass"`,
 				"runtime_deps": `[":java-binary-host_lib"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -321,7 +321,7 @@
         "-flag2",
     ]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -329,7 +329,7 @@
 				"main_class":   `"com.android.test.MainClass"`,
 				"runtime_deps": `[":java-binary-host_lib"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
diff --git a/bp2build/java_import_conversion_test.go b/bp2build/java_import_conversion_test.go
index 5661620..bba2f50 100644
--- a/bp2build/java_import_conversion_test.go
+++ b/bp2build/java_import_conversion_test.go
@@ -21,6 +21,13 @@
 	"testing"
 )
 
+func runJavaImportTestCaseWithRegistrationCtxFunc(t *testing.T, tc Bp2buildTestCase, registrationCtxFunc func(ctx android.RegistrationContext)) {
+	t.Helper()
+	(&tc).ModuleTypeUnderTest = "java_import"
+	(&tc).ModuleTypeUnderTestFactory = java.ImportFactory
+	RunBp2BuildTestCase(t, registrationCtxFunc, tc)
+}
+
 func runJavaImportTestCase(t *testing.T, tc Bp2buildTestCase) {
 	t.Helper()
 	RunBp2BuildTestCase(t, registerJavaImportModuleTypes, tc)
@@ -81,8 +88,8 @@
 		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"],
+        "//build/bazel_common_rules/platforms/os:android": ["android.jar"],
+        "//build/bazel_common_rules/platforms/os:linux_glibc": ["linux.jar"],
         "//conditions:default": [],
     })`,
 			}),
@@ -120,3 +127,31 @@
 			}),
 		}})
 }
+
+func TestJavaImportSameNameAsJavaLibrary(t *testing.T) {
+	runJavaImportTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
+		Description: "java_import has the same name as other package java_library's",
+		Filesystem: map[string]string{
+			"foo/bar/Android.bp": simpleModule("java_library", "test_lib"),
+			"test.jar":           "",
+		},
+		Blueprint: `java_import {
+    name: "test_lib",
+    jars: ["test.jar"],
+    bazel_module: { bp2build_available: true },
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("java_import", "test_lib", AttrNameToString{
+				"jars": `["test.jar"]`,
+			}),
+			MakeBazelTarget("java_library", "test_lib-neverlink", AttrNameToString{
+				"exports":     `[":test_lib"]`,
+				"neverlink":   `True`,
+				"sdk_version": `"none"`,
+			}),
+		},
+	}, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("java_library", java.LibraryFactory)
+	})
+}
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
index 7e4e44e..5099b49 100644
--- a/bp2build/java_library_conversion_test.go
+++ b/bp2build/java_library_conversion_test.go
@@ -192,6 +192,45 @@
 	})
 }
 
+func TestJavaLibraryOpenjdk9(t *testing.T) {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Blueprint: `java_library {
+			name: "java-lib-1",
+		srcs: ["a.java"],
+		exclude_srcs: ["b.java"],
+		javacflags: ["flag"],
+		target: {
+			android: {
+				srcs: ["android.java"],
+			},
+		},
+		openjdk9: {
+			srcs: ["b.java", "foo.java"],
+			javacflags: ["extraflag"],
+		},
+		sdk_version: "current",
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
+				"srcs": `[
+        "a.java",
+        "foo.java",
+    ] + select({
+        "//build/bazel_common_rules/platforms/os:android": ["android.java"],
+        "//conditions:default": [],
+    })`,
+				"sdk_version": `"current"`,
+				"javacopts": `[
+        "flag",
+        "extraflag",
+    ]`,
+			}),
+			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
+		},
+	})
+
+}
+
 func TestJavaLibraryErrorproneEnabledManually(t *testing.T) {
 	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
 		StubbedBuildDefinitions: []string{"plugin2"},
@@ -424,6 +463,7 @@
 		},
 		Blueprint: `java_library {
 	name: "java-lib-1",
+	srcs: ["foo.java"],
 	java_resource_dirs: ["res", "res1"],
 	sdk_version: "current",
 }`,
@@ -433,9 +473,10 @@
 				"resources":             `["res1/b.res"]`,
 			}),
 			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"additional_resources":  `["java-lib-1_resource_dir_res1"]`,
+				"deps":                  `["java-lib-1_resource_dir_res1"]`,
 				"resources":             `["res/a.res"]`,
 				"resource_strip_prefix": `"res"`,
+				"srcs":                  `["foo.java"]`,
 				"sdk_version":           `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
@@ -453,6 +494,7 @@
 		java_resources: ["res1", "res2"],
 		java_resource_dirs: ["resdir"],
 		sdk_version: "current",
+		srcs: ["foo.java"],
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_resources", "java-lib-1_resource_dir_resdir", AttrNameToString{
@@ -460,12 +502,13 @@
 				"resources":             `["resdir/a.res"]`,
 			}),
 			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"additional_resources":  `["java-lib-1_resource_dir_resdir"]`,
+				"deps":                  `["java-lib-1_resource_dir_resdir"]`,
 				"resource_strip_prefix": `"."`,
 				"resources": `[
         "res1",
         "res2",
     ]`,
+				"srcs":        `["foo.java"]`,
 				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
@@ -567,12 +610,20 @@
 		"b.aidl",
 	],
 }
+filegroup {
+	name: "aidls_files",
+	srcs: [
+		"a.aidl",
+		"b.aidl",
+	],
+}
 java_library {
 	name: "example_lib",
 	srcs: [
 		"a.java",
 		"b.java",
 		":aidl_files",
+		":aidls_files",
 		":random_other_files",
 	],
 	sdk_version: "current",
@@ -586,8 +637,18 @@
     ]`,
 				"tags": `["apex_available=//apex_available:anyapex"]`,
 			}),
+			MakeBazelTargetNoRestrictions("aidl_library", "aidls_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"]`,
+				"deps": `[
+        ":aidl_files",
+        ":aidls_files",
+    ]`,
 			}),
 			MakeBazelTarget("java_library", "example_lib", AttrNameToString{
 				"deps":    `[":example_lib_java_aidl_library"]`,
@@ -617,7 +678,7 @@
 		Description:                "java_library with non adjacent aidl filegroup",
 		ModuleTypeUnderTest:        "java_library",
 		ModuleTypeUnderTestFactory: java.LibraryFactory,
-		StubbedBuildDefinitions:    []string{"A_aidl"},
+		StubbedBuildDefinitions:    []string{"//path/to/A:A_aidl"},
 		Filesystem: map[string]string{
 			"path/to/A/Android.bp": `
 filegroup {
@@ -762,7 +823,7 @@
 				AttrNameToString{
 					"srcs": `["lib.java"] + select({
         "//build/bazel/platforms/arch/variants:arm-neon": [],
-        "//build/bazel/platforms/arch:arm": ["arm_non_neon.java"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["arm_non_neon.java"],
         "//conditions:default": [],
     })`,
 					"manifest":       `"manifest/AndroidManifest.xml"`,
@@ -881,11 +942,11 @@
 			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"srcs": `["a.java"]`,
 				"exports": `select({
-        "//build/bazel/platforms/os:android": [":java-lib-4"],
+        "//build/bazel_common_rules/platforms/os:android": [":java-lib-4"],
         "//conditions:default": [],
     })`,
 				"deps": `[":java-lib-2-neverlink"] + select({
-        "//build/bazel/platforms/os:android": [
+        "//build/bazel_common_rules/platforms/os:android": [
             ":java-lib-3-neverlink",
             ":java-lib-4",
         ],
@@ -916,7 +977,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"srcs": `["b.java"] + select({
-        "//build/bazel/platforms/os:android": [],
+        "//build/bazel_common_rules/platforms/os:android": [],
         "//conditions:default": ["a.java"],
     })`,
 				"sdk_version": `"current"`,
@@ -1007,7 +1068,7 @@
 				"srcs":                  `["a.java"]`,
 				"resources":             `["a.res"]`,
 				"resource_strip_prefix": `"."`,
-				"additional_resources": `[
+				"deps": `[
         "java-lib-1_filegroup_resources_filegroup1",
         "java-lib-1_filegroup_resources_filegroup2",
     ]`,
@@ -1023,3 +1084,48 @@
 		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	})
 }
+
+func TestJavaLibrarySameNameAsPrebuilt(t *testing.T) {
+	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
+		Description: "java_library and prebuilt module have the same name",
+		Filesystem: map[string]string{
+			"foo/bar/Android.bp": simpleModule("java_import", "test_lib"),
+		},
+		Blueprint: `java_library {
+    name: "test_lib",
+    srcs: ["a.java"],
+    sdk_version: "current",
+    bazel_module: { bp2build_available: true },
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("java_library", "test_lib", AttrNameToString{
+				"srcs":        `["a.java"]`,
+				"sdk_version": `"current"`,
+			}),
+			MakeNeverlinkDuplicateTarget("java_library", "test_lib"),
+		},
+	}, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("java_import", java.ImportFactory)
+	})
+}
+
+func TestJavaLibrarySharding(t *testing.T) {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Description: "java library with sharded compilation",
+		Blueprint: `java_library {
+			name: "lib1",
+			srcs: ["a.java"],
+			javac_shard_size: 3,
+			sdk_version: "current",
+		}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("java_library", "lib1", AttrNameToString{
+				"srcs":             `["a.java"]`,
+				"sdk_version":      `"current"`,
+				"javac_shard_size": "3",
+			}),
+			MakeNeverlinkDuplicateTarget("java_library", "lib1"),
+		},
+	})
+}
diff --git a/bp2build/java_library_host_conversion_test.go b/bp2build/java_library_host_conversion_test.go
index 9e47b09..d0fdec6 100644
--- a/bp2build/java_library_host_conversion_test.go
+++ b/bp2build/java_library_host_conversion_test.go
@@ -50,7 +50,7 @@
 				"srcs": `["a.java"]`,
 				"deps": `[":java-lib-host-2-neverlink"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -58,7 +58,7 @@
 				"exports":   `[":java-lib-host-1"]`,
 				"neverlink": `True`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -66,7 +66,7 @@
 				"java_version": `"9"`,
 				"srcs":         `["c.java"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -74,7 +74,7 @@
 				"exports":   `[":java-lib-host-2"]`,
 				"neverlink": `True`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/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
index dcc17b5..e63cc55 100644
--- a/bp2build/java_plugin_conversion_test.go
+++ b/bp2build/java_plugin_conversion_test.go
@@ -55,7 +55,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_plugin", "java-plug-1", AttrNameToString{
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 				"deps": `[
@@ -95,7 +95,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_plugin", "java-plug-1", AttrNameToString{
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 				"deps": `[
diff --git a/bp2build/java_proto_conversion_test.go b/bp2build/java_proto_conversion_test.go
index 3d55eb2..cd89978 100644
--- a/bp2build/java_proto_conversion_test.go
+++ b/bp2build/java_proto_conversion_test.go
@@ -141,17 +141,22 @@
 func TestJavaLibsAndOnlyProtoSrcs(t *testing.T) {
 	runJavaProtoTestCase(t, Bp2buildTestCase{
 		Description:             "java_library that has only proto srcs",
-		StubbedBuildDefinitions: []string{"java-lib"},
+		StubbedBuildDefinitions: []string{"java-lib-1", "java-lib-2"},
 		Blueprint: `java_library_static {
     name: "java-protos",
     srcs: ["a.proto"],
-    libs: ["java-lib"],
+    libs: ["java-lib-1"],
+    static_libs: ["java-lib-2"],
     java_version: "7",
     sdk_version: "current",
 }
 
 java_library_static {
-    name: "java-lib",
+    name: "java-lib-1",
+}
+
+java_library_static {
+    name: "java-lib-2",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -162,12 +167,19 @@
 				"java_lite_proto_library",
 				"java-protos_java_proto_lite",
 				AttrNameToString{
-					"deps":         `[":java-protos_proto"]`,
+					"deps": `[":java-protos_proto"]`,
+					"additional_proto_deps": `[
+        ":java-lib-1-neverlink",
+        ":java-lib-2",
+    ]`,
 					"java_version": `"7"`,
 					"sdk_version":  `"current"`,
 				}),
 			MakeBazelTarget("java_library", "java-protos", AttrNameToString{
-				"exports":      `[":java-protos_java_proto_lite"]`,
+				"exports": `[
+        ":java-lib-2",
+        ":java-protos_java_proto_lite",
+    ]`,
 				"java_version": `"7"`,
 				"sdk_version":  `"current"`,
 			}),
@@ -181,3 +193,46 @@
 		},
 	})
 }
+
+func TestJavaProtoPlugin(t *testing.T) {
+	runJavaProtoTestCase(t, Bp2buildTestCase{
+		Description:             "java_library proto plugin",
+		StubbedBuildDefinitions: []string{"protoc-gen-test-plugin"},
+		Blueprint: `java_library_static {
+    name: "java-protos",
+    srcs: ["a.proto"],
+    proto: {
+        plugin: "test-plugin",
+    },
+    sdk_version: "current",
+}
+
+java_library_static {
+    name: "protoc-gen-test-plugin",
+}
+`,
+		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"]`,
+					"plugin":      `":protoc-gen-test-plugin"`,
+					"sdk_version": `"current"`,
+				}),
+			MakeBazelTarget("java_library", "java-protos", AttrNameToString{
+				"exports":     `[":java-protos_java_proto_lite"]`,
+				"sdk_version": `"current"`,
+			}),
+			MakeNeverlinkDuplicateTargetWithAttrs(
+				"java_library",
+				"java-protos",
+				AttrNameToString{
+					"sdk_version": `"current"`,
+				}),
+		},
+	})
+}
diff --git a/bp2build/java_test_host_conversion_test.go b/bp2build/java_test_host_conversion_test.go
index 95c239d..5d93f58 100644
--- a/bp2build/java_test_host_conversion_test.go
+++ b/bp2build/java_test_host_conversion_test.go
@@ -34,7 +34,7 @@
 	runJavaTestHostTestCase(t, Bp2buildTestCase{
 		Description:             "java_test_host general",
 		Filesystem:              map[string]string{},
-		StubbedBuildDefinitions: []string{"lib_a", "lib_b"},
+		StubbedBuildDefinitions: []string{"lib_a", "static_libs_a"},
 		Blueprint: `
 java_test_host {
     name: "java_test_host-1",
@@ -64,7 +64,7 @@
 				"javacopts":    `["-Xdoclint:all/protected"]`,
 				"srcs":         `["a.java"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -76,7 +76,7 @@
     ]`,
 				"srcs": `["a.java"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -97,14 +97,13 @@
 
 java_library {
     name: "lib_a",
-    bazel_module: { bp2build_available: false },
 }
 
 java_library {
     name: "static_libs_a",
-    bazel_module: { bp2build_available: false },
 }
 `,
+		StubbedBuildDefinitions: []string{"lib_a", "static_libs_a"},
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_test", "java_test_host-1", AttrNameToString{
 				"runtime_deps": `[
@@ -112,7 +111,7 @@
         ":static_libs_a",
     ]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -138,7 +137,7 @@
     ]`,
 				"runtime_deps": `[":java_test_host-1_lib"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -148,7 +147,7 @@
         "b.kt",
     ]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
diff --git a/bp2build/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go
index e237303..c8cfd87 100644
--- a/bp2build/prebuilt_etc_conversion_test.go
+++ b/bp2build/prebuilt_etc_conversion_test.go
@@ -26,10 +26,17 @@
 	t.Helper()
 	(&tc).ModuleTypeUnderTest = "prebuilt_etc"
 	(&tc).ModuleTypeUnderTestFactory = etc.PrebuiltEtcFactory
-	RunBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc)
+	RunBp2BuildTestCase(t, registerPrebuiltModuleTypes, tc)
 }
 
-func registerPrebuiltEtcModuleTypes(ctx android.RegistrationContext) {
+func runPrebuiltRootHostTestCase(t *testing.T, tc Bp2buildTestCase) {
+	t.Helper()
+	(&tc).ModuleTypeUnderTest = "prebuilt_root_host"
+	(&tc).ModuleTypeUnderTestFactory = etc.PrebuiltRootHostFactory
+	RunBp2BuildTestCase(t, registerPrebuiltModuleTypes, tc)
+}
+
+func registerPrebuiltModuleTypes(ctx android.RegistrationContext) {
 }
 
 func TestPrebuiltEtcSimple(t *testing.T) {
@@ -80,8 +87,8 @@
 				"filename":    `"tz_version"`,
 				"installable": `False`,
 				"src": `select({
-        "//build/bazel/platforms/arch:arm": "arm",
-        "//build/bazel/platforms/arch:arm64": "arm64",
+        "//build/bazel_common_rules/platforms/arch:arm": "arm",
+        "//build/bazel_common_rules/platforms/arch:arm64": "arm64",
         "//conditions:default": "version/tz_version",
     })`,
 				"dir": `"etc/tz"`,
@@ -119,11 +126,11 @@
 				"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",
+        "//build/bazel_common_rules/platforms/os_arch:android_arm": "arm",
+        "//build/bazel_common_rules/platforms/os_arch:android_arm64": "darwin_or_arm64",
+        "//build/bazel_common_rules/platforms/os_arch:darwin_arm64": "darwin_or_arm64",
+        "//build/bazel_common_rules/platforms/os_arch:darwin_x86_64": "darwin_or_arm64",
+        "//build/bazel_common_rules/platforms/os_arch:linux_bionic_arm64": "darwin_or_arm64",
         "//conditions:default": "version/tz_version",
     })`,
 				"dir": `"etc/tz"`,
@@ -160,7 +167,7 @@
 	t.Helper()
 	(&tc).ModuleTypeUnderTest = "prebuilt_usr_share"
 	(&tc).ModuleTypeUnderTestFactory = etc.PrebuiltUserShareFactory
-	RunBp2BuildTestCase(t, registerPrebuiltEtcModuleTypes, tc)
+	RunBp2BuildTestCase(t, registerPrebuiltModuleTypes, tc)
 }
 
 func registerPrebuiltUsrShareModuleTypes(ctx android.RegistrationContext) {
@@ -270,8 +277,8 @@
 				"filename_from_src": `True`,
 				"dir":               `"etc"`,
 				"src": `select({
-        "//build/bazel/platforms/arch:arm": "barSrc",
-        "//build/bazel/platforms/arch:arm64": "bazSrc",
+        "//build/bazel_common_rules/platforms/arch:arm": "barSrc",
+        "//build/bazel_common_rules/platforms/arch:arm64": "bazSrc",
         "//conditions:default": None,
     })`,
 			})}})
@@ -317,8 +324,8 @@
 				"filename": `"fooFilename"`,
 				"dir":      `"etc"`,
 				"src": `select({
-        "//build/bazel/platforms/arch:arm": "armSrc",
         "//build/bazel/product_config/config_settings:native_coverage-arm": "nativeCoverageArmSrc",
+        "//build/bazel_common_rules/platforms/arch:arm": "armSrc",
         "//conditions:default": None,
     })`,
 			})}})
@@ -360,3 +367,30 @@
 		ExpectedBazelTargets: []string{},
 	})
 }
+
+func TestPrebuiltRootHostWithWildCardInSrc(t *testing.T) {
+	runPrebuiltRootHostTestCase(t, Bp2buildTestCase{
+		Description: "prebuilt_root_host - src string has wild card",
+		Filesystem: map[string]string{
+			"prh.dat": "",
+		},
+		Blueprint: `
+prebuilt_root_host {
+    name: "prh_test",
+    src: "*.dat",
+    filename_from_src: true,
+    relative_install_path: "test/install/path",
+    bazel_module: { bp2build_available: true },
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("prebuilt_file", "prh_test", AttrNameToString{
+				"filename": `"prh.dat"`,
+				"src":      `"prh.dat"`,
+				"dir":      `"./test/install/path"`,
+				"target_compatible_with": `select({
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+			})}})
+}
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index b69c4ea..eb993c2 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -56,7 +56,7 @@
         "b/d.py",
     ]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -90,7 +90,7 @@
 				"imports":        `["."]`,
 				"srcs":           `["a.py"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -124,7 +124,7 @@
 				"imports": `["."]`,
 				"srcs":    `["a.py"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -156,12 +156,12 @@
 			MakeBazelTarget("py_binary", "foo-arm", AttrNameToString{
 				"imports": `["."]`,
 				"srcs": `select({
-        "//build/bazel/platforms/arch:arm": ["arm.py"],
-        "//build/bazel/platforms/arch:x86": ["x86.py"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["arm.py"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["x86.py"],
         "//conditions:default": [],
     })`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -183,7 +183,7 @@
 			MakeBazelTarget("py_binary", "foo", AttrNameToString{
 				"imports": `["."]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -212,7 +212,7 @@
 				"main":    `":a"`,
 				"imports": `["."]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -241,7 +241,7 @@
 				"main":    `"//a:b.py"`,
 				"imports": `["."]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -269,7 +269,7 @@
 				"main":    `"a/b.py"`,
 				"imports": `["."]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
@@ -311,7 +311,7 @@
         ":r2",
     ]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
diff --git a/bp2build/python_library_conversion_test.go b/bp2build/python_library_conversion_test.go
index 497df80..ad6a27b 100644
--- a/bp2build/python_library_conversion_test.go
+++ b/bp2build/python_library_conversion_test.go
@@ -25,7 +25,7 @@
 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"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`
 	}
@@ -296,8 +296,8 @@
 				name: "foo",
 				attrs: AttrNameToString{
 					"srcs": `select({
-        "//build/bazel/platforms/arch:arm": ["arm.py"],
-        "//build/bazel/platforms/arch:x86": ["x86.py"],
+        "//build/bazel_common_rules/platforms/arch:arm": ["arm.py"],
+        "//build/bazel_common_rules/platforms/arch:x86": ["x86.py"],
         "//conditions:default": [],
     })`,
 					"srcs_version": `"PY3"`,
diff --git a/bp2build/python_test_conversion_test.go b/bp2build/python_test_conversion_test.go
index fa2e485..fca7efb 100644
--- a/bp2build/python_test_conversion_test.go
+++ b/bp2build/python_test_conversion_test.go
@@ -58,7 +58,7 @@
         "b/d.py",
     ]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			}),
diff --git a/bp2build/rust_ffi_conversion_test.go b/bp2build/rust_ffi_conversion_test.go
new file mode 100644
index 0000000..97fe297
--- /dev/null
+++ b/bp2build/rust_ffi_conversion_test.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 bp2build
+
+import (
+	"android/soong/android"
+	"android/soong/rust"
+	"testing"
+)
+
+func runRustFfiTestCase(t *testing.T, tc Bp2buildTestCase) {
+	t.Helper()
+	RunBp2BuildTestCase(t, registerRustFfiModuleTypes, tc)
+}
+
+func registerRustFfiModuleTypes(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("rust_ffi_static", rust.RustFFIStaticFactory)
+	ctx.RegisterModuleType("rust_library", rust.RustLibraryFactory)
+}
+
+func TestRustFfiStatic(t *testing.T) {
+	runRustFfiTestCase(t, Bp2buildTestCase{
+		Dir:       "external/rust/crates/foo",
+		Blueprint: "",
+		Filesystem: map[string]string{
+			"external/rust/crates/foo/src/lib.rs":    "",
+			"external/rust/crates/foo/src/helper.rs": "",
+			"external/rust/crates/foo/Android.bp": `
+rust_ffi_static {
+	name: "libfoo",
+	crate_name: "foo",
+	host_supported: true,
+	srcs: ["src/lib.rs"],
+	edition: "2015",
+	include_dirs: [
+		"include",
+	],
+	rustlibs: ["libbar"],
+	bazel_module: { bp2build_available: true },
+}
+`,
+			"external/rust/crates/bar/Android.bp": `
+rust_library {
+	name: "libbar",
+	crate_name: "bar",
+	host_supported: true,
+	srcs: ["src/lib.rs"],
+	bazel_module: { bp2build_available: true },
+}
+`,
+		},
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions("rust_ffi_static", "libfoo", AttrNameToString{
+				"crate_name": `"foo"`,
+				"deps":       `["//external/rust/crates/bar:libbar"]`,
+				"srcs": `[
+        "src/helper.rs",
+        "src/lib.rs",
+    ]`,
+				"edition":         `"2015"`,
+				"export_includes": `["include"]`,
+			}),
+		},
+	},
+	)
+}
diff --git a/bp2build/rust_library_conversion_test.go b/bp2build/rust_library_conversion_test.go
index 0bc80df..09fc0ed 100644
--- a/bp2build/rust_library_conversion_test.go
+++ b/bp2build/rust_library_conversion_test.go
@@ -101,8 +101,7 @@
 `,
 		},
 		ExpectedBazelTargets: []string{
-			// TODO(b/290790800): Remove the restriction when rust toolchain for android is implemented
-			makeBazelTargetHostOrDevice("rust_library", "libfoo", expectedAttrs, android.HostSupported),
+			MakeBazelTargetNoRestrictions("rust_library", "libfoo", expectedAttrs),
 			makeBazelTargetHostOrDevice("rust_library", "libfoo_host", expectedAttrs, android.HostSupported),
 		},
 	},
diff --git a/bp2build/rust_protobuf_conversion_test.go b/bp2build/rust_protobuf_conversion_test.go
index cf256aa..bd4f54b 100644
--- a/bp2build/rust_protobuf_conversion_test.go
+++ b/bp2build/rust_protobuf_conversion_test.go
@@ -27,7 +27,7 @@
 
 func registerRustProtobufModuleTypes(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("rust_protobuf_host", rust.RustProtobufHostFactory)
-
+	ctx.RegisterModuleType("rust_protobuf", rust.RustProtobufHostFactory)
 }
 
 func TestRustProtobufHostTestCase(t *testing.T) {
@@ -58,3 +58,32 @@
 	},
 	)
 }
+
+func TestRustProtobufTestCase(t *testing.T) {
+	runRustProtobufTestCase(t, Bp2buildTestCase{
+		Dir:       "external/rust/crates/foo",
+		Blueprint: "",
+		Filesystem: map[string]string{
+			"external/rust/crates/foo/src/lib.rs":    "",
+			"external/rust/crates/foo/src/helper.rs": "",
+			"external/rust/crates/foo/Android.bp": `
+rust_protobuf {
+	name: "libfoo",
+	crate_name: "foo",
+	protos: ["src/foo.proto"],
+    bazel_module: { bp2build_available: true },
+}
+`,
+		},
+		ExpectedBazelTargets: []string{
+			makeBazelTargetHostOrDevice("proto_library", "libfoo_proto", AttrNameToString{
+				"srcs": `["src/foo.proto"]`,
+			}, android.HostSupported),
+			makeBazelTargetHostOrDevice("rust_proto_library", "libfoo", AttrNameToString{
+				"crate_name": `"foo"`,
+				"deps":       `[":libfoo_proto"]`,
+			}, android.HostSupported),
+		},
+	},
+	)
+}
diff --git a/bp2build/sh_test_conversion_test.go b/bp2build/sh_test_conversion_test.go
index e99d566..4bea396 100644
--- a/bp2build/sh_test_conversion_test.go
+++ b/bp2build/sh_test_conversion_test.go
@@ -22,11 +22,18 @@
 )
 
 func TestShTestSimple(t *testing.T) {
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
-		Description:                "sh_test test",
-		ModuleTypeUnderTest:        "sh_test",
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+	}, Bp2buildTestCase{
+		Description:         "sh_test test",
+		ModuleTypeUnderTest: "sh_test",
+		StubbedBuildDefinitions: []string{"android.hardware.bluetooth@1.1-service.sim",
+			"android.hardware.bluetooth@1.1-impl-sim", "libc++", "libcrypto"},
 		ModuleTypeUnderTestFactory: sh.ShTestFactory,
-		Blueprint: `sh_test{
+		Blueprint: simpleModule("filegroup", "android.hardware.bluetooth@1.1-service.sim") +
+			simpleModule("filegroup", "android.hardware.bluetooth@1.1-impl-sim") +
+			simpleModule("filegroup", "libc++") +
+			simpleModule("filegroup", "libcrypto") + `sh_test{
     name: "sts-rootcanal-sidebins",
     src: "empty.sh",
     test_suites: [
@@ -47,28 +54,37 @@
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("sh_test", "sts-rootcanal-sidebins", AttrNameToString{
-				"srcs": `["empty.sh"]`,
+				"srcs":    `["empty.sh"]`,
+				"runs_on": `["device"]`,
 				"data": `[
         "android.hardware.bluetooth@1.1-service.sim.rc",
-        "android.hardware.bluetooth@1.1-service.sim",
-        "android.hardware.bluetooth@1.1-impl-sim",
-        "libc++",
-        "libcrypto",
+        ":android.hardware.bluetooth@1.1-service.sim",
+        ":android.hardware.bluetooth@1.1-impl-sim",
+        ":libc++",
+        ":libcrypto",
     ]`,
-				"test_config":          `"art-gtests-target-install-apex.xml"`,
-				"test_config_template": `":art-run-test-target-template"`,
-				"auto_gen_config":      "False",
-				"tags":                 `["no-remote"]`,
+				"data_bins": `[
+        ":android.hardware.bluetooth@1.1-service.sim",
+        ":android.hardware.bluetooth@1.1-impl-sim",
+    ]`,
+				"tags": `["no-remote"]`,
 			})},
 	})
 }
 
 func TestShTestHostSimple(t *testing.T) {
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
-		Description:                "sh_test_host test",
-		ModuleTypeUnderTest:        "sh_test_host",
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+	}, Bp2buildTestCase{
+		Description:         "sh_test_host test",
+		ModuleTypeUnderTest: "sh_test_host",
+		StubbedBuildDefinitions: []string{"android.hardware.bluetooth@1.1-service.sim",
+			"android.hardware.bluetooth@1.1-impl-sim", "libc++", "libcrypto"},
 		ModuleTypeUnderTestFactory: sh.ShTestHostFactory,
-		Blueprint: `sh_test_host{
+		Blueprint: simpleModule("filegroup", "android.hardware.bluetooth@1.1-service.sim") +
+			simpleModule("filegroup", "android.hardware.bluetooth@1.1-impl-sim") +
+			simpleModule("filegroup", "libc++") +
+			simpleModule("filegroup", "libcrypto") + `sh_test_host{
     name: "sts-rootcanal-sidebins",
     src: "empty.sh",
     test_suites: [
@@ -89,32 +105,153 @@
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("sh_test", "sts-rootcanal-sidebins", AttrNameToString{
-				"srcs": `["empty.sh"]`,
+				"srcs":    `["empty.sh"]`,
+				"runs_on": `["host_without_device"]`,
 				"data": `[
         "android.hardware.bluetooth@1.1-service.sim.rc",
-        "android.hardware.bluetooth@1.1-service.sim",
-        "android.hardware.bluetooth@1.1-impl-sim",
-        "libc++",
-        "libcrypto",
+        ":android.hardware.bluetooth@1.1-service.sim",
+        ":android.hardware.bluetooth@1.1-impl-sim",
+        ":libc++",
+        ":libcrypto",
     ]`,
-				"tags":                 `["no-remote"]`,
-				"test_config":          `"art-gtests-target-install-apex.xml"`,
-				"test_config_template": `":art-run-test-target-template"`,
-				"auto_gen_config":      "False",
+				"data_bins": `[
+        ":android.hardware.bluetooth@1.1-service.sim",
+        ":android.hardware.bluetooth@1.1-impl-sim",
+    ]`,
+				"tags": `["no-remote"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			})},
 	})
 }
 
-func TestShTestSimpleUnset(t *testing.T) {
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
-		Description:                "sh_test test",
-		ModuleTypeUnderTest:        "sh_test",
+func TestShTestAutogen(t *testing.T) {
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+	}, Bp2buildTestCase{
+		Description:         "sh_test test",
+		ModuleTypeUnderTest: "sh_test",
+		StubbedBuildDefinitions: []string{"android.hardware.bluetooth@1.1-service.sim",
+			"android.hardware.bluetooth@1.1-impl-sim", "libc++", "libcrypto", "art-run-test-target-template"},
 		ModuleTypeUnderTestFactory: sh.ShTestFactory,
-		Blueprint: `sh_test{
+		Blueprint: simpleModule("filegroup", "android.hardware.bluetooth@1.1-service.sim") +
+			simpleModule("filegroup", "android.hardware.bluetooth@1.1-impl-sim") +
+			simpleModule("filegroup", "libc++") +
+			simpleModule("filegroup", "libcrypto") +
+			simpleModule("filegroup", "art-run-test-target-template") + `sh_test{
+    name: "sts-rootcanal-sidebins",
+    src: "empty.sh",
+    test_suites: [
+        "sts",
+        "sts-lite",
+    ],
+    data_bins: [
+        "android.hardware.bluetooth@1.1-service.sim",
+        "android.hardware.bluetooth@1.1-impl-sim"
+    ],
+    data: ["android.hardware.bluetooth@1.1-service.sim.rc"],
+    data_libs: ["libc++","libcrypto"],
+		test_config: "art-gtests-target-install-apex.xml",
+		test_config_template: ":art-run-test-target-template",
+		auto_gen_config: true,
+    test_options:{tags: ["no-remote"],
+	},
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("sh_test", "sts-rootcanal-sidebins", AttrNameToString{
+				"srcs":                      `["empty.sh"]`,
+				"runs_on":                   `["device"]`,
+				"auto_generate_test_config": "True",
+				"target_compatible_with":    `["//build/bazel_common_rules/platforms/os:android"]`,
+				"template_test_config":      `":art-run-test-target-template"`,
+				"data": `[
+        "android.hardware.bluetooth@1.1-service.sim.rc",
+        ":android.hardware.bluetooth@1.1-service.sim",
+        ":android.hardware.bluetooth@1.1-impl-sim",
+        ":libc++",
+        ":libcrypto",
+    ]`,
+				"data_bins": `[
+        ":android.hardware.bluetooth@1.1-service.sim",
+        ":android.hardware.bluetooth@1.1-impl-sim",
+    ]`,
+				"tags": `["no-remote"]`,
+			})},
+	})
+}
+
+func TestShTestHostAutogen(t *testing.T) {
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+	}, Bp2buildTestCase{
+		Description:         "sh_test_host test",
+		ModuleTypeUnderTest: "sh_test_host",
+		StubbedBuildDefinitions: []string{"android.hardware.bluetooth@1.1-service.sim",
+			"android.hardware.bluetooth@1.1-impl-sim", "libc++", "libcrypto", "art-run-test-target-template"},
+		ModuleTypeUnderTestFactory: sh.ShTestHostFactory,
+		Blueprint: simpleModule("filegroup", "android.hardware.bluetooth@1.1-service.sim") +
+			simpleModule("filegroup", "android.hardware.bluetooth@1.1-impl-sim") +
+			simpleModule("filegroup", "libc++") +
+			simpleModule("filegroup", "libcrypto") +
+			simpleModule("filegroup", "art-run-test-target-template") + `sh_test_host{
+    name: "sts-rootcanal-sidebins",
+    src: "empty.sh",
+    test_suites: [
+        "sts",
+        "sts-lite",
+    ],
+    data_bins: [
+        "android.hardware.bluetooth@1.1-service.sim",
+        "android.hardware.bluetooth@1.1-impl-sim"
+    ],
+    data: ["android.hardware.bluetooth@1.1-service.sim.rc"],
+    data_libs: ["libc++","libcrypto"],
+		test_config: "art-gtests-target-install-apex.xml",
+		test_config_template: ":art-run-test-target-template",
+		auto_gen_config: true,
+    test_options:{tags: ["no-remote"],
+	},
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("sh_test", "sts-rootcanal-sidebins", AttrNameToString{
+				"srcs":                      `["empty.sh"]`,
+				"runs_on":                   `["host_without_device"]`,
+				"auto_generate_test_config": "True",
+				"target_compatible_with": `select({
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    })`,
+				"template_test_config": `":art-run-test-target-template"`,
+				"data": `[
+        "android.hardware.bluetooth@1.1-service.sim.rc",
+        ":android.hardware.bluetooth@1.1-service.sim",
+        ":android.hardware.bluetooth@1.1-impl-sim",
+        ":libc++",
+        ":libcrypto",
+    ]`,
+				"data_bins": `[
+        ":android.hardware.bluetooth@1.1-service.sim",
+        ":android.hardware.bluetooth@1.1-impl-sim",
+    ]`,
+				"tags": `["no-remote"]`,
+			})},
+	})
+}
+func TestShTestSimpleUnset(t *testing.T) {
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+	}, Bp2buildTestCase{
+		Description:         "sh_test test",
+		ModuleTypeUnderTest: "sh_test",
+		StubbedBuildDefinitions: []string{"android.hardware.bluetooth@1.1-service.sim",
+			"android.hardware.bluetooth@1.1-impl-sim", "libc++", "libcrypto"},
+		ModuleTypeUnderTestFactory: sh.ShTestFactory,
+		Blueprint: simpleModule("filegroup", "android.hardware.bluetooth@1.1-service.sim") +
+			simpleModule("filegroup", "android.hardware.bluetooth@1.1-impl-sim") +
+			simpleModule("filegroup", "libc++") +
+			simpleModule("filegroup", "libcrypto") + `sh_test{
     name: "sts-rootcanal-sidebins",
     src: "empty.sh",
     test_suites: [
@@ -132,13 +269,18 @@
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("sh_test", "sts-rootcanal-sidebins", AttrNameToString{
-				"srcs": `["empty.sh"]`,
+				"srcs":    `["empty.sh"]`,
+				"runs_on": `["device"]`,
 				"data": `[
         "android.hardware.bluetooth@1.1-service.sim.rc",
-        "android.hardware.bluetooth@1.1-service.sim",
-        "android.hardware.bluetooth@1.1-impl-sim",
-        "libc++",
-        "libcrypto",
+        ":android.hardware.bluetooth@1.1-service.sim",
+        ":android.hardware.bluetooth@1.1-impl-sim",
+        ":libc++",
+        ":libcrypto",
+    ]`,
+				"data_bins": `[
+        ":android.hardware.bluetooth@1.1-service.sim",
+        ":android.hardware.bluetooth@1.1-impl-sim",
     ]`,
 				"tags": `["no-remote"]`,
 			})},
@@ -146,11 +288,18 @@
 }
 
 func TestShTestHostSimpleUnset(t *testing.T) {
-	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+	}, Bp2buildTestCase{
 		Description:                "sh_test_host test",
 		ModuleTypeUnderTest:        "sh_test_host",
 		ModuleTypeUnderTestFactory: sh.ShTestHostFactory,
-		Blueprint: `sh_test_host{
+		StubbedBuildDefinitions: []string{"android.hardware.bluetooth@1.1-service.sim",
+			"android.hardware.bluetooth@1.1-impl-sim", "libc++", "libcrypto"},
+		Blueprint: simpleModule("filegroup", "android.hardware.bluetooth@1.1-service.sim") +
+			simpleModule("filegroup", "android.hardware.bluetooth@1.1-impl-sim") +
+			simpleModule("filegroup", "libc++") +
+			simpleModule("filegroup", "libcrypto") + `sh_test_host{
     name: "sts-rootcanal-sidebins",
     src: "empty.sh",
     test_suites: [
@@ -168,17 +317,22 @@
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("sh_test", "sts-rootcanal-sidebins", AttrNameToString{
-				"srcs": `["empty.sh"]`,
+				"srcs":    `["empty.sh"]`,
+				"runs_on": `["host_without_device"]`,
 				"data": `[
         "android.hardware.bluetooth@1.1-service.sim.rc",
-        "android.hardware.bluetooth@1.1-service.sim",
-        "android.hardware.bluetooth@1.1-impl-sim",
-        "libc++",
-        "libcrypto",
+        ":android.hardware.bluetooth@1.1-service.sim",
+        ":android.hardware.bluetooth@1.1-impl-sim",
+        ":libc++",
+        ":libcrypto",
+    ]`,
+				"data_bins": `[
+        ":android.hardware.bluetooth@1.1-service.sim",
+        ":android.hardware.bluetooth@1.1-impl-sim",
     ]`,
 				"tags": `["no-remote"]`,
 				"target_compatible_with": `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`,
 			})},
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
index 5ec6bab..2535cf3 100644
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -1207,13 +1207,13 @@
     local_includes = ["."],
     srcs = ["main.cc"],
     target_compatible_with = select({
-        "//build/bazel/platforms/os_arch:android_x86_64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:darwin_arm64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:darwin_x86_64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:linux_bionic_x86_64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:linux_glibc_x86_64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:linux_musl_x86_64": ["@platforms//:incompatible"],
-        "//build/bazel/platforms/os_arch:windows_x86_64": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os_arch:android_x86_64": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os_arch:darwin_arm64": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os_arch:darwin_x86_64": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os_arch:linux_bionic_x86_64": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os_arch:linux_glibc_x86_64": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os_arch:linux_musl_x86_64": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os_arch:windows_x86_64": ["@platforms//:incompatible"],
         "//conditions:default": [],
     }) + select({
         "//build/bazel/product_config/config_settings:alphabet_module__special_build": [],
@@ -1423,7 +1423,7 @@
 		ExpectedBazelTargets: []string{`cc_binary(
     name = "my_binary",
     copts = select({
-        "//build/bazel/platforms/os:android": ["-DFOO"],
+        "//build/bazel_common_rules/platforms/os:android": ["-DFOO"],
         "//conditions:default": [],
     }) + select({
         "//build/bazel/product_config/config_settings:my_namespace__my_bool_variable__android": ["-DBAR"],
@@ -1440,7 +1440,7 @@
     }),
     local_includes = ["."],
     srcs = ["main.cc"],
-    target_compatible_with = ["//build/bazel/platforms/os:android"],
+    target_compatible_with = ["//build/bazel_common_rules/platforms/os:android"],
 )`}})
 }
 
diff --git a/bp2build/symlink_forest.go b/bp2build/symlink_forest.go
index 966b94a..15a6df0 100644
--- a/bp2build/symlink_forest.go
+++ b/bp2build/symlink_forest.go
@@ -22,7 +22,6 @@
 	"regexp"
 	"sort"
 	"strconv"
-	"strings"
 	"sync"
 	"sync/atomic"
 
@@ -32,19 +31,12 @@
 )
 
 // 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
+// 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 = 2
-
 type instructionsNode struct {
 	name     string
 	excluded bool // If false, this is just an intermediate node
@@ -193,7 +185,7 @@
 	srcPath := shared.JoinPath(topdir, src)
 	dstPath := shared.JoinPath(topdir, dst)
 
-	// Check if a symlink already exists.
+	// Check whether 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)
@@ -240,44 +232,49 @@
 	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
+// Returns the mtime of the soong_build binary to determine whether we should
+// force symlink_forest to re-execute
+func getSoongBuildMTime() (int64, error) {
+	binaryPath, err := os.Executable()
+	if err != nil {
+		return 0, 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
-		}
+
+	info, err := os.Stat(binaryPath)
+	if err != nil {
+		return 0, err
 	}
-	return nil
+
+	return info.ModTime().UnixMilli(), 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)
+// cleanSymlinkForest will remove the whole symlink forest directory
+func cleanSymlinkForest(topdir, forest string) error {
+	return os.RemoveAll(shared.JoinPath(topdir, forest))
+}
+
+// This returns whether symlink forest should clean and replant symlinks.
+// It compares the mtime of this executable with the mtime of the last-run
+// soong_build binary. If they differ, then we should clean and replant.
+func shouldCleanSymlinkForest(topdir string, forest string, soongBuildMTime int64) (bool, error) {
+	mtimeFilePath := shared.JoinPath(topdir, forest, "soong_build_mtime")
+	mtimeFileContents, err := os.ReadFile(mtimeFilePath)
 	if err != nil {
-		if !os.IsNotExist(err) {
-			return err
-		}
-		err = os.WriteFile(versionFilePath, []byte(strconv.Itoa(symlinkForestVersion)+"\n"), 0666)
-		if err != nil {
-			return err
+		if os.IsNotExist(err) {
+			// This is likely the first time this has run with this functionality - clean away!
+			return true, nil
+		} else {
+			return false, err
 		}
 	}
-	return nil
+	return strconv.FormatInt(soongBuildMTime, 10) != string(mtimeFileContents), nil
+}
+
+func writeSoongBuildMTimeFile(topdir, forest string, mtime int64) error {
+	mtimeFilePath := shared.JoinPath(topdir, forest, "soong_build_mtime")
+	contents := []byte(strconv.FormatInt(mtime, 10))
+
+	return os.WriteFile(mtimeFilePath, contents, 0666)
 }
 
 // Recursively plants a symlink forest at forestDir. The symlink tree will
@@ -473,12 +470,26 @@
 		symlinkCount: atomic.Uint64{},
 	}
 
-	err := maybeCleanSymlinkForest(topdir, forest, verbose)
+	// Check whether soong_build has been modified since the last run
+	soongBuildMTime, err := getSoongBuildMTime()
 	if err != nil {
 		fmt.Fprintln(os.Stderr, err)
 		os.Exit(1)
 	}
 
+	shouldClean, err := shouldCleanSymlinkForest(topdir, forest, soongBuildMTime)
+
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(1)
+	} else if shouldClean {
+		err = cleanSymlinkForest(topdir, forest)
+		if err != nil {
+			fmt.Fprintln(os.Stderr, err)
+			os.Exit(1)
+		}
+	}
+
 	instructions := instructionsFromExcludePathList(exclude)
 	go func() {
 		context.wg.Add(1)
@@ -491,11 +502,10 @@
 		deps = append(deps, dep)
 	}
 
-	err = maybeWriteVersionFile(topdir, forest)
+	err = writeSoongBuildMTimeFile(topdir, forest, soongBuildMTime)
 	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
index a810709..c978164 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -27,6 +27,8 @@
 	"strings"
 	"testing"
 
+	"android/soong/ui/metrics/bp2build_metrics_proto"
+
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -87,6 +89,15 @@
 	// ExpectedBazelTargets compares the BazelTargets generated in `Dir` (if not empty).
 	// Otherwise, it checks the BazelTargets generated by `Blueprint` in the root directory.
 	ExpectedBazelTargets []string
+	// ExpectedConvertedModules asserts that modules in this list are labeled as "converted
+	// by bp2build" in the metrics reported by bp2build.
+	ExpectedConvertedModules []string
+	// ExpectedHandcraftedModules asserts that modules in this list are labeled as "handcrafted
+	// in build files" in the metrics reported by bp2build. Such modules are either explicitly
+	// defined in a BUILD file (by name), or registered as "otherwise implicitly handled"
+	// by bp2build (for example, by macros owned by other modules).
+	ExpectedHandcraftedModules []string
+
 	// AlreadyExistingBuildContents, if non-empty, simulates an already-present source BUILD file
 	// in the directory under test. The BUILD file has the given contents. This BUILD file
 	// will also be treated as "BUILD file to keep" by the simulated bp2build environment.
@@ -114,13 +125,26 @@
 	// 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
+
+	// An extra FixturePreparer to use when running the test. If you need multiple extra
+	// FixturePreparers, use android.GroupFixturePreparers()
+	ExtraFixturePreparer android.FixturePreparer
+
+	// If bp2build_product_config.go should run as part of the test.
+	RunBp2buildProductConfig bool
 }
 
 func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
 	t.Helper()
-	bp2buildSetup := android.GroupFixturePreparers(
+	preparers := []android.FixturePreparer{
 		android.FixtureRegisterWithContext(registerModuleTypes),
-		SetBp2BuildTestRunner,
+	}
+	if tc.ExtraFixturePreparer != nil {
+		preparers = append(preparers, tc.ExtraFixturePreparer)
+	}
+	preparers = append(preparers, android.FixtureSetTestRunner(&bazelTestRunner{generateProductConfigTargets: tc.RunBp2buildProductConfig}))
+	bp2buildSetup := android.GroupFixturePreparers(
+		preparers...,
 	)
 	runBp2BuildTestCaseWithSetup(t, bp2buildSetup, tc)
 }
@@ -223,14 +247,13 @@
 		checkDir: tc.ExpectedBazelTargets,
 	}
 
-	result.CompareAllBazelTargets(t, tc.Description, expectedTargets, true)
+	result.CompareAllBazelTargets(t, tc, expectedTargets, true)
 }
 
-// SetBp2BuildTestRunner customizes the test fixture mechanism to run tests in Bp2Build mode.
-var SetBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{})
-
 // bazelTestRunner customizes the test fixture mechanism to run tests of the bp2build build mode.
-type bazelTestRunner struct{}
+type bazelTestRunner struct {
+	generateProductConfigTargets bool
+}
 
 func (b *bazelTestRunner) FinalPreparer(result *android.TestResult) android.CustomTestResult {
 	ctx := result.TestContext
@@ -253,6 +276,16 @@
 	if bazelResult.CollateErrs(errs) {
 		return
 	}
+	if b.generateProductConfigTargets {
+		productConfig, err := createProductConfigFiles(codegenCtx, res.moduleNameToPartition, res.metrics.convertedModulePathMap)
+		if err != nil {
+			bazelResult.CollateErrs([]error{err})
+			return
+		}
+		for k, v := range productConfig.bp2buildTargets {
+			res.buildFileToTargets[k] = append(res.buildFileToTargets[k], v...)
+		}
+	}
 
 	// Store additional data for access by tests.
 	bazelResult.conversionResults = res
@@ -274,7 +307,7 @@
 // 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) {
+func (b BazelTestResult) CompareAllBazelTargets(t *testing.T, tc Bp2buildTestCase, expectedTargets map[string][]string, ignoreUnexpected bool) {
 	t.Helper()
 	actualTargets := b.buildFileToTargets
 
@@ -301,7 +334,24 @@
 				t.Errorf("expected %d bazel modules in %q but did not find any", expectedCount, dir)
 			}
 		} else {
-			b.CompareBazelTargets(t, description, expected, actual)
+			b.CompareBazelTargets(t, tc.Description, expected, actual)
+		}
+	}
+
+	for _, module := range tc.ExpectedConvertedModules {
+		if _, found := b.metrics.convertedModulePathMap[module]; !found {
+			t.Errorf("expected %s to be generated by bp2build, but was not. Map of converted modules: %s", module, b.metrics.convertedModulePathMap)
+		}
+	}
+
+	for _, module := range tc.ExpectedHandcraftedModules {
+		if reason, found := b.metrics.serialized.UnconvertedModules[module]; !found {
+			t.Errorf("expected %s to be marked 'unconverted' by bp2build, but was not found. Full list: %s",
+				module, b.metrics.serialized.UnconvertedModules)
+		} else {
+			if reason.Type != bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE {
+				t.Errorf("expected %s to be marked 'handcrafted' by bp2build, but was disabled for another reason: %s", module, reason)
+			}
 		}
 	}
 }
@@ -363,6 +413,10 @@
 	// Prop used to indicate this conversion should be 1 module -> multiple targets
 	One_to_many_prop *bool
 
+	// Prop used to simulate an unsupported property in bp2build conversion. If this
+	// is true, this module should be treated as "unconvertible" via bp2build.
+	Does_not_convert_to_bazel *bool
+
 	Api *string // File describing the APIs of this module
 
 	Test_config_setting *bool // Used to test generation of config_setting targets
@@ -498,6 +552,10 @@
 }
 
 func (m *customModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
+	if p := m.props.Does_not_convert_to_bazel; p != nil && *p {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "")
+		return
+	}
 	if p := m.props.One_to_many_prop; p != nil && *p {
 		customBp2buildOneToMany(ctx, m)
 		return
@@ -571,23 +629,6 @@
 	)
 }
 
-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.Bp2buildMutatorContext, m *customModule) {
@@ -653,11 +694,11 @@
 		switch hod {
 		case android.HostSupported:
 			attrs["target_compatible_with"] = `select({
-        "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
+        "//build/bazel_common_rules/platforms/os:android": ["@platforms//:incompatible"],
         "//conditions:default": [],
     })`
 		case android.DeviceSupported:
-			attrs["target_compatible_with"] = `["//build/bazel/platforms/os:android"]`
+			attrs["target_compatible_with"] = `["//build/bazel_common_rules/platforms/os:android"]`
 		}
 	}
 
diff --git a/cc/Android.bp b/cc/Android.bp
index c32d854..8fa0fbe 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -18,6 +18,7 @@
         "soong-genrule",
         "soong-multitree",
         "soong-snapshot",
+        "soong-sysprop-bp2build",
         "soong-tradefed",
     ],
     srcs: [
@@ -49,7 +50,6 @@
         "snapshot_utils.go",
         "stl.go",
         "strip.go",
-        "sysprop.go",
         "tidy.go",
         "util.go",
         "vendor_snapshot.go",
diff --git a/cc/afdo.go b/cc/afdo.go
index 23d196d..ac210d4 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -84,6 +84,10 @@
 		// 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.
diff --git a/cc/binary.go b/cc/binary.go
index 0722f81..0f05605 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -651,7 +651,7 @@
 
 		Features: baseAttrs.features,
 
-		sdkAttributes: bp2BuildParseSdkAttributes(m),
+		SdkAttributes: Bp2BuildParseSdkAttributes(m),
 
 		Native_coverage: baseAttrs.Native_coverage,
 	}
@@ -708,7 +708,7 @@
 
 	Features bazel.StringListAttribute
 
-	sdkAttributes
+	SdkAttributes
 
 	tidyAttributes
 
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 569f721..919b4d4 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -85,7 +85,7 @@
 
 	Features bazel.StringListAttribute
 
-	sdkAttributes
+	SdkAttributes
 
 	tidyAttributes
 }
@@ -99,7 +99,7 @@
 	Tidy_timeout_srcs     bazel.LabelListAttribute
 }
 
-func (m *Module) convertTidyAttributes(ctx android.BaseMutatorContext, moduleAttrs *tidyAttributes) {
+func (m *Module) convertTidyAttributes(ctx android.Bp2buildMutatorContext, moduleAttrs *tidyAttributes) {
 	for _, f := range m.features {
 		if tidy, ok := f.(*tidyFeature); ok {
 			var tidyAttr *string
@@ -223,7 +223,7 @@
 }
 
 // bp2BuildParseLibProps returns the attributes for a variant of a cc_library.
-func bp2BuildParseLibProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) staticOrSharedAttributes {
+func bp2BuildParseLibProps(ctx android.Bp2buildMutatorContext, module *Module, isStatic bool) staticOrSharedAttributes {
 	lib, ok := module.compiler.(*libraryDecorator)
 	if !ok {
 		return staticOrSharedAttributes{}
@@ -232,12 +232,12 @@
 }
 
 // bp2buildParseSharedProps returns the attributes for the shared variant of a cc_library.
-func bp2BuildParseSharedProps(ctx android.BazelConversionPathContext, module *Module) staticOrSharedAttributes {
+func bp2BuildParseSharedProps(ctx android.Bp2buildMutatorContext, 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 {
+func bp2BuildParseStaticProps(ctx android.Bp2buildMutatorContext, module *Module) staticOrSharedAttributes {
 	return bp2BuildParseLibProps(ctx, module, true)
 }
 
@@ -246,9 +246,9 @@
 	implementation bazel.LabelList
 }
 
-type bazelLabelForDepsFn func(android.BazelConversionPathContext, []string) bazel.LabelList
+type bazelLabelForDepsFn func(android.Bp2buildMutatorContext, []string) bazel.LabelList
 
-func maybePartitionExportedAndImplementationsDeps(ctx android.BazelConversionPathContext, exportsDeps bool, allDeps, exportedDeps []string, fn bazelLabelForDepsFn) depsPartition {
+func maybePartitionExportedAndImplementationsDeps(ctx android.Bp2buildMutatorContext, exportsDeps bool, allDeps, exportedDeps []string, fn bazelLabelForDepsFn) depsPartition {
 	if !exportsDeps {
 		return depsPartition{
 			implementation: fn(ctx, allDeps),
@@ -263,9 +263,9 @@
 	}
 }
 
-type bazelLabelForDepsExcludesFn func(android.BazelConversionPathContext, []string, []string) bazel.LabelList
+type bazelLabelForDepsExcludesFn func(android.Bp2buildMutatorContext, []string, []string) bazel.LabelList
 
-func maybePartitionExportedAndImplementationsDepsExcludes(ctx android.BazelConversionPathContext, exportsDeps bool, allDeps, excludes, exportedDeps []string, fn bazelLabelForDepsExcludesFn) depsPartition {
+func maybePartitionExportedAndImplementationsDepsExcludes(ctx android.Bp2buildMutatorContext, exportsDeps bool, allDeps, excludes, exportedDeps []string, fn bazelLabelForDepsExcludesFn) depsPartition {
 	if !exportsDeps {
 		return depsPartition{
 			implementation: fn(ctx, allDeps, excludes),
@@ -288,7 +288,7 @@
 }
 
 // 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 {
+func bp2buildParseStaticOrSharedProps(ctx android.Bp2buildMutatorContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes {
 	attrs := staticOrSharedAttributes{}
 
 	setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
@@ -334,7 +334,7 @@
 	attrs.Srcs_c = partitionedSrcs[cSrcPartition]
 	attrs.Srcs_as = partitionedSrcs[asSrcPartition]
 
-	attrs.Apex_available = android.ConvertApexAvailableToTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), apexAvailable)
+	attrs.Apex_available = android.ConvertApexAvailableToTagsWithoutTestApexes(ctx, apexAvailable)
 
 	attrs.Features.Append(convertHiddenVisibilityToFeatureStaticOrShared(ctx, module, isStatic))
 
@@ -352,7 +352,7 @@
 	Enabled bazel.BoolAttribute
 }
 
-func parseSrc(ctx android.BazelConversionPathContext, srcLabelAttribute *bazel.LabelAttribute, axis bazel.ConfigurationAxis, config string, srcs []string) {
+func parseSrc(ctx android.Bp2buildMutatorContext, 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)
 	}
@@ -370,7 +370,7 @@
 }
 
 // NOTE: Used outside of Soong repo project, in the clangprebuilts.go bootstrap_go_package
-func Bp2BuildParsePrebuiltLibraryProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) prebuiltAttributes {
+func Bp2BuildParsePrebuiltLibraryProps(ctx android.Bp2buildMutatorContext, module *Module, isStatic bool) prebuiltAttributes {
 
 	var srcLabelAttribute bazel.LabelAttribute
 	bp2BuildPropParseHelper(ctx, module, &prebuiltLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
@@ -407,7 +407,7 @@
 	}
 }
 
-func bp2BuildParsePrebuiltBinaryProps(ctx android.BazelConversionPathContext, module *Module) prebuiltAttributes {
+func bp2BuildParsePrebuiltBinaryProps(ctx android.Bp2buildMutatorContext, 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 {
@@ -420,7 +420,7 @@
 	}
 }
 
-func bp2BuildParsePrebuiltObjectProps(ctx android.BazelConversionPathContext, module *Module) prebuiltAttributes {
+func bp2BuildParsePrebuiltObjectProps(ctx android.Bp2buildMutatorContext, 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 {
@@ -555,7 +555,7 @@
 	return result
 }
 
-func (ca *compilerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, config string, props *BaseCompilerProperties) {
+func (ca *compilerAttributes) bp2buildForAxisAndConfig(ctx android.Bp2buildMutatorContext, axis bazel.ConfigurationAxis, config string, props *BaseCompilerProperties) {
 	// If there's arch specific srcs or exclude_srcs, generate a select entry for it.
 	// TODO(b/186153868): do this for OS specific srcs and exclude_srcs too.
 	srcsList, ok := parseSrcs(ctx, props)
@@ -680,7 +680,7 @@
 }
 
 // Parse srcs from an arch or OS's props value.
-func parseSrcs(ctx android.BazelConversionPathContext, props *BaseCompilerProperties) (bazel.LabelList, bool) {
+func parseSrcs(ctx android.Bp2buildMutatorContext, 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.
@@ -1143,7 +1143,7 @@
 	compilerAttrs compilerAttributes,
 ) *bazel.LabelAttribute {
 	var aidlLibsFromSrcs, aidlFiles bazel.LabelListAttribute
-	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), ctx.Module())
+	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx, ctx.Module())
 
 	if !aidlSrcs.IsEmpty() {
 		aidlLibsFromSrcs, aidlFiles = aidlSrcs.Partition(func(src bazel.Label) bool {
@@ -1185,7 +1185,7 @@
 		implementationDynamicDeps := linkerAttrs.dynamicDeps.Clone()
 		implementationDynamicDeps.Append(linkerAttrs.implementationDynamicDeps)
 
-		sdkAttrs := bp2BuildParseSdkAttributes(m)
+		sdkAttrs := Bp2BuildParseSdkAttributes(m)
 
 		exportedIncludes := bp2BuildParseExportedIncludes(ctx, m, &compilerAttrs.includes)
 		includeAttrs := includesAttributes{
@@ -1207,7 +1207,7 @@
 				Implementation_deps:         *implementationDeps,
 				Implementation_dynamic_deps: *implementationDynamicDeps,
 				Tags:                        apexAvailableTags,
-				sdkAttributes:               sdkAttrs,
+				SdkAttributes:               sdkAttrs,
 				includesAttributes:          includeAttrs,
 			},
 		)
@@ -1222,14 +1222,14 @@
 	return nil
 }
 
-func bp2BuildParseSdkAttributes(module *Module) sdkAttributes {
-	return sdkAttributes{
+func Bp2BuildParseSdkAttributes(module *Module) SdkAttributes {
+	return SdkAttributes{
 		Sdk_version:     module.Properties.Sdk_version,
 		Min_sdk_version: module.Properties.Min_sdk_version,
 	}
 }
 
-type sdkAttributes struct {
+type SdkAttributes struct {
 	Sdk_version     *string
 	Min_sdk_version *string
 }
@@ -1265,7 +1265,7 @@
 
 // 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) {
+func (la *linkerAttributes) resolveTargetApexProp(ctx android.Bp2buildMutatorContext, props *BaseLinkerProperties) {
 	excludeSharedLibs := bazelLabelForSharedDeps(ctx, props.Target.Apex.Exclude_shared_libs)
 	sharedExcludes := bazel.LabelList{Excludes: excludeSharedLibs.Includes}
 	sharedExcludesLabelList := bazel.LabelListAttribute{}
@@ -1283,7 +1283,7 @@
 	la.implementationDeps.Append(staticExcludesLabelList)
 }
 
-func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, module *Module, axis bazel.ConfigurationAxis, config string, props *BaseLinkerProperties) {
+func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.Bp2buildMutatorContext, 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
@@ -1378,10 +1378,10 @@
 		// having stubs or not, so Bazel select() statement can be used to choose
 		// source/stub variants of them.
 		apexAvailable := module.ApexAvailable()
-		SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, 0, false)
-		SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1, false)
+		SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.export, &la.dynamicDeps, &la.deps, 0, false)
+		SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, &la.deps, 1, false)
 		if len(systemSharedLibs) > 0 {
-			SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, bazelLabelForSharedDeps(ctx, systemSharedLibs), &la.systemDynamicDeps, 2, true)
+			SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, bazelLabelForSharedDeps(ctx, systemSharedLibs), &la.systemDynamicDeps, &la.deps, 2, true)
 		}
 	}
 
@@ -1490,7 +1490,7 @@
 // Note that this is an anti-pattern: The config_setting should be created from the apex definition
 // and not from a cc_library.
 // This anti-pattern is needed today since not all apexes have been allowlisted.
-func createInApexConfigSetting(ctx android.TopDownMutatorContext, apexName string) {
+func createInApexConfigSetting(ctx android.Bp2buildMutatorContext, apexName string) {
 	if apexName == android.AvailableToPlatform || apexName == android.AvailableToAnyApex {
 		// These correspond to android-non_apex and android-in_apex
 		return
@@ -1514,7 +1514,7 @@
 		Constraint_values: bazel.MakeLabelListAttribute(
 			bazel.MakeLabelList(
 				[]bazel.Label{
-					bazel.Label{Label: "//build/bazel/platforms/os:android"},
+					bazel.Label{Label: "//build/bazel_common_rules/platforms/os:android"},
 				},
 			),
 		),
@@ -1587,13 +1587,13 @@
 	return exists && ctx.OtherModuleType(mod) == "ndk_library"
 }
 
-func SetStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
-	config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) {
+func SetStubsForDynamicDeps(ctx android.Bp2buildMutatorContext, axis bazel.ConfigurationAxis,
+	config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, deps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) {
 
 	// Create a config_setting for each apex_available.
 	// This will be used to select impl of a dep if dep is available to the same apex.
 	for _, aa := range apexAvailable {
-		createInApexConfigSetting(ctx.(android.TopDownMutatorContext), aa)
+		createInApexConfigSetting(ctx, aa)
 	}
 
 	apiDomainForSelects := []string{}
@@ -1669,9 +1669,21 @@
 			existingValue.Append(bazel.MakeLabelList([]bazel.Label{label}))
 			dynamicDeps.SetSelectValue(bazel.OsAndInApexAxis, "unbundled_app", bazel.FirstUniqueBazelLabelList(existingValue))
 		}
+
+		// Add ndk_sysroot to deps.
+		// ndk_sysroot has a dependency edge on all ndk_headers, and will provide the .h files of _every_ ndk library
+		existingValue := deps.SelectValue(bazel.OsAndInApexAxis, "unbundled_app")
+		existingValue.Append(bazel.MakeLabelList([]bazel.Label{ndkSysrootLabel}))
+		deps.SetSelectValue(bazel.OsAndInApexAxis, "unbundled_app", bazel.FirstUniqueBazelLabelList(existingValue))
 	}
 }
 
+var (
+	ndkSysrootLabel = bazel.Label{
+		Label: "//build/bazel/rules/cc:ndk_sysroot",
+	}
+)
+
 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 {
@@ -1684,7 +1696,7 @@
 	})
 }
 
-func (la *linkerAttributes) convertProductVariables(ctx android.BazelConversionPathContext, productVariableProps android.ProductConfigProperties) {
+func (la *linkerAttributes) convertProductVariables(ctx android.Bp2buildMutatorContext, productVariableProps android.ProductConfigProperties) {
 
 	type productVarDep struct {
 		// the name of the corresponding excludes field, if one exists
@@ -1692,7 +1704,7 @@
 		// 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
+		depResolutionFunc func(ctx android.Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList
 	}
 
 	// an intermediate attribute that holds Header_libs info, and will be appended to
@@ -1750,7 +1762,7 @@
 	la.implementationDeps.Append(headerDeps)
 }
 
-func (la *linkerAttributes) finalize(ctx android.BazelConversionPathContext) {
+func (la *linkerAttributes) finalize(ctx android.Bp2buildMutatorContext) {
 	// 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.
@@ -1891,39 +1903,39 @@
 	return xsd.CppBp2buildTargetName()
 }
 
-func bazelLabelForWholeDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticWholeModuleDeps)
+func bazelLabelForWholeDeps(ctx android.Bp2buildMutatorContext, modules []string) bazel.LabelList {
+	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticWholeModuleDeps, true)
 }
 
-func bazelLabelForWholeDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+func bazelLabelForWholeDepsExcludes(ctx android.Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList {
 	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForStaticWholeModuleDeps)
 }
 
-func bazelLabelForStaticDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+func bazelLabelForStaticDepsExcludes(ctx android.Bp2buildMutatorContext, 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 bazelLabelForStaticDeps(ctx android.Bp2buildMutatorContext, modules []string) bazel.LabelList {
+	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticModule, true)
 }
 
-func bazelLabelForSharedDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForSharedModule)
+func bazelLabelForSharedDeps(ctx android.Bp2buildMutatorContext, modules []string) bazel.LabelList {
+	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForSharedModule, true)
 }
 
-func bazelLabelForHeaderDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
+func bazelLabelForHeaderDeps(ctx android.Bp2buildMutatorContext, 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 {
+func bazelLabelForHeaderDepsExcludes(ctx android.Bp2buildMutatorContext, 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 {
+func bazelLabelForSharedDepsExcludes(ctx android.Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList {
 	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForSharedModule)
 }
 
diff --git a/cc/builder.go b/cc/builder.go
index f5e0dcc..3f582fa 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -534,7 +534,7 @@
 		toolingCppflags += " ${config.NoOverride64GlobalCflags}"
 	}
 
-	modulePath := android.PathForModuleSrc(ctx).String()
+	modulePath := ctx.ModuleDir()
 	if android.IsThirdPartyPath(modulePath) {
 		cflags += " ${config.NoOverrideExternalGlobalCflags}"
 		toolingCflags += " ${config.NoOverrideExternalGlobalCflags}"
@@ -875,7 +875,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")
 
@@ -892,6 +893,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,
diff --git a/cc/cc.go b/cc/cc.go
index 81a6cd6..814a66c 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -589,7 +589,7 @@
 	GeneratorFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags
 	GeneratorSources(ctx ModuleContext) GeneratedSource
 	GeneratorBuildActions(ctx ModuleContext, flags Flags, deps PathDeps)
-	GeneratorBp2build(ctx android.Bp2buildMutatorContext) bool
+	GeneratorBp2build(ctx android.Bp2buildMutatorContext, module *Module) bool
 }
 
 // compiler is the interface for a compiler helper object. Different module decorators may implement
@@ -1895,8 +1895,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
@@ -4219,7 +4218,7 @@
 	if len(c.generators) > 0 {
 		allConverted := true
 		for _, generator := range c.generators {
-			allConverted = allConverted && generator.GeneratorBp2build(ctx)
+			allConverted = allConverted && generator.GeneratorBp2build(ctx, c)
 		}
 		if allConverted {
 			return
@@ -4273,24 +4272,6 @@
 	}
 }
 
-var _ android.ApiProvider = (*Module)(nil)
-
-func (c *Module) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
-	if c.IsPrebuilt() {
-		return
-	}
-	switch c.typ() {
-	case fullLibrary:
-		apiContributionBp2Build(ctx, c)
-	case sharedLibrary:
-		apiContributionBp2Build(ctx, c)
-	case headerLibrary:
-		// Aggressively generate api targets for all header modules
-		// This is necessary since the header module does not know if it is a dep of API surface stub library
-		apiLibraryHeadersBp2Build(ctx, c)
-	}
-}
-
 // Defaults
 type Defaults struct {
 	android.ModuleBase
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 7ce0f37..794c5ee 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -41,7 +41,6 @@
 	PrepareForTestWithCcIncludeVndk,
 	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 		variables.DeviceVndkVersion = StringPtr("current")
-		variables.ProductVndkVersion = StringPtr("current")
 		variables.Platform_vndk_version = StringPtr("29")
 	}),
 )
@@ -104,33 +103,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 +139,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
@@ -523,7 +494,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)
@@ -707,6 +677,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"})
 
@@ -889,63 +860,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.
@@ -1111,6 +1025,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1132,6 +1047,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1153,6 +1069,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1175,6 +1092,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1390,6 +1308,7 @@
 		cc_library {
 			name: "libanothervndksp",
 			vendor_available: true,
+			product_available: true,
 		}
 	`)
 }
@@ -1467,7 +1386,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)
@@ -1482,70 +1400,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.
@@ -1920,7 +1774,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)
@@ -3034,24 +2887,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
diff --git a/cc/compiler.go b/cc/compiler.go
index 5bed8a7..490d3cc 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -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...)
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_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 a586a3f..2ca9df9 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -29,83 +29,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",
-
-		"-O2",
-		"-fdebug-default-version=5",
-
-		"-fno-strict-aliasing",
-
+		// Using __DATE__/__TIME__ causes build nondeterminism.
 		"-Werror=date-time",
+		// Detects forgotten */& that usually cause a crash
+		"-Werror=int-conversion",
+		// Detects unterminated alignment modification pragmas, which often lead
+		// to ABI mismatch between modules and hard-to-debug crashes.
 		"-Werror=pragma-pack",
+		// Same as above, but detects alignment pragmas around a header
+		// inclusion.
 		"-Werror=pragma-pack-suspicious-include",
+		// Detects dividing an array size by itself, which is a common typo that
+		// leads to bugs.
+		"-Werror=sizeof-array-div",
+		// Detects a typo that cuts off a prefix from a string literal.
 		"-Werror=string-plus-int",
+		// Detects for loops that will never execute more than once (for example
+		// due to unconditional break), but have a non-empty loop increment
+		// clause. Often a mistake/bug.
 		"-Werror=unreachable-code-loop-increment",
 
-		// Force deprecation warnings to be warnings for code that compiles with -Werror.
-		// Making deprecated usages an error causes extreme pain when trying to deprecate anything.
+		// Warnings that should not be errors even for modules with -Werror.
+
+		// Making deprecated usages an error causes extreme pain when trying to
+		// deprecate anything.
 		"-Wno-error=deprecated-declarations",
 
+		// Warnings disabled by default.
+
+		// Designated initializer syntax is recommended by the Google C++ style
+		// and is OK to use even if not formally supported by the chosen C++
+		// version.
+		"-Wno-c99-designator",
+		// Detects uses of a GNU C extension equivalent to a limited form of
+		// constexpr. Enabling this would require replacing many constants with
+		// macros, which is not a good trade-off.
+		"-Wno-gnu-folding-constant",
+		// AIDL generated code redeclares pure virtual methods in each
+		// subsequent version of an interface, so this warning is currently
+		// infeasible to enable.
+		"-Wno-inconsistent-missing-override",
+		// Detects designated initializers that are in a different order than
+		// the fields in the initialized type, which causes the side effects
+		// of initializers to occur out of order with the source code.
+		// In practice, this warning has extremely poor signal to noise ratio,
+		// because it is triggered even for initializers with no side effects.
+		// Individual modules can still opt into it via cflags.
+		"-Wno-error=reorder-init-list",
+		"-Wno-reorder-init-list",
+		// Incompatible with the Google C++ style guidance to use 'int' for loop
+		// indices; poor signal to noise ratio.
+		"-Wno-sign-compare",
+		// Poor signal to noise ratio.
+		"-Wno-unused",
+
+		// Global preprocessor constants.
+
+		"-DANDROID",
+		"-DNDEBUG",
+		"-UDEBUG",
 		"-D__compiler_offsetof=__builtin_offsetof",
+		// Allows the bionic versioning.h to indirectly determine whether the
+		// option -Wunguarded-availability is on or not.
+		"-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__",
+
+		// -f and -g options.
 
 		// Emit address-significance table which allows linker to perform safe ICF. Clang does
 		// not emit the table by default on Android since NDK still uses GNU binutils.
 		"-faddrsig",
 
-		// Help catch common 32/64-bit errors.
-		"-Werror=int-conversion",
+		// 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",
 
-		// -Wno-sign-compare is incompatible with the Google C++ style guidance
-		// to use 'int' for loop indices, and the signal to noise ratio is poor
-		// anyway.
-		"-Wno-sign-compare",
-
-		// AIDL generated code redeclares pure virtual methods in each
-		// subsequent version of an interface, so this is currently infeasible
-		// to enable.
-		"-Wno-inconsistent-missing-override",
-
-		// Designated initializer syntax is recommended by the Google C++ style
-		// guide and should not be a warning, at least by default.
-		"-Wno-c99-designator",
-
-		// Warnings from clang-12
-		"-Wno-gnu-folding-constant",
-
-		// http://b/145210666
-		"-Wno-error=reorder-init-list",
-
-		// 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{}
@@ -117,6 +155,7 @@
 		"-fdebug-default-version=4",
 	}
 
+	// Compilation flags for device code; not applied to host code.
 	deviceGlobalCflags = []string{
 		"-ffunction-sections",
 		"-fdata-sections",
@@ -135,9 +174,6 @@
 		"-Werror=format-security",
 		"-nostdlibinc",
 
-		// Enable MLGO for register allocation.
-		"-mllvm -regalloc-enable-advisor=release",
-
 		// Emit additional debug info for AutoFDO
 		"-fdebug-info-for-profiling",
 	}
@@ -152,6 +188,7 @@
 		"-fvisibility-inlines-hidden",
 	}
 
+	// Linking flags for device code; not applied to host binaries.
 	deviceGlobalLdflags = []string{
 		"-Wl,-z,noexecstack",
 		"-Wl,-z,relro",
@@ -165,11 +202,11 @@
 		"-Wl,--exclude-libs,libgcc_stripped.a",
 		"-Wl,--exclude-libs,libunwind_llvm.a",
 		"-Wl,--exclude-libs,libunwind.a",
-		// Enable MLGO for register allocation.
-		"-Wl,-mllvm,-regalloc-enable-advisor=release",
 	}
 
-	deviceGlobalLldflags = append(deviceGlobalLdflags, commonGlobalLldflags...)
+	deviceGlobalLldflags = append(append(deviceGlobalLdflags, commonGlobalLldflags...),
+		"-Wl,--compress-debug-sections=zstd",
+	)
 
 	hostGlobalCflags = []string{}
 
@@ -180,8 +217,6 @@
 	hostGlobalLldflags = commonGlobalLldflags
 
 	commonGlobalCppflags = []string{
-		"-Wsign-promo",
-
 		// -Wimplicit-fallthrough is not enabled by -Wall.
 		"-Wimplicit-fallthrough",
 
@@ -194,6 +229,14 @@
 
 	// 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",
@@ -211,6 +254,7 @@
 		"-Werror=fortify-source",
 
 		"-Werror=address-of-temporary",
+		"-Werror=incompatible-function-pointer-types",
 		"-Werror=null-dereference",
 		"-Werror=return-type",
 
@@ -245,35 +289,9 @@
 
 	noOverride64GlobalCflags = []string{}
 
-	// Similar to noOverrideGlobalCflags, but applies only 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/)
-	noOverrideExternalGlobalCflags = []string{
-		// http://b/151457797
-		"-fcommon",
-		// http://b/191699019
-		"-Wno-format-insufficient-args",
-		// http://b/296321145
-		// Indicates potential memory or stack corruption, so should be changed
-		// to a hard error. Currently triggered by some vendor code.
-		"-Wno-incompatible-function-pointer-types",
-		// 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",
-	}
-
-	// 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",
@@ -303,11 +321,37 @@
 		"-Wno-deprecated-non-prototype",
 	}
 
-	llvmNextExtraCommonGlobalCflags = []string{
-		// Do not report warnings when testing with the top of trunk LLVM.
-		"-Wno-error",
+	// 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-everything",
+	}
+
+	// Flags that must not appear in any command line.
 	IllegalFlags = []string{
 		"-w",
 	}
@@ -420,6 +464,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, " ")
 	})
diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go
index e048622..d5bc760 100644
--- a/cc/config/riscv64_device.go
+++ b/cc/config/riscv64_device.go
@@ -27,6 +27,9 @@
 		"-Werror=implicit-function-declaration",
 		"-fno-emulated-tls",
 		"-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",
 	}
 
 	riscv64ArchVariantCflags = map[string][]string{}
@@ -34,6 +37,9 @@
 	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",
 	}
 
 	riscv64Lldflags = append(riscv64Ldflags,
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index 9f093bb..00a395f 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",
@@ -94,10 +96,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().PageSizeAgnostic() {
+			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_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/fdo_profile.go b/cc/fdo_profile.go
index 05a8f46..cd3eb1e 100644
--- a/cc/fdo_profile.go
+++ b/cc/fdo_profile.go
@@ -72,7 +72,8 @@
 
 	ctx.CreateBazelTargetModuleWithRestrictions(
 		bazel.BazelTargetModuleProperties{
-			Rule_class: "fdo_profile",
+			Bzl_load_location: "//build/bazel/rules/fdo:fdo_profile.bzl",
+			Rule_class:        "fdo_profile",
 		},
 		android.CommonAttributes{
 			Name: fp.Name(),
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 227fe8b..df9f21a 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -357,10 +357,10 @@
 // their architecture & target/host specific zip file.
 type ccRustFuzzPackager struct {
 	fuzz.FuzzPackager
-	fuzzPackagingArchModules         			string
-	fuzzTargetSharedDepsInstallPairs 			string
-	allFuzzTargetsName               			string
-	onlyIncludePresubmits						bool
+	fuzzPackagingArchModules         string
+	fuzzTargetSharedDepsInstallPairs string
+	allFuzzTargetsName               string
+	onlyIncludePresubmits            bool
 }
 
 func fuzzPackagingFactory() android.Singleton {
@@ -369,7 +369,7 @@
 		fuzzPackagingArchModules:         "SOONG_FUZZ_PACKAGING_ARCH_MODULES",
 		fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
 		allFuzzTargetsName:               "ALL_FUZZ_TARGETS",
-		onlyIncludePresubmits:			  false,
+		onlyIncludePresubmits:            false,
 	}
 	return fuzzPackager
 }
@@ -380,7 +380,7 @@
 		fuzzPackagingArchModules:         "SOONG_PRESUBMIT_FUZZ_PACKAGING_ARCH_MODULES",
 		fuzzTargetSharedDepsInstallPairs: "PRESUBMIT_FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS",
 		allFuzzTargetsName:               "ALL_PRESUBMIT_FUZZ_TARGETS",
-		onlyIncludePresubmits:			  true,
+		onlyIncludePresubmits:            true,
 	}
 	return fuzzPackager
 }
@@ -451,7 +451,7 @@
 			if fpm.FuzzProperties.Fuzz_config == nil {
 				return
 			}
-			if !BoolDefault(fpm.FuzzProperties.Fuzz_config.Use_for_presubmit, false){
+			if !BoolDefault(fpm.FuzzProperties.Fuzz_config.Use_for_presubmit, false) {
 				return
 			}
 		}
diff --git a/cc/gen.go b/cc/gen.go
index b15f164..151f23d 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -20,6 +20,7 @@
 
 	"android/soong/aidl_library"
 	"android/soong/bazel"
+	"android/soong/sysprop/bp2build"
 
 	"github.com/google/blueprint"
 
@@ -240,12 +241,13 @@
 }
 
 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",
+	labels := bp2build.SyspropLibraryLabels{
+		SyspropLibraryLabel:  moduleName + "_sysprop_library",
+		CcStaticLibraryLabel: moduleName + "_cc_sysprop_library_static",
 	}
-	Bp2buildSysprop(ctx, labels, srcs, minSdkVersion)
-	return createLabelAttributeCorrespondingToSrcs(":"+labels.StaticLibraryLabel, srcs)
+	bp2build.Bp2buildBaseSyspropLibrary(ctx, labels.SyspropLibraryLabel, srcs)
+	bp2build.Bp2buildSyspropCc(ctx, labels, minSdkVersion)
+	return createLabelAttributeCorrespondingToSrcs(":"+labels.CcStaticLibraryLabel, srcs)
 }
 
 // Creates a LabelAttribute for a given label where the value is only set for
diff --git a/cc/genrule.go b/cc/genrule.go
index d1c4c2a..63c728c 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -84,7 +84,7 @@
 		return true
 	}
 
-	if ctx.DeviceConfig().ProductVndkVersion() != "" && ctx.ProductSpecific() {
+	if ctx.ProductSpecific() {
 		return false
 	}
 
@@ -134,15 +134,8 @@
 		}
 	}
 
-	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)
-		}
 	}
 
 	return variants
diff --git a/cc/image.go b/cc/image.go
index f91762a..239f1db 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -427,7 +427,6 @@
 
 	platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
 	boardVndkVersion := mctx.DeviceConfig().VndkVersion()
-	productVndkVersion := mctx.DeviceConfig().ProductVndkVersion()
 	recoverySnapshotVersion := mctx.DeviceConfig().RecoverySnapshotVersion()
 	usingRecoverySnapshot := recoverySnapshotVersion != "current" &&
 		recoverySnapshotVersion != ""
@@ -444,9 +443,6 @@
 	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,
@@ -462,9 +458,6 @@
 		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.
@@ -473,9 +466,6 @@
 		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.
@@ -507,10 +497,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 +524,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() {
diff --git a/cc/library.go b/cc/library.go
index b9dc71b..d22bcec 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -286,7 +286,7 @@
 	Implementation_dynamic_deps bazel.LabelListAttribute
 	Tags                        bazel.StringListAttribute
 
-	sdkAttributes
+	SdkAttributes
 	includesAttributes
 }
 
@@ -347,7 +347,7 @@
 		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),
+		SdkAttributes:                     Bp2BuildParseSdkAttributes(m),
 		Native_coverage:                   baseAttributes.Native_coverage,
 		Additional_compiler_inputs:        compilerAttrs.additionalCompilerInputs,
 	}
@@ -375,7 +375,7 @@
 		Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps,
 		System_dynamic_deps:               *linkerAttrs.systemDynamicDeps.Clone().Append(sharedAttrs.System_dynamic_deps),
 		Runtime_deps:                      linkerAttrs.runtimeDeps,
-		sdkAttributes:                     bp2BuildParseSdkAttributes(m),
+		SdkAttributes:                     Bp2BuildParseSdkAttributes(m),
 		Native_coverage:                   baseAttributes.Native_coverage,
 		Additional_compiler_inputs:        compilerAttrs.additionalCompilerInputs,
 	}
@@ -468,12 +468,16 @@
 		android.CommonAttributes{
 			Name: m.Name() + "_bp2build_cc_library_static",
 			Tags: tagsForStaticVariant,
+			// TODO: b/303307456 - Remove this when data is properly supported in cc rules.
+			SkipData: proptools.BoolPtr(true),
 		},
 		staticTargetAttrs, staticAttrs.Enabled)
 	ctx.CreateBazelTargetModuleWithRestrictions(sharedProps,
 		android.CommonAttributes{
 			Name: m.Name(),
 			Tags: tagsForSharedVariant,
+			// TODO: b/303307456 - Remove this when data is properly supported in cc rules.
+			SkipData: proptools.BoolPtr(true),
 		},
 		sharedTargetAttrs, sharedAttrs.Enabled)
 
@@ -496,8 +500,15 @@
 			Deps:                 baseAttributes.deps,
 			Api_surface:          proptools.StringPtr("module-libapi"),
 		}
-		ctx.CreateBazelTargetModule(stubSuitesProps,
-			android.CommonAttributes{Name: m.Name() + "_stub_libs"},
+		if _, isNdk := ctx.ModuleFromName(m.Name() + ".ndk"); isNdk {
+			stubSuitesAttrs.Included_in_ndk = proptools.BoolPtr(true)
+		}
+
+		ctx.CreateBazelTargetModule(stubSuitesProps, android.CommonAttributes{
+			Name: m.Name() + "_stub_libs",
+			// TODO: b/303307456 - Remove this when data is properly supported in cc rules.
+			SkipData: proptools.BoolPtr(true),
+		},
 			stubSuitesAttrs)
 
 		// Add alias for the stub shared_library in @api_surfaces repository
@@ -517,70 +528,6 @@
 	}
 }
 
-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 {
@@ -611,54 +558,6 @@
 	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
@@ -2005,17 +1904,19 @@
 		}
 		exportedHeaderFlags := strings.Join(SourceAbiFlags, " ")
 		headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx)
-		library.sAbiOutputFile = transformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedHeaderFlags,
-			android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)),
-			headerAbiChecker.Exclude_symbol_versions,
-			headerAbiChecker.Exclude_symbol_tags)
-
-		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()
+		currVersion := currRefAbiDumpVersion(ctx, isVndk)
+		library.sAbiOutputFile = transformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedHeaderFlags,
+			android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)),
+			headerAbiChecker.Exclude_symbol_versions,
+			headerAbiChecker.Exclude_symbol_tags,
+			currVersion)
+
+		addLsdumpPath(classifySourceAbiDump(ctx) + ":" + library.sAbiOutputFile.String())
+
 		dumpDir := getRefAbiDumpDir(isNdk, isVndk)
 		binderBitness := ctx.DeviceConfig().BinderBitness()
 		// If NDK or PLATFORM library, check against previous version ABI.
@@ -2031,7 +1932,6 @@
 			}
 		}
 		// Check against the current version.
-		currVersion := currRefAbiDumpVersion(ctx, isVndk)
 		currDumpDir := filepath.Join(dumpDir, currVersion, binderBitness)
 		currDumpFile := getRefAbiDumpFile(ctx, currDumpDir, fileName)
 		if currDumpFile.Valid() {
@@ -2296,7 +2196,7 @@
 
 			// do not install vndk libs
 			// vndk libs are packaged into VNDK APEX
-			if ctx.isVndk() && !ctx.IsVndkExt() && !ctx.Config().IsVndkDeprecated() {
+			if ctx.isVndk() && !ctx.IsVndkExt() && !ctx.Config().IsVndkDeprecated() && !ctx.inProduct() {
 				return
 			}
 		} else if library.hasStubsVariants() && !ctx.Host() && ctx.directlyInAnyApex() {
@@ -2962,7 +2862,7 @@
 		Whole_archive_deps:                linkerAttrs.wholeArchiveDeps,
 		Implementation_whole_archive_deps: linkerAttrs.implementationWholeArchiveDeps,
 		System_dynamic_deps:               linkerAttrs.systemDynamicDeps,
-		sdkAttributes:                     bp2BuildParseSdkAttributes(module),
+		SdkAttributes:                     Bp2BuildParseSdkAttributes(module),
 		Runtime_deps:                      linkerAttrs.runtimeDeps,
 		Native_coverage:                   baseAttributes.Native_coverage,
 		Additional_compiler_inputs:        compilerAttrs.additionalCompilerInputs,
@@ -3047,7 +2947,12 @@
 
 	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, module)
 
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: module.Name(), Tags: tags}, attrs)
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
+		Name: module.Name(),
+		Tags: tags,
+		// TODO: b/303307456 - Remove this when data is properly supported in cc rules.
+		SkipData: proptools.BoolPtr(true),
+	}, attrs)
 }
 
 type includesAttributes struct {
@@ -3123,6 +3028,13 @@
 	Soname               *string
 	Deps                 bazel.LabelListAttribute
 	Api_surface          *string
+
+	// Unless the library is in the NDK, module-libapi stubs should *not* include the public symbols
+	// Soong uses a global variable to determine if the library is in the NDK
+	// Since Bazel does not have global analysis, create an explicit property
+	// This property is only relevant if `api_surface = module-libapi`
+	// https://cs.android.com/android/_/android/platform/build/soong/+/main:cc/library.go;l=1214-1219;drc=7123cc5370a38983ee6325b5f5f6df19f4e4f10b;bpv=1;bpt=0
+	Included_in_ndk *bool
 }
 
 type bazelCcHeaderAbiCheckerAttributes struct {
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 5eba6ab..2e5a195 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -15,8 +15,6 @@
 package cc
 
 import (
-	"github.com/google/blueprint/proptools"
-
 	"android/soong/android"
 	"android/soong/bazel"
 	"android/soong/bazel/cquery"
@@ -124,9 +122,7 @@
 	Export_absolute_includes bazel.StringListAttribute
 	Export_system_includes   bazel.StringListAttribute
 	Deps                     bazel.LabelListAttribute
-	Implementation_deps      bazel.LabelListAttribute
-	System_dynamic_deps      bazel.LabelListAttribute
-	sdkAttributes
+	SdkAttributes
 }
 
 func libraryHeadersBp2Build(ctx android.Bp2buildMutatorContext, module *Module) {
@@ -141,9 +137,8 @@
 		Export_absolute_includes: exportedIncludes.AbsoluteIncludes,
 		Export_system_includes:   exportedIncludes.SystemIncludes,
 		Deps:                     linkerAttrs.deps,
-		System_dynamic_deps:      linkerAttrs.systemDynamicDeps,
 		Hdrs:                     baseAttributes.hdrs,
-		sdkAttributes:            bp2BuildParseSdkAttributes(module),
+		SdkAttributes:            Bp2BuildParseSdkAttributes(module),
 	}
 
 	props := bazel.BazelTargetModuleProperties{
@@ -163,118 +158,3 @@
 		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/lto.go b/cc/lto.go
index df9ca0a..ad1a1b1 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -35,11 +35,11 @@
 // optimized at link time and may not be compatible with features that require
 // LTO, such as CFI.
 //
-// This file adds support to soong to automatically propogate LTO options to a
+// This file adds support to soong to automatically propagate LTO options to a
 // new variant of all static dependencies for each module with LTO enabled.
 
 type LTOProperties struct {
-	// Lto must violate capitialization style for acronyms so that it can be
+	// Lto must violate capitalization style for acronyms so that it can be
 	// referred to in blueprint files as "lto"
 	Lto struct {
 		Never *bool `android:"arch_variant"`
@@ -67,10 +67,12 @@
 }
 
 func (lto *lto) begin(ctx BaseModuleContext) {
-	// First, determine the module indepedent default LTO mode.
-	ltoDefault := GlobalThinLTO(ctx)
+	// First, determine the module independent default LTO mode.
+	ltoDefault := true
 	if ctx.Config().IsEnvTrue("DISABLE_LTO") {
 		ltoDefault = false
+	} else if lto.Never() {
+		ltoDefault = false
 	} else if ctx.Host() {
 		// Performance and binary size are less important for host binaries.
 		ltoDefault = false
@@ -145,6 +147,19 @@
 			}
 		}
 
+		if !ctx.Config().IsEnvFalse("THINLTO_USE_MLGO") {
+			// Register allocation MLGO flags for ARM64.
+			if ctx.Arch().ArchType == android.Arm64 {
+				ltoCFlags = append(ltoCFlags, "-mllvm -regalloc-enable-advisor=release")
+				ltoLdFlags = append(ltoLdFlags, "-Wl,-mllvm,-regalloc-enable-advisor=release")
+			}
+			// Flags for training MLGO model.
+			if ctx.Config().IsEnvTrue("THINLTO_EMIT_INDEXES_AND_IMPORTS") {
+				ltoLdFlags = append(ltoLdFlags, "-Wl,--save-temps=import")
+				ltoLdFlags = append(ltoLdFlags, "-Wl,--thinlto-emit-index-files")
+			}
+		}
+
 		flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlags...)
 		flags.Local.AsFlags = append(flags.Local.AsFlags, ltoCFlags...)
 		flags.Local.LdFlags = append(flags.Local.LdFlags, ltoCFlags...)
@@ -161,10 +176,6 @@
 	return lto != nil && proptools.Bool(lto.Properties.Lto.Never)
 }
 
-func GlobalThinLTO(ctx android.BaseModuleContext) bool {
-	return !ctx.Config().IsEnvFalse("GLOBAL_THINLTO")
-}
-
 // Propagate lto requirements down from binaries
 func ltoDepsMutator(mctx android.TopDownMutatorContext) {
 	if m, ok := mctx.Module().(*Module); ok {
@@ -203,8 +214,6 @@
 
 // Create lto variants for modules that need them
 func ltoMutator(mctx android.BottomUpMutatorContext) {
-	globalThinLTO := GlobalThinLTO(mctx)
-
 	if m, ok := mctx.Module().(*Module); ok && m.lto != nil {
 		// Create variations for LTO types required as static
 		// dependencies
@@ -216,10 +225,10 @@
 			variationNames = append(variationNames, "lto-none")
 		}
 
-		if globalThinLTO && !m.lto.Properties.LtoEnabled {
+		if !m.lto.Properties.LtoEnabled {
 			mctx.SetDependencyVariation("lto-none")
 		}
-		if !globalThinLTO && m.lto.Properties.LtoEnabled {
+		if m.lto.Properties.LtoEnabled {
 			mctx.SetDependencyVariation("lto-thin")
 		}
 
diff --git a/cc/lto_test.go b/cc/lto_test.go
index e0afd4a..7b7fe8c 100644
--- a/cc/lto_test.go
+++ b/cc/lto_test.go
@@ -23,11 +23,19 @@
 	"github.com/google/blueprint"
 )
 
-var NoGlobalThinLTOPreparer = android.GroupFixturePreparers(
+var LTOPreparer = android.GroupFixturePreparers(
 	prepareForCcTest,
-	android.FixtureModifyEnv(func(env map[string]string) {
-		env["GLOBAL_THINLTO"] = "false"
-	}))
+)
+
+func hasDep(result *android.TestResult, m android.Module, wantDep android.Module) bool {
+	var found bool
+	result.VisitDirectDeps(m, func(dep blueprint.Module) {
+		if dep == wantDep {
+			found = true
+		}
+	})
+	return found
+}
 
 func TestThinLtoDeps(t *testing.T) {
 	t.Parallel()
@@ -37,9 +45,6 @@
 		srcs: ["src.c"],
 		static_libs: ["foo", "lib_never_lto"],
 		shared_libs: ["bar"],
-		lto: {
-			thin: true,
-		}
 	}
 	cc_library_static {
 		name: "foo",
@@ -63,50 +68,40 @@
 	}
 `
 
-	result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
+	result := LTOPreparer.RunTestWithBp(t, bp)
 
 	libLto := result.ModuleForTests("lto_enabled", "android_arm64_armv8-a_shared").Module()
 
-	hasDep := func(m android.Module, wantDep android.Module) bool {
-		var found bool
-		result.VisitDirectDeps(m, func(dep blueprint.Module) {
-			if dep == wantDep {
-				found = true
-			}
-		})
-		return found
+	libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static").Module()
+	if !hasDep(result, libLto, libFoo) {
+		t.Errorf("'lto_enabled' missing dependency on the default variant of 'foo'")
 	}
 
-	libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static_lto-thin").Module()
-	if !hasDep(libLto, libFoo) {
-		t.Errorf("'lto_enabled' missing dependency on thin lto variant of 'foo'")
+	libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static").Module()
+	if !hasDep(result, libFoo, libBaz) {
+		t.Errorf("'foo' missing dependency on the default variant of transitive dep 'baz'")
 	}
 
-	libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static_lto-thin").Module()
-	if !hasDep(libFoo, libBaz) {
-		t.Errorf("'foo' missing dependency on thin lto variant of transitive dep 'baz'")
-	}
-
-	libNeverLto := result.ModuleForTests("lib_never_lto", "android_arm64_armv8-a_static_lto-thin").Module()
-	if !hasDep(libLto, libNeverLto) {
-		t.Errorf("'lto_enabled' missing dependency on NO-thin lto variant of 'lib_never_lto'")
+	libNeverLto := result.ModuleForTests("lib_never_lto", "android_arm64_armv8-a_static").Module()
+	if !hasDep(result, libLto, libNeverLto) {
+		t.Errorf("'lto_enabled' missing dependency on the default variant of 'lib_never_lto'")
 	}
 
 	libBar := result.ModuleForTests("bar", "android_arm64_armv8-a_shared").Module()
-	if !hasDep(libLto, libBar) {
-		t.Errorf("'lto_enabled' missing dependency on non-thin lto variant of 'bar'")
+	if !hasDep(result, libLto, libBar) {
+		t.Errorf("'lto_enabled' missing dependency on the default variant of 'bar'")
 	}
 
 	barVariants := result.ModuleVariantsForTests("bar")
 	for _, v := range barVariants {
-		if strings.Contains(v, "lto-thin") {
-			t.Errorf("Expected variants for 'bar' to not contain 'lto-thin', but found %q", v)
+		if strings.Contains(v, "lto-none") {
+			t.Errorf("Expected variants for 'bar' to not contain 'lto-none', but found %q", v)
 		}
 	}
 	quxVariants := result.ModuleVariantsForTests("qux")
 	for _, v := range quxVariants {
-		if strings.Contains(v, "lto-thin") {
-			t.Errorf("Expected variants for 'qux' to not contain 'lto-thin', but found %q", v)
+		if strings.Contains(v, "lto-none") {
+			t.Errorf("Expected variants for 'qux' to not contain 'lto-none', but found %q", v)
 		}
 	}
 }
@@ -141,28 +136,18 @@
 	}
 `
 
-	result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
+	result := LTOPreparer.RunTestWithBp(t, bp)
 
 	libRoot := result.ModuleForTests("root", "android_arm64_armv8-a_shared").Module()
 	libRootLtoNever := result.ModuleForTests("root_no_lto", "android_arm64_armv8-a_shared").Module()
 
-	hasDep := func(m android.Module, wantDep android.Module) bool {
-		var found bool
-		result.VisitDirectDeps(m, func(dep blueprint.Module) {
-			if dep == wantDep {
-				found = true
-			}
-		})
-		return found
-	}
-
 	libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static")
-	if !hasDep(libRoot, libFoo.Module()) {
-		t.Errorf("'root' missing dependency on thin lto variant of 'foo'")
+	if !hasDep(result, libRoot, libFoo.Module()) {
+		t.Errorf("'root' missing dependency on the default variant of 'foo'")
 	}
 
-	if !hasDep(libRootLtoNever, libFoo.Module()) {
-		t.Errorf("'root_no_lto' missing dependency on thin lto variant of 'foo'")
+	if !hasDep(result, libRootLtoNever, libFoo.Module()) {
+		t.Errorf("'root_no_lto' missing dependency on the default variant of 'foo'")
 	}
 
 	libFooCFlags := libFoo.Rule("cc").Args["cFlags"]
@@ -170,9 +155,9 @@
 		t.Errorf("'foo' expected to have flags %q, but got %q", w, libFooCFlags)
 	}
 
-	libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static_lto-thin")
-	if !hasDep(libFoo.Module(), libBaz.Module()) {
-		t.Errorf("'foo' missing dependency on thin lto variant of transitive dep 'baz'")
+	libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static")
+	if !hasDep(result, libFoo.Module(), libBaz.Module()) {
+		t.Errorf("'foo' missing dependency on the default variant of transitive dep 'baz'")
 	}
 
 	libBazCFlags := libFoo.Rule("cc").Args["cFlags"]
@@ -199,7 +184,7 @@
 			},
 		},
 	}`
-	result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
+	result := LTOPreparer.RunTestWithBp(t, bp)
 
 	libFooWithLto := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
 	libFooWithoutLto := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld")
@@ -227,7 +212,7 @@
 		},
 	}`
 
-	result := NoGlobalThinLTOPreparer.RunTestWithBp(t, bp)
+	result := LTOPreparer.RunTestWithBp(t, bp)
 
 	libFoo := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld")
 	libBar := result.ModuleForTests("runtime_libbar", "android_arm_armv7-a-neon_shared").Rule("ld")
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index da5db1c..461aa96 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -19,6 +19,7 @@
 	"path/filepath"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 	"android/soong/bazel"
@@ -151,6 +152,7 @@
 	Strip_import_prefix *string
 	Import_prefix       *string
 	Hdrs                bazel.LabelListAttribute
+	Run_versioner       *bool
 }
 
 func (h *headerModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
@@ -217,6 +219,7 @@
 // Note that this is really only built to handle bionic/libc/include.
 type versionedHeaderModule struct {
 	android.ModuleBase
+	android.BazelModuleBase
 
 	properties versionedHeaderProperties
 
@@ -255,6 +258,25 @@
 	processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, m.srcPaths, installPaths)
 }
 
+func (h *versionedHeaderModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "ndk_headers",
+		Bzl_load_location: "//build/bazel/rules/cc:ndk_headers.bzl",
+	}
+	globPattern := headerGlobPattern(proptools.String(h.properties.From))
+	attrs := &bazelNdkHeadersAttributes{
+		Strip_import_prefix: h.properties.From,
+		Import_prefix:       h.properties.To,
+		Run_versioner:       proptools.BoolPtr(true),
+		Hdrs:                bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, []string{globPattern})),
+	}
+	ctx.CreateBazelTargetModule(
+		props,
+		android.CommonAttributes{Name: h.Name()},
+		attrs,
+	)
+}
+
 func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path,
 	srcPaths android.Paths, installPaths []android.WritablePath) android.Path {
 	// The versioner depends on a dependencies directory to simplify determining include paths
@@ -298,12 +320,13 @@
 // 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)
 
 	android.InitAndroidModule(module)
+	android.InitBazelModule(module)
 
 	return module
 }
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index b3bb2da..df775de 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -61,7 +61,7 @@
 			// because we don't want to spam the build output with "nothing
 			// changed" messages, so redirect output message to $out, and if
 			// changes were detected print the output and fail.
-			Command:     "$stgdiff $args --stg $in -o $out || (cat $out && false)",
+			Command:     "$stgdiff $args --stg $in -o $out || (cat $out && echo 'Run $$ANDROID_BUILD_TOP/development/tools/ndk/update_ndk_abi.sh to update the ABI dumps.' && false)",
 			CommandDeps: []string{"$stgdiff"},
 		}, "args")
 
@@ -386,9 +386,11 @@
 	// level.
 	abiDiffPath := android.PathForModuleOut(ctx, "stgdiff.timestamp")
 	prebuiltAbiDump := this.findPrebuiltAbiDump(ctx, this.apiLevel)
+	missingPrebuiltErrorTemplate :=
+		"Did not find prebuilt ABI dump for %q (%q). Generate with " +
+			"//development/tools/ndk/update_ndk_abi.sh."
 	missingPrebuiltError := fmt.Sprintf(
-		"Did not find prebuilt ABI dump for %q (%q). Generate with "+
-			"//development/tools/ndk/update_ndk_abi.sh.", this.libraryName(ctx),
+		missingPrebuiltErrorTemplate, this.libraryName(ctx),
 		prebuiltAbiDump.InvalidReason())
 	if !prebuiltAbiDump.Valid() {
 		ctx.Build(pctx, android.BuildParams{
@@ -424,12 +426,15 @@
 		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 {
@@ -575,15 +580,6 @@
 	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.Bp2buildMutatorContext, c *Module) {
 	ndk, _ := c.linker.(*stubDecorator)
 	props := bazel.BazelTargetModuleProperties{
@@ -598,9 +594,10 @@
 	symbolFileLabel := android.BazelLabelForModuleSrcSingle(ctx, proptools.String(ndk.properties.Symbol_file))
 	attrs := &bazelCcStubSuiteAttributes{
 		// TODO - b/300504837 Add ndk headers
-		Symbol_file: proptools.StringPtr(symbolFileLabel.Label),
-		Soname:      proptools.StringPtr(sourceLibraryName + ".so"),
-		Api_surface: proptools.StringPtr(android.PublicApi.String()),
+		Symbol_file:     proptools.StringPtr(symbolFileLabel.Label),
+		Soname:          proptools.StringPtr(sourceLibraryName + ".so"),
+		Api_surface:     proptools.StringPtr(android.PublicApi.String()),
+		Included_in_ndk: proptools.BoolPtr(true),
 	}
 	if sourceLibrary, exists := ctx.ModuleFromName(sourceLibraryName); exists {
 		// the source library might not exist in minimal/unbuildable branches like kernel-build-tools.
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 54a2ee2..483d23b 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -64,7 +64,7 @@
 func RegisterNdkModuleTypes(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("ndk_headers", NdkHeadersFactory)
 	ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
-	ctx.RegisterModuleType("versioned_ndk_headers", versionedNdkHeadersFactory)
+	ctx.RegisterModuleType("versioned_ndk_headers", VersionedNdkHeadersFactory)
 	ctx.RegisterModuleType("preprocessed_ndk_headers", preprocessedNdkHeadersFactory)
 	ctx.RegisterParallelSingletonType("ndk", NdkSingleton)
 }
diff --git a/cc/object.go b/cc/object.go
index a3000e0..d6eb369 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -151,7 +151,7 @@
 	Stl                 *string
 	Linker_script       bazel.LabelAttribute
 	Crt                 *bool
-	sdkAttributes
+	SdkAttributes
 }
 
 // objectBp2Build is the bp2build converter from cc_object modules to the
@@ -218,7 +218,7 @@
 		Stl:                 compilerAttrs.stl,
 		Linker_script:       linkerScript,
 		Crt:                 m.linker.(*objectLinker).Properties.Crt,
-		sdkAttributes:       bp2BuildParseSdkAttributes(m),
+		SdkAttributes:       Bp2BuildParseSdkAttributes(m),
 	}
 
 	props := bazel.BazelTargetModuleProperties{
diff --git a/cc/orderfile.go b/cc/orderfile.go
index b64c1c7..9192e81 100644
--- a/cc/orderfile.go
+++ b/cc/orderfile.go
@@ -58,17 +58,17 @@
 
 type OrderfileProperties struct {
 	Orderfile struct {
-		Instrumentation    *bool
-		Order_file_path    *string `android:"arch_variant"`
-		Load_order_file    *bool `android:"arch_variant"`
+		Instrumentation *bool
+		Order_file_path *string `android:"arch_variant"`
+		Load_order_file *bool   `android:"arch_variant"`
 		// Additional compiler flags to use when building this module
 		// for orderfile profiling.
 		Cflags []string `android:"arch_variant"`
 	} `android:"arch_variant"`
 
-	ShouldProfileModule 	  bool `blueprint:"mutated"`
-	OrderfileLoad             bool `blueprint:"mutated"`
-	OrderfileInstrLink        bool `blueprint:"mutated"`
+	ShouldProfileModule bool `blueprint:"mutated"`
+	OrderfileLoad       bool `blueprint:"mutated"`
+	OrderfileInstrLink  bool `blueprint:"mutated"`
 }
 
 type orderfile struct {
@@ -128,7 +128,6 @@
 	return flags
 }
 
-
 func (props *OrderfileProperties) loadOrderfileFlags(ctx ModuleContext, file string) []string {
 	flags := []string{fmt.Sprintf(orderfileUseFormat, file)}
 	flags = append(flags, orderfileOtherFlags...)
@@ -217,7 +216,7 @@
 
 			if dep, ok := dep.(*Module); ok {
 				if m.orderfile.Properties.OrderfileInstrLink {
-					dep.orderfile.Properties.OrderfileInstrLink = true;
+					dep.orderfile.Properties.OrderfileInstrLink = true
 				}
 			}
 
diff --git a/cc/orderfile_test.go b/cc/orderfile_test.go
index f68457d..3486f96 100644
--- a/cc/orderfile_test.go
+++ b/cc/orderfile_test.go
@@ -15,8 +15,8 @@
 package cc
 
 import (
-	"testing"
 	"strings"
+	"testing"
 
 	"android/soong/android"
 )
@@ -193,8 +193,8 @@
 	}
 
 	// Check cFlags of orderfile variant static libraries
-	libFooOfVariant  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_orderfile")
-	libBarOfVariant  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_orderfile")
+	libFooOfVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_orderfile")
+	libBarOfVariant := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_orderfile")
 
 	cFlags = libFooOfVariant.Rule("cc").Args["cFlags"]
 	if !strings.Contains(cFlags, expectedCFlag) {
@@ -216,8 +216,8 @@
 	}
 
 	// Check cFlags of the non-orderfile variant static libraries
-	libFoo  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
-	libBar  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+	libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
 
 	cFlags = libFoo.Rule("cc").Args["cFlags"]
 	if strings.Contains(cFlags, expectedCFlag) {
@@ -281,8 +281,8 @@
 		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")
+	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()) {
@@ -351,8 +351,8 @@
 	}
 
 	// Check cFlags of the static and shared libraries
-	libFoo  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_shared")
-	libBar  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+	libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_shared")
+	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
 
 	cFlags = libFoo.Rule("cc").Args["cFlags"]
 	if strings.Contains(cFlags, expectedCFlag) {
@@ -431,8 +431,8 @@
 	}
 
 	// Check cFlags of the static libraries
-	libFoo  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
-	libBar  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+	libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
 
 	cFlags = libFoo.Rule("cc").Args["cFlags"]
 	if strings.Contains(cFlags, expectedCFlag) {
@@ -467,4 +467,4 @@
 			t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v)
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/cc/proto.go b/cc/proto.go
index 0ed4381..4e08a4c 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -246,7 +246,7 @@
 	protoAttrs.Min_sdk_version = m.Properties.Min_sdk_version
 
 	name := m.Name() + suffix
-	tags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), m)
+	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
 	ctx.CreateBazelTargetModule(
 		bazel.BazelTargetModuleProperties{
 			Rule_class:        rule_class,
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 9ceb1c8..6624d4b 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -86,7 +86,7 @@
 	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"
 )
@@ -1113,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
 }
 
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
index 49117a0..31e668e 100644
--- a/cc/sanitize_test.go
+++ b/cc/sanitize_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"reflect"
 	"runtime"
 	"strings"
 	"testing"
@@ -1273,3 +1274,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/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 7a6cf1b..5b778dc 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -791,7 +791,7 @@
 
 // cc_test that builds using gtest needs some additional deps
 // addImplicitGtestDeps makes these deps explicit in the generated BUILD files
-func addImplicitGtestDeps(ctx android.BazelConversionPathContext, attrs *testBinaryAttributes, gtest, gtestIsolated bool) {
+func addImplicitGtestDeps(ctx android.Bp2buildMutatorContext, attrs *testBinaryAttributes, gtest, gtestIsolated bool) {
 	addDepsAndDedupe := func(lla *bazel.LabelListAttribute, modules []string) {
 		moduleLabels := android.BazelLabelForModuleDeps(ctx, modules)
 		lla.Value.Append(moduleLabels)
diff --git a/cc/testing.go b/cc/testing.go
index 36bc261..71d986b 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -68,26 +68,6 @@
 
 func commonDefaultModules() string {
 	return `
-		prebuilt_build_tool {
-			name: "clang++",
-			src: "bin/clang++",
-		}
-		prebuilt_build_tool {
-			name: "clang++.real",
-			src: "bin/clang++.real",
-		}
-		prebuilt_build_tool {
-			name: "lld",
-			src: "bin/lld",
-		}
-		prebuilt_build_tool {
-			name: "ld.lld",
-			src: "bin/ld.lld",
-		}
-		prebuilt_build_tool {
-			name: "llvm-ar",
-			src: "bin/llvm-ar",
-		}
 		cc_defaults {
 			name: "toolchain_libs_defaults",
 			host_supported: true,
@@ -589,12 +569,6 @@
 
 	// Additional files needed in tests that disallow non-existent source.
 	android.MockFS{
-		"defaults/cc/common/bin/clang++":      nil,
-		"defaults/cc/common/bin/clang++.real": nil,
-		"defaults/cc/common/bin/lld":          nil,
-		"defaults/cc/common/bin/ld.lld":       nil,
-		"defaults/cc/common/bin/llvm-ar":      nil,
-
 		"defaults/cc/common/libc.map.txt":      nil,
 		"defaults/cc/common/libdl.map.txt":     nil,
 		"defaults/cc/common/libm.map.txt":      nil,
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 9ea337b..e8e930e 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.
diff --git a/cc/vndk.go b/cc/vndk.go
index 5ac5032..a849455 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"
@@ -40,6 +42,7 @@
 )
 
 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" {
 		// We can assume all txt files are snapshotted if we find one of them.
 		currentVndkSnapshotted := ctx.OtherModuleExists(insertVndkVersion(llndkLibrariesTxt, ctx.DeviceConfig().PlatformVndkVersion()))
@@ -51,20 +54,13 @@
 			vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
 		} else {
 			// Use the txt files generated from the source
-			result := []string{
+			return []string{
+				llndkLibrariesTxtForApex,
 				vndkCoreLibrariesTxt,
 				vndkSpLibrariesTxt,
 				vndkPrivateLibrariesTxt,
 				vndkProductLibrariesTxt,
 			}
-
-			// TODO(b/290159430) This part will not be required once deprecation
-			// of VNDK is handled with 'ro.vndk.version' property
-			if !ctx.Config().IsVndkDeprecated() {
-				result = append(result, llndkLibrariesTxt)
-			}
-
-			return result
 		}
 	}
 
@@ -451,6 +447,7 @@
 
 func RegisterVndkLibraryTxtTypes(ctx android.RegistrationContext) {
 	ctx.RegisterParallelSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory)
+	ctx.RegisterParallelSingletonModuleType("llndk_libraries_txt_for_apex", llndkLibrariesTxtApexOnlyFactory)
 	ctx.RegisterParallelSingletonModuleType("vndksp_libraries_txt", vndkSPLibrariesTxtFactory)
 	ctx.RegisterParallelSingletonModuleType("vndkcore_libraries_txt", vndkCoreLibrariesTxtFactory)
 	ctx.RegisterParallelSingletonModuleType("vndkprivate_libraries_txt", vndkPrivateLibrariesTxtFactory)
@@ -474,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.
@@ -557,15 +563,10 @@
 }
 
 func (txt *vndkLibrariesTxt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	filename := txt.Name()
+	filename := proptools.StringDefault(txt.properties.Stem, txt.Name())
 
-	shouldInsertVndkVersion := BoolDefault(txt.properties.Insert_vndk_version, true)
-	// llndk.libraries.txt file installed in the system image should not contain version info.
-	if ctx.Config().IsVndkDeprecated() && txt.Name() == llndkLibrariesTxt {
-		shouldInsertVndkVersion = false
-	}
-	if shouldInsertVndkVersion {
-		filename = insertVndkVersion(txt.Name(), ctx.DeviceConfig().PlatformVndkVersion())
+	if Bool(txt.properties.Insert_vndk_version) {
+		filename = insertVndkVersion(filename, ctx.DeviceConfig().PlatformVndkVersion())
 	}
 
 	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
@@ -592,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
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_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index a70a9d1..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
diff --git a/cmd/merge_zips/merge_zips_test.go b/cmd/merge_zips/merge_zips_test.go
index 767d4e61..64b08d0 100644
--- a/cmd/merge_zips/merge_zips_test.go
+++ b/cmd/merge_zips/merge_zips_test.go
@@ -22,40 +22,45 @@
 	"strconv"
 	"strings"
 	"testing"
+	"time"
 
 	"android/soong/jar"
 	"android/soong/third_party/zip"
 )
 
 type testZipEntry struct {
-	name   string
-	mode   os.FileMode
-	data   []byte
-	method uint16
+	name      string
+	mode      os.FileMode
+	data      []byte
+	method    uint16
+	timestamp time.Time
 }
 
 var (
-	A     = testZipEntry{"A", 0755, []byte("foo"), zip.Deflate}
-	a     = testZipEntry{"a", 0755, []byte("foo"), zip.Deflate}
-	a2    = testZipEntry{"a", 0755, []byte("FOO2"), zip.Deflate}
-	a3    = testZipEntry{"a", 0755, []byte("Foo3"), zip.Deflate}
-	bDir  = testZipEntry{"b/", os.ModeDir | 0755, nil, zip.Deflate}
-	bbDir = testZipEntry{"b/b/", os.ModeDir | 0755, nil, zip.Deflate}
-	bbb   = testZipEntry{"b/b/b", 0755, nil, zip.Deflate}
-	ba    = testZipEntry{"b/a", 0755, []byte("foo"), zip.Deflate}
-	bc    = testZipEntry{"b/c", 0755, []byte("bar"), zip.Deflate}
-	bd    = testZipEntry{"b/d", 0700, []byte("baz"), zip.Deflate}
-	be    = testZipEntry{"b/e", 0700, []byte(""), zip.Deflate}
+	A     = testZipEntry{"A", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime}
+	a     = testZipEntry{"a", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime}
+	a2    = testZipEntry{"a", 0755, []byte("FOO2"), zip.Deflate, jar.DefaultTime}
+	a3    = testZipEntry{"a", 0755, []byte("Foo3"), zip.Deflate, jar.DefaultTime}
+	bDir  = testZipEntry{"b/", os.ModeDir | 0755, nil, zip.Deflate, jar.DefaultTime}
+	bbDir = testZipEntry{"b/b/", os.ModeDir | 0755, nil, zip.Deflate, jar.DefaultTime}
+	bbb   = testZipEntry{"b/b/b", 0755, nil, zip.Deflate, jar.DefaultTime}
+	ba    = testZipEntry{"b/a", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime}
+	bc    = testZipEntry{"b/c", 0755, []byte("bar"), zip.Deflate, jar.DefaultTime}
+	bd    = testZipEntry{"b/d", 0700, []byte("baz"), zip.Deflate, jar.DefaultTime}
+	be    = testZipEntry{"b/e", 0700, []byte(""), zip.Deflate, jar.DefaultTime}
 
-	service1a        = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\n"), zip.Store}
-	service1b        = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass3\n"), zip.Deflate}
-	service1combined = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\nclass3\n"), zip.Store}
-	service2         = testZipEntry{"META-INF/services/service2", 0755, []byte("class1\nclass2\n"), zip.Deflate}
+	withTimestamp    = testZipEntry{"timestamped", 0755, nil, zip.Store, jar.DefaultTime.Add(time.Hour)}
+	withoutTimestamp = testZipEntry{"timestamped", 0755, nil, zip.Store, jar.DefaultTime}
 
-	metainfDir     = testZipEntry{jar.MetaDir, os.ModeDir | 0755, nil, zip.Deflate}
-	manifestFile   = testZipEntry{jar.ManifestFile, 0755, []byte("manifest"), zip.Deflate}
-	manifestFile2  = testZipEntry{jar.ManifestFile, 0755, []byte("manifest2"), zip.Deflate}
-	moduleInfoFile = testZipEntry{jar.ModuleInfoClass, 0755, []byte("module-info"), zip.Deflate}
+	service1a        = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\n"), zip.Store, jar.DefaultTime}
+	service1b        = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass3\n"), zip.Deflate, jar.DefaultTime}
+	service1combined = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\nclass3\n"), zip.Store, jar.DefaultTime}
+	service2         = testZipEntry{"META-INF/services/service2", 0755, []byte("class1\nclass2\n"), zip.Deflate, jar.DefaultTime}
+
+	metainfDir     = testZipEntry{jar.MetaDir, os.ModeDir | 0755, nil, zip.Deflate, jar.DefaultTime}
+	manifestFile   = testZipEntry{jar.ManifestFile, 0755, []byte("manifest"), zip.Deflate, jar.DefaultTime}
+	manifestFile2  = testZipEntry{jar.ManifestFile, 0755, []byte("manifest2"), zip.Deflate, jar.DefaultTime}
+	moduleInfoFile = testZipEntry{jar.ModuleInfoClass, 0755, []byte("module-info"), zip.Deflate, jar.DefaultTime}
 )
 
 type testInputZip struct {
@@ -252,6 +257,14 @@
 			jar: true,
 			out: []testZipEntry{service1combined, service2},
 		},
+		{
+			name: "strip timestamps",
+			in: [][]testZipEntry{
+				{withTimestamp},
+				{a},
+			},
+			out: []testZipEntry{withoutTimestamp, a},
+		},
 	}
 
 	for _, test := range testCases {
@@ -307,6 +320,7 @@
 		}
 		fh.SetMode(e.mode)
 		fh.Method = e.method
+		fh.SetModTime(e.timestamp)
 		fh.UncompressedSize64 = uint64(len(e.data))
 		fh.CRC32 = crc32.ChecksumIEEE(e.data)
 		if fh.Method == zip.Store {
@@ -354,7 +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/soong_build/main.go b/cmd/soong_build/main.go
index d20847b..5abbdb7 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -84,7 +84,7 @@
 	flag.BoolVar(&cmdlineArgs.BazelMode, "bazel-mode", false, "use bazel for analysis of certain modules")
 	flag.BoolVar(&cmdlineArgs.BazelModeStaging, "bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules")
 	flag.BoolVar(&cmdlineArgs.UseBazelProxy, "use-bazel-proxy", false, "communicate with bazel using unix socket proxy instead of spawning subprocesses")
-	flag.BoolVar(&cmdlineArgs.BuildFromTextStub, "build-from-text-stub", false, "build Java stubs from API text files instead of source files")
+	flag.BoolVar(&cmdlineArgs.BuildFromSourceStub, "build-from-source-stub", false, "build Java stubs from source files instead of API text files")
 	flag.BoolVar(&cmdlineArgs.EnsureAllowlistIntegrity, "ensure-allowlist-integrity", false, "verify that allowlisted modules are mixed-built")
 	// Flags that probably shouldn't be flags of soong_build, but we haven't found
 	// the time to remove them yet
@@ -422,6 +422,7 @@
 	metricsDir := availableEnv["LOG_DIR"]
 
 	ctx := newContext(configuration)
+	android.StartBackgroundMetrics(configuration)
 
 	var finalOutputFile string
 
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 3b8f4f5..c94ff07 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -91,14 +91,6 @@
 		config:      buildActionConfig,
 		stdio:       stdio,
 		run:         runMake,
-	}, {
-		flag:        "--finalize-bazel-metrics",
-		description: "finalize b metrics and upload",
-		config:      build.UploadOnlyConfig,
-		stdio:       stdio,
-		// Finalize-bazel-metrics mode updates metrics files and calls the metrics
-		// uploader. This marks the end of a b invocation.
-		run: finalizeBazelMetrics,
 	},
 }
 
@@ -190,8 +182,12 @@
 		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)
 
@@ -199,7 +195,6 @@
 	soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
 	rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
 	bp2buildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"bp2build_metrics.pb")
-	bazelMetricsFile := filepath.Join(logsDir, c.logsPrefix+"bazel_metrics.pb")
 	soongBuildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_build_metrics.pb")
 
 	metricsFiles := []string{
@@ -207,7 +202,6 @@
 		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.
 	}
@@ -223,6 +217,15 @@
 		log.Verbosef("  [%d] %s", i, arg)
 	}
 
+	// We need to call preProductConfigSetup before we can do product config, which is how we get
+	// PRODUCT_CONFIG_RELEASE_MAPS set for the final product config for the build.
+	// When product config uses a declarative language, we won't need to rerun product config.
+	preProductConfigSetup(buildCtx, config)
+	if build.SetProductReleaseConfigMaps(buildCtx, config) {
+		log.Verbose("Product release config maps found\n")
+		config = freshConfig()
+	}
+
 	defer func() {
 		stat.Finish()
 		criticalPath.WriteToMetrics(met)
@@ -235,7 +238,9 @@
 
 }
 
-func logAndSymlinkSetup(buildCtx build.Context, config build.Config) {
+// This function must not modify config, since product config may cause us to recreate the config,
+// and we won't call this function a second time.
+func preProductConfigSetup(buildCtx build.Context, config build.Config) {
 	log := buildCtx.ContextImpl.Logger
 	logsPrefix := config.GetLogsPrefix()
 	build.SetupOutDir(buildCtx, config)
@@ -247,10 +252,9 @@
 	soongMetricsFile := filepath.Join(logsDir, logsPrefix+"soong_metrics")
 	bp2buildMetricsFile := filepath.Join(logsDir, logsPrefix+"bp2build_metrics.pb")
 	soongBuildMetricsFile := filepath.Join(logsDir, logsPrefix+"soong_build_metrics.pb")
-	bazelMetricsFile := filepath.Join(logsDir, logsPrefix+"bazel_metrics.pb")
 
 	//Delete the stale metrics files
-	staleFileSlice := []string{buildErrorFile, rbeMetricsFile, soongMetricsFile, bp2buildMetricsFile, soongBuildMetricsFile, bazelMetricsFile}
+	staleFileSlice := []string{buildErrorFile, rbeMetricsFile, soongMetricsFile, bp2buildMetricsFile, soongBuildMetricsFile}
 	if err := deleteStaleMetrics(staleFileSlice); err != nil {
 		log.Fatalln(err)
 	}
@@ -322,7 +326,6 @@
 }
 
 func dumpVar(ctx build.Context, config build.Config, args []string) {
-	logAndSymlinkSetup(ctx, config)
 	flags := flag.NewFlagSet("dumpvar", flag.ExitOnError)
 	flags.SetOutput(ctx.Writer)
 
@@ -375,7 +378,6 @@
 }
 
 func dumpVars(ctx build.Context, config build.Config, args []string) {
-	logAndSymlinkSetup(ctx, config)
 
 	flags := flag.NewFlagSet("dumpvars", flag.ExitOnError)
 	flags.SetOutput(ctx.Writer)
@@ -555,7 +557,6 @@
 }
 
 func runMake(ctx build.Context, config build.Config, _ []string) {
-	logAndSymlinkSetup(ctx, config)
 	logsDir := config.LogsDir()
 	if config.IsVerbose() {
 		writer := ctx.Writer
@@ -691,9 +692,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)
@@ -701,28 +704,3 @@
 		ctx.Println("Failed to increase file limit:", err)
 	}
 }
-
-func finalizeBazelMetrics(ctx build.Context, config build.Config, args []string) {
-	updateTotalRealTime(ctx, config, args)
-
-	logsDir := config.LogsDir()
-	logsPrefix := config.GetLogsPrefix()
-	bazelMetricsFile := filepath.Join(logsDir, logsPrefix+"bazel_metrics.pb")
-	bazelProfileFile := filepath.Join(logsDir, logsPrefix+"analyzed_bazel_profile.txt")
-	build.ProcessBazelMetrics(bazelProfileFile, bazelMetricsFile, ctx, config)
-}
-func updateTotalRealTime(ctx build.Context, config build.Config, args []string) {
-	soongMetricsFile := filepath.Join(config.LogsDir(), "soong_metrics")
-
-	//read file into proto
-	data, err := os.ReadFile(soongMetricsFile)
-	if err != nil {
-		ctx.Fatal(err)
-	}
-	met := ctx.ContextImpl.Metrics
-
-	err = met.UpdateTotalRealTimeAndNonZeroExit(data, config.BazelExitCode())
-	if err != nil {
-		ctx.Fatal(err)
-	}
-}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index ba41f4a..c871e85 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.
 
@@ -691,45 +691,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(),
-		TestOnlyArtBootImageJars:           android.EmptyConfiguredJarList(),
-		SystemServerJars:                   android.EmptyConfiguredJarList(),
-		SystemServerApps:                   nil,
-		ApexSystemServerJars:               android.EmptyConfiguredJarList(),
-		StandaloneSystemServerJars:         android.EmptyConfiguredJarList(),
-		ApexStandaloneSystemServerJars:     android.EmptyConfiguredJarList(),
-		SpeedApps:                          nil,
-		PreoptFlags:                        nil,
-		DefaultCompilerFilter:              "",
-		SystemServerCompilerFilter:         "",
-		GenerateDMFiles:                    false,
-		NoDebugInfo:                        false,
-		DontResolveStartupStrings:          false,
-		AlwaysSystemServerDebugInfo:        false,
-		NeverSystemServerDebugInfo:         false,
-		AlwaysOtherDebugInfo:               false,
-		NeverOtherDebugInfo:                false,
-		IsEng:                              false,
-		SanitizeLite:                       false,
-		DefaultAppImages:                   false,
-		Dex2oatXmx:                         "",
-		Dex2oatXms:                         "",
-		EmptyDirectory:                     "empty_dir",
-		CpuVariant:                         nil,
-		InstructionSetFeatures:             nil,
-		BootImageProfiles:                  nil,
-		BootFlags:                          "",
-		Dex2oatImageXmx:                    "",
-		Dex2oatImageXms:                    "",
+		DisablePreopt:                  false,
+		DisablePreoptModules:           nil,
+		OnlyPreoptArtBootImage:         false,
+		HasSystemOther:                 false,
+		PatternsOnSystemOther:          nil,
+		DisableGenerateProfile:         false,
+		ProfileDir:                     "",
+		BootJars:                       android.EmptyConfiguredJarList(),
+		ApexBootJars:                   android.EmptyConfiguredJarList(),
+		ArtApexJars:                    android.EmptyConfiguredJarList(),
+		TestOnlyArtBootImageJars:       android.EmptyConfiguredJarList(),
+		SystemServerJars:               android.EmptyConfiguredJarList(),
+		SystemServerApps:               nil,
+		ApexSystemServerJars:           android.EmptyConfiguredJarList(),
+		StandaloneSystemServerJars:     android.EmptyConfiguredJarList(),
+		ApexStandaloneSystemServerJars: android.EmptyConfiguredJarList(),
+		SpeedApps:                      nil,
+		PreoptFlags:                    nil,
+		DefaultCompilerFilter:          "",
+		SystemServerCompilerFilter:     "",
+		GenerateDMFiles:                false,
+		NoDebugInfo:                    false,
+		DontResolveStartupStrings:      false,
+		AlwaysSystemServerDebugInfo:    false,
+		NeverSystemServerDebugInfo:     false,
+		AlwaysOtherDebugInfo:           false,
+		NeverOtherDebugInfo:            false,
+		IsEng:                          false,
+		SanitizeLite:                   false,
+		DefaultAppImages:               false,
+		Dex2oatXmx:                     "",
+		Dex2oatXms:                     "",
+		EmptyDirectory:                 "empty_dir",
+		CpuVariant:                     nil,
+		InstructionSetFeatures:         nil,
+		BootImageProfiles:              nil,
+		BootFlags:                      "",
+		Dex2oatImageXmx:                "",
+		Dex2oatImageXms:                "",
 	}
 }
 
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 29ae188..c13e14a 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -124,12 +124,7 @@
 		return true
 	}
 
-	// If OnlyPreoptBootImageAndSystemServer=true and module is not in boot class path skip
-	// Also preopt system server jars since selinux prevents system server from loading anything from
-	// /data. If we don't do this they will need to be extracted which is not favorable for RAM usage
-	// or performance. If PreoptExtractedApk is true, we ignore the only preopt boot image options.
-	if global.OnlyPreoptBootImageAndSystemServer && !global.BootJars.ContainsJar(module.Name) &&
-		!global.AllSystemServerJars(ctx).ContainsJar(module.Name) && !module.PreoptExtractedApk {
+	if global.OnlyPreoptArtBootImage && !module.PreoptExtractedApk {
 		return true
 	}
 
diff --git a/docs/clion.md b/docs/clion.md
index d6ae19a..110891b 100644
--- a/docs/clion.md
+++ b/docs/clion.md
@@ -3,6 +3,10 @@
 Soong can generate CLion projects. This is intended for source code editing
 only. Build should still be done via make/m/mm(a)/mmm(a).
 
+Note: alternatively, you can use
+[aidegen to generate a Clion or VSCode project](https://android.googlesource.com/platform/tools/asuite/+/refs/heads/master/aidegen/README.md)
+with a single command, using the `-i c` flag.
+
 CMakeLists.txt project file generation is enabled via environment variable:
 
 ```bash
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 9423531..b7d2971 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -65,6 +65,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)
 
@@ -149,12 +150,16 @@
 	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
 }
 
 type Defaults struct {
@@ -345,9 +350,16 @@
 	// 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())
 
 	// Call InstallFile even when uninstallable to make the module included in the package
@@ -404,8 +416,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{
@@ -508,6 +526,7 @@
 	// This module is host-only
 	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
+	android.InitBazelModule(module)
 	return module
 }
 
@@ -571,6 +590,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 {
@@ -759,7 +791,7 @@
 		filename = *moduleProps.Filename
 	} else if moduleProps.Filename_from_src != nil && *moduleProps.Filename_from_src {
 		if moduleProps.Src != nil {
-			filename = *moduleProps.Src
+			filename = android.BazelLabelForModuleSrcSingle(ctx, *moduleProps.Src).Label
 		}
 		filenameFromSrc = true
 	} else {
@@ -767,8 +799,8 @@
 	}
 
 	var dir = module.installDirBase
-	if subDir := module.subdirProperties.Sub_dir; subDir != nil {
-		dir = dir + "/" + *subDir
+	if module.SubDir() != "" {
+		dir = dir + "/" + module.SubDir()
 	}
 
 	var installable bazel.BoolAttribute
@@ -796,8 +828,9 @@
 // which we treat as *PrebuiltFile*
 func (module *PrebuiltEtc) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
 	var dir = module.installDirBase
-	// prebuilt_file supports only `etc` or `usr/share`
-	if !(dir == "etc" || dir == "usr/share") {
+	// prebuilt_file only supports "etc" or "usr/share" or "." as module installDirBase
+	if !(dir == "etc" || dir == "usr/share" || dir == ".") {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "dir")
 		return
 	}
 
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 023c69a..3d49114 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -104,6 +104,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 +335,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 +350,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())
 	}
 
diff --git a/genrule/allowlists.go b/genrule/allowlists.go
index afa52cc..4674e19 100644
--- a/genrule/allowlists.go
+++ b/genrule/allowlists.go
@@ -16,129 +16,86 @@
 
 var (
 	DepfileAllowList = []string{
+		// go/keep-sorted start
 		"depfile_allowed_for_test",
+		"tflite_support_metadata_schema",
 		"tflite_support_spm_config",
 		"tflite_support_spm_encoder_config",
-		"gen_uwb_core_proto",
-		"libtextclassifier_fbgen_utils_flatbuffers_flatbuffers_test",
-		"libtextclassifier_fbgen_utils_lua_utils_tests",
-		"libtextclassifier_fbgen_lang_id_common_flatbuffers_model",
-		"libtextclassifier_fbgen_lang_id_common_flatbuffers_embedding-network",
-		"libtextclassifier_fbgen_annotator_datetime_datetime",
-		"libtextclassifier_fbgen_annotator_model",
-		"libtextclassifier_fbgen_annotator_experimental_experimental",
-		"libtextclassifier_fbgen_annotator_entity-data",
-		"libtextclassifier_fbgen_annotator_person_name_person_name_model",
-		"libtextclassifier_fbgen_utils_tflite_text_encoder_config",
-		"libtextclassifier_fbgen_utils_codepoint-range",
-		"libtextclassifier_fbgen_utils_intents_intent-config",
-		"libtextclassifier_fbgen_utils_flatbuffers_flatbuffers",
-		"libtextclassifier_fbgen_utils_zlib_buffer",
-		"libtextclassifier_fbgen_utils_tokenizer",
-		"libtextclassifier_fbgen_utils_grammar_rules",
-		"libtextclassifier_fbgen_utils_grammar_semantics_expression",
-		"libtextclassifier_fbgen_utils_resources",
-		"libtextclassifier_fbgen_utils_i18n_language-tag",
-		"libtextclassifier_fbgen_utils_normalization",
-		"libtextclassifier_fbgen_utils_container_bit-vector",
-		"libtextclassifier_fbgen_actions_actions-entity-data",
-		"libtextclassifier_fbgen_actions_actions_model",
-		"libtextclassifier_fbgen_utils_grammar_testing_value",
+		// go/keep-sorted end
 	}
 
 	SandboxingDenyModuleList = []string{
-		"RsBalls-rscript",
-		"pvmfw_fdt_template_rs",
-		"RSTest_v14-rscript",
-		"com.android.apex.test.bar_stripped",
-		"com.android.apex.test.sharedlibs_secondary_generated",
+		// go/keep-sorted start
+		"CtsApkVerityTestDebugFiles",
+		"ImageProcessing-rscript",
+		"ImageProcessing2-rscript",
 		"ImageProcessingJB-rscript",
+		"MultiDexLegacyTestApp_genrule",
 		"RSTest-rscript",
-		"BluetoothGeneratedDumpsysBinarySchema_bfbs",
+		"RSTest_v11-rscript",
+		"RSTest_v14-rscript",
+		"RSTest_v16-rscript",
+		"Refocus-rscript",
+		"RsBalls-rscript",
+		"ScriptGroupTest-rscript",
+		"TracingVMProtoStub_cc",
 		"TracingVMProtoStub_h",
 		"VehicleServerProtoStub_cc",
-		"AudioFocusControlProtoStub_cc",
-		"AudioFocusControlProtoStub_h",
-		"TracingVMProtoStub_cc",
+		"VehicleServerProtoStub_cc@2.0-grpc-trout",
+		"VehicleServerProtoStub_cc@default-grpc",
 		"VehicleServerProtoStub_h",
-		"hidl2aidl_translate_cpp_test_gen_headers",
-		"hidl2aidl_translate_cpp_test_gen_src",
-		"hidl2aidl_translate_java_test_gen_src",
-		"hidl2aidl_translate_ndk_test_gen_headers",
-		"hidl2aidl_translate_ndk_test_gen_src",
-		"hidl_hash_test_gen",
-		"nos_app_avb_service_genc++",
-		"nos_app_avb_service_genc++_headers",
-		"nos_app_avb_service_genc++_mock",
-		"nos_app_identity_service_genc++",
-		"nos_app_keymaster_service_genc++",
-		"nos_generator_test_service_genc++_headers",
-		"nos_generator_test_service_genc++_mock",
-		"r8retrace-run-retrace",
-		"ltp_config_arm",
-		"ltp_config_arm_64_hwasan",
-		"ltp_config_arm_lowmem",
-		"ltp_config_arm_64",
-		"ltp_config_riscv_64",
-		"ltp_config_x86_64",
-		"vm-tests-tf-lib",
-		"hidl_cpp_impl_test_gen-headers",
-		"Refocus-rscript",
-		"RSTest_v11-rscript",
-		"RSTest_v16-rscript",
-		"ScriptGroupTest-rscript",
-		"ImageProcessing2-rscript",
-		"ImageProcessing-rscript",
-		"com.android.apex.test.pony_stripped",
-		"com.android.apex.test.baz_stripped",
-		"com.android.apex.test.foo_stripped",
-		"com.android.apex.test.sharedlibs_generated",
-		"BlueberryFacadeAndCertGeneratedStub_py",
-		"BlueberryFacadeGeneratedStub_cc",
-		"BlueberryFacadeGeneratedStub_h",
-		"BluetoothGeneratedDumpsysDataSchema_h",
+		"VehicleServerProtoStub_h@2.0-grpc-trout",
+		"VehicleServerProtoStub_h@default-grpc",
+		"aidl-golden-test-build-hook-gen",
+		"aidl_camera_build_version",
+		"android-cts-verifier",
+		"android-support-multidex-instrumentation-version",
+		"android-support-multidex-version",
+		"angle_commit_id",
+		"atest_integration_fake_src",
+		"awkgram.tab.h",
 		"c2hal_test_genc++",
 		"c2hal_test_genc++_headers",
-		"hidl2aidl_test_gen_aidl",
-		"hidl_error_test_gen",
-		"hidl_export_test_gen-headers",
-		"hidl_format_test_diff",
-		"hidl_hash_version_gen",
-		"libbt_topshim_facade_py_proto",
-		"nos_app_identity_service_genc++_headers",
-		"nos_app_identity_service_genc++_mock",
-		"nos_app_keymaster_service_genc++_headers",
-		"nos_app_keymaster_service_genc++_mock",
-		"nos_app_weaver_service_genc++",
-		"nos_app_weaver_service_genc++_headers",
-		"nos_app_weaver_service_genc++_mock",
-		"nos_generator_test_service_genc++",
-		"aidl_camera_build_version",
-		"cronet_aml_base_android_runtime_unchecked_jni_headers",
+		"camera-its",
+		"checkIn-service-stub-lite",
+		"chre_atoms_log.h",
 		"cronet_aml_base_android_runtime_jni_headers",
-		"aidl-golden-test-build-hook-gen",
-		"PacketStreamerStub_h",
-		"FrontendStub_cc",
-		"FrontendStub_h",
-		"PacketStreamerStub_cc",
-		"pixelstatsatoms.h",
-		"pixelatoms_defs.h",
-		"pixelstatsatoms.cpp",
-		"hidl_java_impl_test_gen",
 		"cronet_aml_base_android_runtime_jni_headers__testing",
+		"cronet_aml_base_android_runtime_unchecked_jni_headers",
 		"cronet_aml_base_android_runtime_unchecked_jni_headers__testing",
-		"hidl_cpp_impl_test_gen-sources",
+		"deqp_spvtools_update_build_version",
+		"emp_ematch.yacc.c",
+		"emp_ematch.yacc.h",
+		"fdt_test_tree_empty_memory_range_dtb",
 		"fdt_test_tree_multiple_memory_ranges_dtb",
 		"fdt_test_tree_one_memory_range_dtb",
-		"fdt_test_tree_empty_memory_range_dtb",
-		"ltp_config_arm_64_lowmem",
-		"ltp_config_arm_64_lowmem_hwasan",
-		"ltp_config_x86",
+		"gen_corrupt_rebootless_apex",
+		"gen_key_mismatch_capex",
 		"libbssl_sys_src_nostd",
+		"libc_musl_sysroot_bits",
+		"libchrome-crypto-include",
+		"libchrome-include",
+		"libcore-non-cts-tests-txt",
+		"libxml2_schema_fuzz_corpus",
+		"libxml2_xml_fuzz_corpus",
+		"pixelatoms_defs.h",
+		"pixelstatsatoms.cpp",
+		"pixelstatsatoms.h",
+		"pvmfw_fdt_template_rs",
+		"r8retrace-dexdump-sample-app",
+		"r8retrace-run-retrace",
+		"seller-frontend-service-stub-lite",
+		"swiftshader_spvtools_update_build_version",
+		"ue_unittest_erofs_imgs",
+		"vm-tests-tf-lib",
+		"vndk_abi_dump_zip",
+		// go/keep-sorted end
 	}
 
 	SandboxingDenyPathList = []string{
+		// go/keep-sorted start
 		"art/test",
-		"external/perfetto",
+		"external/cronet",
+		// go/keep-sorted end
 	}
 )
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 01cac5b..8f2c047 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -189,9 +189,6 @@
 
 	subName string
 	subDir  string
-
-	// Collect the module directory for IDE info in java/jdeps.go.
-	modulePaths []string
 }
 
 var _ android.MixedBuildBuildable = (*Module)(nil)
@@ -289,9 +286,6 @@
 func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) {
 	g.subName = ctx.ModuleSubDir()
 
-	// Collect the module directory for IDE info in java/jdeps.go.
-	g.modulePaths = append(g.modulePaths, ctx.ModuleDir())
-
 	if len(g.properties.Export_include_dirs) > 0 {
 		for _, dir := range g.properties.Export_include_dirs {
 			g.exportedIncludeDirs = append(g.exportedIncludeDirs,
@@ -668,7 +662,6 @@
 			dpInfo.Deps = append(dpInfo.Deps, src)
 		}
 	}
-	dpInfo.Paths = append(dpInfo.Paths, g.modulePaths...)
 }
 
 func (g *Module) AndroidMk() android.AndroidMkData {
diff --git a/jar/jar.go b/jar/jar.go
index f164ee1..54eded9 100644
--- a/jar/jar.go
+++ b/jar/jar.go
@@ -166,10 +166,23 @@
 	}
 	s.IsIdentRune = javaIdentRune
 
-	tok := s.Scan()
-	if sErr != nil {
-		return "", sErr
+	var tok rune
+	for {
+		tok = s.Scan()
+		if sErr != nil {
+			return "", sErr
+		}
+		// If the first token is an annotation, it could be annotating a package declaration, so consume them.
+		// Note that this does not support "complex" annotations with attributes, e.g. @Foo(x=y).
+		if tok != '@' {
+			break
+		}
+		tok = s.Scan()
+		if tok != scanner.Ident || sErr != nil {
+			return "", fmt.Errorf("expected annotation identifier, got @%v", tok)
+		}
 	}
+
 	if tok == scanner.Ident {
 		switch s.TokenText() {
 		case "package":
@@ -189,9 +202,6 @@
 		default:
 			return "", fmt.Errorf(`expected first token of java file to be "package", got %q`, s.TokenText())
 		}
-	} else if tok == '@' {
-		// File has no package statement, first token is an annotation
-		return "", nil
 	} else if tok == scanner.EOF {
 		// File no package statement, it has no non-whitespace non-comment tokens
 		return "", nil
diff --git a/jar/jar_test.go b/jar/jar_test.go
index c92011e..61da9bb 100644
--- a/jar/jar_test.go
+++ b/jar/jar_test.go
@@ -61,6 +61,16 @@
 			in:      "package 0foo.bar;",
 			wantErr: true,
 		},
+		{
+			name: "annotations",
+			in:   "@NonNullApi\n@X\npackage foo.bar;",
+			want: "foo.bar",
+		},
+		{
+			name:    "complex annotation",
+			in:      "@Foo(x=y)\n@package foo.bar;",
+			wantErr: true, // Complex annotation not supported yet.
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/java/Android.bp b/java/Android.bp
index 4450c42..29c0957 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -15,6 +15,7 @@
         "soong-dexpreopt",
         "soong-genrule",
         "soong-java-config",
+        "soong-testing",
         "soong-provenance",
         "soong-python",
         "soong-remoteexec",
diff --git a/java/aapt2.go b/java/aapt2.go
index 3bb70b5..17ee6ee 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
diff --git a/java/aar.go b/java/aar.go
index f28d971..e579008 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -66,6 +66,9 @@
 	// ones.
 	Aapt_include_all_resources *bool
 
+	// list of files to use as assets.
+	Assets []string `android:"path"`
+
 	// list of directories relative to the Blueprints file containing assets.
 	// Defaults to ["assets"] if a directory called assets exists.  Set to []
 	// to disable the default.
@@ -99,6 +102,9 @@
 
 	// 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 {
@@ -131,6 +137,10 @@
 	resourcesNodesDepSet *android.DepSet[*resourcesNode]
 	rroDirsDepSet        *android.DepSet[rroDir]
 	manifestsDepSet      *android.DepSet[android.Path]
+
+	manifestValues struct {
+		applicationId string
+	}
 }
 
 type split struct {
@@ -155,6 +165,10 @@
 	return BoolDefault(a.aaptProperties.Use_resource_processor, false)
 }
 
+func (a *aapt) filterProduct() string {
+	return String(a.aaptProperties.Filter_product)
+}
+
 func (a *aapt) ExportPackage() android.Path {
 	return a.exportPackage
 }
@@ -192,6 +206,11 @@
 	linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)
 
 	// Find implicit or explicit asset and resource dirs
+	assets := android.PathsRelativeToModuleSourceDir(android.SourceInput{
+		Context:     ctx,
+		Paths:       a.aaptProperties.Assets,
+		IncludeDirs: false,
+	})
 	assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets")
 	resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res")
 	resourceZips := android.PathsForModuleSrc(ctx, a.aaptProperties.Resource_zips)
@@ -226,6 +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)
@@ -301,23 +342,29 @@
 		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
+}
 
-	staticResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedDeps, libFlags :=
-		aaptLibs(ctx, sdkContext, classLoaderContexts)
+func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptions) {
+
+	staticResourcesNodesDepSet, sharedResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedExportPackages, libFlags :=
+		aaptLibs(ctx, opts.sdkContext, opts.classLoaderContexts)
 
 	// Exclude any libraries from the supplied list.
-	classLoaderContexts = classLoaderContexts.ExcludeLibs(excludedLibs)
+	opts.classLoaderContexts = opts.classLoaderContexts.ExcludeLibs(opts.excludedLibs)
 
 	// App manifest file
 	manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
 	manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
 
 	manifestPath := ManifestFixer(ctx, manifestSrcPath, ManifestFixerParams{
-		SdkContext:                     sdkContext,
-		ClassLoaderContexts:            classLoaderContexts,
+		SdkContext:                     opts.sdkContext,
+		ClassLoaderContexts:            opts.classLoaderContexts,
 		IsLibrary:                      a.isLibrary,
 		DefaultManifestVersion:         a.defaultManifestVersion,
 		UseEmbeddedNativeLibs:          a.useEmbeddedNativeLibs,
@@ -325,10 +372,11 @@
 		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)
@@ -341,7 +389,12 @@
 	transitiveManifestPaths = append(transitiveManifestPaths, staticManifestsDepSet.ToList()...)
 
 	if len(transitiveManifestPaths) > 1 && !Bool(a.aaptProperties.Dont_merge_manifests) {
-		a.mergedManifestFile = manifestMerger(ctx, transitiveManifestPaths[0], transitiveManifestPaths[1:], a.isLibrary)
+		manifestMergerParams := ManifestMergerParams{
+			staticLibManifests: transitiveManifestPaths[1:],
+			isLibrary:          a.isLibrary,
+			packageName:        a.manifestValues.applicationId,
+		}
+		a.mergedManifestFile = manifestMerger(ctx, transitiveManifestPaths[0], manifestMergerParams)
 		if !a.isLibrary {
 			// Only use the merged manifest for applications.  For libraries, the transitive closure of manifests
 			// will be propagated to the final application and merged there.  The merged manifest for libraries is
@@ -352,12 +405,12 @@
 		a.mergedManifestFile = manifestPath
 	}
 
-	compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, sdkContext, manifestPath)
+	compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, opts.sdkContext, manifestPath)
 
 	linkFlags = append(linkFlags, libFlags...)
-	linkDeps = append(linkDeps, sharedDeps...)
+	linkDeps = append(linkDeps, sharedExportPackages...)
 	linkDeps = append(linkDeps, staticDeps.resPackages()...)
-	linkFlags = append(linkFlags, extraLinkFlags...)
+	linkFlags = append(linkFlags, opts.extraLinkFlags...)
 	if a.isLibrary {
 		linkFlags = append(linkFlags, "--static-lib")
 	}
@@ -386,7 +439,7 @@
 	var compiledResDirs []android.Paths
 	for _, dir := range resDirs {
 		a.resourceFiles = append(a.resourceFiles, dir.files...)
-		compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths())
+		compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files, compileFlags, a.filterProduct()).Paths())
 	}
 
 	for i, zip := range resZips {
@@ -413,6 +466,11 @@
 				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.
@@ -440,7 +498,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
@@ -621,7 +679,7 @@
 
 // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
 func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap) (
-	staticResourcesNodes *android.DepSet[*resourcesNode], staticRRODirs *android.DepSet[rroDir],
+	staticResourcesNodes, sharedResourcesNodes *android.DepSet[*resourcesNode], staticRRODirs *android.DepSet[rroDir],
 	staticManifests *android.DepSet[android.Path], sharedLibs android.Paths, flags []string) {
 
 	if classLoaderContexts == nil {
@@ -635,7 +693,8 @@
 		sharedLibs = append(sharedLibs, sdkDep.jars...)
 	}
 
-	var resourcesNodeDepSets []*android.DepSet[*resourcesNode]
+	var staticResourcesNodeDepSets []*android.DepSet[*resourcesNode]
+	var sharedResourcesNodeDepSets []*android.DepSet[*resourcesNode]
 	rroDirsDepSetBuilder := android.NewDepSetBuilder[rroDir](android.TOPOLOGICAL)
 	manifestsDepSetBuilder := android.NewDepSetBuilder[android.Path](android.TOPOLOGICAL)
 
@@ -653,6 +712,7 @@
 			// Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2.
 		case sdkLibTag, libTag:
 			if exportPackage != nil {
+				sharedResourcesNodeDepSets = append(sharedResourcesNodeDepSets, aarDep.ResourcesNodeDepSet())
 				sharedLibs = append(sharedLibs, exportPackage)
 			}
 		case frameworkResTag:
@@ -661,7 +721,7 @@
 			}
 		case staticLibTag:
 			if exportPackage != nil {
-				resourcesNodeDepSets = append(resourcesNodeDepSets, aarDep.ResourcesNodeDepSet())
+				staticResourcesNodeDepSets = append(staticResourcesNodeDepSets, aarDep.ResourcesNodeDepSet())
 				rroDirsDepSetBuilder.Transitive(aarDep.RRODirsDepSet())
 				manifestsDepSetBuilder.Transitive(aarDep.ManifestsDepSet())
 			}
@@ -677,7 +737,9 @@
 	// 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(resourcesNodeDepSets))
+		android.ReverseSliceInPlace(staticResourcesNodeDepSets))
+	sharedResourcesNodes = android.NewDepSet(android.TOPOLOGICAL, nil,
+		android.ReverseSliceInPlace(sharedResourcesNodeDepSets))
 
 	staticRRODirs = rroDirsDepSetBuilder.Build()
 	staticManifests = manifestsDepSetBuilder.Build()
@@ -690,7 +752,7 @@
 		flags = append(flags, "-I "+sharedLib.String())
 	}
 
-	return staticResourcesNodes, staticRRODirs, staticManifests, sharedLibs, flags
+	return staticResourcesNodes, sharedResourcesNodes, staticRRODirs, staticManifests, sharedLibs, flags
 }
 
 type AndroidLibrary struct {
@@ -729,7 +791,13 @@
 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()
 
@@ -750,8 +818,11 @@
 	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)
+	ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
+	a.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
+	a.extraProguardFlagFiles = append(a.extraProguardFlagFiles, a.exportedProguardFlagFiles...)
+	a.extraProguardFlagFiles = append(a.extraProguardFlagFiles, a.proguardOptionsFile)
 
 	var extraSrcJars android.Paths
 	var extraCombinedJars android.Paths
@@ -777,10 +848,6 @@
 		ctx.CheckbuildFile(a.aarFile)
 	}
 
-	proguardSpecInfo := a.collectProguardSpecInfo(ctx)
-	ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
-	a.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
-
 	prebuiltJniPackages := android.Paths{}
 	ctx.VisitDirectDeps(func(module android.Module) {
 		if info, ok := ctx.OtherModuleProvider(module, JniPackageProvider).(JniPackageInfo); ok {
@@ -794,6 +861,17 @@
 	}
 }
 
+func (a *AndroidLibrary) IDEInfo(dpInfo *android.IdeInfo) {
+	a.Library.IDEInfo(dpInfo)
+	a.aapt.IDEInfo(dpInfo)
+}
+
+func (a *aapt) IDEInfo(dpInfo *android.IdeInfo) {
+	if a.useResourceProcessorBusyBox() {
+		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
@@ -1080,10 +1158,12 @@
 	linkFlags = append(linkFlags, "--manifest "+a.manifest.String())
 	linkDeps = append(linkDeps, a.manifest)
 
-	staticResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedLibs, libFlags :=
+	staticResourcesNodesDepSet, sharedResourcesNodesDepSet, staticRRODirsDepSet, staticManifestsDepSet, sharedLibs, libFlags :=
 		aaptLibs(ctx, android.SdkContext(a), nil)
 
+	_ = sharedResourcesNodesDepSet
 	_ = staticRRODirsDepSet
+
 	staticDeps := transitiveAarDeps(staticResourcesNodesDepSet.ToList())
 
 	linkDeps = append(linkDeps, sharedLibs...)
@@ -1223,6 +1303,7 @@
 type bazelAapt struct {
 	Manifest       bazel.Label
 	Resource_files bazel.LabelListAttribute
+	Resource_zips  bazel.LabelListAttribute
 	Assets_dir     bazel.StringAttribute
 	Assets         bazel.LabelListAttribute
 }
@@ -1267,15 +1348,30 @@
 		assets = bazel.MakeLabelList(android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir)))
 
 	}
+	var resourceZips bazel.LabelList
+	if len(a.aaptProperties.Resource_zips) > 0 {
+		if ctx.ModuleName() == "framework-res" {
+			resourceZips = android.BazelLabelForModuleSrc(ctx, a.aaptProperties.Resource_zips)
+		} else {
+			//TODO: b/301593550 - Implement support for this
+			ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "resource_zips")
+			return &bazelAapt{}, false
+		}
+	}
 	return &bazelAapt{
 		android.BazelLabelForModuleSrcSingle(ctx, manifest),
 		bazel.MakeLabelListAttribute(resourceFiles),
+		bazel.MakeLabelListAttribute(resourceZips),
 		assetsDir,
 		bazel.MakeLabelListAttribute(assets),
 	}, true
 }
 
 func (a *AARImport) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
+	if len(a.properties.Aars) == 0 {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "aars can't be empty")
+		return
+	}
 	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.
@@ -1340,10 +1436,12 @@
 	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.MarkBp2buildUnconvertible(
-			bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED,
-			"Module has direct dependencies but no sources. Bazel will not allow this.")
-		return
+		// android_library does not accept deps when there are no srcs because
+		// there is no compilation happening, but it accepts exports.
+		// The non-empty deps here are unnecessary as deps on the android_library
+		// since they aren't being propagated to any dependencies.
+		// So we can drop deps here.
+		deps = bazel.LabelListAttribute{}
 	}
 	name := a.Name()
 	props := AndroidLibraryBazelTargetModuleProperties()
@@ -1352,6 +1450,9 @@
 	if !supported {
 		return
 	}
+	if hasJavaResources := aaptAttrs.ConvertJavaResources(ctx, commonAttrs); hasJavaResources {
+		return
+	}
 	ctx.CreateBazelTargetModule(
 		props,
 		android.CommonAttributes{Name: name},
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
index b12d778..5909b1e 100644
--- a/java/android_manifest_test.go
+++ b/java/android_manifest_test.go
@@ -15,8 +15,9 @@
 package java
 
 import (
-	"android/soong/android"
 	"testing"
+
+	"android/soong/android"
 )
 
 func TestManifestMerger(t *testing.T) {
@@ -77,10 +78,7 @@
 		}
 	`
 
-	result := android.GroupFixturePreparers(
-		PrepareForTestWithJavaDefaultModules,
-		PrepareForTestWithOverlayBuildComponents,
-	).RunTestWithBp(t, bp)
+	result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, bp)
 
 	manifestMergerRule := result.ModuleForTests("app", "android_common").Rule("manifestMerger")
 	android.AssertPathRelativeToTopEquals(t, "main manifest",
@@ -101,3 +99,38 @@
 		},
 		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 b7e2d2f..84f78c8 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,7 +81,7 @@
 	} 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 library.properties.Headers_only {
+	} 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 {
@@ -341,10 +343,15 @@
 			Disabled: true,
 		}}
 	}
+	var required []string
+	if proptools.Bool(app.appProperties.Generate_product_characteristics_rro) {
+		required = []string{app.productCharacteristicsRROPackageName()}
+	}
 	return []android.AndroidMkEntries{android.AndroidMkEntries{
 		Class:      "APPS",
 		OutputFile: android.OptionalPathForPath(app.outputFile),
 		Include:    "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+		Required:   required,
 		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
 			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
 				// App module names can be overridden.
diff --git a/java/app.go b/java/app.go
index dabc319..9b7f4c4 100755
--- a/java/app.go
+++ b/java/app.go
@@ -22,6 +22,7 @@
 	"path/filepath"
 	"strings"
 
+	"android/soong/testing"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -130,6 +131,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
@@ -308,6 +319,13 @@
 }
 
 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)
 }
 
@@ -447,8 +465,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())
 	}
 
@@ -481,8 +500,15 @@
 	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...)
+	a.aapt.buildActions(ctx,
+		aaptBuildActionOptions{
+			android.SdkContext(a),
+			a.classLoaderContexts,
+			a.usesLibraryProperties.Exclude_uses_libs,
+			a.enforceDefaultTargetSdkVersion(),
+			aaptLinkFlags,
+		},
+	)
 
 	// apps manifests are handled by aapt, don't let Module see them
 	a.properties.Manifest = nil
@@ -1042,6 +1068,8 @@
 		}
 	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)
 }
@@ -1066,6 +1094,19 @@
 
 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{}
@@ -1092,9 +1133,66 @@
 	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
@@ -1104,6 +1202,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 {
@@ -1148,6 +1248,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 {
@@ -1159,6 +1266,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{})
 }
 
 func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig android.Path) android.Path {
@@ -1252,6 +1360,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 {
@@ -1548,7 +1658,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
 	}
 
@@ -1638,6 +1748,15 @@
 	Updatable        *bool
 }
 
+func (b bazelAapt) ConvertJavaResources(ctx android.Bp2buildMutatorContext, javaAttrs *javaCommonAttributes) bool {
+	// TODO (b/300470246) bp2build support for java_resources & java_resource_dirs in android rules
+	hasJavaResources := !javaAttrs.javaResourcesAttributes.Resources.IsEmpty()
+	if hasJavaResources {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "(b/300470246) java resources in android_* module")
+	}
+	return hasJavaResources
+}
+
 func convertWithBp2build(ctx android.Bp2buildMutatorContext, a *AndroidApp) (bool, android.CommonAttributes, *bazelAndroidAppAttributes) {
 	aapt, supported := a.convertAaptAttrsWithBp2Build(ctx)
 	if !supported {
@@ -1674,9 +1793,25 @@
 		Updatable:        a.appProperties.Updatable,
 	}
 
-	if !BoolDefault(a.dexProperties.Optimize.Enabled, true) {
-		appAttrs.Optimize = proptools.BoolPtr(false)
-	} else {
+	// As framework-res has no sources, no deps in the Bazel sense, and java compilation, dexing and optimization is skipped by
+	// Soong specifically for it, return early here before any of the conversion work for the above is attempted.
+	if ctx.ModuleName() == "framework-res" {
+		appAttrs.bazelAapt = aapt
+		return true, android.CommonAttributes{Name: a.Name(), SkipData: proptools.BoolPtr(true)}, appAttrs
+	}
+
+	// Optimization is..
+	// - enabled by default for android_app, android_test_helper_app
+	// - disabled by default for android_test
+	//
+	// TODO(b/192032291): Disable android_test_helper_app optimization by
+	// default after auditing downstream usage.
+	if a.dexProperties.Optimize.EnabledByDefault != a.dexer.effectiveOptimizeEnabled() {
+		// Property is explicitly defined by default from default, so emit the Bazel attribute.
+		appAttrs.Optimize = proptools.BoolPtr(a.dexer.effectiveOptimizeEnabled())
+	}
+
+	if a.dexer.effectiveOptimizeEnabled() {
 		handCraftedFlags := ""
 		if Bool(a.dexProperties.Optimize.Ignore_warnings) {
 			handCraftedFlags += "-ignorewarning "
@@ -1712,6 +1847,10 @@
 	if !supported {
 		return false, android.CommonAttributes{}, &bazelAndroidAppAttributes{}
 	}
+	if hasJavaResources := aapt.ConvertJavaResources(ctx, commonAttrs); hasJavaResources {
+		return false, android.CommonAttributes{}, &bazelAndroidAppAttributes{}
+	}
+
 	depLabels := bp2BuildInfo.DepLabels
 
 	deps := depLabels.Deps
@@ -1762,11 +1901,18 @@
 // ConvertWithBp2build is used to convert android_app to Bazel.
 func (a *AndroidApp) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
 	if ok, commonAttrs, appAttrs := convertWithBp2build(ctx, a); ok {
-		props := bazel.BazelTargetModuleProperties{
-			Rule_class:        "android_binary",
-			Bzl_load_location: "//build/bazel/rules/android:android_binary.bzl",
+		var props bazel.BazelTargetModuleProperties
+		if ctx.ModuleName() == "framework-res" {
+			props = bazel.BazelTargetModuleProperties{
+				Rule_class:        "framework_resources",
+				Bzl_load_location: "//build/bazel/rules/android:framework_resources.bzl",
+			}
+		} else {
+			props = bazel.BazelTargetModuleProperties{
+				Rule_class:        "android_binary",
+				Bzl_load_location: "//build/bazel/rules/android:android_binary.bzl",
+			}
 		}
-
 		ctx.CreateBazelTargetModule(props, commonAttrs, appAttrs)
 	}
 
@@ -1790,13 +1936,12 @@
 		// an android_test_helper_app is an android_binary with testonly = True
 		commonAttrs.Testonly = proptools.BoolPtr(true)
 
-		// additionally, it sets default values differently to android_app,
+		// android_test_helper_app sets default values differently to android_app,
 		// https://cs.android.com/android/platform/superproject/main/+/main:build/soong/java/app.go;l=1273-1279;drc=e12c083198403ec694af6c625aed11327eb2bf7f
 		//
 		// installable: true (settable prop)
 		// use_embedded_native_libs: true (settable prop)
 		// lint.test: true (settable prop)
-		// optimize EnabledByDefault: true (blueprint mutated prop)
 		// AlwaysPackageNativeLibs: true (blueprint mutated prop)
 		// dexpreopt isTest: true (not prop)
 
diff --git a/java/app_test.go b/java/app_test.go
index fc57f44..5cb4a23 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -558,7 +558,6 @@
 		t.Run(testCase.name, func(t *testing.T) {
 			result := android.GroupFixturePreparers(
 				PrepareForTestWithJavaDefaultModules,
-				PrepareForTestWithOverlayBuildComponents,
 				fs.AddToFixture(),
 			).RunTestWithBp(t, fmt.Sprintf(bp, testCase.prop))
 
@@ -608,6 +607,15 @@
 				asset_dirs: ["assets_b"],
 			}
 
+			android_library {
+				name: "lib5",
+				sdk_version: "current",
+				assets: [
+					"path/to/asset_file_1",
+					"path/to/asset_file_2",
+				],
+			}
+
 			android_library_import {
 				name: "import",
 				sdk_version: "current",
@@ -616,9 +624,11 @@
 		`
 
 	testCases := []struct {
-		name          string
-		assetFlag     string
-		assetPackages []string
+		name               string
+		assetFlag          string
+		assetPackages      []string
+		tmpAssetDirInputs  []string
+		tmpAssetDirOutputs []string
 	}{
 		{
 			name: "foo",
@@ -644,6 +654,18 @@
 			name:      "lib4",
 			assetFlag: "-A assets_b",
 		},
+		{
+			name:      "lib5",
+			assetFlag: "-A out/soong/.intermediates/lib5/android_common/tmp_asset_dir",
+			tmpAssetDirInputs: []string{
+				"path/to/asset_file_1",
+				"path/to/asset_file_2",
+			},
+			tmpAssetDirOutputs: []string{
+				"out/soong/.intermediates/lib5/android_common/tmp_asset_dir/path/to/asset_file_1",
+				"out/soong/.intermediates/lib5/android_common/tmp_asset_dir/path/to/asset_file_2",
+			},
+		},
 	}
 	ctx := testApp(t, bp)
 
@@ -671,6 +693,14 @@
 				mergeAssets := m.Output("package-res.apk")
 				android.AssertPathsRelativeToTopEquals(t, "mergeAssets inputs", test.assetPackages, mergeAssets.Inputs)
 			}
+
+			if len(test.tmpAssetDirInputs) > 0 {
+				rule := m.Rule("tmp_asset_dir")
+				inputs := rule.Implicits
+				outputs := append(android.WritablePaths{rule.Output}, rule.ImplicitOutputs...).Paths()
+				android.AssertPathsRelativeToTopEquals(t, "tmp_asset_dir inputs", test.tmpAssetDirInputs, inputs)
+				android.AssertPathsRelativeToTopEquals(t, "tmp_asset_dir outputs", test.tmpAssetDirOutputs, outputs)
+			}
 		})
 	}
 }
@@ -722,10 +752,13 @@
 
 func TestAndroidResourceProcessor(t *testing.T) {
 	testCases := []struct {
-		name                string
-		appUsesRP           bool
-		directLibUsesRP     bool
-		transitiveLibUsesRP bool
+		name                            string
+		appUsesRP                       bool
+		directLibUsesRP                 bool
+		transitiveLibUsesRP             bool
+		sharedLibUsesRP                 bool
+		sharedTransitiveStaticLibUsesRP bool
+		sharedTransitiveSharedLibUsesRP bool
 
 		dontVerifyApp bool
 		appResources  []string
@@ -760,6 +793,14 @@
 		transitiveImportResources  []string
 		transitiveImportOverlays   []string
 		transitiveImportImports    []string
+
+		dontVerifyShared bool
+		sharedResources  []string
+		sharedOverlays   []string
+		sharedImports    []string
+		sharedSrcJars    []string
+		sharedClasspath  []string
+		sharedCombined   []string
 	}{
 		{
 			// Test with all modules set to use_resource_processor: false (except android_library_import modules,
@@ -779,10 +820,14 @@
 				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
 				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
 			},
-			appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			appImports: []string{
+				"out/soong/.intermediates/shared/android_common/package-res.apk",
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+			},
 			appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"},
 			appClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
 				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
 			},
@@ -819,6 +864,26 @@
 			transitiveClasspath: []string{"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar"},
 			transitiveCombined:  nil,
 
+			sharedResources: nil,
+			sharedOverlays: []string{
+				"out/soong/.intermediates/shared_transitive_static/android_common/package-res.apk",
+				"out/soong/.intermediates/shared/android_common/aapt2/shared/res/values_strings.arsc.flat",
+			},
+			sharedImports: []string{
+				"out/soong/.intermediates/shared_transitive_shared/android_common/package-res.apk",
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+			},
+			sharedSrcJars: []string{"out/soong/.intermediates/shared/android_common/gen/android/R.srcjar"},
+			sharedClasspath: []string{
+				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/shared_transitive_shared/android_common/turbine-combined/shared_transitive_shared.jar",
+				"out/soong/.intermediates/shared_transitive_static/android_common/turbine-combined/shared_transitive_static.jar",
+			},
+			sharedCombined: []string{
+				"out/soong/.intermediates/shared/android_common/javac/shared.jar",
+				"out/soong/.intermediates/shared_transitive_static/android_common/javac/shared_transitive_static.jar",
+			},
+
 			directImportResources: nil,
 			directImportOverlays:  []string{"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata"},
 			directImportImports: []string{
@@ -835,10 +900,13 @@
 		},
 		{
 			// Test with all modules set to use_resource_processor: true.
-			name:                "resource_processor",
-			appUsesRP:           true,
-			directLibUsesRP:     true,
-			transitiveLibUsesRP: true,
+			name:                            "resource_processor",
+			appUsesRP:                       true,
+			directLibUsesRP:                 true,
+			transitiveLibUsesRP:             true,
+			sharedLibUsesRP:                 true,
+			sharedTransitiveSharedLibUsesRP: true,
+			sharedTransitiveStaticLibUsesRP: true,
 
 			appResources: nil,
 			appOverlays: []string{
@@ -850,11 +918,15 @@
 				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
 				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
 			},
-			appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			appImports: []string{
+				"out/soong/.intermediates/shared/android_common/package-res.apk",
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+			},
 			appSrcJars: nil,
 			appClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
 				"out/soong/.intermediates/app/android_common/busybox/R.jar",
+				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
 				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
 			},
@@ -899,6 +971,27 @@
 			},
 			transitiveCombined: nil,
 
+			sharedResources: nil,
+			sharedOverlays:  []string{"out/soong/.intermediates/shared/android_common/aapt2/shared/res/values_strings.arsc.flat"},
+			sharedImports: []string{
+				"out/soong/.intermediates/shared_transitive_shared/android_common/package-res.apk",
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+				"out/soong/.intermediates/shared_transitive_static/android_common/package-res.apk",
+			},
+			sharedSrcJars: nil,
+			sharedClasspath: []string{
+				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/shared_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{
@@ -930,12 +1023,16 @@
 				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
 				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
 			},
-			appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			appImports: []string{
+				"out/soong/.intermediates/shared/android_common/package-res.apk",
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+			},
 			appSrcJars: nil,
 			appClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
 				// R.jar has to come before direct.jar
 				"out/soong/.intermediates/app/android_common/busybox/R.jar",
+				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
 				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
 			},
@@ -948,6 +1045,7 @@
 
 			dontVerifyDirect:           true,
 			dontVerifyTransitive:       true,
+			dontVerifyShared:           true,
 			dontVerifyDirectImport:     true,
 			dontVerifyTransitiveImport: true,
 		},
@@ -968,10 +1066,14 @@
 				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
 				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
 			},
-			appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			appImports: []string{
+				"out/soong/.intermediates/shared/android_common/package-res.apk",
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+			},
 			appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"},
 			appClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
 				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
 			},
@@ -1005,6 +1107,7 @@
 			},
 
 			dontVerifyTransitive:       true,
+			dontVerifyShared:           true,
 			dontVerifyDirectImport:     true,
 			dontVerifyTransitiveImport: true,
 		},
@@ -1025,10 +1128,14 @@
 				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
 				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
 			},
-			appImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			appImports: []string{
+				"out/soong/.intermediates/shared/android_common/package-res.apk",
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+			},
 			appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"},
 			appClasspath: []string{
 				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar",
 				"out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar",
 				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
 			},
@@ -1068,6 +1175,7 @@
 			},
 			transitiveCombined: nil,
 
+			dontVerifyShared:           true,
 			dontVerifyDirectImport:     true,
 			dontVerifyTransitiveImport: true,
 		},
@@ -1082,6 +1190,7 @@
 					srcs: ["app/app.java"],
 					resource_dirs: ["app/res"],
 					manifest: "app/AndroidManifest.xml",
+					libs: ["shared"],
 					static_libs: ["direct", "direct_import"],
 					use_resource_processor: %v,
 				}
@@ -1105,6 +1214,35 @@
 					use_resource_processor: %v,
 				}
 
+				android_library {
+					name: "shared",
+					sdk_version: "current",
+					srcs: ["shared/shared.java"],
+					resource_dirs: ["shared/res"],
+					manifest: "shared/AndroidManifest.xml",
+					use_resource_processor: %v,
+					libs: ["shared_transitive_shared"],
+					static_libs: ["shared_transitive_static"],
+				}
+
+				android_library {
+					name: "shared_transitive_shared",
+					sdk_version: "current",
+					srcs: ["shared_transitive_shared/shared_transitive_shared.java"],
+					resource_dirs: ["shared_transitive_shared/res"],
+					manifest: "shared_transitive_shared/AndroidManifest.xml",
+					use_resource_processor: %v,
+				}
+
+				android_library {
+					name: "shared_transitive_static",
+					sdk_version: "current",
+					srcs: ["shared_transitive_static/shared.java"],
+					resource_dirs: ["shared_transitive_static/res"],
+					manifest: "shared_transitive_static/AndroidManifest.xml",
+					use_resource_processor: %v,
+				}
+
 				android_library_import {
 					name: "direct_import",
 					sdk_version: "current",
@@ -1130,17 +1268,20 @@
 					sdk_version: "current",
 					aars: ["transitive_import_dep.aar"],
 				}
-			`, testCase.appUsesRP, testCase.directLibUsesRP, testCase.transitiveLibUsesRP)
+			`, testCase.appUsesRP, testCase.directLibUsesRP, testCase.transitiveLibUsesRP,
+				testCase.sharedLibUsesRP, testCase.sharedTransitiveSharedLibUsesRP, testCase.sharedTransitiveStaticLibUsesRP)
 
 			fs := android.MockFS{
-				"app/res/values/strings.xml":        nil,
-				"direct/res/values/strings.xml":     nil,
-				"transitive/res/values/strings.xml": nil,
+				"app/res/values/strings.xml":                      nil,
+				"direct/res/values/strings.xml":                   nil,
+				"transitive/res/values/strings.xml":               nil,
+				"shared/res/values/strings.xml":                   nil,
+				"shared_transitive_static/res/values/strings.xml": nil,
+				"shared_transitive_shared/res/values/strings.xml": nil,
 			}
 
 			result := android.GroupFixturePreparers(
 				PrepareForTestWithJavaDefaultModules,
-				PrepareForTestWithOverlayBuildComponents,
 				fs.AddToFixture(),
 			).RunTestWithBp(t, bp)
 
@@ -1182,6 +1323,7 @@
 			app := getAaptInfo("app")
 			direct := getAaptInfo("direct")
 			transitive := getAaptInfo("transitive")
+			shared := getAaptInfo("shared")
 			directImport := getAaptInfo("direct_import")
 			transitiveImport := getAaptInfo("transitive_import")
 
@@ -1212,6 +1354,15 @@
 				android.AssertPathsRelativeToTopEquals(t, "transitive combined", testCase.transitiveCombined, transitive.combined)
 			}
 
+			if !testCase.dontVerifyShared {
+				android.AssertPathsRelativeToTopEquals(t, "shared resources", testCase.sharedResources, shared.resources)
+				android.AssertPathsRelativeToTopEquals(t, "shared overlays", testCase.sharedOverlays, shared.overlays)
+				android.AssertPathsRelativeToTopEquals(t, "shared imports", testCase.sharedImports, shared.imports)
+				android.AssertPathsRelativeToTopEquals(t, "shared srcjars", testCase.sharedSrcJars, shared.srcJars)
+				android.AssertPathsRelativeToTopEquals(t, "shared classpath", testCase.sharedClasspath, shared.classpath)
+				android.AssertPathsRelativeToTopEquals(t, "shared combined", testCase.sharedCombined, shared.combined)
+			}
+
 			if !testCase.dontVerifyDirectImport {
 				android.AssertPathsRelativeToTopEquals(t, "direct_import resources", testCase.directImportResources, directImport.resources)
 				android.AssertPathsRelativeToTopEquals(t, "direct_import overlays", testCase.directImportOverlays, directImport.overlays)
@@ -1413,7 +1564,6 @@
 		t.Run(testCase.name, func(t *testing.T) {
 			result := android.GroupFixturePreparers(
 				PrepareForTestWithJavaDefaultModules,
-				PrepareForTestWithOverlayBuildComponents,
 				fs.AddToFixture(),
 				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 					variables.DeviceResourceOverlays = deviceResourceOverlays
diff --git a/java/base.go b/java/base.go
index a110aff..fdc164e 100644
--- a/java/base.go
+++ b/java/base.go
@@ -134,7 +134,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
@@ -194,7 +194,7 @@
 	Generated_srcjars []android.Path `android:"mutated"`
 
 	// If true, then only the headers are built and not the implementation jar.
-	Headers_only bool
+	Headers_only *bool
 }
 
 // Properties that are specific to device modules. Host module factories should not add these when
@@ -432,6 +432,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
@@ -494,9 +497,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
@@ -579,7 +579,7 @@
 
 func (j *Module) checkHeadersOnly(ctx android.ModuleContext) {
 	if _, ok := ctx.Module().(android.SdkContext); ok {
-		headersOnly := proptools.Bool(&j.properties.Headers_only)
+		headersOnly := proptools.Bool(j.properties.Headers_only)
 		installable := proptools.Bool(j.properties.Installable)
 
 		if headersOnly && installable {
@@ -638,6 +638,11 @@
 		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)
 	}
@@ -711,6 +716,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)
@@ -1002,8 +1011,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")
@@ -1012,7 +1029,12 @@
 
 	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
@@ -1089,6 +1111,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)
@@ -1168,7 +1193,7 @@
 	flags.classpath = append(android.CopyOf(extraClasspathJars), flags.classpath...)
 
 	// If compiling headers then compile them and skip the rest
-	if j.properties.Headers_only {
+	if proptools.Bool(j.properties.Headers_only) {
 		if srcFiles.HasExt(".kt") {
 			ctx.ModuleErrorf("Compiling headers_only with .kt not supported")
 		}
@@ -1343,10 +1368,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)
@@ -1687,6 +1719,8 @@
 		j.linter.lint(ctx)
 	}
 
+	j.collectTransitiveSrcFiles(ctx, srcFiles)
+
 	ctx.CheckbuildFile(outputFile)
 
 	j.collectTransitiveAconfigFiles(ctx)
@@ -1701,6 +1735,7 @@
 		AidlIncludeDirs:                j.exportAidlIncludeDirs,
 		SrcJarArgs:                     j.srcJarArgs,
 		SrcJarDeps:                     j.srcJarDeps,
+		TransitiveSrcFiles:             j.transitiveSrcFiles,
 		ExportedPlugins:                j.exportedPluginJars,
 		ExportedPluginClasses:          j.exportedPluginClasses,
 		ExportedPluginDisableTurbine:   j.exportedDisableTurbine,
@@ -1908,19 +1943,22 @@
 		}
 
 		dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
-		if dep.TransitiveLibsHeaderJars != nil {
-			transitiveLibs = append(transitiveLibs, dep.TransitiveLibsHeaderJars)
-		}
-		if dep.TransitiveStaticLibsHeaderJars != nil {
-			transitiveStaticLibs = append(transitiveStaticLibs, dep.TransitiveStaticLibsHeaderJars)
-		}
-
 		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)
@@ -1974,7 +2012,6 @@
 	if j.expandJarjarRules != nil {
 		dpInfo.Jarjar_rules = append(dpInfo.Jarjar_rules, j.expandJarjarRules.String())
 	}
-	dpInfo.Paths = append(dpInfo.Paths, j.modulePaths...)
 	dpInfo.Static_libs = append(dpInfo.Static_libs, j.properties.Static_libs...)
 	dpInfo.Libs = append(dpInfo.Libs, j.properties.Libs...)
 	dpInfo.SrcJars = append(dpInfo.SrcJars, j.annoSrcJars.Strings()...)
@@ -2025,6 +2062,21 @@
 	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 := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+			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)
 }
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index dcc2dec..191a65e 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -23,6 +23,7 @@
 
 	"android/soong/android"
 	"android/soong/dexpreopt"
+	"android/soong/testing"
 
 	"github.com/google/blueprint/proptools"
 
@@ -238,9 +239,6 @@
 
 	sourceOnlyProperties SourceOnlyBootclasspathProperties
 
-	// Collect the module directory for IDE info in java/jdeps.go.
-	modulePaths []string
-
 	// Path to the boot image profile.
 	profilePath android.WritablePath
 }
@@ -471,9 +469,6 @@
 	// Generate classpaths.proto config
 	b.generateClasspathProtoBuildActions(ctx)
 
-	// Collect the module directory for IDE info in java/jdeps.go.
-	b.modulePaths = append(b.modulePaths, ctx.ModuleDir())
-
 	// Gather the bootclasspath fragment's contents.
 	var contents []android.Module
 	ctx.VisitDirectDeps(func(module android.Module) {
@@ -505,6 +500,7 @@
 	if ctx.Module() != ctx.FinalModule() {
 		b.HideFromMake()
 	}
+	ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 // getProfileProviderApex returns the name of the apex that provides a boot image profile, or an
@@ -582,7 +578,7 @@
 		// So ignore it even if it is not in PRODUCT_APEX_BOOT_JARS.
 		// TODO(b/202896428): Add better way to handle this.
 		_, unknown = android.RemoveFromList("android.car-module", unknown)
-		if len(unknown) > 0 {
+		if isActiveModule(ctx.Module()) && len(unknown) > 0 {
 			ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_APEX_BOOT_JARS", unknown)
 		}
 	}
@@ -632,21 +628,6 @@
 	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 {
@@ -782,7 +763,7 @@
 	dexLocations := make([]string, 0, len(contents))
 	for _, module := range contents {
 		dexPaths = append(dexPaths, modules[module.Name()])
-		dexLocations = append(dexLocations, filepath.Join("/", "apex", apex, "javalib", module.Name() + ".jar"))
+		dexLocations = append(dexLocations, filepath.Join("/", "apex", apex, "javalib", module.Name()+".jar"))
 	}
 
 	// Build a profile for the modules in this fragment.
@@ -816,7 +797,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 {
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 888caad..828de21 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -316,6 +316,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,
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/droidstubs.go b/java/config/droidstubs.go
new file mode 100644
index 0000000..b7aab5a
--- /dev/null
+++ b/java/config/droidstubs.go
@@ -0,0 +1,81 @@
+// 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",
+		"--hide InvalidNullabilityOverride",
+
+		// 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",
+		"--hide AnnotationExtraction",
+		// b/222738070
+		"--hide BannedThrow",
+	}
+
+	MetalavaAnnotationsWarningsFlags = strings.Join(metalavaAnnotationsWarningsFlags, " ")
+
+	metalavaHideFlaggedApis = []string{
+		"--hide-annotation",
+		"android.annotation.FlaggedApi",
+	}
+
+	MetalavaHideFlaggedApis = strings.Join(metalavaHideFlaggedApis, " ")
+)
+
+const (
+	MetalavaAddOpens = "-J--add-opens=java.base/java.util=ALL-UNNAMED"
+)
+
+func init() {
+	exportedVars.ExportStringList("MetalavaFlags", metalavaFlags)
+
+	exportedVars.ExportString("MetalavaAddOpens", MetalavaAddOpens)
+
+	exportedVars.ExportStringList("MetalavaHideFlaggedApis", metalavaHideFlaggedApis)
+
+	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 4e09195..649b6c5 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -34,8 +34,6 @@
 
 	ctx.Strict("ANDROID_JAVA_HOME", "${JavaHome}")
 	ctx.Strict("ANDROID_JAVA8_HOME", "prebuilts/jdk/jdk8/${hostPrebuiltTag}")
-	ctx.Strict("ANDROID_JAVA9_HOME", "prebuilts/jdk/jdk9/${hostPrebuiltTag}")
-	ctx.Strict("ANDROID_JAVA11_HOME", "prebuilts/jdk/jdk11/${hostPrebuiltTag}")
 	ctx.Strict("ANDROID_JAVA_TOOLCHAIN", "${JavaToolchain}")
 	ctx.Strict("JAVA", "${JavaCmd} ${JavaVmFlags}")
 	ctx.Strict("JAVAC", "${JavacCmd} ${JavacVmFlags}")
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index 4380f4f..c6ab561 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -66,6 +66,7 @@
     libs: [
         "stub-annotations",
     ],
+    enable_validation: false,
 }
 
 java_library {
@@ -206,6 +207,26 @@
     ],
 }
 
+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"],
+}
+
 // Produces a dist file that is used by the
 // prebuilts/sdk/update_prebuilts.py script to update the prebuilts/sdk
 // directory.
@@ -503,7 +524,3 @@
         "art-module-intra-core-api-stubs-system-modules-lib",
     ],
 }
-
-build = [
-    "TxtStubLibraries.bp",
-]
diff --git a/java/core-libraries/TxtStubLibraries.bp b/java/core-libraries/TxtStubLibraries.bp
deleted file mode 100644
index c46f8b8..0000000
--- a/java/core-libraries/TxtStubLibraries.bp
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (C) 2023 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// This file contains java_system_modules provided by the SDK.
-// These system modules transitively depend on core stub libraries generated from .txt files.
-
-// Same as core-public-stubs-system-modules, but the stubs are generated from .txt files
-java_system_modules {
-    name: "core-public-stubs-system-modules.from-text",
-    visibility: ["//visibility:public"],
-    libs: [
-        "core-current-stubs-for-system-modules-no-annotations.from-text",
-    ],
-}
-
-java_library {
-    name: "core-current-stubs-for-system-modules-no-annotations.from-text",
-    visibility: ["//visibility:private"],
-    defaults: [
-        "system-modules-no-annotations",
-    ],
-    static_libs: [
-        "core.current.stubs.from-text",
-        "core-lambda-stubs.from-text",
-    ],
-}
-
-// Same as core-module-lib-stubs-system-modules, but the stubs are generated from .txt files
-java_system_modules {
-    name: "core-module-lib-stubs-system-modules.from-text",
-    visibility: ["//visibility:public"],
-    libs: [
-        "core-module-lib-stubs-for-system-modules-no-annotations.from-text",
-    ],
-}
-
-java_library {
-    name: "core-module-lib-stubs-for-system-modules-no-annotations.from-text",
-    visibility: ["//visibility:private"],
-    defaults: [
-        "system-modules-no-annotations",
-    ],
-    static_libs: [
-        "core.module_lib.stubs.from-text",
-        "core-lambda-stubs.from-text",
-    ],
-}
-
-java_api_library {
-    name: "core.module_lib.stubs.from-text",
-    api_surface: "module-lib",
-    api_contributions: [
-        "art.module.public.api.stubs.source.api.contribution",
-        "art.module.public.api.stubs.source.system.api.contribution",
-        "art.module.public.api.stubs.source.module_lib.api.contribution",
-
-        // Add the module-lib correspondence when Conscrypt or i18N module
-        // provides @SystemApi(MODULE_LIBRARIES). Currently, assume that only ART module provides
-        // @SystemApi(MODULE_LIBRARIES).
-        "conscrypt.module.public.api.stubs.source.api.contribution",
-        "i18n.module.public.api.stubs.source.api.contribution",
-    ],
-    libs: [
-        "stub-annotations",
-    ],
-    visibility: ["//visibility:private"],
-}
-
-// Same as legacy-core-platform-api-stubs-system-modules, but the stubs are generated from .txt files
-java_system_modules {
-    name: "legacy-core-platform-api-stubs-system-modules.from-text",
-    visibility: core_platform_visibility,
-    libs: [
-        "legacy.core.platform.api.no.annotations.stubs.from-text",
-        "core-lambda-stubs.from-text",
-    ],
-}
-
-java_library {
-    name: "legacy.core.platform.api.no.annotations.stubs.from-text",
-    visibility: core_platform_visibility,
-    defaults: [
-        "system-modules-no-annotations",
-    ],
-    hostdex: true,
-    compile_dex: true,
-
-    static_libs: [
-        "legacy.core.platform.api.stubs.from-text",
-    ],
-    patch_module: "java.base",
-}
-
-// Same as stable-core-platform-api-stubs-system-modules, but the stubs are generated from .txt files
-java_system_modules {
-    name: "stable-core-platform-api-stubs-system-modules.from-text",
-    visibility: core_platform_visibility,
-    libs: [
-        "stable.core.platform.api.no.annotations.stubs.from-text",
-        "core-lambda-stubs.from-text",
-    ],
-}
-
-java_library {
-    name: "stable.core.platform.api.no.annotations.stubs.from-text",
-    visibility: core_platform_visibility,
-    defaults: [
-        "system-modules-no-annotations",
-    ],
-    hostdex: true,
-    compile_dex: true,
-
-    static_libs: [
-        "stable.core.platform.api.stubs.from-text",
-    ],
-    patch_module: "java.base",
-}
-
-java_api_library {
-    name: "core-lambda-stubs.from-text",
-    api_surface: "toolchain",
-    api_contributions: [
-        "art.module.toolchain.api.api.contribution",
-    ],
-    libs: [
-        // LambdaMetaFactory depends on CallSite etc. which is part of the Core API surface
-        "core.current.stubs.from-text",
-    ],
-}
diff --git a/java/dex.go b/java/dex.go
index c1d51c7..aa01783 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -106,14 +106,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} --output $outDir $d8Flags --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}",
 		},
@@ -132,16 +130,14 @@
 			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} -injars $in --output $outDir ` +
 			`--no-data-resources ` +
 			`-printmapping ${outDict} ` +
 			`-printconfiguration ${outConfig} ` +
@@ -152,12 +148,12 @@
 			`${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}",
 		},
@@ -185,7 +181,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"}, []string{"implicits"})
 
 func (d *dexer) dexCommonFlags(ctx android.ModuleContext,
 	dexParams *compileDexParams) (flags []string, deps android.Paths) {
@@ -304,6 +300,8 @@
 
 	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...)
 
@@ -368,7 +366,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) {
@@ -406,7 +403,6 @@
 			"outUsage":       proguardUsage.String(),
 			"outUsageZip":    proguardUsageZip.String(),
 			"outDir":         outDir.String(),
-			"tmpJar":         tmpJar.String(),
 			"mergeZipsFlags": mergeZipsFlags,
 		}
 		if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") {
@@ -442,7 +438,6 @@
 				"d8Flags":        strings.Join(append(commonFlags, d8Flags...), " "),
 				"zipFlags":       zipFlags,
 				"outDir":         outDir.String(),
-				"tmpJar":         tmpJar.String(),
 				"mergeZipsFlags": mergeZipsFlags,
 			},
 		})
diff --git a/java/dex_test.go b/java/dex_test.go
index ec1ef15..1ecdae0 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -385,13 +385,53 @@
 func TestProguardFlagsInheritance(t *testing.T) {
 	directDepFlagsFileName := "direct_dep.flags"
 	transitiveDepFlagsFileName := "transitive_dep.flags"
-	bp := `
-		android_app {
-			name: "app",
-			static_libs: ["androidlib"], // this must be static_libs to initate dexing
-			platform_apis: true,
-		}
 
+	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"],
@@ -558,43 +598,46 @@
 		},
 	}
 
-	for _, tc := range testcases {
-		t.Run(tc.name, func(t *testing.T) {
-			result := android.GroupFixturePreparers(
-				PrepareForTestWithJavaDefaultModules,
-				android.FixtureMergeMockFs(android.MockFS{
-					directDepFlagsFileName:     nil,
-					transitiveDepFlagsFileName: nil,
-				}),
-			).RunTestWithBp(t,
-				fmt.Sprintf(
-					bp,
-					tc.depType,
-					tc.transitiveDepType,
-					tc.depExportsFlagsFiles,
-					tc.transitiveDepExportsFlagsFiles,
-				),
-			)
-			appR8 := result.ModuleForTests("app", "android_common").Rule("r8")
+	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)
-			}
+				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)
-			}
-		})
+				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)
+				}
+			})
+		}
 	}
 }
 
@@ -606,11 +649,6 @@
 			platform_apis: true,
 		}
 
-		android_library {
-			name: "androidlib",
-			static_libs: ["aarimport"],
-		}
-
 		android_library_import {
 			name: "aarimport",
 			aars: ["import.aar"],
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 003f2de..5fb36df 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -610,7 +610,8 @@
 	profile := bootImageProfileRule(ctx, imageConfig)
 
 	// If dexpreopt of boot image jars should be skipped, stop after generating a profile.
-	if SkipDexpreoptBootJars(ctx) {
+	global := dexpreopt.GetGlobalConfig(ctx)
+	if SkipDexpreoptBootJars(ctx) || (global.OnlyPreoptArtBootImage && imageConfig.name != "art") {
 		return
 	}
 
@@ -628,7 +629,7 @@
 }
 
 type apexJarModulePair struct {
-	apex string
+	apex      string
 	jarModule android.Module
 }
 
@@ -640,7 +641,7 @@
 			name := android.RemoveOptionalPrebuiltPrefix(module.Name())
 			if name == imageConfig.modules.Jar(i) {
 				modules = append(modules, apexJarModulePair{
-					apex: imageConfig.modules.Apex(i),
+					apex:      imageConfig.modules.Apex(i),
 					jarModule: module,
 				})
 				found = true
@@ -1178,7 +1179,7 @@
 		Rule:        android.Phony,
 		Output:      phony,
 		Inputs:      allPhonies,
-		Description: "dump-oat-"+name,
+		Description: "dump-oat-" + name,
 	})
 }
 
diff --git a/java/dexpreopt_check.go b/java/dexpreopt_check.go
index 7499481..33be603 100644
--- a/java/dexpreopt_check.go
+++ b/java/dexpreopt_check.go
@@ -68,7 +68,7 @@
 
 	// The check should be skipped on unbundled builds because system server jars are not preopted on
 	// unbundled builds since the artifacts are installed into the system image, not the APEXes.
-	if global.DisablePreopt || len(targets) == 0 || ctx.Config().UnbundledBuild() {
+	if global.DisablePreopt || global.OnlyPreoptArtBootImage || len(targets) == 0 || ctx.Config().UnbundledBuild() {
 		return
 	}
 
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 0f4bd9b..2bd696c 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -210,57 +210,18 @@
 	return false
 }
 
-// Apex boot config allows to access build/install paths of apex boot jars without going
-// through the usual trouble of registering dependencies on those modules and extracting build paths
-// from those dependencies.
-type apexBootConfig struct {
-	// A list of apex boot jars.
-	modules android.ConfiguredJarList
-
-	// A list of predefined build paths to apex boot jars. They are configured very early,
-	// before the modules for these jars are processed and the actual paths are generated, and
-	// later on a singleton adds commands to copy actual jars to the predefined paths.
-	dexPaths android.WritablePaths
-
-	// Map from module name (without prebuilt_ prefix) to the predefined build path.
-	dexPathsByModule map[string]android.WritablePath
-
-	// A list of dex locations (a.k.a. on-device paths) to the boot jars.
-	dexLocations []string
-}
-
-var updatableBootConfigKey = android.NewOnceKey("apexBootConfig")
-
-// Returns apex boot config.
-func GetApexBootConfig(ctx android.PathContext) apexBootConfig {
-	return ctx.Config().Once(updatableBootConfigKey, func() interface{} {
-		apexBootJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
-		dir := android.PathForOutput(ctx, getDexpreoptDirName(ctx), "apex_bootjars")
-		dexPaths := apexBootJars.BuildPaths(ctx, dir)
-		dexPathsByModuleName := apexBootJars.BuildPathsByModule(ctx, dir)
-
-		dexLocations := apexBootJars.DevicePaths(ctx.Config(), android.Android)
-
-		return apexBootConfig{apexBootJars, dexPaths, dexPathsByModuleName, dexLocations}
-	}).(apexBootConfig)
-}
-
 // Returns a list of paths and a list of locations for the boot jars used in dexpreopt (to be
 // passed in -Xbootclasspath and -Xbootclasspath-locations arguments for dex2oat).
 func bcpForDexpreopt(ctx android.PathContext, withUpdatable bool) (android.WritablePaths, []string) {
-	// Non-updatable boot jars (they are used both in the boot image and in dexpreopt).
 	bootImage := defaultBootImageConfig(ctx)
+	if withUpdatable {
+		bootImage = mainlineBootImageConfig(ctx)
+	}
+
 	dexPaths := bootImage.dexPathsDeps
 	// The dex locations for all Android variants are identical.
 	dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps
 
-	if withUpdatable {
-		// Apex boot jars (they are used only in dexpreopt, but not in the boot image).
-		apexBootConfig := GetApexBootConfig(ctx)
-		dexPaths = append(dexPaths, apexBootConfig.dexPaths...)
-		dexLocations = append(dexLocations, apexBootConfig.dexLocations...)
-	}
-
 	return dexPaths, dexLocations
 }
 
@@ -278,7 +239,7 @@
 	prefix := "dexpreopt_"
 	targets := ctx.Config().Targets[android.Android]
 	if len(targets) > 0 {
-		return prefix+targets[0].Arch.ArchType.String()
+		return prefix + targets[0].Arch.ArchType.String()
 	}
-	return prefix+"unknown_target"
+	return prefix + "unknown_target"
 }
diff --git a/java/dexpreopt_config_testing.go b/java/dexpreopt_config_testing.go
index 176c251..41d4b72 100644
--- a/java/dexpreopt_config_testing.go
+++ b/java/dexpreopt_config_testing.go
@@ -77,7 +77,7 @@
 
 func PrepareApexBootJarModule(apexName string, moduleName string) android.FixturePreparer {
 	moduleSourceDir := fmt.Sprintf("packages/modules/%s", apexName)
-	fragmentName := apexName+"-bootclasspath-fragment"
+	fragmentName := apexName + "-bootclasspath-fragment"
 	imageNameProp := ""
 	if apexName == "com.android.art" {
 		fragmentName = "art-bootclasspath-fragment"
diff --git a/java/droiddoc.go b/java/droiddoc.go
index d5547d0..f7d7de6 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -136,6 +136,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
 
@@ -300,7 +303,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())
 	}
@@ -665,6 +668,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 1d5dd76..180ba92 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -19,12 +19,12 @@
 	"path/filepath"
 	"regexp"
 	"sort"
+	"strconv"
 	"strings"
 
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/java/config"
 	"android/soong/remoteexec"
 )
@@ -48,6 +48,7 @@
 // Droidstubs
 type Droidstubs struct {
 	Javadoc
+	embeddableInModuleAndImport
 
 	properties              DroidstubsProperties
 	apiFile                 android.Path
@@ -123,7 +124,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.
@@ -172,6 +173,10 @@
 	ApiStubsSrcProvider
 }
 
+type currentApiTimestampProvider interface {
+	CurrentApiTimestamp() android.Path
+}
+
 // droidstubs passes sources files through Metalava to generate stub .java files that only contain the API to be
 // documented, filtering out hidden classes and methods.  The resulting .java files are intended to be passed to
 // a droiddoc module to generate documentation.
@@ -180,6 +185,7 @@
 
 	module.AddProperties(&module.properties,
 		&module.Javadoc.properties)
+	module.initModuleAndImport(module)
 
 	InitDroiddocModule(module, android.HostAndDeviceSupported)
 
@@ -239,10 +245,15 @@
 	return d.stubsSrcJar
 }
 
+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)
@@ -314,9 +325,7 @@
 
 func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
 	if Bool(d.properties.Annotations_enabled) {
-		cmd.Flag("--include-annotations")
-
-		cmd.FlagWithArg("--exclude-annotation ", "androidx.annotation.RequiresApi")
+		cmd.Flag(config.MetalavaAnnotationsFlags)
 
 		validatingNullability :=
 			strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") ||
@@ -344,14 +353,7 @@
 			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)
 	}
 }
 
@@ -498,6 +500,7 @@
 	if metalavaUseRbe(ctx) {
 		rule.Remoteable(android.RemoteRuleSupports{RBE: true})
 		execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
+		compare, _ := strconv.ParseBool(ctx.Config().GetenvWithDefault("RBE_METALAVA_COMPARE", "false"))
 		labels := map[string]string{"type": "tool", "name": "metalava"}
 		// TODO: metalava pool rejects these jobs
 		pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16")
@@ -506,12 +509,15 @@
 			ExecStrategy:    execStrategy,
 			ToolchainInputs: []string{config.JavaCmd(ctx).String()},
 			Platform:        map[string]string{remoteexec.PoolKey: pool},
+			Compare:         compare,
+			NumLocalRuns:    1,
+			NumRemoteRuns:   1,
 		})
 	}
 
 	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)
@@ -524,22 +530,10 @@
 		cmd.FlagWithInputList("--classpath ", combinedPaths, ":")
 	}
 
-	cmd.Flag("--color").
-		Flag("--quiet").
-		Flag("--format=v2").
-		FlagWithArg("--repeat-errors-max ", "10").
-		FlagWithArg("--hide ", "UnresolvedImport").
-		FlagWithArg("--hide ", "InvalidNullabilityOverride").
-		// b/223382732
-		FlagWithArg("--hide ", "ChangedDefault")
-
-	// Force metalava to ignore classes on the classpath when an API file contains missing classes.
-	// See b/285140653 for more information.
-	cmd.FlagWithArg("--api-class-resolution ", "api")
-
-	// Force metalava to sort overloaded methods by their order in the source code.
-	// See b/285312164 for more information.
-	cmd.FlagWithArg("--format-defaults ", "overloaded-method-order=source")
+	cmd.Flag(config.MetalavaFlags)
+	if ctx.DeviceConfig().HideFlaggedApis() {
+		cmd.Flag(config.MetalavaHideFlaggedApis)
+	}
 
 	return cmd
 }
@@ -781,6 +775,11 @@
 			`         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`+
 			`******************************\n`, ctx.ModuleName())
 
 		rule.Command().
@@ -855,34 +854,6 @@
 	}
 }
 
-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)
-}
-
 func (d *Droidstubs) createApiContribution(ctx android.DefaultableHookContext) {
 	api_file := d.properties.Check_api.Current.Api_file
 	api_surface := d.properties.Api_surface
@@ -966,6 +937,8 @@
 type PrebuiltStubsSources struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	embeddableInModuleAndImport
+
 	prebuilt android.Prebuilt
 
 	properties PrebuiltStubsSourcesProperties
@@ -1044,6 +1017,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..f86e1ac 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -22,6 +22,8 @@
 	"testing"
 
 	"android/soong/android"
+
+	"github.com/google/blueprint/proptools"
 )
 
 func TestDroidstubs(t *testing.T) {
@@ -390,7 +392,7 @@
 						removed_api_file: "A/removed.txt",
 					}
 				},
-				visibility: ["//a"],
+				visibility: ["//a", "//b"],
 			}
 		`,
 		map[string][]byte{
@@ -403,3 +405,35 @@
 
 	ctx.ModuleForTests("bar", "android_common")
 }
+
+func TestDroidstubsHideFlaggedApi(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.NextReleaseHideFlaggedApi = proptools.BoolPtr(true)
+			variables.Release_expose_flagged_api = proptools.BoolPtr(false)
+		}),
+		android.FixtureMergeMockFs(map[string][]byte{
+			"a/A.java":      nil,
+			"a/current.txt": nil,
+			"a/removed.txt": nil,
+		}),
+	).RunTestWithBp(t, `
+	droidstubs {
+		name: "foo",
+		srcs: ["a/A.java"],
+		api_surface: "public",
+		check_api: {
+			current: {
+				api_file: "a/current.txt",
+				removed_api_file: "a/removed.txt",
+			}
+		},
+	}
+	`)
+
+	m := result.ModuleForTests("foo", "android_common")
+	manifest := m.Output("metalava.sbox.textproto")
+	cmdline := String(android.RuleBuilderSboxProtoForTests(t, manifest).Commands[0].Command)
+	android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "--hide-annotation android.annotation.FlaggedApi")
+}
diff --git a/java/generated_java_library.go b/java/generated_java_library.go
index 578237e..930bfd2 100644
--- a/java/generated_java_library.go
+++ b/java/generated_java_library.go
@@ -35,6 +35,8 @@
 	// 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
+
+	Bp2build(ctx android.Bp2buildMutatorContext, module *GeneratedJavaLibraryModule)
 }
 
 // GeneratedJavaLibraryModuleFactory provides a utility for modules that are generated
@@ -108,3 +110,7 @@
 	module.Library.properties.Generated_srcjars = append(module.Library.properties.Generated_srcjars, srcJarPath)
 	module.Library.GenerateAndroidBuildActions(ctx)
 }
+
+func (module *GeneratedJavaLibraryModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
+	module.callbacks.Bp2build(ctx, module)
+}
diff --git a/java/generated_java_library_test.go b/java/generated_java_library_test.go
index 7f52fd1..7fbbfee 100644
--- a/java/generated_java_library_test.go
+++ b/java/generated_java_library_test.go
@@ -41,6 +41,9 @@
 	return android.PathForOutput(ctx, "blah.srcjar")
 }
 
+func (callbacks *JavaGenLibTestCallbacks) Bp2build(ctx android.Bp2buildMutatorContext, module *GeneratedJavaLibraryModule) {
+}
+
 func testGenLib(t *testing.T, errorHandler android.FixtureErrorHandler, bp string) *android.TestResult {
 	return android.GroupFixturePreparers(
 		PrepareForIntegrationTestWithJava,
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index f31f5d1..fbc0197 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -38,10 +38,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 +90,9 @@
 		if ctx.Config().AlwaysUsePrebuiltSdks() {
 			return l.nonUpdatablePrebuiltModule
 		} else {
+			if l.nonUpdatableFromTextModule != "" && ctx.Config().BuildFromTextStub() {
+				return l.nonUpdatableFromTextModule
+			}
 			return l.nonUpdatableSourceModule
 		}
 	} else {
@@ -117,8 +124,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",
@@ -350,7 +358,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)
 
@@ -647,7 +655,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.
@@ -998,7 +1006,7 @@
 
 	// 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)
 
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 d5aeb7c..500ae37 100644
--- a/java/java.go
+++ b/java/java.go
@@ -27,6 +27,7 @@
 	"android/soong/bazel"
 	"android/soong/bazel/cquery"
 	"android/soong/remoteexec"
+	"android/soong/testing"
 	"android/soong/ui/metrics/bp2build_metrics_proto"
 
 	"github.com/google/blueprint"
@@ -278,6 +279,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
@@ -694,6 +698,11 @@
 
 	j.stem = proptools.StringDefault(j.overridableDeviceProperties.Stem, ctx.ModuleName())
 
+	proguardSpecInfo := j.collectProguardSpecInfo(ctx)
+	ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
+	j.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
+	j.extraProguardFlagFiles = append(j.extraProguardFlagFiles, j.exportedProguardFlagFiles...)
+
 	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
 	if !apexInfo.IsForPlatform() {
 		j.hideApexVariantFromMake = true
@@ -711,9 +720,6 @@
 	}
 	j.compile(ctx, nil, nil, nil)
 
-	// Collect the module directory for IDE info in java/jdeps.go.
-	j.modulePaths = append(j.modulePaths, ctx.ModuleDir())
-
 	exclusivelyForApex := !apexInfo.IsForPlatform()
 	if (Bool(j.properties.Installable) || ctx.Host()) && !exclusivelyForApex {
 		var extraInstallDeps android.Paths
@@ -738,10 +744,6 @@
 		}
 		j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...)
 	}
-
-	proguardSpecInfo := j.collectProguardSpecInfo(ctx)
-	ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
-	j.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
 }
 
 func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -1084,6 +1086,10 @@
 	return true
 }
 
+func (j *TestHost) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
+	return ctx.DeviceConfig().NativeCoverageEnabled()
+}
+
 func (j *TestHost) addDataDeviceBinsDeps(ctx android.BottomUpMutatorContext) {
 	if len(j.testHostProperties.Data_device_bins_first) > 0 {
 		deviceVariations := ctx.Config().AndroidFirstDeviceTarget.Variations()
@@ -1220,10 +1226,12 @@
 	}
 
 	j.Test.generateAndroidBuildActionsWithConfig(ctx, configs)
+	ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.generateAndroidBuildActionsWithConfig(ctx, nil)
+	ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, configs []tradefed.Config) {
@@ -1605,6 +1613,7 @@
 type JavaApiContribution struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
+	embeddableInModuleAndImport
 
 	properties struct {
 		// name of the API surface
@@ -1620,6 +1629,7 @@
 	android.InitAndroidModule(module)
 	android.InitDefaultableModule(module)
 	module.AddProperties(&module.properties)
+	module.initModuleAndImport(module)
 	return module
 }
 
@@ -1648,6 +1658,7 @@
 
 	hiddenAPI
 	dexer
+	embeddableInModuleAndImport
 
 	properties JavaApiLibraryProperties
 
@@ -1657,6 +1668,8 @@
 	extractedSrcJar           android.WritablePath
 	// .dex of stubs, used for hiddenapi processing
 	dexJarFile OptionalDexJarPath
+
+	validationPaths android.Paths
 }
 
 type JavaApiLibraryProperties struct {
@@ -1667,11 +1680,6 @@
 	// This is a list of Soong modules
 	Api_contributions []string
 
-	// list of api.txt files relative to this directory that contribute to the
-	// API surface.
-	// This is a list of relative paths
-	Api_files []string `android:"path"`
-
 	// List of flags to be passed to the javac compiler to generate jar file
 	Javacflags []string
 
@@ -1691,12 +1699,25 @@
 
 	// 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
 }
@@ -1710,7 +1731,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())
 
@@ -1749,12 +1771,17 @@
 		FlagWithArg("--hide ", "InvalidNullabilityOverride").
 		FlagWithArg("--hide ", "ChangedDefault")
 
-	// 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")
+	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
 }
@@ -1773,6 +1800,12 @@
 	}
 }
 
+func (al *ApiLibrary) addValidation(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, validationPaths android.Paths) {
+	for _, validationPath := range validationPaths {
+		cmd.Validation(validationPath)
+	}
+}
+
 // This method extracts the stub class files from the stub jar file provided
 // from full_api_surface_stub module instead of compiling the srcjar generated from invoking metalava.
 // This method is used because metalava can generate compilable from-text stubs only when
@@ -1809,47 +1842,55 @@
 
 func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
 	apiContributions := al.properties.Api_contributions
+	addValidations := !ctx.Config().IsEnvTrue("DISABLE_STUB_VALIDATION") &&
+		proptools.BoolDefault(al.properties.Enable_validation, true)
 	for _, apiContributionName := range apiContributions {
 		ctx.AddDependency(ctx.Module(), javaApiContributionTag, apiContributionName)
+
+		// Add the java_api_contribution module generating droidstubs module
+		// as dependency when validation adding conditions are met and
+		// the java_api_contribution module name has ".api.contribution" suffix.
+		// All droidstubs-generated modules possess the suffix in the name,
+		// but there is no such guarantee for tests.
+		if addValidations {
+			if strings.HasSuffix(apiContributionName, ".api.contribution") {
+				ctx.AddDependency(ctx.Module(), metalavaCurrentApiTimestampTag, strings.TrimSuffix(apiContributionName, ".api.contribution"))
+			} else {
+				ctx.ModuleErrorf("Validation is enabled for module %s but a "+
+					"current timestamp provider is not found for the api "+
+					"contribution %s",
+					ctx.ModuleName(),
+					apiContributionName,
+				)
+			}
+		}
 	}
 	ctx.AddVariationDependencies(nil, libTag, al.properties.Libs...)
 	ctx.AddVariationDependencies(nil, staticLibTag, al.properties.Static_libs...)
 	if al.properties.Full_api_surface_stub != nil {
 		ctx.AddVariationDependencies(nil, depApiSrcsTag, String(al.properties.Full_api_surface_stub))
 	}
+	if al.properties.System_modules != nil {
+		ctx.AddVariationDependencies(nil, systemModulesTag, String(al.properties.System_modules))
+	}
 }
 
-// API signature file names sorted from
-// the narrowest api scope to the widest api scope
-var scopeOrderedSourceFileNames = allApiScopes.Strings(
-	func(s *apiScope) string { return s.apiFilePrefix + "current.txt" })
+// Map where key is the api scope name and value is the int value
+// representing the order of the api scope, narrowest to the widest
+var scopeOrderMap = allApiScopes.MapToIndex(
+	func(s *apiScope) string { return s.name })
 
-func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFilesInfo []JavaApiImportInfo, apiFiles android.Paths) android.Paths {
-	var sortedSrcFiles android.Paths
-
-	for i, apiScope := range allApiScopes {
-		for _, srcFileInfo := range srcFilesInfo {
-			if srcFileInfo.ApiFile.Base() == scopeOrderedSourceFileNames[i] || srcFileInfo.ApiSurface == apiScope.name {
-				sortedSrcFiles = append(sortedSrcFiles, android.PathForSource(ctx, srcFileInfo.ApiFile.String()))
-			}
-		}
-		// TODO: b/300964421 - Remove when api_files property is removed
-		for _, apiFileName := range apiFiles {
-			if apiFileName.Base() == scopeOrderedSourceFileNames[i] {
-				sortedSrcFiles = append(sortedSrcFiles, apiFileName)
-			}
+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]
+	})
 
-	if len(srcFilesInfo)+len(apiFiles) != len(sortedSrcFiles) {
-		var srcFiles android.Paths
-		for _, srcFileInfo := range srcFilesInfo {
-			srcFiles = append(srcFiles, srcFileInfo.ApiFile)
-		}
-		ctx.ModuleErrorf("Unrecognizable source file found within %s", append(srcFiles, apiFiles...))
-	}
-
-	return sortedSrcFiles
+	return srcFilesInfo
 }
 
 func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -1860,8 +1901,7 @@
 		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())
 
@@ -1871,6 +1911,7 @@
 	var classPaths android.Paths
 	var staticLibs android.Paths
 	var depApiSrcsStubsJar android.Path
+	var systemModulesPaths android.Paths
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		tag := ctx.OtherModuleDependencyTag(dep)
 		switch tag {
@@ -1889,24 +1930,27 @@
 		case depApiSrcsTag:
 			provider := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
 			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
-	// These are api files in the module subdirectory, which are not provided by
-	// java_api_contribution but provided directly as module property.
-	var apiFiles android.Paths
-	for _, api := range al.properties.Api_files {
-		apiFiles = append(apiFiles, android.PathForModuleSrc(ctx, api))
+	srcFilesInfo = al.sortApiFilesByApiScope(ctx, srcFilesInfo)
+	var srcFiles android.Paths
+	for _, srcFileInfo := range srcFilesInfo {
+		srcFiles = append(srcFiles, android.PathForSource(ctx, srcFileInfo.ApiFile.String()))
 	}
 
-	srcFiles := al.sortApiFilesByApiScope(ctx, srcFilesInfo, apiFiles)
-
 	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)
 
@@ -1916,6 +1960,8 @@
 		cmd.FlagWithInput("--migrate-nullness ", previousApi)
 	}
 
+	al.addValidation(ctx, cmd, al.validationPaths)
+
 	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()))
@@ -1938,6 +1984,7 @@
 		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")
 
@@ -2772,7 +2819,7 @@
 type javaResourcesAttributes struct {
 	Resources             bazel.LabelListAttribute
 	Resource_strip_prefix *string
-	Additional_resources  bazel.LabelListAttribute
+	Additional_resources  bazel.LabelListAttribute `blueprint:"mutated"`
 }
 
 func (m *Library) getResourceFilegroupStripPrefix(ctx android.Bp2buildMutatorContext, resourceFilegroup string) (*string, bool) {
@@ -2874,6 +2921,7 @@
 	Sdk_version             bazel.StringAttribute
 	Java_version            bazel.StringAttribute
 	Errorprone_force_enable bazel.BoolAttribute
+	Javac_shard_size        *int64
 }
 
 type javaDependencyLabels struct {
@@ -2932,8 +2980,8 @@
 
 	archVariantProps := m.GetArchVariantProperties(ctx, &CommonProperties{})
 	for axis, configToProps := range archVariantProps {
-		for config, _props := range configToProps {
-			if archProps, ok := _props.(*CommonProperties); ok {
+		for config, p := range configToProps {
+			if archProps, ok := p.(*CommonProperties); ok {
 				archSrcs := android.BazelLabelForModuleSrcExcludes(ctx, archProps.Srcs, archProps.Exclude_srcs)
 				srcs.SetSelectValue(axis, config, archSrcs)
 				if archProps.Jarjar_rules != nil {
@@ -2943,6 +2991,11 @@
 			}
 		}
 	}
+	srcs.Append(
+		bazel.MakeLabelListAttribute(
+			android.BazelLabelForModuleSrcExcludes(ctx,
+				m.properties.Openjdk9.Srcs,
+				m.properties.Exclude_srcs)))
 	srcs.ResolveExcludes()
 
 	javaSrcPartition := "java"
@@ -3026,8 +3079,9 @@
 	plugins := bazel.MakeLabelListAttribute(
 		android.BazelLabelForModuleDeps(ctx, m.properties.Plugins),
 	)
-	if m.properties.Javacflags != nil {
-		javacopts = bazel.MakeStringListAttribute(m.properties.Javacflags)
+	if m.properties.Javacflags != nil || m.properties.Openjdk9.Javacflags != nil {
+		javacopts = bazel.MakeStringListAttribute(
+			append(append([]string{}, m.properties.Javacflags...), m.properties.Openjdk9.Javacflags...))
 	}
 
 	epEnabled := m.properties.Errorprone.Enabled
@@ -3043,14 +3097,17 @@
 		javacopts.Append(bazel.MakeStringListAttribute([]string{"-XepDisableAllChecks"}))
 	}
 
+	resourcesAttrs := m.convertJavaResourcesAttributes(ctx)
+
 	commonAttrs := &javaCommonAttributes{
 		Srcs:                    javaSrcs,
-		javaResourcesAttributes: m.convertJavaResourcesAttributes(ctx),
+		javaResourcesAttributes: resourcesAttrs,
 		Plugins:                 plugins,
 		Javacopts:               javacopts,
 		Java_version:            bazel.StringAttribute{Value: m.properties.Java_version},
 		Sdk_version:             bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
 		Errorprone_force_enable: errorproneForceEnable,
+		Javac_shard_size:        m.properties.Javac_shard_size,
 	}
 
 	for axis, configToProps := range archVariantProps {
@@ -3067,18 +3124,8 @@
 		}
 	}
 
-	protoDepLabel := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition])
-	// Soong does not differentiate between a java_library and the Bazel equivalent of
-	// a java_proto_library + proto_library pair. Instead, in Soong proto sources are
-	// listed directly in the srcs of a java_library, and the classes produced
-	// by protoc are included directly in the resulting JAR. Thus upstream dependencies
-	// that depend on a java_library with proto sources can link directly to the protobuf API,
-	// and so this should be a static dependency.
-	if protoDepLabel != nil {
-		staticDeps.Append(bazel.MakeSingleLabelListAttribute(*protoDepLabel))
-	}
-
 	depLabels := &javaDependencyLabels{}
+	deps.Append(resourcesAttrs.Additional_resources)
 	depLabels.Deps = deps
 
 	for axis, configToProps := range archVariantProps {
@@ -3093,6 +3140,20 @@
 	}
 	depLabels.StaticDeps.Append(staticDeps)
 
+	var additionalProtoDeps bazel.LabelListAttribute
+	additionalProtoDeps.Append(depLabels.Deps)
+	additionalProtoDeps.Append(depLabels.StaticDeps)
+	protoDepLabel := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition], additionalProtoDeps)
+	// Soong does not differentiate between a java_library and the Bazel equivalent of
+	// a java_proto_library + proto_library pair. Instead, in Soong proto sources are
+	// listed directly in the srcs of a java_library, and the classes produced
+	// by protoc are included directly in the resulting JAR. Thus upstream dependencies
+	// that depend on a java_library with proto sources can link directly to the protobuf API,
+	// and so this should be a static dependency.
+	if protoDepLabel != nil {
+		depLabels.StaticDeps.Append(bazel.MakeSingleLabelListAttribute(*protoDepLabel))
+	}
+
 	hasKotlin := !kotlinSrcs.IsEmpty()
 	commonAttrs.kotlinAttributes = &kotlinAttributes{
 		Kotlincflags: &m.properties.Kotlincflags,
@@ -3456,6 +3517,7 @@
 	android.InitDefaultableModule(module)
 	android.InitPrebuiltModule(module, &[]string{""})
 	module.AddProperties(&module.properties)
+	module.AddProperties(&module.sdkLibraryComponentProperties)
 	return module
 }
 
diff --git a/java/java_test.go b/java/java_test.go
index 2ee05ec..81119a7 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -47,10 +47,6 @@
 	cc.PrepareForTestWithCcBuildComponents,
 	// Include all the default java modules.
 	PrepareForTestWithDexpreopt,
-	PrepareForTestWithOverlayBuildComponents,
-	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
-		ctx.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory)
-	}),
 )
 
 func TestMain(m *testing.M) {
@@ -1847,9 +1843,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 {
@@ -1874,7 +1878,20 @@
 		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",
@@ -1885,13 +1902,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
@@ -1903,7 +1915,7 @@
 		},
 		{
 			moduleName:         "bar2",
-			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt", "api1/current.txt", "api2/current.txt"},
+			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt"},
 		},
 	}
 	for _, c := range testcases {
@@ -1945,7 +1957,22 @@
 		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",
@@ -1975,15 +2002,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
@@ -2000,7 +2020,7 @@
 		{
 			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", "api1/current.txt", "api2/current.txt", "c/system-current.txt", "d/system-current.txt"},
+			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt", "c/system-current.txt", "d/system-current.txt"},
 		},
 	}
 	for _, c := range testcases {
@@ -2028,7 +2048,20 @@
 		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",
@@ -2040,11 +2073,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
@@ -2096,7 +2125,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",
@@ -2110,15 +2156,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
@@ -2173,7 +2211,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",
@@ -2187,15 +2242,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
@@ -2244,19 +2291,28 @@
 	}
 	`
 
-	ctx, _ := testJavaWithFS(t, `
+	ctx := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureMergeMockFs(
+			map[string][]byte{
+				"a/Android.bp": []byte(provider_bp_a),
+				"b/Android.bp": []byte(provider_bp_b),
+				"c/Android.bp": []byte(lib_bp_a),
+			},
+		),
+		android.FixtureMergeEnv(
+			map[string]string{
+				"DISABLE_STUB_VALIDATION": "true",
+			},
+		),
+	).RunTestWithBp(t, `
 		java_api_library {
 			name: "bar1",
 			api_surface: "public",
 			api_contributions: ["foo1"],
 			full_api_surface_stub: "lib1",
 		}
-		`,
-		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")
@@ -2265,27 +2321,26 @@
 	android.AssertStringDoesContain(t, "Command expected to contain full_api_surface_stub output jar", manifestCommand, "lib1.jar")
 }
 
-func TestJavaApiLibraryFilegroupInput(t *testing.T) {
-	ctx, _ := testJavaWithFS(t, `
-	    filegroup {
-			name: "default_current.txt",
-			srcs: ["current.txt"],
+func TestTransitiveSrcFiles(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_library {
+			name: "a",
+			srcs: ["a.java"],
 		}
-
-		java_api_library {
-			name: "foo",
-			api_files: [":default_current.txt"],
+		java_library {
+			name: "b",
+			srcs: ["b.java"],
 		}
-		`,
-		map[string][]byte{
-			"current.txt": nil,
-		})
-
-	m := ctx.ModuleForTests("foo", "android_common")
-	outputs := fmt.Sprint(m.AllOutputs())
-	if !strings.Contains(outputs, "foo/foo.jar") {
-		t.Errorf("Module output does not contain expected jar %s", "foo/foo.jar")
-	}
+		java_library {
+			name: "c",
+			srcs: ["c.java"],
+			libs: ["a"],
+			static_libs: ["b"],
+		}
+	`)
+	c := ctx.ModuleForTests("c", "android_common").Module()
+	transitiveSrcFiles := android.Paths(ctx.ModuleProvider(c, JavaInfoProvider).(JavaInfo).TransitiveSrcFiles.ToList())
+	android.AssertArrayString(t, "unexpected jar deps", []string{"b.java", "c.java"}, transitiveSrcFiles.Strings())
 }
 
 func TestTradefedOptions(t *testing.T) {
@@ -2405,7 +2460,14 @@
 }
 
 func TestJavaApiContributionImport(t *testing.T) {
-	ctx, _ := testJava(t, `
+	ctx := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureMergeEnv(
+			map[string]string{
+				"DISABLE_STUB_VALIDATION": "true",
+			},
+		),
+	).RunTestWithBp(t, `
 		java_api_library {
 			name: "foo",
 			api_contributions: ["bar"],
@@ -2423,3 +2485,143 @@
 	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, 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, manifest)
+	manifestCommand := sboxProto.Commands[0].GetCommand()
+	classPathFlag := "--classpath __SBOX_SANDBOX_DIR__/out/.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/metalava/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")))
+}
diff --git a/java/jdeps.go b/java/jdeps.go
index 4c8c11c..7e3a14f 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -75,7 +75,7 @@
 		dpInfo.Jarjar_rules = android.FirstUniqueStrings(dpInfo.Jarjar_rules)
 		dpInfo.Jars = android.FirstUniqueStrings(dpInfo.Jars)
 		dpInfo.SrcJars = android.FirstUniqueStrings(dpInfo.SrcJars)
-		dpInfo.Paths = android.FirstUniqueStrings(dpInfo.Paths)
+		dpInfo.Paths = []string{ctx.ModuleDir(module)}
 		dpInfo.Static_libs = android.FirstUniqueStrings(dpInfo.Static_libs)
 		dpInfo.Libs = android.FirstUniqueStrings(dpInfo.Libs)
 		moduleInfos[name] = dpInfo
diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go
index 6cb549e..4be7d04 100644
--- a/java/legacy_core_platform_api_usage.go
+++ b/java/legacy_core_platform_api_usage.go
@@ -28,6 +28,7 @@
 	"FloralClocks",
 	"framework-jobscheduler",
 	"framework-minus-apex",
+	"framework-minus-apex-headers",
 	"framework-minus-apex-intdefs",
 	"FrameworksCoreTests",
 	"HelloOslo",
diff --git a/java/lint.go b/java/lint.go
index f84f1c0..34720e5 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -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
 	}
 }
 
@@ -504,7 +508,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")
 	}
 
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index ade7395..0d52614 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -57,6 +57,9 @@
 
 	// Path to the monolithic hiddenapi-unsupported.csv file.
 	hiddenAPIMetadataCSV android.OutputPath
+
+	// Path to a srcjar containing all the transitive sources of the bootclasspath.
+	srcjar android.OutputPath
 }
 
 type platformBootclasspathProperties struct {
@@ -95,6 +98,8 @@
 		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)
@@ -173,6 +178,18 @@
 	allModules = append(allModules, apexModules...)
 	b.configuredModules = allModules
 
+	var transitiveSrcFiles android.Paths
+	for _, module := range allModules {
+		depInfo := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+		if depInfo.TransitiveSrcFiles != nil {
+			transitiveSrcFiles = append(transitiveSrcFiles, depInfo.TransitiveSrcFiles.ToList()...)
+		}
+	}
+	jarArgs := resourcePathsToJarArgs(transitiveSrcFiles)
+	jarArgs = append(jarArgs, "-srcjar") // Move srcfiles to the right package
+	b.srcjar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-transitive.srcjar").OutputPath
+	TransformResourcesToJar(ctx, b.srcjar, jarArgs, transitiveSrcFiles)
+
 	// Gather all the fragments dependencies.
 	b.fragments = gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag)
 
@@ -185,8 +202,6 @@
 
 	bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments)
 	buildRuleForBootJarsPackageCheck(ctx, bootDexJarByModule)
-
-	b.copyApexBootJarsForAppsDexpreopt(ctx, apexModules)
 }
 
 // Generate classpaths.proto config
@@ -398,10 +413,3 @@
 	// INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/.
 	ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", b.hiddenAPIFlagsCSV.String())
 }
-
-// Copy apex module dex jars to their predefined locations. They will be used for dexpreopt for apps.
-func (b *platformBootclasspathModule) copyApexBootJarsForAppsDexpreopt(ctx android.ModuleContext, apexModules []android.Module) {
-	config := GetApexBootConfig(ctx)
-	apexBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, apexModules)
-	copyBootJarsToPredefinedLocations(ctx, apexBootDexJarsByModule, config.dexPathsByModule)
-}
diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go
index ff2da4b..37ff639 100644
--- a/java/platform_bootclasspath_test.go
+++ b/java/platform_bootclasspath_test.go
@@ -81,6 +81,15 @@
 			RunTest(t)
 	})
 
+	fooSourceSrc := "source/a.java"
+	barSrc := "a.java"
+
+	checkSrcJarInputs := func(t *testing.T, result *android.TestResult, name string, expected []string) {
+		t.Helper()
+		srcjar := result.ModuleForTests(name, "android_common").Output(name + "-transitive.srcjar")
+		android.AssertStringDoesContain(t, "srcjar arg", srcjar.Args["jarArgs"], "-srcjar")
+		android.AssertArrayString(t, "srcjar inputs", expected, srcjar.Implicits.Strings())
+	}
 	t.Run("source", func(t *testing.T) {
 		result := android.GroupFixturePreparers(
 			preparer,
@@ -91,6 +100,10 @@
 			"platform:foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			fooSourceSrc,
+			barSrc,
+		})
 	})
 
 	t.Run("prebuilt", func(t *testing.T) {
@@ -103,6 +116,10 @@
 			"platform:prebuilt_foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			// TODO(b/151360309): This should also have the srcs for prebuilt_foo
+			barSrc,
+		})
 	})
 
 	t.Run("source+prebuilt - source preferred", func(t *testing.T) {
@@ -116,6 +133,10 @@
 			"platform:foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			fooSourceSrc,
+			barSrc,
+		})
 	})
 
 	t.Run("source+prebuilt - prebuilt preferred", func(t *testing.T) {
@@ -129,6 +150,10 @@
 			"platform:prebuilt_foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			// TODO(b/151360309): This should also have the srcs for prebuilt_foo
+			barSrc,
+		})
 	})
 
 	t.Run("dex import", func(t *testing.T) {
@@ -146,6 +171,10 @@
 			"platform:prebuilt_foo",
 			"platform:bar",
 		})
+		checkSrcJarInputs(t, result, "platform-bootclasspath", []string{
+			// TODO(b/151360309): This should also have the srcs for prebuilt_foo
+			barSrc,
+		})
 	})
 }
 
diff --git a/java/proto.go b/java/proto.go
index 2ed7b27..c88d3d7 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -151,11 +151,19 @@
 	// a specific .proto file module explicitly.
 	Transitive_deps bazel.LabelListAttribute
 
+	// This is the libs and the static_libs of the original java_library module.
+	// On the bazel side, after proto sources are generated in java_*_proto_library, a java_library
+	// will compile them. The libs and static_libs from the original java_library module need
+	// to be linked because they are necessary in compile-time classpath.
+	Additional_proto_deps bazel.LabelListAttribute
+
 	Sdk_version  bazel.StringAttribute
 	Java_version bazel.StringAttribute
+
+	Plugin bazel.LabelAttribute
 }
 
-func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) *bazel.Label {
+func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute, AdditionalProtoDeps bazel.LabelListAttribute) *bazel.Label {
 	protoInfo, ok := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, protoSrcs)
 	if !ok {
 		return nil
@@ -183,11 +191,18 @@
 		ctx.PropertyErrorf("proto.type", "cannot handle conversion at this time: %q", typ)
 	}
 
+	plugin := bazel.LabelAttribute{}
+	if m.protoProperties.Proto.Plugin != nil {
+		plugin.SetValue(android.BazelLabelForModuleDepSingle(ctx, "protoc-gen-"+*m.protoProperties.Proto.Plugin))
+	}
+
 	protoAttrs := &protoAttributes{
-		Deps:            bazel.MakeLabelListAttribute(protoInfo.Proto_libs),
-		Transitive_deps: bazel.MakeLabelListAttribute(protoInfo.Transitive_proto_libs),
-		Java_version:    bazel.StringAttribute{Value: m.properties.Java_version},
-		Sdk_version:     bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
+		Deps:                  bazel.MakeLabelListAttribute(protoInfo.Proto_libs),
+		Transitive_deps:       bazel.MakeLabelListAttribute(protoInfo.Transitive_proto_libs),
+		Additional_proto_deps: AdditionalProtoDeps,
+		Java_version:          bazel.StringAttribute{Value: m.properties.Java_version},
+		Sdk_version:           bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
+		Plugin:                plugin,
 	}
 
 	name := m.Name() + suffix
diff --git a/java/robolectric.go b/java/robolectric.go
index 0041af4..a8e6bfa 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -22,6 +22,7 @@
 
 	"android/soong/android"
 	"android/soong/java/config"
+	"android/soong/testing"
 	"android/soong/tradefed"
 
 	"github.com/google/blueprint/proptools"
@@ -34,7 +35,7 @@
 
 var robolectricDefaultLibs = []string{
 	"mockito-robolectric-prebuilt",
-	"truth-prebuilt",
+	"truth",
 	// TODO(ccross): this is not needed at link time
 	"junitxml",
 }
@@ -253,6 +254,7 @@
 	}
 
 	r.installFile = ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...)
+	ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath,
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 7c702c4..ad71fb2 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.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")
@@ -76,7 +72,8 @@
 		// Core is by definition what is included in the system module for the public API so should
 		// just use its system modules.
 		systemModuleKind = android.SdkPublic
-	} else if systemModuleKind == android.SdkSystem || systemModuleKind == android.SdkTest {
+	} else if systemModuleKind == android.SdkSystem || systemModuleKind == android.SdkTest ||
+		systemModuleKind == android.SdkTestFrameworksCore {
 		// The core system and test APIs are currently the same as the public API so they should use
 		// its system modules.
 		systemModuleKind = android.SdkPublic
@@ -192,7 +189,7 @@
 			bootclasspath:    corePlatformBootclasspathLibraries(ctx),
 			noFrameworksLibs: true,
 		}
-	case android.SdkPublic, android.SdkSystem, android.SdkTest:
+	case android.SdkPublic, android.SdkSystem, android.SdkTest, android.SdkTestFrameworksCore:
 		return toModule(sdkVersion.Kind.DefaultJavaLibraryName(), sdkFrameworkAidlPath(ctx))
 	case android.SdkCore:
 		return sdkDep{
@@ -212,44 +209,6 @@
 	}
 }
 
-func sdkPreSingletonFactory() android.Singleton {
-	return sdkPreSingleton{}
-}
-
-type sdkPreSingleton struct{}
-
-func (sdkPreSingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	sdkJars, err := ctx.GlobWithDeps("prebuilts/sdk/*/public/android.jar", nil)
-	if err != nil {
-		ctx.Errorf("failed to glob prebuilts/sdk/*/public/android.jar: %s", err.Error())
-	}
-
-	var sdkVersions []int
-	for _, sdkJar := range sdkJars {
-		dir := filepath.Base(filepath.Dir(filepath.Dir(sdkJar)))
-		v, err := strconv.Atoi(dir)
-		if scerr, ok := err.(*strconv.NumError); ok && scerr.Err == strconv.ErrSyntax {
-			continue
-		} else if err != nil {
-			ctx.Errorf("invalid sdk jar %q, %s, %v", sdkJar, err.Error())
-		}
-		sdkVersions = append(sdkVersions, v)
-	}
-
-	sort.Ints(sdkVersions)
-
-	ctx.Config().Once(sdkVersionsKey, func() interface{} { return sdkVersions })
-}
-
-func LatestSdkVersionInt(ctx android.EarlyModuleContext) int {
-	sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int)
-	latestSdkVersion := 0
-	if len(sdkVersions) > 0 {
-		latestSdkVersion = sdkVersions[len(sdkVersions)-1]
-	}
-	return latestSdkVersion
-}
-
 func sdkSingletonFactory() android.Singleton {
 	return sdkSingleton{}
 }
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 27f8626..fb27812 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -286,6 +286,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
@@ -459,6 +470,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 {
@@ -604,8 +618,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
+
 	// TODO: determines whether to create HTML doc or not
 	// Html_doc *bool
 }
@@ -1642,6 +1667,7 @@
 	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.
@@ -1714,6 +1740,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
@@ -1731,15 +1758,15 @@
 			android.JoinWithPrefix(module.sdkLibraryProperties.Hidden_api_packages, " --hide-package "))
 	}
 	droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...)
-	disabledWarnings := []string{
-		"BroadcastBehavior",
-		"DeprecationMismatch",
-		"HiddenSuperclass",
-		"HiddenTypeParameter",
-		"MissingPermission",
-		"SdkConstant",
-		"Todo",
-		"UnavailableSymbol",
+	disabledWarnings := []string{"HiddenSuperclass"}
+	if proptools.BoolDefault(module.sdkLibraryProperties.Api_lint.Legacy_errors_allowed, true) {
+		disabledWarnings = append(disabledWarnings,
+			"BroadcastBehavior",
+			"DeprecationMismatch",
+			"MissingPermission",
+			"SdkConstant",
+			"Todo",
+		)
 	}
 	droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
 
@@ -1815,7 +1842,7 @@
 		}
 	}
 
-	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) {
@@ -1826,6 +1853,8 @@
 		Libs                  []string
 		Static_libs           []string
 		Full_api_surface_stub *string
+		System_modules        *string
+		Enable_validation     *bool
 	}{}
 
 	props.Name = proptools.StringPtr(module.apiLibraryModuleName(apiScope))
@@ -1851,6 +1880,7 @@
 	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())
@@ -1864,7 +1894,18 @@
 		props.Full_api_surface_stub = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName() + "_full.from-text")
 	}
 
-	mctx.CreateModule(ApiLibraryFactory, &props)
+	// java_sdk_library modules that set sdk_version as none does not depend on other api
+	// domains. Therefore, java_api_library created from such modules should not depend on
+	// full_api_surface_stubs but create and compile stubs by the java_api_library module
+	// itself.
+	if module.SdkVersion(mctx).Kind == android.SdkNone {
+		props.Full_api_surface_stub = nil
+	}
+
+	props.System_modules = module.deviceProperties.System_modules
+	props.Enable_validation = proptools.BoolPtr(true)
+
+	mctx.CreateModule(ApiLibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
 }
 
 func (module *SdkLibrary) createTopLevelStubsLibrary(
@@ -1932,6 +1973,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)
@@ -2562,7 +2607,7 @@
 	// 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) {
@@ -2581,7 +2626,7 @@
 	props.Api_file = api_file
 	props.Visibility = []string{"//visibility:override", "//visibility:public"}
 
-	mctx.CreateModule(ApiContributionImportFactory, &props)
+	mctx.CreateModule(ApiContributionImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
 }
 
 // Add the dependencies on the child module in the component deps mutator so that it
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 0b46919..82f8a4d 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -1068,6 +1068,137 @@
 	})
 }
 
+// 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",
+			],
+		}
+		all_apex_contributions {
+			name: "all_apex_contributions",
+		}
+		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.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+			android.RegisterApexContributionsBuildComponents(ctx)
+		}),
+		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 {
@@ -1421,6 +1552,32 @@
 	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs, "bar-lib")
 }
 
+func TestJavaSdkLibrary_Scope_Libs_PassedToDroidstubs(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("foo"),
+	).RunTestWithBp(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["a.java"],
+			public: {
+				enabled: true,
+				libs: ["bar-lib"],
+			},
+		}
+
+		java_library {
+			name: "bar-lib",
+			srcs: ["b.java"],
+		}
+		`)
+
+	// The foo.stubs.source should depend on bar-lib
+	fooStubsSources := result.ModuleForTests("foo.stubs.source", "android_common").Module().(*Droidstubs)
+	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs, "bar-lib")
+}
+
 func TestJavaSdkLibrary_ApiLibrary(t *testing.T) {
 	result := android.GroupFixturePreparers(
 		prepareForJavaTest,
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/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index 17d301b..30dd55f 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 {
diff --git a/java/testing.go b/java/testing.go
index f2bcccf..e883bcb 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -73,10 +73,15 @@
 		// Needed for various deps defined in GatherRequiredDepsForTest()
 		defaultJavaDir + "/a.java":                        nil,
 		defaultJavaDir + "/api/current.txt":               nil,
+		defaultJavaDir + "/api/removed.txt":               nil,
 		defaultJavaDir + "/api/system-current.txt":        nil,
+		defaultJavaDir + "/api/system-removed.txt":        nil,
 		defaultJavaDir + "/api/test-current.txt":          nil,
+		defaultJavaDir + "/api/test-removed.txt":          nil,
 		defaultJavaDir + "/api/module-lib-current.txt":    nil,
+		defaultJavaDir + "/api/module-lib-removed.txt":    nil,
 		defaultJavaDir + "/api/system-server-current.txt": nil,
+		defaultJavaDir + "/api/system-server-removed.txt": nil,
 
 		// Needed for R8 rules on apps
 		"build/make/core/proguard.flags":             nil,
@@ -113,8 +118,6 @@
 	dexpreopt.PrepareForTestByEnablingDexpreopt,
 )
 
-var PrepareForTestWithOverlayBuildComponents = android.FixtureRegisterWithContext(registerOverlayBuildComponents)
-
 // Prepare a fixture to use all java module types, mutators and singletons fully.
 //
 // This should only be used by tests that want to run with as much of the build enabled as possible.
@@ -410,6 +413,7 @@
 		"stub-annotations",
 
 		"aconfig-annotations-lib",
+		"unsupportedappusage",
 	}
 
 	for _, extra := range extraModules {
@@ -424,30 +428,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",
-		"android-non-updatable.stubs.from-text":            "api/current.txt",
-		"android-non-updatable.stubs.system.from-text":     "api/system-current.txt",
-		"android-non-updatable.stubs.test.from-text":       "api/test-current.txt",
-		"android-non-updatable.stubs.module_lib.from-text": "api/module-lib-current.txt",
+	type droidstubsStruct struct {
+		name        string
+		apiSurface  string
+		apiFile     string
+		removedFile string
 	}
 
-	for libName, apiFile := range extraApiLibraryModules {
+	var publicDroidstubs = droidstubsStruct{
+		name:        "api-stubs-docs-non-updatable",
+		apiSurface:  "public",
+		apiFile:     "api/current.txt",
+		removedFile: "api/removed.txt",
+	}
+	var systemDroidstubs = droidstubsStruct{
+		name:        "system-api-stubs-docs-non-updatable",
+		apiSurface:  "system",
+		apiFile:     "api/system-current.txt",
+		removedFile: "api/system-removed.txt",
+	}
+	var testDroidstubs = droidstubsStruct{
+		name:        "test-api-stubs-docs-non-updatable",
+		apiSurface:  "test",
+		apiFile:     "api/test-current.txt",
+		removedFile: "api/test-removed.txt",
+	}
+	var moduleLibDroidstubs = droidstubsStruct{
+		name:        "module-lib-api-stubs-docs-non-updatable",
+		apiSurface:  "module-lib",
+		apiFile:     "api/module-lib-current.txt",
+		removedFile: "api/module-lib-removed.txt",
+	}
+	var systemServerDroidstubs = droidstubsStruct{
+		// This module does not exist but is named this way for consistency
+		name:        "system-server-api-stubs-docs-non-updatable",
+		apiSurface:  "system-server",
+		apiFile:     "api/system-server-current.txt",
+		removedFile: "api/system-server-removed.txt",
+	}
+	var droidstubsStructs = []droidstubsStruct{
+		publicDroidstubs,
+		systemDroidstubs,
+		testDroidstubs,
+		moduleLibDroidstubs,
+		systemServerDroidstubs,
+	}
+
+	extraApiLibraryModules := map[string]droidstubsStruct{
+		"android_stubs_current.from-text":                  publicDroidstubs,
+		"android_system_stubs_current.from-text":           systemDroidstubs,
+		"android_test_stubs_current.from-text":             testDroidstubs,
+		"android_module_lib_stubs_current.from-text":       moduleLibDroidstubs,
+		"android_module_lib_stubs_current_full.from-text":  moduleLibDroidstubs,
+		"android_system_server_stubs_current.from-text":    systemServerDroidstubs,
+		"core.current.stubs.from-text":                     publicDroidstubs,
+		"legacy.core.platform.api.stubs.from-text":         publicDroidstubs,
+		"stable.core.platform.api.stubs.from-text":         publicDroidstubs,
+		"core-lambda-stubs.from-text":                      publicDroidstubs,
+		"android-non-updatable.stubs.from-text":            publicDroidstubs,
+		"android-non-updatable.stubs.system.from-text":     systemDroidstubs,
+		"android-non-updatable.stubs.test.from-text":       testDroidstubs,
+		"android-non-updatable.stubs.module_lib.from-text": moduleLibDroidstubs,
+		"android-non-updatable.stubs.test_module_lib":      moduleLibDroidstubs,
+	}
+
+	for _, droidstubs := range droidstubsStructs {
+		bp += fmt.Sprintf(`
+			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 += `
@@ -502,7 +573,7 @@
 	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{}
@@ -511,11 +582,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) {
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/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 8225df6..78ab771 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -635,6 +635,13 @@
 	case "+=":
 		asgn.flavor = asgnAppend
 	case "?=":
+		if _, ok := lhs.(*productConfigVariable); ok {
+			// Make sets all product configuration variables to empty strings before running product
+			// config makefiles. ?= will have no effect on a variable that has been assigned before,
+			// even if assigned to an empty string. So just skip emitting any code for this
+			// assignment.
+			return nil
+		}
 		asgn.flavor = asgnMaybeSet
 	default:
 		panic(fmt.Errorf("unexpected assignment type %s", a.Type))
@@ -941,6 +948,8 @@
 
 func (ctx *parseContext) handleInclude(v *mkparser.Directive) []starlarkNode {
 	loadAlways := v.Name[0] != '-'
+	v.Args.TrimRightSpaces()
+	v.Args.TrimLeftSpaces()
 	return ctx.handleSubConfig(v, ctx.parseMakeString(v, v.Args), loadAlways, func(im inheritedModule) starlarkNode {
 		return &includeNode{im, loadAlways}
 	})
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index 7e68026..0c4d213 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -193,6 +193,31 @@
 	},
 
 	{
+		desc:   "Include with trailing whitespace",
+		mkname: "product.mk",
+		in: `
+# has a trailing whitespace after cfg.mk
+include vendor/$(foo)/cfg.mk 
+`,
+		expected: `# has a trailing whitespace after cfg.mk
+load("//build/make/core:product_config.rbc", "rblf")
+load("//vendor/foo1:cfg.star|init", _cfg_init = "init")
+load("//vendor/bar/baz:cfg.star|init", _cfg1_init = "init")
+
+def init(g, handle):
+  cfg = rblf.cfg(handle)
+  _entry = {
+    "vendor/foo1/cfg.mk": ("vendor/foo1/cfg", _cfg_init),
+    "vendor/bar/baz/cfg.mk": ("vendor/bar/baz/cfg", _cfg1_init),
+  }.get("vendor/%s/cfg.mk" % _foo)
+  (_varmod, _varmod_init) = _entry if _entry else (None, None)
+  if not _varmod_init:
+    rblf.mkerror("product.mk", "Cannot find %s" % ("vendor/%s/cfg.mk" % _foo))
+  _varmod_init(g, handle)
+`,
+	},
+
+	{
 		desc:   "Synonymous inherited configurations",
 		mkname: "path/product.mk",
 		in: `
@@ -898,8 +923,6 @@
   cfg["PRODUCT_LIST2"] += ["a"]
   cfg["PRODUCT_LIST1"] += ["b"]
   cfg["PRODUCT_LIST2"] += ["b"]
-  if cfg.get("PRODUCT_LIST3") == None:
-    cfg["PRODUCT_LIST3"] = ["a"]
   cfg["PRODUCT_LIST1"] = ["c"]
   g.setdefault("PLATFORM_LIST", [])
   g["PLATFORM_LIST"] += ["x"]
@@ -941,9 +964,10 @@
 PRODUCT_LIST2 ?= a $(PRODUCT_LIST2)
 PRODUCT_LIST3 += a
 
-# Now doing them again should not have a setdefault because they've already been set
+# Now doing them again should not have a setdefault because they've already been set, except 2
+# which did not emit an assignment before
 PRODUCT_LIST1 = a $(PRODUCT_LIST1)
-PRODUCT_LIST2 ?= a $(PRODUCT_LIST2)
+PRODUCT_LIST2 = a $(PRODUCT_LIST2)
 PRODUCT_LIST3 += a
 `,
 		expected: `# All of these should have a setdefault because they're self-referential and not defined before
@@ -954,18 +978,15 @@
   rblf.setdefault(handle, "PRODUCT_LIST1")
   cfg["PRODUCT_LIST1"] = (["a"] +
       cfg.get("PRODUCT_LIST1", []))
-  if cfg.get("PRODUCT_LIST2") == None:
-    rblf.setdefault(handle, "PRODUCT_LIST2")
-    cfg["PRODUCT_LIST2"] = (["a"] +
-        cfg.get("PRODUCT_LIST2", []))
   rblf.setdefault(handle, "PRODUCT_LIST3")
   cfg["PRODUCT_LIST3"] += ["a"]
-  # Now doing them again should not have a setdefault because they've already been set
+  # Now doing them again should not have a setdefault because they've already been set, except 2
+  # which did not emit an assignment before
   cfg["PRODUCT_LIST1"] = (["a"] +
       cfg["PRODUCT_LIST1"])
-  if cfg.get("PRODUCT_LIST2") == None:
-    cfg["PRODUCT_LIST2"] = (["a"] +
-        cfg["PRODUCT_LIST2"])
+  rblf.setdefault(handle, "PRODUCT_LIST2")
+  cfg["PRODUCT_LIST2"] = (["a"] +
+      cfg.get("PRODUCT_LIST2", []))
   cfg["PRODUCT_LIST3"] += ["a"]
 `,
 	},
diff --git a/mk2rbc/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/python/Android.bp b/python/Android.bp
index 7578673..87810c9 100644
--- a/python/Android.bp
+++ b/python/Android.bp
@@ -10,6 +10,7 @@
         "soong-android",
         "soong-tradefed",
         "soong-cc",
+        "soong-testing",
     ],
     srcs: [
         "binary.go",
diff --git a/python/test.go b/python/test.go
index 6e23a44..cd7c73b 100644
--- a/python/test.go
+++ b/python/test.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 
+	"android/soong/testing"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -205,6 +206,7 @@
 			p.data = append(p.data, android.DataPath{SrcPath: javaDataSrcPath})
 		}
 	}
+	ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 func (p *PythonTestModule) AndroidMkEntries() []android.AndroidMkEntries {
diff --git a/remoteexec/remoteexec.go b/remoteexec/remoteexec.go
index 9e7a0f1..1e181fb 100644
--- a/remoteexec/remoteexec.go
+++ b/remoteexec/remoteexec.go
@@ -15,6 +15,7 @@
 package remoteexec
 
 import (
+	"fmt"
 	"sort"
 	"strings"
 )
@@ -29,7 +30,7 @@
 	// DefaultImage is the default container image used for Android remote execution. The
 	// image was built with the Dockerfile at
 	// https://android.googlesource.com/platform/prebuilts/remoteexecution-client/+/refs/heads/master/docker/Dockerfile
-	DefaultImage = "docker://gcr.io/androidbuild-re-dockerimage/android-build-remoteexec-image@sha256:582efb38f0c229ea39952fff9e132ccbe183e14869b39888010dacf56b360d62"
+	DefaultImage = "docker://gcr.io/androidbuild-re-dockerimage/android-build-remoteexec-image@sha256:1eb7f64b9e17102b970bd7a1af7daaebdb01c3fb777715899ef462d6c6d01a45"
 
 	// DefaultWrapperPath is the default path to the remote execution wrapper.
 	DefaultWrapperPath = "prebuilts/remoteexecution-client/live/rewrapper"
@@ -84,6 +85,12 @@
 	// 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
 }
 
 func init() {
@@ -135,6 +142,10 @@
 	}
 	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 len(r.Inputs) > 0 {
 		args += " --inputs=" + strings.Join(r.Inputs, ",")
 	}
diff --git a/rust/afdo_test.go b/rust/afdo_test.go
index 80327af..0cdf704 100644
--- a/rust/afdo_test.go
+++ b/rust/afdo_test.go
@@ -54,8 +54,8 @@
 
 	expectedCFlag := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo.afdo")
 
-	if !strings.Contains(foo.RuleParams.Command, expectedCFlag) {
-		t.Errorf("Expected 'foo' to enable afdo, but did not find %q in command %q", expectedCFlag, foo.RuleParams.Command)
+	if !strings.Contains(foo.Args["rustcFlags"], expectedCFlag) {
+		t.Errorf("Expected 'foo' to enable afdo, but did not find %q in cflags %q", expectedCFlag, foo.Args["rustcFlags"])
 	}
 }
 
@@ -96,17 +96,17 @@
 		rustMockedFiles.AddToFixture(),
 	).RunTestWithBp(t, bp)
 
-	fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon").Description("rustc")
-	fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a").Description("rustc")
+	fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon").Rule("rustc")
+	fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
 
 	expectedCFlagArm := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo_arm.afdo")
 	expectedCFlagArm64 := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo_arm64.afdo")
 
-	if !strings.Contains(fooArm.RuleParams.Command, expectedCFlagArm) {
-		t.Errorf("Expected 'fooArm' to enable afdo, but did not find %q in command %q", expectedCFlagArm, fooArm.RuleParams.Command)
+	if !strings.Contains(fooArm.Args["rustcFlags"], expectedCFlagArm) {
+		t.Errorf("Expected 'fooArm' to enable afdo, but did not find %q in cflags %q", expectedCFlagArm, fooArm.Args["rustcFlags"])
 	}
 
-	if !strings.Contains(fooArm64.RuleParams.Command, expectedCFlagArm64) {
-		t.Errorf("Expected 'fooArm64' to enable afdo, but did not find %q in command %q", expectedCFlagArm64, fooArm.RuleParams.Command)
+	if !strings.Contains(fooArm64.Args["rustcFlags"], expectedCFlagArm64) {
+		t.Errorf("Expected 'fooArm64' to enable afdo, but did not find %q in cflags %q", expectedCFlagArm64, fooArm64.Args["rustcFlags"])
 	}
 }
diff --git a/rust/binary.go b/rust/binary.go
index 353381d..860dc94 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -77,14 +77,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")
 
@@ -149,6 +146,7 @@
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
+	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
 
 	if binary.stripper.NeedsStrip(ctx) {
 		strippedOutputFile := outputFile
@@ -159,7 +157,7 @@
 	}
 	binary.baseCompiler.unstrippedOutputFile = outputFile
 
-	ret.kytheFile = TransformSrcToBinary(ctx, binary, crateRootPath, deps, flags, outputFile).kytheFile
+	ret.kytheFile = TransformSrcToBinary(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	return ret
 }
 
diff --git a/rust/binary_test.go b/rust/binary_test.go
index ab1d2bc..ef93037 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -135,7 +135,7 @@
 
 	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustc")
 
-	flags := fizzBuzz.RuleParams.Command
+	flags := fizzBuzz.Args["rustcFlags"]
 	if strings.Contains(flags, "--test") {
 		t.Errorf("extra --test flag, rustcFlags: %#v", flags)
 	}
@@ -153,8 +153,8 @@
 	foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
 
 	flag := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker64"
-	if !strings.Contains(foo.RuleParams.Command, flag) {
-		t.Errorf("missing link flag to use bootstrap linker, expecting %#v, command: %#v", flag, foo.RuleParams.Command)
+	if !strings.Contains(foo.Args["linkFlags"], flag) {
+		t.Errorf("missing link flag to use bootstrap linker, expecting %#v, linkFlags: %#v", flag, foo.Args["linkFlags"])
 	}
 }
 
@@ -169,15 +169,16 @@
 	fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc")
 	fizzMod := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module)
 
-	flags := fizzOut.RuleParams.Command
+	flags := fizzOut.Args["rustcFlags"]
+	linkFlags := fizzOut.Args["linkFlags"]
 	if !strings.Contains(flags, "-C relocation-model=static") {
-		t.Errorf("static binary missing '-C relocation-model=static' in command, found: %#v", flags)
+		t.Errorf("static binary missing '-C relocation-model=static' in rustcFlags, found: %#v", flags)
 	}
 	if !strings.Contains(flags, "-C panic=abort") {
-		t.Errorf("static binary missing '-C panic=abort' in command, found: %#v", flags)
+		t.Errorf("static binary missing '-C panic=abort' in rustcFlags, found: %#v", flags)
 	}
-	if !strings.Contains(flags, "-static") {
-		t.Errorf("static binary missing '-static' in command, found: %#v", flags)
+	if !strings.Contains(linkFlags, "-static") {
+		t.Errorf("static binary missing '-static' in linkFlags, found: %#v", flags)
 	}
 
 	if !android.InList("libc", fizzMod.Properties.AndroidMkStaticLibs) {
@@ -200,8 +201,9 @@
 		}`)
 
 	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustc")
-	if !strings.Contains(fizzBuzz.RuleParams.Command, "/libfoo.so") {
-		t.Errorf("missing shared dependency 'libfoo.so' in command: %#v", fizzBuzz.RuleParams.Command)
+	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 a80a587..ffe532f 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -124,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)
diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go
index 12cdb3c..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) {
diff --git a/rust/builder.go b/rust/builder.go
index 0740518..162d1aa 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -15,7 +15,6 @@
 package rust
 
 import (
-	"fmt"
 	"path/filepath"
 	"strings"
 
@@ -26,6 +25,49 @@
 )
 
 var (
+	_     = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc")
+	rustc = pctx.AndroidStaticRule("rustc",
+		blueprint.RuleParams{
+			Command: "$envVars $rustcCmd " +
+				"-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"},
+			// 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:
+			//     "warning: depfile has multiple output paths"
+			// For ninja, we keep/grep only the dependency rule for the rust $out file.
+			Deps:    blueprint.DepsGCC,
+			Depfile: "$out.d",
+		},
+		"rustcFlags", "earlyLinkFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars")
+
+	_       = pctx.SourcePathVariable("rustdocCmd", "${config.RustBin}/rustdoc")
+	rustdoc = pctx.AndroidStaticRule("rustdoc",
+		blueprint.RuleParams{
+			Command: "$envVars $rustdocCmd $rustdocFlags $in -o $outDir && " +
+				"touch $out",
+			CommandDeps: []string{"$rustdocCmd"},
+		},
+		"rustdocFlags", "outDir", "envVars")
+
+	_            = pctx.SourcePathVariable("clippyCmd", "${config.RustBin}/clippy-driver")
+	clippyDriver = pctx.AndroidStaticRule("clippy",
+		blueprint.RuleParams{
+			Command: "$envVars $clippyCmd " +
+				// Because clippy-driver uses rustc as backend, we need to have some output even during the linting.
+				// Use the metadata output as it has the smallest footprint.
+				"--emit metadata -o $out --emit dep-info=$out.d.raw $in ${libFlags} " +
+				"$rustcFlags $clippyFlags" +
+				" && grep \"^$out:\" $out.d.raw > $out.d",
+			CommandDeps: []string{"$clippyCmd"},
+			Deps:        blueprint.DepsGCC,
+			Depfile:     "$out.d",
+		},
+		"rustcFlags", "libFlags", "clippyFlags", "envVars")
+
 	zip = pctx.AndroidStaticRule("zip",
 		blueprint.RuleParams{
 			Command:        "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp",
@@ -34,7 +76,7 @@
 			RspfileContent: "$in",
 		})
 
-	cpDir = pctx.AndroidStaticRule("cpDir",
+	cp = pctx.AndroidStaticRule("cp",
 		blueprint.RuleParams{
 			Command:        "cp `cat $outDir.rsp` $outDir",
 			Rspfile:        "${outDir}.rsp",
@@ -42,12 +84,6 @@
 		},
 		"outDir")
 
-	cp = pctx.AndroidStaticRule("cp",
-		blueprint.RuleParams{
-			Command:     "rm -f $out && cp $in $out",
-			Description: "cp $out",
-		})
-
 	// Cross-referencing:
 	_ = pctx.SourcePathVariable("rustExtractor",
 		"prebuilts/build-tools/${config.HostPrebuiltTag}/bin/rust_extractor")
@@ -55,6 +91,24 @@
 		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() })
 	_ = pctx.VariableFunc("kytheCuEncoding",
 		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCuEncoding() })
+	_            = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json")
+	kytheExtract = pctx.AndroidStaticRule("kythe",
+		blueprint.RuleParams{
+			Command: `KYTHE_CORPUS=${kytheCorpus} ` +
+				`KYTHE_OUTPUT_FILE=$out ` +
+				`KYTHE_VNAMES=$kytheVnames ` +
+				`KYTHE_KZIP_ENCODING=${kytheCuEncoding} ` +
+				`KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative ` +
+				`$rustExtractor $envVars ` +
+				`$rustcCmd ` +
+				`-C linker=${config.RustLinker} ` +
+				`-C link-args="${crtBegin} ${linkFlags} ${crtEnd}" ` +
+				`$in ${libFlags} $rustcFlags`,
+			CommandDeps:    []string{"$rustExtractor", "$kytheVnames"},
+			Rspfile:        "${out}.rsp",
+			RspfileContent: "$in",
+		},
+		"rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars")
 )
 
 type buildOutput struct {
@@ -66,40 +120,40 @@
 	pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
 }
 
-func TransformSrcToBinary(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrcToBinary(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
 	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
 
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "bin")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin")
 }
 
-func TransformSrctoRlib(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "rlib")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib")
 }
 
-func TransformSrctoDylib(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoDylib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
 	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
 
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "dylib")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib")
 }
 
-func TransformSrctoStatic(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoStatic(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
 	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "staticlib")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib")
 }
 
-func TransformSrctoShared(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoShared(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
 	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "cdylib")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib")
 }
 
-func TransformSrctoProcMacro(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps,
+func TransformSrctoProcMacro(ctx ModuleContext, mainSrc android.Path, deps PathDeps,
 	flags Flags, outputFile android.WritablePath) buildOutput {
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "proc-macro")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro")
 }
 
 func rustLibsToPaths(libs RustLibraries) android.Paths {
@@ -110,46 +164,28 @@
 	return paths
 }
 
-func makeLibFlags(deps PathDeps, ruleCmd *android.RuleBuilderCommand) []string {
+func makeLibFlags(deps PathDeps) []string {
 	var libFlags []string
 
 	// Collect library/crate flags
-	for _, lib := range deps.Rlibs.ToListDirect() {
-		libPath := ruleCmd.PathForInput(lib.Path)
-		libFlags = append(libFlags, "--extern "+lib.CrateName+"="+libPath)
+	for _, lib := range deps.RLibs {
+		libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
 	}
-	for _, lib := range deps.Dylibs.ToListDirect() {
-		libPath := ruleCmd.PathForInput(lib.Path)
-		libFlags = append(libFlags, "--extern "+lib.CrateName+"="+libPath)
+	for _, lib := range deps.DyLibs {
+		libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
 	}
-	for _, procMacro := range deps.ProcMacros.ToListDirect() {
-		procMacroPath := ruleCmd.PathForInput(procMacro.Path)
-		libFlags = append(libFlags, "--extern "+procMacro.CrateName+"="+procMacroPath)
+	for _, proc_macro := range deps.ProcMacros {
+		libFlags = append(libFlags, "--extern "+proc_macro.CrateName+"="+proc_macro.Path.String())
 	}
 
 	for _, path := range deps.linkDirs {
-		libFlags = append(libFlags, "-L "+ruleCmd.PathForInput(path))
+		libFlags = append(libFlags, "-L "+path)
 	}
 
 	return libFlags
 }
 
-func collectImplicits(deps PathDeps) android.Paths {
-	depPaths := android.Paths{}
-	depPaths = append(depPaths, rustLibsToPaths(deps.Rlibs.ToList())...)
-	depPaths = append(depPaths, rustLibsToPaths(deps.Dylibs.ToList())...)
-	depPaths = append(depPaths, rustLibsToPaths(deps.ProcMacros.ToList())...)
-	depPaths = append(depPaths, deps.AfdoProfiles...)
-	depPaths = append(depPaths, deps.WholeStaticLibs...)
-	depPaths = append(depPaths, deps.SrcDeps...)
-	depPaths = append(depPaths, deps.srcProviderFiles...)
-	depPaths = append(depPaths, deps.LibDeps...)
-	depPaths = append(depPaths, deps.linkObjects...)
-	depPaths = append(depPaths, deps.BuildToolSrcDeps...)
-	return depPaths
-}
-
-func rustEnvVars(ctx ModuleContext, deps PathDeps, cmd *android.RuleBuilderCommand) []string {
+func rustEnvVars(ctx ModuleContext, deps PathDeps) []string {
 	var envVars []string
 
 	// libstd requires a specific environment variable to be set. This is
@@ -163,17 +199,15 @@
 		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 outDir string
-		if filepath.IsAbs(moduleGenDir.String()) {
-			// If OUT_DIR is absolute, then moduleGenDir will be an absolute path, so we don't need to set this to anything.
-			outDir = moduleGenDir.String()
-		} else if moduleGenDir.Valid() {
+		var outDirPrefix string
+		if !filepath.IsAbs(moduleGenDir.String()) {
 			// If OUT_DIR is not absolute, we use $$PWD to generate an absolute path (os.Getwd() returns '/')
-			outDir = filepath.Join("$$PWD/", cmd.PathForInput(moduleGenDir.Path()))
+			outDirPrefix = "$$PWD/"
 		} else {
-			outDir = "$$PWD/"
+			// If OUT_DIR is absolute, then moduleGenDir will be an absolute path, so we don't need to set this to anything.
+			outDirPrefix = ""
 		}
-		envVars = append(envVars, "OUT_DIR="+outDir)
+		envVars = append(envVars, "OUT_DIR="+filepath.Join(outDirPrefix, moduleGenDir.String()))
 	} else {
 		// TODO(pcc): Change this to "OUT_DIR=" after fixing crates to not rely on this value.
 		envVars = append(envVars, "OUT_DIR=out")
@@ -204,8 +238,6 @@
 		}
 	}
 
-	envVars = append(envVars, "AR="+cmd.PathForTool(deps.Llvm_ar))
-
 	if ctx.Darwin() {
 		envVars = append(envVars, "ANDROID_RUST_DARWIN=true")
 	}
@@ -213,18 +245,22 @@
 	return envVars
 }
 
-func transformSrctoCrate(ctx ModuleContext, comp compiler, main android.Path, deps PathDeps, flags Flags,
+func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath, crateType string) buildOutput {
 
 	var inputs android.Paths
+	var implicits android.Paths
+	var orderOnly android.Paths
 	var output buildOutput
 	var rustcFlags, linkFlags []string
-	var earlyLinkFlags []string
+	var earlyLinkFlags string
 
 	output.outputFile = outputFile
 	crateName := ctx.RustModule().CrateName()
 	targetTriple := ctx.toolchain().RustTriple()
 
+	envVars := rustEnvVars(ctx, deps)
+
 	inputs = append(inputs, main)
 
 	// Collect rustc flags
@@ -245,27 +281,50 @@
 	// Enable incremental compilation if requested by user
 	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=\"\"")
 	}
 
 	// Collect linker flags
 	if !ctx.Darwin() {
-		earlyLinkFlags = append(earlyLinkFlags, "-Wl,--as-needed")
+		earlyLinkFlags = "-Wl,--as-needed"
 	}
 
+	linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
+	linkFlags = append(linkFlags, flags.LinkFlags...)
+
+	// Check if this module needs to use the bootstrap linker
+	if ctx.RustModule().Bootstrap() && !ctx.RustModule().InRecovery() && !ctx.RustModule().InRamdisk() && !ctx.RustModule().InVendorRamdisk() {
+		dynamicLinker := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker"
+		if ctx.toolchain().Is64Bit() {
+			dynamicLinker += "64"
+		}
+		linkFlags = append(linkFlags, dynamicLinker)
+	}
+
+	libFlags := makeLibFlags(deps)
+
 	// Collect dependencies
-	var linkImplicits android.Paths
-	implicits := collectImplicits(deps)
-	toolImplicits := android.Concat(deps.BuildToolDeps)
-	linkImplicits = append(linkImplicits, deps.CrtBegin...)
-	linkImplicits = append(linkImplicits, deps.CrtEnd...)
-	implicits = append(implicits, comp.compilationSourcesAndData(ctx)...)
+	implicits = append(implicits, rustLibsToPaths(deps.RLibs)...)
+	implicits = append(implicits, rustLibsToPaths(deps.DyLibs)...)
+	implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...)
+	implicits = append(implicits, deps.StaticLibs...)
+	implicits = append(implicits, deps.SharedLibDeps...)
+	implicits = append(implicits, deps.srcProviderFiles...)
+	implicits = append(implicits, deps.AfdoProfiles...)
+
+	implicits = append(implicits, deps.CrtBegin...)
+	implicits = append(implicits, deps.CrtEnd...)
+
+	orderOnly = append(orderOnly, deps.SharedLibs...)
 
 	if len(deps.SrcDeps) > 0 {
 		moduleGenDir := ctx.RustModule().compiler.CargoOutDir()
@@ -280,7 +339,7 @@
 		}
 
 		ctx.Build(pctx, android.BuildParams{
-			Rule:        cpDir,
+			Rule:        cp,
 			Description: "cp " + moduleGenDir.Path().Rel(),
 			Outputs:     outputs,
 			Inputs:      deps.SrcDeps,
@@ -292,176 +351,69 @@
 	}
 
 	if flags.Clippy {
-		// TODO(b/298461712) remove this hack to let slim manifest branches build
-		if deps.Clippy_driver == nil {
-			deps.Clippy_driver = config.RustPath(ctx, "bin/clippy-driver")
-		}
-
-		clippyRule := getRuleBuilder(ctx, pctx, false, "clippy")
-		clippyCmd := clippyRule.Command()
 		clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
-		clippyDepInfoFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy.d.raw")
-		clippyDepFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy.d")
-
-		clippyCmd.
-			Flags(rustEnvVars(ctx, deps, clippyCmd)).
-			Tool(deps.Clippy_driver).
-			Flag("--emit metadata").
-			FlagWithOutput("-o ", clippyFile).
-			FlagWithOutput("--emit dep-info=", clippyDepInfoFile).
-			Inputs(inputs).
-			Flags(makeLibFlags(deps, clippyCmd)).
-			Flags(rustcFlags).
-			Flags(flags.ClippyFlags).
-			ImplicitTools(toolImplicits).
-			Implicits(implicits)
-
-		depfileCreationCmd := clippyRule.Command()
-		depfileCreationCmd.
-			Flag(fmt.Sprintf(
-				`grep "^%s:" %s >`,
-				depfileCreationCmd.PathForOutput(clippyFile),
-				depfileCreationCmd.PathForOutput(clippyDepInfoFile),
-			)).
-			DepFile(clippyDepFile)
-
-		clippyRule.BuildWithUnescapedNinjaVars("clippy", "clippy "+main.Rel())
-
+		ctx.Build(pctx, android.BuildParams{
+			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, " "),
+				"clippyFlags": strings.Join(flags.ClippyFlags, " "),
+				"envVars":     strings.Join(envVars, " "),
+			},
+		})
 		// Declare the clippy build as an implicit dependency of the original crate.
 		implicits = append(implicits, clippyFile)
 	}
 
-	sboxDirectory := "rustc"
-	rustSboxOutputFile := android.PathForModuleOut(ctx, sboxDirectory, outputFile.Base())
-	depFile := android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".d")
-	depInfoFile := android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".d.raw")
-	var rustcImplicitOutputs android.WritablePaths
-
-	sandboxedCompilation := comp.crateRoot(ctx) != nil
-	rustcRule := getRuleBuilder(ctx, pctx, sandboxedCompilation, sboxDirectory)
-	rustcCmd := rustcRule.Command()
-
-	linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
-	linkFlags = append(linkFlags, flags.LinkFlags...)
-	linkFlags = append(linkFlags, rustcCmd.PathsForInputs(deps.linkObjects)...)
-
-	// Check if this module needs to use the bootstrap linker
-	if ctx.RustModule().Bootstrap() && !ctx.RustModule().InRecovery() && !ctx.RustModule().InRamdisk() && !ctx.RustModule().InVendorRamdisk() {
-		dynamicLinker := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker"
-		if ctx.toolchain().Is64Bit() {
-			dynamicLinker += "64"
-		}
-		linkFlags = append(linkFlags, dynamicLinker)
-	}
-
-	libFlags := makeLibFlags(deps, rustcCmd)
-
-	usesLinker := crateType == "bin" || crateType == "dylib" || crateType == "cdylib" || crateType == "proc-macro"
-	if usesLinker {
-		rustSboxOutputFile = android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".rsp")
-		rustcImplicitOutputs = android.WritablePaths{
-			android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".whole.a"),
-			android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".a"),
-		}
-	}
-
-	// TODO(b/298461712) remove this hack to let slim manifest branches build
-	if deps.Rustc == nil {
-		deps.Rustc = config.RustPath(ctx, "bin/rustc")
-	}
-
-	rustcCmd.
-		Flags(rustEnvVars(ctx, deps, rustcCmd)).
-		Tool(deps.Rustc).
-		FlagWithInput("-C linker=", android.PathForSource(ctx, "build", "soong", "scripts", "mkcratersp.py")).
-		Flag("--emit link").
-		Flag("-o").
-		Output(rustSboxOutputFile).
-		FlagWithOutput("--emit dep-info=", depInfoFile).
-		Inputs(inputs).
-		Flags(libFlags).
-		ImplicitTools(toolImplicits).
-		Implicits(implicits).
-		Flags(rustcFlags).
-		ImplicitOutputs(rustcImplicitOutputs)
-
-	depfileCreationCmd := rustcRule.Command()
-	depfileCreationCmd.
-		Flag(fmt.Sprintf(
-			`grep "^%s:" %s >`,
-			depfileCreationCmd.PathForOutput(rustSboxOutputFile),
-			depfileCreationCmd.PathForOutput(depInfoFile),
-		)).
-		DepFile(depFile)
-
-	if !usesLinker {
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   cp,
-			Input:  rustSboxOutputFile,
-			Output: outputFile,
-		})
-	} else {
-		// TODO: delmerico - separate rustLink into its own rule
-		// mkcratersp.py hardcodes paths to files within the sandbox, so
-		// those need to be renamed/symlinked to something in the rustLink sandbox
-		// if we want to separate the rules
-		linkerSboxOutputFile := android.PathForModuleOut(ctx, sboxDirectory, outputFile.Base())
-		rustLinkCmd := rustcRule.Command()
-		rustLinkCmd.
-			Tool(deps.Clang).
-			Flag("-o").
-			Output(linkerSboxOutputFile).
-			Inputs(deps.CrtBegin).
-			Flags(earlyLinkFlags).
-			FlagWithInput("@", rustSboxOutputFile).
-			Flags(linkFlags).
-			Inputs(deps.CrtEnd).
-			ImplicitTools(toolImplicits).
-			Implicits(rustcImplicitOutputs.Paths()).
-			Implicits(implicits).
-			Implicits(linkImplicits)
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   cp,
-			Input:  linkerSboxOutputFile,
-			Output: outputFile,
-		})
-	}
-
-	rustcRule.BuildWithUnescapedNinjaVars("rustc", "rustc "+main.Rel())
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        rustc,
+		Description: "rustc " + main.Rel(),
+		Output:      outputFile,
+		Inputs:      inputs,
+		Implicits:   implicits,
+		OrderOnly:   orderOnly,
+		Args: map[string]string{
+			"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 flags.EmitXrefs {
-		kytheRule := getRuleBuilder(ctx, pctx, false, "kythe")
-		kytheCmd := kytheRule.Command()
 		kytheFile := android.PathForModuleOut(ctx, outputFile.Base()+".kzip")
-		kytheCmd.
-			Flag("KYTHE_CORPUS=${kytheCorpus}").
-			FlagWithOutput("KYTHE_OUTPUT_FILE=", kytheFile).
-			FlagWithInput("KYTHE_VNAMES=", android.PathForSource(ctx, "build", "soong", "vnames.json")).
-			Flag("KYTHE_KZIP_ENCODING=${kytheCuEncoding}").
-			Flag("KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative").
-			Tool(ctx.Config().PrebuiltBuildTool(ctx, "rust_extractor")).
-			Flags(rustEnvVars(ctx, deps, kytheCmd)).
-			Tool(deps.Rustc).
-			Flag("-C linker=true").
-			Inputs(inputs).
-			Flags(makeLibFlags(deps, kytheCmd)).
-			Flags(rustcFlags).
-			ImplicitTools(toolImplicits).
-			Implicits(implicits)
-		kytheRule.BuildWithUnescapedNinjaVars("kythe", "Xref Rust extractor "+main.Rel())
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        kytheExtract,
+			Description: "Xref Rust extractor " + main.Rel(),
+			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, " "),
+			},
+		})
 		output.kytheFile = kytheFile
 	}
 	return output
 }
 
-func Rustdoc(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags) android.ModuleOutPath {
-	// TODO(b/298461712) remove this hack to let slim manifest branches build
-	if deps.Rustdoc == nil {
-		deps.Rustdoc = config.RustPath(ctx, "bin/rustdoc")
-	}
-
-	rustdocRule := getRuleBuilder(ctx, pctx, false, "rustdoc")
-	rustdocCmd := rustdocRule.Command()
+func Rustdoc(ctx ModuleContext, main android.Path, deps PathDeps,
+	flags Flags) android.ModuleOutPath {
 
 	rustdocFlags := append([]string{}, flags.RustdocFlags...)
 	rustdocFlags = append(rustdocFlags, "--sysroot=/dev/null")
@@ -480,11 +432,11 @@
 	crateName := ctx.RustModule().CrateName()
 	rustdocFlags = append(rustdocFlags, "--crate-name "+crateName)
 
-	rustdocFlags = append(rustdocFlags, makeLibFlags(deps, rustdocCmd)...)
+	rustdocFlags = append(rustdocFlags, makeLibFlags(deps)...)
 	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")
 	}
@@ -496,26 +448,18 @@
 	// https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/render/write_shared.rs#L144-L146
 	docDir := android.PathForOutput(ctx, "rustdoc")
 
-	rustdocCmd.
-		Flags(rustEnvVars(ctx, deps, rustdocCmd)).
-		Tool(deps.Rustdoc).
-		Flags(rustdocFlags).
-		Input(main).
-		Flag("-o "+docDir.String()).
-		FlagWithOutput("&& touch ", docTimestampFile).
-		Implicit(ctx.RustModule().UnstrippedOutputFile())
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        rustdoc,
+		Description: "rustdoc " + main.Rel(),
+		Output:      docTimestampFile,
+		Input:       main,
+		Implicit:    ctx.RustModule().UnstrippedOutputFile(),
+		Args: map[string]string{
+			"rustdocFlags": strings.Join(rustdocFlags, " "),
+			"outDir":       docDir.String(),
+			"envVars":      strings.Join(rustEnvVars(ctx, deps), " "),
+		},
+	})
 
-	rustdocRule.BuildWithUnescapedNinjaVars("rustdoc", "rustdoc "+main.Rel())
 	return docTimestampFile
 }
-
-func getRuleBuilder(ctx android.ModuleContext, pctx android.PackageContext, sbox bool, sboxDirectory string) *android.RuleBuilder {
-	r := android.NewRuleBuilder(pctx, ctx)
-	if sbox {
-		r = r.Sbox(
-			android.PathForModuleOut(ctx, sboxDirectory),
-			android.PathForModuleOut(ctx, sboxDirectory+".sbox.textproto"),
-		).SandboxInputs()
-	}
-	return r
-}
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/clippy_test.go b/rust/clippy_test.go
index 2703a1c..bd3bfb1 100644
--- a/rust/clippy_test.go
+++ b/rust/clippy_test.go
@@ -63,14 +63,14 @@
 			).RunTest(t)
 
 			r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("clippy")
-			android.AssertStringDoesContain(t, "libfoo flags", r.RuleParams.Command, tc.fooFlags)
+			android.AssertStringEquals(t, "libfoo flags", tc.fooFlags, r.Args["clippyFlags"])
 
 			r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("clippy")
-			android.AssertStringDoesContain(t, "libbar flags", r.RuleParams.Command, "${config.ClippyDefaultLints}")
+			android.AssertStringEquals(t, "libbar flags", "${config.ClippyDefaultLints}", r.Args["clippyFlags"])
 
 			r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("clippy")
 			if r.Rule != nil {
-				t.Errorf("libfoobar is setup to use clippy when explicitly disabled: command=%q", r.RuleParams.Command)
+				t.Errorf("libfoobar is setup to use clippy when explicitly disabled: clippyFlags=%q", r.Args["clippyFlags"])
 			}
 		})
 	}
diff --git a/rust/compiler.go b/rust/compiler.go
index 3fa3ccd..4c7961d 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -82,9 +82,6 @@
 	//          not directly used as source files.
 	Crate_root *string `android:"path,arch_variant"`
 
-	// Additional data files that are used during compilation only. These are not accessible at runtime.
-	Compile_data []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
@@ -163,7 +160,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.
@@ -330,10 +327,15 @@
 		flags.LinkFlags = append(flags.LinkFlags, cc.RpathFlags(ctx)...)
 	}
 
-	if !ctx.toolchain().Bionic() && ctx.Os() != android.LinuxMusl && !ctx.Windows() {
-		// Add -ldl, -lpthread, -lm and -lrt to host builds to match the default behavior of device
-		// builds. This is irrelevant for the Windows target as these are Posix specific.
+	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",
@@ -346,23 +348,6 @@
 	panic(fmt.Errorf("baseCrater doesn't know how to crate things!"))
 }
 
-func (compile *baseCompiler) crateRoot(ctx ModuleContext) android.Path {
-	if compile.Properties.Crate_root != nil {
-		return android.PathForModuleSrc(ctx, *compile.Properties.Crate_root)
-	}
-	return nil
-}
-
-// compilationSourcesAndData returns a list of files necessary to complete the compilation.
-// This includes the rust source files as well as any other data files that
-// are referenced during the build.
-func (compile *baseCompiler) compilationSourcesAndData(ctx ModuleContext) android.Paths {
-	return android.PathsForModuleSrc(ctx, android.Concat(
-		compile.Properties.Srcs,
-		compile.Properties.Compile_data,
-	))
-}
-
 func (compiler *baseCompiler) rustdoc(ctx ModuleContext, flags Flags,
 	deps PathDeps) android.OptionalPath {
 
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index e5cc888..ec6829a 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -36,9 +36,9 @@
 
 	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
 
-	if !strings.Contains(libfooDylib.RuleParams.Command, "cfg 'feature=\"fizz\"'") ||
-		!strings.Contains(libfooDylib.RuleParams.Command, "cfg 'feature=\"buzz\"'") {
-		t.Fatalf("missing fizz and buzz feature flags for libfoo dylib, command: %#v", libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"fizz\"'") ||
+		!strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"buzz\"'") {
+		t.Fatalf("missing fizz and buzz feature flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
 	}
 }
 
@@ -57,9 +57,9 @@
 
 	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
 
-	if !strings.Contains(libfooDylib.RuleParams.Command, "cfg 'std'") ||
-		!strings.Contains(libfooDylib.RuleParams.Command, "cfg 'cfg1=\"one\"'") {
-		t.Fatalf("missing std and cfg1 flags for libfoo dylib, rustcFlags: %#v", libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'std'") ||
+		!strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'cfg1=\"one\"'") {
+		t.Fatalf("missing std and cfg1 flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
 	}
 }
 
@@ -146,14 +146,14 @@
 
 	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc")
 
-	if !strings.Contains(fizz.RuleParams.Command, "CARGO_BIN_NAME=fizz") {
-		t.Fatalf("expected 'CARGO_BIN_NAME=fizz' in envVars, actual command: %#v", fizz.RuleParams.Command)
+	if !strings.Contains(fizz.Args["envVars"], "CARGO_BIN_NAME=fizz") {
+		t.Fatalf("expected 'CARGO_BIN_NAME=fizz' in envVars, actual envVars: %#v", fizz.Args["envVars"])
 	}
-	if !strings.Contains(fizz.RuleParams.Command, "CARGO_CRATE_NAME=foo") {
-		t.Fatalf("expected 'CARGO_CRATE_NAME=foo' in envVars, actual command: %#v", fizz.RuleParams.Command)
+	if !strings.Contains(fizz.Args["envVars"], "CARGO_CRATE_NAME=foo") {
+		t.Fatalf("expected 'CARGO_CRATE_NAME=foo' in envVars, actual envVars: %#v", fizz.Args["envVars"])
 	}
-	if !strings.Contains(fizz.RuleParams.Command, "CARGO_PKG_VERSION=1.0.0") {
-		t.Fatalf("expected 'CARGO_PKG_VERSION=1.0.0' in envVars, actual command: %#v", fizz.RuleParams.Command)
+	if !strings.Contains(fizz.Args["envVars"], "CARGO_PKG_VERSION=1.0.0") {
+		t.Fatalf("expected 'CARGO_PKG_VERSION=1.0.0' in envVars, actual envVars: %#v", fizz.Args["envVars"])
 	}
 }
 
@@ -230,13 +230,13 @@
 			).RunTest(t)
 
 			r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
-			android.AssertStringDoesContain(t, "libfoo flags", r.RuleParams.Command, tc.fooFlags)
+			android.AssertStringDoesContain(t, "libfoo flags", r.Args["rustcFlags"], tc.fooFlags)
 
 			r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
-			android.AssertStringDoesContain(t, "libbar flags", r.RuleParams.Command, "${config.RustDefaultLints}")
+			android.AssertStringDoesContain(t, "libbar flags", r.Args["rustcFlags"], "${config.RustDefaultLints}")
 
 			r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
-			android.AssertStringDoesContain(t, "libfoobar flags", r.RuleParams.Command, "${config.RustAllowAllLints}")
+			android.AssertStringDoesContain(t, "libfoobar flags", r.Args["rustcFlags"], "${config.RustAllowAllLints}")
 		})
 	}
 }
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
index 564168b..6c021c7 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -54,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 0ddc116..64c9460 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -23,9 +23,9 @@
 
 var (
 	pctx         = android.NewPackageContext("android/soong/rust/config")
-	exportedVars = android.NewExportedVariables(pctx)
+	ExportedVars = android.NewExportedVariables(pctx)
 
-	RustDefaultVersion = "1.72.0"
+	RustDefaultVersion = "1.72.1"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2021"
 	Stdlibs            = []string{
@@ -44,7 +44,6 @@
 	GlobalRustFlags = []string{
 		"-Z stack-protector=strong",
 		"-Z remap-cwd-prefix=.",
-		"-C codegen-units=1",
 		"-C debuginfo=2",
 		"-C opt-level=3",
 		"-C relocation-model=pic",
@@ -52,11 +51,23 @@
 		"-C force-unwind-tables=yes",
 		// Use v0 mangling to distinguish from C++ symbols
 		"-C symbol-mangling-version=v0",
-		"--color always",
-		"-Zdylib-lto",
+		// This flag requires to have no space so that when it's exported to bazel
+		// it can be removed. See aosp/2768339
+		"--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",
 		// Generate additional debug info for AutoFDO
@@ -76,6 +87,7 @@
 		"-Wl,--use-android-relr-tags",
 		"-Wl,--no-undefined",
 		"-B${cc_config.ClangBin}",
+		"-Wl,--compress-debug-sections=zstd",
 	}
 )
 
@@ -100,7 +112,17 @@
 
 	pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " "))
 
-	exportedVars.ExportStringStaticVariable("RUST_DEFAULT_VERSION", RustDefaultVersion)
+	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 {
@@ -124,29 +146,5 @@
 
 // BazelRustToolchainVars returns a string with
 func BazelRustToolchainVars(config android.Config) string {
-	return android.BazelToolchainVars(config, exportedVars)
-}
-
-func RustPath(ctx android.PathContext, file string) android.SourcePath {
-	type rustToolKey string
-	key := android.NewCustomOnceKey(rustToolKey(file))
-	return ctx.Config().OnceSourcePath(key, func() android.SourcePath {
-		return rustPath(ctx).Join(ctx, file)
-	})
-}
-
-var rustPathKey = android.NewOnceKey("clangPath")
-
-func rustPath(ctx android.PathContext) android.SourcePath {
-	return ctx.Config().OnceSourcePath(rustPathKey, func() android.SourcePath {
-		rustBase := RustDefaultBase
-		if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" {
-			rustBase = override
-		}
-		rustVersion := RustDefaultVersion
-		if override := ctx.Config().Getenv("RUST_DEFAULT_VERSION"); override != "" {
-			rustVersion = override
-		}
-		return android.PathForSource(ctx, rustBase, ctx.Config().PrebuiltOS(), rustVersion)
-	})
+	return android.BazelToolchainVars(config, ExportedVars)
 }
diff --git a/rust/config/x86_64_device.go b/rust/config/x86_64_device.go
index 45d1fd0..c797eef 100644
--- a/rust/config/x86_64_device.go
+++ b/rust/config/x86_64_device.go
@@ -53,7 +53,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..822f281 100644
--- a/rust/config/x86_device.go
+++ b/rust/config/x86_device.go
@@ -55,6 +55,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 b312194..bc6504d 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -17,7 +17,6 @@
 import (
 	"github.com/google/blueprint"
 
-	"android/soong/android"
 	"android/soong/cc"
 )
 
@@ -66,15 +65,12 @@
 			"-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() {
 			profiler_builtins := ctx.GetDirectDepWithTag(ProfilerBuiltins, rlibDepTag).(*Module)
-			deps.Rlibs = android.AddDirectToDepSet[RustLibrary](deps.Rlibs, RustLibrary{
-				Path:      profiler_builtins.OutputFile().Path(),
-				CrateName: profiler_builtins.CrateName(),
-			})
+			deps.RLibs = append(deps.RLibs, RustLibrary{Path: profiler_builtins.OutputFile().Path(), CrateName: profiler_builtins.CrateName()})
 		}
 
 		if cc.EnableContinuousCoverage(ctx) {
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
index 1466e0c..0f599d7 100644
--- a/rust/coverage_test.go
+++ b/rust/coverage_test.go
@@ -55,27 +55,23 @@
 	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("rustc")
-	libbarNoCovLink := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc")
-	fizzCovLink := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
-	buzzNoCovLink := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
 
 	rustcCoverageFlags := []string{"-C instrument-coverage", " -g "}
 	for _, flag := range rustcCoverageFlags {
 		missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
 		containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
 
-		if !strings.Contains(fizzCov.RuleParams.Command, flag) {
-			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.RuleParams.Command)
+		if !strings.Contains(fizzCov.Args["rustcFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["rustcFlags"])
 		}
-		if !strings.Contains(libfooCov.RuleParams.Command, flag) {
-			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.RuleParams.Command)
+		if !strings.Contains(libfooCov.Args["rustcFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["rustcFlags"])
 		}
-		if strings.Contains(buzzNoCov.RuleParams.Command, flag) {
-			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.RuleParams.Command)
+		if strings.Contains(buzzNoCov.Args["rustcFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["rustcFlags"])
 		}
-		if strings.Contains(libbarNoCov.RuleParams.Command, flag) {
-			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.RuleParams.Command)
+		if strings.Contains(libbarNoCov.Args["rustcFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["rustcFlags"])
 		}
 	}
 
@@ -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.RuleParams.Command, flag) {
-			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCovLink.RuleParams.Command)
+		if !strings.Contains(fizzCov.Args["linkFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["linkFlags"])
 		}
-		if !strings.Contains(libfooCovLink.RuleParams.Command, flag) {
-			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCovLink.RuleParams.Command)
+		if !strings.Contains(libfooCov.Args["linkFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["linkFlags"])
 		}
-		if strings.Contains(buzzNoCovLink.RuleParams.Command, flag) {
-			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCovLink.RuleParams.Command)
+		if strings.Contains(buzzNoCov.Args["linkFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["linkFlags"])
 		}
-		if strings.Contains(libbarNoCovLink.RuleParams.Command, flag) {
-			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCovLink.RuleParams.Command)
+		if strings.Contains(libbarNoCov.Args["linkFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["linkFlags"])
 		}
 	}
 
@@ -108,7 +104,7 @@
 		}`)
 
 	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustc")
-	if !strings.Contains(fizz.RuleParams.Command, "libprofile-clang-extras.a") {
-		t.Fatalf("missing expected coverage 'libprofile-clang-extras' dependency in linkFlags: %#v", fizz.RuleParams.Command)
+	if !strings.Contains(fizz.Args["linkFlags"], "libprofile-clang-extras.a") {
+		t.Fatalf("missing expected coverage 'libprofile-clang-extras' dependency in linkFlags: %#v", fizz.Args["linkFlags"])
 	}
 }
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
index ea35905..ee28c6d 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -51,23 +51,23 @@
 
 	// 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.RuleParams.Command, "-C passes='sancov-module'") ||
-		!strings.Contains(fuzz_libtest.RuleParams.Command, "--cfg fuzzing") {
+	if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov-module'") ||
+		!strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") {
 		t.Errorf("rust_fuzz module does not contain the expected flags (sancov-module, cfg fuzzing).")
 	}
 
 	// Check that host modules support fuzzing.
 	host_fuzzer := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc")
-	if !strings.Contains(host_fuzzer.RuleParams.Command, "-C passes='sancov-module'") ||
-		!strings.Contains(host_fuzzer.RuleParams.Command, "--cfg fuzzing") {
+	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").Rule("rustc")
-	if !strings.Contains(libtest_fuzzer.RuleParams.Command, "-C passes='sancov-module'") ||
-		!strings.Contains(libtest_fuzzer.RuleParams.Command, "--cfg fuzzing") {
-		t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing). command: %q", libtest_fuzzer.RuleParams.Command)
+	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"], "-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).")
 	}
 }
 
diff --git a/rust/image_test.go b/rust/image_test.go
index 813c5bc..fb4d9c1 100644
--- a/rust/image_test.go
+++ b/rust/image_test.go
@@ -59,36 +59,36 @@
 
 	vendor := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_static").Rule("rustc")
 
-	if !strings.Contains(vendor.RuleParams.Command, "--cfg 'android_vndk'") {
-		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.RuleParams.Command)
+	if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vndk'") {
+		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
 	}
-	if !strings.Contains(vendor.RuleParams.Command, "--cfg 'android_vendor'") {
-		t.Errorf("missing \"--cfg 'android_vendor'\" for libfoo vendor variant, rustcFlags: %#v", vendor.RuleParams.Command)
+	if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vendor'") {
+		t.Errorf("missing \"--cfg 'android_vendor'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
 	}
-	if strings.Contains(vendor.RuleParams.Command, "--cfg 'android_product'") {
-		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo vendor variant, rustcFlags: %#v", vendor.RuleParams.Command)
+	if strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_product'") {
+		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
 	}
 
 	product := ctx.ModuleForTests("libfoo", "android_product.29_arm64_armv8-a_static").Rule("rustc")
-	if !strings.Contains(product.RuleParams.Command, "--cfg 'android_vndk'") {
-		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo product variant, rustcFlags: %#v", product.RuleParams.Command)
+	if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vndk'") {
+		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
 	}
-	if strings.Contains(product.RuleParams.Command, "--cfg 'android_vendor'") {
-		t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo product variant, rustcFlags: %#v", product.RuleParams.Command)
+	if strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vendor'") {
+		t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
 	}
-	if !strings.Contains(product.RuleParams.Command, "--cfg 'android_product'") {
-		t.Errorf("missing \"--cfg 'android_product'\" for libfoo product variant, rustcFlags: %#v", product.RuleParams.Command)
+	if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_product'") {
+		t.Errorf("missing \"--cfg 'android_product'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
 	}
 
 	system := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Rule("rustc")
-	if strings.Contains(system.RuleParams.Command, "--cfg 'android_vndk'") {
-		t.Errorf("unexpected \"--cfg 'android_vndk'\" for libfoo system variant, rustcFlags: %#v", system.RuleParams.Command)
+	if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vndk'") {
+		t.Errorf("unexpected \"--cfg 'android_vndk'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"])
 	}
-	if strings.Contains(system.RuleParams.Command, "--cfg 'android_vendor'") {
-		t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo system variant, rustcFlags: %#v", system.RuleParams.Command)
+	if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vendor'") {
+		t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"])
 	}
-	if strings.Contains(system.RuleParams.Command, "--cfg 'android_product'") {
-		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo system variant, rustcFlags: %#v", product.RuleParams.Command)
+	if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_product'") {
+		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo system variant, rustcFlags: %#v", product.Args["rustcFlags"])
 	}
 
 }
diff --git a/rust/library.go b/rust/library.go
index 7bb82bc..18bf0a0 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -485,23 +485,6 @@
 	return flags
 }
 
-func (library *libraryDecorator) compilationSourcesAndData(ctx ModuleContext) android.Paths {
-	var extraSrcs android.Paths
-	if library.rlib() {
-		extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Rlib.Srcs)
-	} else if library.dylib() {
-		extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Dylib.Srcs)
-	} else if library.static() {
-		extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Static.Srcs)
-	} else if library.shared() {
-		extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Shared.Srcs)
-	}
-	return android.Concat(
-		library.baseCompiler.compilationSourcesAndData(ctx),
-		extraSrcs,
-	)
-}
-
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
 	var outputFile android.ModuleOutPath
 	var ret buildOutput
@@ -542,6 +525,7 @@
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
+	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
 
 	if library.dylib() {
 		// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
@@ -552,19 +536,18 @@
 
 	// Call the appropriate builder for this library type
 	if library.rlib() {
-		ret.kytheFile = TransformSrctoRlib(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoRlib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.dylib() {
-		ret.kytheFile = TransformSrctoDylib(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoDylib(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.static() {
-		ret.kytheFile = TransformSrctoStatic(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoStatic(ctx, crateRootPath, deps, flags, outputFile).kytheFile
 	} else if library.shared() {
-		ret.kytheFile = TransformSrctoShared(ctx, library, crateRootPath, 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() {
@@ -818,6 +801,10 @@
 }
 
 type rustLibraryAttributes struct {
+	commonLibraryAttrs
+}
+
+type commonLibraryAttrs struct {
 	Srcs            bazel.LabelListAttribute
 	Compile_data    bazel.LabelListAttribute
 	Crate_name      bazel.StringAttribute
@@ -828,7 +815,7 @@
 	Proc_macro_deps bazel.LabelListAttribute
 }
 
-func libraryBp2build(ctx android.Bp2buildMutatorContext, m *Module) {
+func commonLibraryAttrsBp2build(ctx android.Bp2buildMutatorContext, m *Module) *commonLibraryAttrs {
 	lib := m.compiler.(*libraryDecorator)
 
 	srcs, compileData := srcsAndCompileDataAttrs(ctx, *lib.baseCompiler)
@@ -852,7 +839,7 @@
 		rustcFLags = append(rustcFLags, fmt.Sprintf("--cfg=%s", cfg))
 	}
 
-	attrs := &rustLibraryAttributes{
+	return &commonLibraryAttrs{
 		Srcs: bazel.MakeLabelListAttribute(
 			srcs,
 		),
@@ -882,11 +869,10 @@
 		},
 	}
 
-	// TODO(b/290790800): Remove the restriction when rust toolchain for android is implemented
-	var restriction bazel.BoolAttribute
-	restriction.SetSelectValue(bazel.OsConfigurationAxis, "android", proptools.BoolPtr(false))
+}
 
-	ctx.CreateBazelTargetModuleWithRestrictions(
+func libraryBp2build(ctx android.Bp2buildMutatorContext, m *Module) {
+	ctx.CreateBazelTargetModule(
 		bazel.BazelTargetModuleProperties{
 			Rule_class:        "rust_library",
 			Bzl_load_location: "@rules_rust//rust:defs.bzl",
@@ -894,8 +880,7 @@
 		android.CommonAttributes{
 			Name: m.Name(),
 		},
-		attrs,
-		restriction,
+		commonLibraryAttrsBp2build(ctx, m),
 	)
 }
 
@@ -968,3 +953,30 @@
 
 	return &name
 }
+
+type ffiStaticAttributes struct {
+	commonLibraryAttrs
+	Export_includes bazel.StringListAttribute
+}
+
+func ffiStaticBp2build(ctx android.Bp2buildMutatorContext, m *Module) {
+	lib := m.compiler.(*libraryDecorator)
+
+	attrs := &ffiStaticAttributes{
+		Export_includes: bazel.StringListAttribute{
+			Value: lib.Properties.Include_dirs,
+		},
+		commonLibraryAttrs: *commonLibraryAttrsBp2build(ctx, m),
+	}
+
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "rust_ffi_static",
+			Bzl_load_location: "//build/bazel/rules/rust:rust_ffi_static.bzl",
+		},
+		android.CommonAttributes{
+			Name: m.Name(),
+		},
+		attrs,
+	)
+}
diff --git a/rust/library_test.go b/rust/library_test.go
index dab9381..e03074d 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -48,23 +48,23 @@
 	staticCrateType := "staticlib"
 
 	// Test crate type for rlib is correct.
-	if !strings.Contains(libfooRlib.RuleParams.Command, "crate-type="+rlibCrateType) {
-		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooRlib.RuleParams.Command)
+	if !strings.Contains(libfooRlib.Args["rustcFlags"], "crate-type="+rlibCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooRlib.Args["rustcFlags"])
 	}
 
 	// Test crate type for dylib is correct.
-	if !strings.Contains(libfooDylib.RuleParams.Command, "crate-type="+dylibCrateType) {
-		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", dylibCrateType, libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "crate-type="+dylibCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", dylibCrateType, libfooDylib.Args["rustcFlags"])
 	}
 
 	// Test crate type for C static libraries is correct.
-	if !strings.Contains(libfooStatic.RuleParams.Command, "crate-type="+staticCrateType) {
-		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.RuleParams.Command)
+	if !strings.Contains(libfooStatic.Args["rustcFlags"], "crate-type="+staticCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.Args["rustcFlags"])
 	}
 
 	// Test crate type for C shared libraries is correct.
-	if !strings.Contains(libfooShared.RuleParams.Command, "crate-type="+sharedCrateType) {
-		t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.RuleParams.Command)
+	if !strings.Contains(libfooShared.Args["rustcFlags"], "crate-type="+sharedCrateType) {
+		t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.Args["rustcFlags"])
 	}
 
 }
@@ -78,10 +78,10 @@
 			crate_name: "foo",
 		}`)
 
-	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Description("rustc")
+	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
 
-	if !strings.Contains(libfooDylib.RuleParams.Command, "prefer-dynamic") {
-		t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") {
+		t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
 	}
 }
 
@@ -94,10 +94,10 @@
 			crate_name: "foo",
 		}`)
 
-	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Description("rustc")
+	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
 
-	if !strings.Contains(libfooDylib.RuleParams.Command, "--cfg 'android_dylib'") {
-		t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "--cfg 'android_dylib'") {
+		t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
 	}
 }
 
@@ -149,9 +149,9 @@
 	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared")
 
 	libfooOutput := libfoo.Rule("rustc")
-	if !strings.Contains(libfooOutput.RuleParams.Command, "-Wl,-soname=libfoo.so") {
+	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.RuleParams.Command)
+			libfooOutput.Args["linkFlags"])
 	}
 
 	if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkDylibs) {
@@ -237,21 +237,19 @@
 	// 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
-	expectedSharedFlag := "-L out/soong/.intermediates/shared_cc_dep/android_arm64_armv8-a_shared"
-	expectedStaticFlag := "-L out/soong/.intermediates/static_cc_dep/android_arm64_armv8-a_static"
 	for _, module := range modules {
-		if !strings.Contains(module.Rule("rustc").RuleParams.Command, expectedSharedFlag) {
+		if !strings.Contains(module.Rule("rustc").Args["libFlags"],
+			"-L out/soong/.intermediates/shared_cc_dep/android_arm64_armv8-a_shared/") {
 			t.Errorf(
-				"expected to find shared library linkdir flag %q, rustcFlags: %#v",
-				expectedSharedFlag,
-				rustRlibRlibStd.Rule("rustc").RuleParams.Command,
+				"missing -L flag for shared_cc_dep, rustcFlags: %#v",
+				rustRlibRlibStd.Rule("rustc").Args["libFlags"],
 			)
 		}
-		if !strings.Contains(module.Rule("rustc").RuleParams.Command, expectedStaticFlag) {
+		if !strings.Contains(module.Rule("rustc").Args["libFlags"],
+			"-L out/soong/.intermediates/static_cc_dep/android_arm64_armv8-a_static/") {
 			t.Errorf(
-				"expected to find static library linkdir flag %q, rustcFlags: %#v",
-				expectedStaticFlag,
-				rustRlibRlibStd.Rule("rustc").RuleParams.Command,
+				"missing -L flag for static_cc_dep, rustcFlags: %#v",
+				rustRlibRlibStd.Rule("rustc").Args["libFlags"],
 			)
 		}
 	}
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
index d012680..fe9d0b5 100644
--- a/rust/prebuilt.go
+++ b/rust/prebuilt.go
@@ -146,10 +146,7 @@
 }
 
 func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
-	deps.linkDirs = append(deps.linkDirs, android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs)...)
-	prebuilt.flagExporter.exportLinkDirs(deps.linkDirs...)
-	prebuilt.flagExporter.exportLinkObjects(deps.linkObjects...)
-	prebuilt.flagExporter.exportLibDeps(deps.LibDeps...)
+	prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...)
 	prebuilt.flagExporter.setProvider(ctx)
 
 	srcPath, paths := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs())
@@ -206,7 +203,7 @@
 }
 
 func (prebuilt *prebuiltProcMacroDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
-	prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs)...)
+	prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...)
 	prebuilt.flagExporter.setProvider(ctx)
 
 	srcPath, paths := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs())
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 3f0d17a..b93b24f 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -80,7 +80,7 @@
 	outputFile := android.PathForModuleOut(ctx, fileName)
 
 	srcPath, _ := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs)
-	ret := TransformSrctoProcMacro(ctx, procMacro, srcPath, deps, flags, outputFile)
+	ret := TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile)
 	procMacro.baseCompiler.unstrippedOutputFile = outputFile
 	return ret
 }
diff --git a/rust/proc_macro_test.go b/rust/proc_macro_test.go
index a547926..cc81938 100644
--- a/rust/proc_macro_test.go
+++ b/rust/proc_macro_test.go
@@ -30,7 +30,7 @@
 
 	libprocmacro := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Rule("rustc")
 
-	if !strings.Contains(libprocmacro.RuleParams.Command, "--extern proc_macro") {
-		t.Errorf("--extern proc_macro flag not being passed to rustc for proc macro %#v", libprocmacro.RuleParams.Command)
+	if !strings.Contains(libprocmacro.Args["rustcFlags"], "--extern proc_macro") {
+		t.Errorf("--extern proc_macro flag not being passed to rustc for proc macro %#v", libprocmacro.Args["rustcFlags"])
 	}
 }
diff --git a/rust/protobuf.go b/rust/protobuf.go
index c8d2bda..2982efd 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -20,6 +20,7 @@
 
 	"android/soong/android"
 	"android/soong/bazel"
+	"android/soong/cc"
 
 	"github.com/google/blueprint/proptools"
 )
@@ -59,14 +60,18 @@
 	// Use protobuf version 3.x. This will be deleted once we migrate all current users
 	// of protobuf off of 2.x.
 	Use_protobuf3 *bool
+
+	// List of exported include paths containing proto files for dependent rust_protobuf modules.
+	Exported_include_dirs []string
 }
 
 type protobufDecorator struct {
 	*BaseSourceProvider
 
-	Properties ProtobufProperties
-	protoNames []string
-	grpcNames  []string
+	Properties       ProtobufProperties
+	protoNames       []string
+	additionalCrates []string
+	grpcNames        []string
 
 	grpcProtoFlags android.ProtoFlags
 	protoFlags     android.ProtoFlags
@@ -184,6 +189,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()...)
 
+	ctx.SetProvider(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
 }
@@ -192,10 +201,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))
@@ -305,7 +320,11 @@
 		},
 	}
 
-	ctx.CreateBazelTargetModule(
+	// TODO(b/295918553): Remove androidRestriction after rust toolchain for android is checked in.
+	var androidRestriction bazel.BoolAttribute
+	androidRestriction.SetSelectValue(bazel.OsConfigurationAxis, "android", proptools.BoolPtr(false))
+
+	ctx.CreateBazelTargetModuleWithRestrictions(
 		bazel.BazelTargetModuleProperties{
 			Rule_class: "proto_library",
 		},
@@ -317,9 +336,10 @@
 				android.BazelLabelForModuleSrc(ctx, protoFiles),
 			),
 		},
+		androidRestriction,
 	)
 
-	ctx.CreateBazelTargetModule(
+	ctx.CreateBazelTargetModuleWithRestrictions(
 		bazel.BazelTargetModuleProperties{
 			Rule_class:        "rust_proto_library",
 			Bzl_load_location: "@rules_rust//proto/protobuf:defs.bzl",
@@ -333,5 +353,6 @@
 			},
 			Deps: protoDeps,
 		},
+		androidRestriction,
 	)
 }
diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go
index b723f3f..9dca029 100644
--- a/rust/protobuf_test.go
+++ b/rust/protobuf_test.go
@@ -118,6 +118,58 @@
 	}
 }
 
+func TestRustProtobufInclude(t *testing.T) {
+	ctx := testRust(t, `
+		rust_protobuf {
+			name: "librust_proto",
+			protos: ["proto.proto"],
+			crate_name: "rust_proto",
+			source_stem: "proto",
+			use_protobuf3: true,
+			rustlibs: ["librust_exported_proto", "libfoo"],
+		}
+		rust_protobuf {
+			name: "librust_exported_proto",
+			protos: ["proto.proto"],
+			crate_name: "rust_exported_proto",
+			source_stem: "exported_proto",
+			use_protobuf3: true,
+			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 6d6b55e..19c5230 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -267,6 +267,15 @@
 	return false
 }
 
+func (mod *Module) Source() bool {
+	if mod.compiler != nil {
+		if library, ok := mod.compiler.(libraryInterface); ok && mod.sourceProvider != nil {
+			return library.source()
+		}
+	}
+	return false
+}
+
 func (mod *Module) RlibStd() bool {
 	if mod.compiler != nil {
 		if library, ok := mod.compiler.(libraryInterface); ok && library.rlib() {
@@ -438,18 +447,13 @@
 }
 
 type PathDeps struct {
-	Dylibs          *android.DepSet[RustLibrary]
-	Rlibs           *android.DepSet[RustLibrary]
-	ProcMacros      *android.DepSet[RustLibrary]
-	LibDeps         android.Paths
-	WholeStaticLibs android.Paths
-	AfdoProfiles    android.Paths
-	// These paths are files needed to run the build tools and will be located under
-	// __SBOX_SANDBOX_DIR__/tools/...
-	BuildToolDeps android.Paths
-	// These paths are files needed to run the build tools and will be located under
-	// __SBOX_SANDBOX_DIR__/...
-	BuildToolSrcDeps 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
@@ -457,8 +461,8 @@
 
 	// 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    android.Paths
-	linkObjects android.Paths
+	linkDirs    []string
+	linkObjects []string
 
 	// Used by bindgen modules which call clang
 	depClangFlags         []string
@@ -472,13 +476,6 @@
 	// Paths to generated source files
 	SrcDeps          android.Paths
 	srcProviderFiles android.Paths
-
-	// Paths to specific build tools
-	Rustc         android.Path
-	Clang         android.Path
-	Llvm_ar       android.Path
-	Clippy_driver android.Path
-	Rustdoc       android.Path
 }
 
 type RustLibraries []RustLibrary
@@ -498,8 +495,6 @@
 	compilerDeps(ctx DepsContext, deps Deps) Deps
 	crateName() string
 	rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath
-	crateRoot(ctx ModuleContext) android.Path
-	compilationSourcesAndData(ctx ModuleContext) android.Paths
 
 	// Output directory in which source-generated code from dependencies is
 	// copied. This is equivalent to Cargo's OUT_DIR variable.
@@ -529,8 +524,8 @@
 }
 
 type exportedFlagsProducer interface {
-	exportLinkDirs(...android.Path)
-	exportLinkObjects(...android.Path)
+	exportLinkDirs(...string)
+	exportLinkObjects(...string)
 }
 
 type xref interface {
@@ -538,28 +533,22 @@
 }
 
 type flagExporter struct {
-	linkDirs    android.Paths
-	linkObjects android.Paths
-	libDeps     android.Paths
+	linkDirs    []string
+	linkObjects []string
 }
 
-func (flagExporter *flagExporter) exportLinkDirs(dirs ...android.Path) {
-	flagExporter.linkDirs = android.FirstUniquePaths(append(flagExporter.linkDirs, dirs...))
+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{
 		LinkDirs:    flagExporter.linkDirs,
 		LinkObjects: flagExporter.linkObjects,
-		LibDeps:     flagExporter.libDeps,
 	})
 }
 
@@ -571,9 +560,8 @@
 
 type FlagExporterInfo struct {
 	Flags       []string
-	LinkDirs    android.Paths
-	LinkObjects android.Paths
-	LibDeps     android.Paths
+	LinkDirs    []string // TODO: this should be android.Paths
+	LinkObjects []string // TODO: this should be android.Paths
 }
 
 var FlagExporterInfoProvider = blueprint.NewProvider(FlagExporterInfo{})
@@ -941,14 +929,6 @@
 func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 }
 
-type RustInfo struct {
-	TransitiveRlibs      *android.DepSet[RustLibrary]
-	TransitiveDylibs     *android.DepSet[RustLibrary]
-	TransitiveProcMacros *android.DepSet[RustLibrary]
-}
-
-var RustInfoProvider = blueprint.NewProvider(RustInfo{})
-
 func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
 	ctx := &moduleContext{
 		ModuleContext: actx,
@@ -1058,12 +1038,6 @@
 
 		ctx.Phony("rust", ctx.RustModule().OutputFile().Path())
 	}
-
-	ctx.SetProvider(RustInfoProvider, RustInfo{
-		TransitiveRlibs:      deps.Rlibs,
-		TransitiveDylibs:     deps.Dylibs,
-		TransitiveProcMacros: deps.ProcMacros,
-	})
 }
 
 func (mod *Module) deps(ctx DepsContext) Deps {
@@ -1122,7 +1096,6 @@
 var _ android.LicenseAnnotationsDependencyTag = dependencyTag{}
 
 var (
-	buildToolDepTag     = dependencyTag{name: "buildToolTag"}
 	customBindgenDepTag = dependencyTag{name: "customBindgenTag"}
 	rlibDepTag          = dependencyTag{name: "rlibTag", library: true}
 	dylibDepTag         = dependencyTag{name: "dylib", library: true, dynamic: true}
@@ -1186,6 +1159,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
 
@@ -1256,9 +1236,7 @@
 
 	var transitiveAndroidMkSharedLibs []*android.DepSet[string]
 	var directAndroidMkSharedLibs []string
-	transitiveRlibs := android.NewDepSetBuilder[RustLibrary](android.PREORDER)
-	transitiveDylibs := android.NewDepSetBuilder[RustLibrary](android.PREORDER)
-	transitiveProcMacros := android.NewDepSetBuilder[RustLibrary](android.PREORDER)
+
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
@@ -1271,17 +1249,6 @@
 			return
 		}
 
-		rustInfo := ctx.OtherModuleProvider(dep, RustInfoProvider).(RustInfo)
-		if rustInfo.TransitiveDylibs != nil {
-			transitiveDylibs.Transitive(rustInfo.TransitiveDylibs)
-		}
-		if rustInfo.TransitiveRlibs != nil {
-			transitiveRlibs.Transitive(rustInfo.TransitiveRlibs)
-		}
-		if rustInfo.TransitiveProcMacros != nil {
-			transitiveProcMacros.Transitive(rustInfo.TransitiveProcMacros)
-		}
-
 		if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() {
 			//Handle Rust Modules
 			makeLibName := rustMakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName)
@@ -1296,12 +1263,9 @@
 				directDylibDeps = append(directDylibDeps, rustDep)
 				mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, makeLibName)
 				mod.Properties.SnapshotDylibs = append(mod.Properties.SnapshotDylibs, cc.BaseLibName(depName))
-				transitiveDylibs.Direct(RustLibrary{
-					Path:      rustDep.UnstrippedOutputFile(),
-					CrateName: rustDep.CrateName(),
-				})
 
 			case rlibDepTag:
+
 				rlib, ok := rustDep.compiler.(libraryInterface)
 				if !ok || !rlib.rlib() {
 					ctx.ModuleErrorf("mod %q not an rlib library", makeLibName)
@@ -1310,18 +1274,15 @@
 				directRlibDeps = append(directRlibDeps, rustDep)
 				mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, makeLibName)
 				mod.Properties.SnapshotRlibs = append(mod.Properties.SnapshotRlibs, cc.BaseLibName(depName))
-				transitiveRlibs.Direct(RustLibrary{
-					Path:      rustDep.UnstrippedOutputFile(),
-					CrateName: rustDep.CrateName(),
-				})
 
 			case procMacroDepTag:
 				directProcMacroDeps = append(directProcMacroDeps, rustDep)
 				mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName)
-				transitiveProcMacros.Direct(RustLibrary{
-					Path:      rustDep.UnstrippedOutputFile(),
-					CrateName: rustDep.CrateName(),
-				})
+
+			case sourceDepTag:
+				if _, ok := mod.sourceProvider.(*protobufDecorator); ok {
+					collectIncludedProtos(mod, rustDep)
+				}
 			}
 
 			transitiveAndroidMkSharedLibs = append(transitiveAndroidMkSharedLibs, rustDep.transitiveAndroidMkSharedLibs)
@@ -1352,16 +1313,23 @@
 				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 {
 				linkFile := rustDep.UnstrippedOutputFile()
+				linkDir := linkPathFromFilePath(linkFile)
 				if lib, ok := mod.compiler.(exportedFlagsProducer); ok {
-					lib.exportLinkDirs(linkFile.Dir())
+					lib.exportLinkDirs(linkDir)
 				}
 			}
-
+			if depTag == sourceDepTag {
+				if _, ok := mod.sourceProvider.(*protobufDecorator); ok && mod.Source() {
+					if _, ok := rustDep.sourceProvider.(*protobufDecorator); ok {
+						exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
+						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)
@@ -1385,7 +1353,7 @@
 				return
 			}
 
-			linkPath := linkObject.Path().Dir()
+			linkPath := linkPathFromFilePath(linkObject.Path())
 
 			exportDep := false
 			switch {
@@ -1400,7 +1368,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())
 					}
@@ -1408,7 +1375,7 @@
 
 				// 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)
@@ -1439,10 +1406,10 @@
 					}
 					return
 				}
-				linkPath = linkObject.Path().Dir()
+				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...)
@@ -1468,31 +1435,10 @@
 			// 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 {
-			case depTag == buildToolDepTag:
-				buildTool := ctx.OtherModuleProvider(dep, android.PrebuiltBuildToolInfoProvider).(android.PrebuiltBuildToolInfo)
-				depPaths.BuildToolDeps = append(depPaths.BuildToolDeps, buildTool.Src)
-				depPaths.BuildToolDeps = append(depPaths.BuildToolDeps, buildTool.Deps...)
-				switch android.RemoveOptionalPrebuiltPrefix(dep.Name()) {
-				case "rustc":
-					depPaths.Rustc = buildTool.Src
-					// rustc expects the standard cc toolchain libraries (libdl, libm, libc, etc.)
-					// not to be under the __SBOX_SANDBOX_DIR__/ directory
-					depPaths.BuildToolSrcDeps = append(depPaths.BuildToolSrcDeps, buildTool.Deps...)
-				case "clang++":
-					depPaths.Clang = buildTool.Src
-				case "llvm-ar":
-					depPaths.Llvm_ar = buildTool.Src
-				case "clippy-driver":
-					depPaths.Clippy_driver = buildTool.Src
-				case "rustdoc":
-					depPaths.Rustdoc = buildTool.Src
-				}
 			case depTag == cc.CrtBeginDepTag:
 				depPaths.CrtBegin = append(depPaths.CrtBegin, android.OutputFileForModule(ctx, dep, ""))
 			case depTag == cc.CrtEndDepTag:
@@ -1508,16 +1454,34 @@
 		}
 	})
 
-	var libDepFiles android.Paths
-	for _, dep := range directStaticLibDeps {
-		libDepFiles = append(libDepFiles, dep.OutputFile().Path())
+	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()})
+	}
+	var dylibDepFiles RustLibraries
+	for _, dep := range directDylibDeps {
+		dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
+	}
+	var procMacroDepFiles RustLibraries
+	for _, dep := range directProcMacroDeps {
+		procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
 	}
 
+	var staticLibDepFiles android.Paths
+	for _, dep := range directStaticLibDeps {
+		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)
 		}
 	}
 
@@ -1531,22 +1495,22 @@
 		srcProviderDepFiles = append(srcProviderDepFiles, srcs...)
 	}
 
-	depPaths.LibDeps = append(depPaths.LibDeps, libDepFiles...)
+	depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...)
+	depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...)
+	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.FirstUniquePaths(depPaths.linkDirs)
-	depPaths.linkObjects = android.FirstUniquePaths(depPaths.linkObjects)
+	depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
+	depPaths.linkObjects = android.FirstUniqueStrings(depPaths.linkObjects)
 	depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
 	depPaths.depClangFlags = android.FirstUniqueStrings(depPaths.depClangFlags)
 	depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths)
 	depPaths.depSystemIncludePaths = android.FirstUniquePaths(depPaths.depSystemIncludePaths)
 
-	depPaths.Rlibs = transitiveRlibs.Build()
-	depPaths.Dylibs = transitiveDylibs.Build()
-	depPaths.ProcMacros = transitiveProcMacros.Build()
-	mod.transitiveAndroidMkSharedLibs = android.NewDepSet[string](android.PREORDER, directAndroidMkSharedLibs, transitiveAndroidMkSharedLibs)
-
 	return depPaths
 }
 
@@ -1569,6 +1533,10 @@
 	return mod.InRecovery()
 }
 
+func linkPathFromFilePath(filepath android.Path) string {
+	return strings.Split(filepath.String(), filepath.Base())[0]
+}
+
 // usePublicApi returns true if the rust variant should link against NDK (publicapi)
 func (r *Module) usePublicApi() bool {
 	return r.Device() && r.UseSdk()
@@ -1611,15 +1579,6 @@
 			blueprint.Variation{Mutator: "rust_stdlinkage", Variation: stdLinkage})
 	}
 
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "rustc")
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "clippy-driver")
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "rustdoc")
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "clang++")
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "clang++.real")
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "lld")
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "ld.lld")
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "llvm-ar")
-
 	// rlibs
 	rlibDepVariations = append(rlibDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: rlibVariation})
 	for _, lib := range deps.Rlibs {
@@ -1636,30 +1595,43 @@
 	}
 
 	// 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})
-
-				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.
+	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 {
@@ -1917,8 +1889,10 @@
 		procMacroBp2build(ctx, m)
 	} else if ctx.ModuleType() == "rust_binary_host" {
 		binaryBp2build(ctx, m)
-	} else if ctx.ModuleType() == "rust_protobuf_host" {
+	} else if ctx.ModuleType() == "rust_protobuf_host" || ctx.ModuleType() == "rust_protobuf" {
 		protoLibraryBp2build(ctx, m)
+	} else if ctx.ModuleType() == "rust_ffi_static" {
+		ffiStaticBp2build(ctx, m)
 	} else {
 		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
 	}
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 576209d..d609c2f 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -15,17 +15,14 @@
 package rust
 
 import (
-	"fmt"
 	"os"
 	"runtime"
 	"strings"
 	"testing"
 
 	"github.com/google/blueprint/proptools"
-	"google.golang.org/protobuf/encoding/prototext"
 
 	"android/soong/android"
-	"android/soong/cmd/sbox/sbox_proto"
 	"android/soong/genrule"
 )
 
@@ -43,7 +40,6 @@
 	PrepareForTestWithRustIncludeVndk,
 	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 		variables.DeviceVndkVersion = StringPtr("current")
-		variables.ProductVndkVersion = StringPtr("current")
 		variables.Platform_vndk_version = StringPtr("29")
 	}),
 )
@@ -67,14 +63,11 @@
 
 // testRust returns a TestContext in which a basic environment has been setup.
 // This environment contains a few mocked files. See rustMockedFiles for the list of these files.
-func testRust(t *testing.T, bp string, preparers ...android.FixturePreparer) *android.TestContext {
+func testRust(t *testing.T, bp string) *android.TestContext {
 	skipTestIfOsNotSupported(t)
 	result := android.GroupFixturePreparers(
 		prepareForRustTest,
 		rustMockedFiles.AddToFixture(),
-		android.GroupFixturePreparers(
-			preparers...,
-		),
 	).
 		RunTestWithBp(t, bp)
 	return result.TestContext
@@ -111,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)
 			},
 		),
@@ -179,7 +171,6 @@
 		android.FixtureModifyProductVariables(
 			func(variables android.FixtureProductVariables) {
 				variables.DeviceVndkVersion = StringPtr("current")
-				variables.ProductVndkVersion = StringPtr("current")
 				variables.Platform_vndk_version = StringPtr("VER")
 			},
 		),
@@ -208,11 +199,11 @@
 // Test that we can extract the link path from a lib path.
 func TestLinkPathFromFilePath(t *testing.T) {
 	barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
-	libName := barPath.Dir()
-	expectedResult := "out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared"
+	libName := linkPathFromFilePath(barPath)
+	expectedResult := "out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/"
 
-	if libName.String() != expectedResult {
-		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName.String())
+	if libName != expectedResult {
+		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName)
 	}
 }
 
@@ -262,7 +253,6 @@
 	`)
 	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("rustc")
 
 	// Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up.
 	if !android.InList("librlib.rlib-std", module.Properties.AndroidMkRlibs) {
@@ -281,20 +271,20 @@
 		t.Errorf("Static library dependency not detected (dependency missing from AndroidMkStaticLibs)")
 	}
 
-	if !strings.Contains(rustc.RuleParams.Command, "-lstatic=wholestatic") {
-		t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.RuleParams.Command)
+	if !strings.Contains(rustc.Args["rustcFlags"], "-lstatic=wholestatic") {
+		t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.Args["rustcFlags"])
 	}
 
-	if !strings.Contains(rustLink.RuleParams.Command, "cc_stubs_dep.so") {
-		t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustLink.RuleParams.Command)
+	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.Implicits.Strings(), "cc_stubs_dep.so") {
-		t.Errorf("shared cc dep not being passed as implicit 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())
 	}
 }
 
@@ -433,7 +423,7 @@
 	`)
 	rustc := ctx.ModuleForTests("libpm", "linux_glibc_x86_64").Rule("rustc")
 
-	if !strings.Contains(rustc.RuleParams.Command, "libbar/linux_glibc_x86_64") {
+	if !strings.Contains(rustc.Args["libFlags"], "libbar/linux_glibc_x86_64") {
 		t.Errorf("Proc_macro is not using host variant of dependent modules.")
 	}
 }
@@ -486,396 +476,3 @@
 		t.Errorf("expected %q got %q", expected, got)
 	}
 }
-
-var (
-	sboxCompilationFiles = []string{
-		"out/soong/.intermediates/defaults/rust/libaddr2line/android_arm64_armv8-a_rlib/libaddr2line.rlib",
-		"out/soong/.intermediates/defaults/rust/libadler/android_arm64_armv8-a_rlib/libadler.rlib",
-		"out/soong/.intermediates/defaults/rust/liballoc/android_arm64_armv8-a_rlib/liballoc.rlib",
-		"out/soong/.intermediates/defaults/rust/libcfg_if/android_arm64_armv8-a_rlib/libcfg_if.rlib",
-		"out/soong/.intermediates/defaults/rust/libcompiler_builtins/android_arm64_armv8-a_rlib/libcompiler_builtins.rlib",
-		"out/soong/.intermediates/defaults/rust/libcore/android_arm64_armv8-a_rlib/libcore.rlib",
-		"out/soong/.intermediates/defaults/rust/libgimli/android_arm64_armv8-a_rlib/libgimli.rlib",
-		"out/soong/.intermediates/defaults/rust/libhashbrown/android_arm64_armv8-a_rlib/libhashbrown.rlib",
-		"out/soong/.intermediates/defaults/rust/liblibc/android_arm64_armv8-a_rlib/liblibc.rlib",
-		"out/soong/.intermediates/defaults/rust/libmemchr/android_arm64_armv8-a_rlib/libmemchr.rlib",
-		"out/soong/.intermediates/defaults/rust/libminiz_oxide/android_arm64_armv8-a_rlib/libminiz_oxide.rlib",
-		"out/soong/.intermediates/defaults/rust/libobject/android_arm64_armv8-a_rlib/libobject.rlib",
-		"out/soong/.intermediates/defaults/rust/libpanic_unwind/android_arm64_armv8-a_rlib/libpanic_unwind.rlib",
-		"out/soong/.intermediates/defaults/rust/librustc_demangle/android_arm64_armv8-a_rlib/librustc_demangle.rlib",
-		"out/soong/.intermediates/defaults/rust/librustc_std_workspace_alloc/android_arm64_armv8-a_rlib/librustc_std_workspace_alloc.rlib",
-		"out/soong/.intermediates/defaults/rust/librustc_std_workspace_core/android_arm64_armv8-a_rlib/librustc_std_workspace_core.rlib",
-		"out/soong/.intermediates/defaults/rust/libstd_detect/android_arm64_armv8-a_rlib/libstd_detect.rlib",
-		"build/soong/scripts/mkcratersp.py",
-		"defaults/rust/linux-x86/1.69.0/bin/rustc",
-		"defaults/rust/linux-x86/1.69.0/lib/libstd.so",
-		"defaults/rust/linux-x86/1.69.0/lib64/libc++.so.1",
-	}
-	sboxCompilationFilesWithCc = []string{
-		"defaults/cc/common",
-		"out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so",
-		"out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so.toc",
-		"out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so",
-		"out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so.toc",
-		"out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so",
-		"out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so.toc",
-		"out/soong/.intermediates/defaults/rust/liblog/android_arm64_armv8-a_shared/liblog.so",
-		"out/soong/.intermediates/defaults/rust/liblog/android_arm64_armv8-a_shared/liblog.so.toc",
-	}
-)
-
-func TestSandboxCompilation(t *testing.T) {
-	ctx := testRust(t, `
-		filegroup {
-			name: "libsrcs1",
-			srcs: ["src_filegroup1.rs"],
-		}
-		filegroup {
-			name: "libsrcs2",
-			srcs: ["src_filegroup2.rs"],
-		}
-		rust_library {
-			name: "libfizz_buzz",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: [
-				"src_lib*.rs",
-				":libsrcs1",
-				":libsrcs2",
-			],
-			compile_data: [
-				"compile_data1.txt",
-				"compile_data2.txt",
-			],
-			dylib: {
-				srcs: ["dylib_only.rs"],
-			},
-			rlib: {
-				srcs: ["rlib_only.rs"],
-			},
-		}
-		rust_binary {
-			name: "fizz_buzz",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: [
-				"src_lib*.rs",
-				":libsrcs1",
-				":libsrcs2",
-			],
-		}
-		rust_ffi {
-			name: "librust_ffi",
-			crate_name: "rust_ffi",
-			crate_root: "foo.rs",
-			static: {
-				srcs: ["static_only.rs"],
-			},
-			shared: {
-				srcs: ["shared_only.rs"],
-			},
-			srcs: ["src1.rs"],
-		}
-		cc_library_static {
-			name: "cc_dep_static",
-		}
-		cc_library_shared {
-			name: "cc_dep_shared",
-		}
-		rust_library {
-			name: "libfizz_buzz_cc_deps",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: ["src*.rs"],
-			shared_libs: ["cc_dep_shared"],
-			static_libs: ["cc_dep_static"],
-		}
-		rust_library {
-			name: "libfizz_buzz_intermediate_cc_deps",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: ["src*.rs"],
-			rustlibs: ["libfizz_buzz_cc_deps"],
-		}
-		rust_library {
-			name: "libfizz_buzz_transitive_cc_deps",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: ["src*.rs"],
-			rustlibs: ["libfizz_buzz_intermediate_cc_deps"],
-		}
-	`,
-		android.FixtureMergeMockFs(android.MockFS{
-			"src_lib1.rs":       nil,
-			"src_lib2.rs":       nil,
-			"src_lib3.rs":       nil,
-			"src_lib4.rs":       nil,
-			"src_filegroup1.rs": nil,
-			"src_filegroup2.rs": nil,
-			"static_only.rs":    nil,
-			"shared_only.rs":    nil,
-		}),
-	)
-
-	testcases := []struct {
-		name                     string
-		moduleName               string
-		variant                  string
-		rustcExpectedFilesToCopy []string
-		expectedFlags            []string
-	}{
-		{
-			name:       "rust_library (dylib)",
-			moduleName: "libfizz_buzz",
-			variant:    "android_arm64_armv8-a_dylib",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, sboxCompilationFilesWithCc, []string{
-				"foo.rs",
-				"src_lib1.rs",
-				"src_lib2.rs",
-				"src_lib3.rs",
-				"src_lib4.rs",
-				"src_filegroup1.rs",
-				"src_filegroup2.rs",
-				"compile_data1.txt",
-				"compile_data2.txt",
-				"dylib_only.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/out/src_filegroup1.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/out/src_filegroup2.rs",
-
-				"out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so",
-				"out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so.toc",
-				"out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so",
-				"out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so.toc",
-				"out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so",
-				"out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so.toc",
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so",
-				"out/soong/.intermediates/defaults/cc/common/crtbegin_so/android_arm64_armv8-a/crtbegin_so.o",
-				"out/soong/.intermediates/defaults/cc/common/crtend_so/android_arm64_armv8-a/crtend_so.o",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so.clippy",
-			}),
-			expectedFlags: []string{
-				"-C linker=build/soong/scripts/mkcratersp.py",
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/libfizz_buzz.dylib.so.rsp",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/libfizz_buzz.dylib.so.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_library (rlib dylib-std)",
-			moduleName: "libfizz_buzz",
-			variant:    "android_arm64_armv8-a_rlib_dylib-std",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, []string{
-				"foo.rs",
-				"src_lib1.rs",
-				"src_lib2.rs",
-				"src_lib3.rs",
-				"src_lib4.rs",
-				"src_filegroup1.rs",
-				"src_filegroup2.rs",
-				"rlib_only.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_dylib-std/out/src_filegroup1.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_dylib-std/out/src_filegroup2.rs",
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_library (rlib rlib-std)",
-			moduleName: "libfizz_buzz",
-			variant:    "android_arm64_armv8-a_rlib_rlib-std",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, []string{
-				"foo.rs",
-				"src_lib1.rs",
-				"src_lib2.rs",
-				"src_lib3.rs",
-				"src_lib4.rs",
-				"src_filegroup1.rs",
-				"src_filegroup2.rs",
-				"rlib_only.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/out/src_filegroup1.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/out/src_filegroup2.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/libfizz_buzz.rlib.clippy",
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_rlib/libstd.rlib",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_binary",
-			moduleName: "fizz_buzz",
-			variant:    "android_arm64_armv8-a",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, sboxCompilationFilesWithCc, []string{
-				"foo.rs",
-				"src_lib1.rs",
-				"src_lib2.rs",
-				"src_lib3.rs",
-				"src_lib4.rs",
-				"src_filegroup1.rs",
-				"src_filegroup2.rs",
-				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/out/src_filegroup1.rs",
-				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/out/src_filegroup2.rs",
-
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so",
-				"out/soong/.intermediates/defaults/cc/common/crtbegin_dynamic/android_arm64_armv8-a/crtbegin_dynamic.o",
-				"out/soong/.intermediates/defaults/cc/common/crtend_android/android_arm64_armv8-a/crtend_android.o",
-				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz.clippy",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/fizz_buzz",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/fizz_buzz.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_ffi static lib variant",
-			moduleName: "librust_ffi",
-			variant:    "android_arm64_armv8-a_static",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, []string{
-				"foo.rs",
-				"src1.rs",
-				"static_only.rs",
-				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_static/librust_ffi.a.clippy",
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_rlib/libstd.rlib",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/librust_ffi.a",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/librust_ffi.a.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_ffi shared lib variant",
-			moduleName: "librust_ffi",
-			variant:    "android_arm64_armv8-a_shared",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, sboxCompilationFilesWithCc, []string{
-				"foo.rs",
-				"src1.rs",
-				"shared_only.rs",
-
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so",
-				"out/soong/.intermediates/defaults/cc/common/crtbegin_so/android_arm64_armv8-a/crtbegin_so.o",
-				"out/soong/.intermediates/defaults/cc/common/crtend_so/android_arm64_armv8-a/crtend_so.o",
-				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/librust_ffi.so.clippy",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/librust_ffi.so",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/librust_ffi.so.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_library with cc deps (dylib)",
-			moduleName: "libfizz_buzz_cc_deps",
-			variant:    "android_arm64_armv8-a_dylib",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with cc deps (rlib rlib-std)",
-			moduleName: "libfizz_buzz_cc_deps",
-			variant:    "android_arm64_armv8-a_rlib_rlib-std",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with cc deps (rlib dylib-std)",
-			moduleName: "libfizz_buzz_cc_deps",
-			variant:    "android_arm64_armv8-a_rlib_dylib-std",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with transitive cc deps (dylib)",
-			moduleName: "libfizz_buzz_transitive_cc_deps",
-			variant:    "android_arm64_armv8-a_dylib",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with transitive cc deps (rlib rlib-std)",
-			moduleName: "libfizz_buzz_transitive_cc_deps",
-			variant:    "android_arm64_armv8-a_rlib_rlib-std",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with transitive cc deps (rlib dylib-std)",
-			moduleName: "libfizz_buzz_transitive_cc_deps",
-			variant:    "android_arm64_armv8-a_rlib_dylib-std",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-	}
-
-	for _, tc := range testcases {
-		t.Run(tc.name, func(t *testing.T) {
-			writeFile := ctx.ModuleForTests(tc.moduleName, tc.variant).Rule("unescapedWriteFile")
-			contents := writeFile.BuildParams.Args["content"]
-			manifestProto := sbox_proto.Manifest{}
-			err := prototext.Unmarshal([]byte(contents), &manifestProto)
-			if err != nil {
-				t.Errorf("expected no errors unmarshaling manifest proto; got %v", err)
-			}
-
-			if len(manifestProto.Commands) != 1 {
-				t.Errorf("expected 1 command; got %v", len(manifestProto.Commands))
-			}
-
-			// check that sandbox contains correct files
-			rustc := manifestProto.Commands[0]
-			actualFilesToCopy := []string{}
-			for _, copy := range rustc.CopyBefore {
-				actualFilesToCopy = append(actualFilesToCopy, copy.GetFrom())
-			}
-			_, expectedFilesNotCopied, _ := android.ListSetDifference(tc.rustcExpectedFilesToCopy, actualFilesToCopy)
-			if len(expectedFilesNotCopied) > 0 {
-				t.Errorf("did not copy expected files to sbox: %v;\n files copied: %v", expectedFilesNotCopied, actualFilesToCopy)
-			}
-
-			rustcCmd := proptools.String(rustc.Command)
-			for _, flag := range tc.expectedFlags {
-				android.AssertStringDoesContain(
-					t,
-					fmt.Sprintf(
-						"missing flag in rustc invocation; expected to find substring %q; got %q",
-						flag,
-						rustcCmd,
-					),
-					rustcCmd,
-					flag,
-				)
-			}
-		})
-	}
-}
diff --git a/rust/sanitize.go b/rust/sanitize.go
index 2f5afd7..0b10435 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -203,6 +203,11 @@
 		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
diff --git a/rust/testing.go b/rust/testing.go
index 9951937..3fe751e 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -52,22 +52,6 @@
 
 func GatherRequiredDepsForTest() string {
 	bp := `
-		prebuilt_build_tool {
-			name: "rustc",
-			src: "linux-x86/1.69.0/bin/rustc",
-			deps: [
-				"linux-x86/1.69.0/lib/libstd.so",
-				"linux-x86/1.69.0/lib64/libc++.so.1",
-			],
-		}
-		prebuilt_build_tool {
-			name: "clippy-driver",
-			src: "linux-x86/1.69.0/bin/clippy-driver",
-		}
-		prebuilt_build_tool {
-			name: "rustdoc",
-			src: "linux-x86/1.69.0/bin/rustdoc",
-		}
 		rust_prebuilt_library {
 				name: "libstd",
 				crate_name: "std",
@@ -79,25 +63,6 @@
 				},
 				host_supported: true,
 				sysroot: true,
-			rlibs: [
-			    "libaddr2line",
-			    "libadler",
-			    "liballoc",
-			    "libcfg_if",
-			    "libcompiler_builtins",
-			    "libcore",
-			    "libgimli",
-			    "libhashbrown",
-			    "liblibc",
-			    "libmemchr",
-			    "libminiz_oxide",
-			    "libobject",
-			    "libpanic_unwind",
-			    "librustc_demangle",
-			    "librustc_std_workspace_alloc",
-			    "librustc_std_workspace_core",
-			    "libstd_detect",
-			],
 		}
 		//////////////////////////////
 		// Device module requirements
@@ -134,278 +99,6 @@
 			nocrt: true,
 			system_shared_libs: [],
 		}
-		rust_library_rlib {
-			name: "libaddr2line",
-			crate_name: "addr2line",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libadler",
-			crate_name: "adler",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "liballoc",
-			crate_name: "alloc",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libcfg_if",
-			crate_name: "cfg_if",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libcompiler_builtins",
-			crate_name: "compiler_builtins",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libcore",
-			crate_name: "core",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libgimli",
-			crate_name: "gimli",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libhashbrown",
-			crate_name: "hashbrown",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "liblibc",
-			crate_name: "libc",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libmemchr",
-			crate_name: "memchr",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libminiz_oxide",
-			crate_name: "miniz_oxide",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libobject",
-			crate_name: "object",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libpanic_unwind",
-			crate_name: "panic_unwind",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "librustc_demangle",
-			crate_name: "rustc_demangle",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "librustc_std_workspace_alloc",
-			crate_name: "rustc_std_workspace_alloc",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "librustc_std_workspace_core",
-			crate_name: "rustc_std_workspace_core",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libstd_detect",
-			crate_name: "std_detect",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
 		rust_library {
 			name: "libstd",
 			crate_name: "std",
@@ -420,25 +113,6 @@
 			sysroot: true,
 			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
 			min_sdk_version: "29",
-			rlibs: [
-			    "libaddr2line",
-			    "libadler",
-			    "liballoc",
-			    "libcfg_if",
-			    "libcompiler_builtins",
-			    "libcore",
-			    "libgimli",
-			    "libhashbrown",
-			    "liblibc",
-			    "libmemchr",
-			    "libminiz_oxide",
-			    "libobject",
-			    "libpanic_unwind",
-			    "librustc_demangle",
-			    "librustc_std_workspace_alloc",
-			    "librustc_std_workspace_core",
-			    "libstd_detect",
-			],
 		}
 		rust_library {
 			name: "libtest",
diff --git a/rust/toolchain_library.go b/rust/toolchain_library.go
index cb345a4..054104c 100644
--- a/rust/toolchain_library.go
+++ b/rust/toolchain_library.go
@@ -89,7 +89,7 @@
 
 func rustSetToolchainSource(ctx android.LoadHookContext) {
 	if toolchainLib, ok := ctx.Module().(*Module).compiler.(*toolchainLibraryDecorator); ok {
-		prefix := filepath.Join(config.HostPrebuiltTag(ctx.Config()), GetRustPrebuiltVersion(ctx))
+		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 {
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 621a724..4f45799 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -1051,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("rustc").RuleParams.Command
+	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"},
@@ -1119,7 +1119,7 @@
 		t.Errorf("Unexpected rust rlib name in AndroidMk: %q, expected: %q\n", rustVendorBinMkDylibName, expectedRustVendorSnapshotName)
 	}
 
-	binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustc").RuleParams.Command
+	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",
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 dad2b47..47eae07 100644
--- a/scripts/check_boot_jars/package_allowed_list.txt
+++ b/scripts/check_boot_jars/package_allowed_list.txt
@@ -44,6 +44,7 @@
 java\.util\.jar
 java\.util\.logging
 java\.util\.prefs
+java\.util\.random
 java\.util\.regex
 java\.util\.spi
 java\.util\.stream
@@ -79,8 +80,10 @@
 jdk\.internal\.reflect
 jdk\.internal\.util
 jdk\.internal\.util\.jar
+jdk\.internal\.util\.random
 jdk\.internal\.vm\.annotation
 jdk\.net
+jdk\.random
 org\.w3c\.dom
 org\.w3c\.dom\.ls
 org\.w3c\.dom\.traversal
diff --git a/scripts/conv_linker_config.py b/scripts/conv_linker_config.py
index c6aa3d0..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,8 +116,7 @@
         with open(other, 'rb') as f:
             pb.MergeFromString(f.read())
 
-    with open(args.out, 'wb') as f:
-        f.write(pb.SerializeToString())
+    ValidateAndWriteAsPbFile(pb, args.output)
 
 
 def Validate(args):
@@ -150,6 +149,34 @@
     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()
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 6ef01eb..0000000
--- a/scripts/mkcratersp.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2023 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-"""
-This script is used as a replacement for the Rust linker. It converts a linker
-command line into a rspfile that can be used during the link phase.
-"""
-
-import os
-import shutil
-import subprocess
-import sys
-
-def create_archive(out, objects, archives):
-  mricmd = f'create {out}\n'
-  for o in objects:
-    mricmd += f'addmod {o}\n'
-  for a in archives:
-    mricmd += f'addlib {a}\n'
-  mricmd += 'save\nend\n'
-  subprocess.run([os.getenv('AR'), '-M'], encoding='utf-8', input=mricmd, check=True)
-
-objects = []
-archives = []
-linkdirs = []
-libs = []
-temp_archives = []
-version_script = None
-
-for i, arg in enumerate(sys.argv):
-  if arg == '-o':
-    out = sys.argv[i+1]
-  if arg == '-L':
-    linkdirs.append(sys.argv[i+1])
-  if arg.startswith('-l') or arg == '-shared':
-    libs.append(arg)
-  if os.getenv('ANDROID_RUST_DARWIN') and (arg == '-dylib' or arg == '-dynamiclib'):
-    libs.append(arg)
-  if arg.startswith('-Wl,--version-script='):
-    version_script = arg[21:]
-  if arg[0] == '-':
-    continue
-  if arg.endswith('.o') or arg.endswith('.rmeta'):
-    objects.append(arg)
-  if arg.endswith('.rlib'):
-    if arg.startswith(os.getenv('TMPDIR')):
-      temp_archives.append(arg)
-    else:
-      archives.append(arg)
-
-create_archive(f'{out}.whole.a', objects, [])
-create_archive(f'{out}.a', [], temp_archives)
-
-with open(out, 'w') as f:
-  if os.getenv("ANDROID_RUST_DARWIN"):
-    print(f'-force_load', file=f)
-    print(f'{out}.whole.a', file=f)
-  else:
-    print(f'-Wl,--whole-archive', file=f)
-    print(f'{out}.whole.a', file=f)
-    print(f'-Wl,--no-whole-archive', file=f)
-  print(f'{out}.a', file=f)
-  for a in archives:
-    print(a, file=f)
-  for linkdir in linkdirs:
-    print(f'-L{linkdir}', file=f)
-  for l in libs:
-    print(l, file=f)
-  if version_script:
-    shutil.copyfile(version_script, f'{out}.version_script')
-    print(f'-Wl,--version-script={out}.version_script', file=f)
diff --git a/scripts/strip.sh b/scripts/strip.sh
index d09c187..71cb1c6 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -98,9 +98,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
diff --git a/sh/Android.bp b/sh/Android.bp
index 1deedc7..930fcf5 100644
--- a/sh/Android.bp
+++ b/sh/Android.bp
@@ -11,6 +11,7 @@
         "soong-android",
         "soong-cc",
         "soong-java",
+        "soong-testing",
         "soong-tradefed",
     ],
     srcs: [
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 79a885f..1bebc60 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -20,6 +20,7 @@
 	"sort"
 	"strings"
 
+	"android/soong/testing"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -452,6 +453,7 @@
 			ctx.PropertyErrorf(property, "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
 		}
 	})
+	ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
 }
 
 func (s *ShTest) InstallInData() bool {
@@ -575,12 +577,12 @@
 }
 
 type bazelShTestAttributes struct {
-	Srcs                 bazel.LabelListAttribute
-	Data                 bazel.LabelListAttribute
-	Tags                 bazel.StringListAttribute
-	Test_config          *string
-	Test_config_template *string
-	Auto_gen_config      *bool
+	Srcs      bazel.LabelListAttribute
+	Data      bazel.LabelListAttribute
+	Data_bins bazel.LabelListAttribute
+	Tags      bazel.StringListAttribute
+	Runs_on   bazel.StringListAttribute
+	tradefed.TestConfigAttributes
 }
 
 func (m *ShBinary) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
@@ -615,28 +617,42 @@
 	srcs := bazel.MakeLabelListAttribute(
 		android.BazelLabelForModuleSrc(ctx, []string{*m.properties.Src}))
 
-	combinedData := append(m.testProperties.Data, m.testProperties.Data_bins...)
-	combinedData = append(combinedData, m.testProperties.Data_libs...)
+	dataBins := bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, m.testProperties.Data_bins))
 
-	data := bazel.MakeLabelListAttribute(
-		android.BazelLabelForModuleSrc(ctx, combinedData))
+	var combinedData bazel.LabelList
+	combinedData.Append(android.BazelLabelForModuleSrc(ctx, m.testProperties.Data))
+	combinedData.Append(android.BazelLabelForModuleDeps(ctx, m.testProperties.Data_bins))
+	combinedData.Append(android.BazelLabelForModuleDeps(ctx, m.testProperties.Data_libs))
+	data := bazel.MakeLabelListAttribute(combinedData)
 
 	tags := bazel.MakeStringListAttribute(
 		m.testProperties.Test_options.Tags)
 
-	test_config := m.testProperties.Test_config
+	testConfigAttributes := tradefed.GetTestConfigAttributes(
+		ctx,
+		m.testProperties.Test_config,
+		[]string{},
+		m.testProperties.Auto_gen_config,
+		m.testProperties.Test_suites,
+		m.testProperties.Test_config_template,
+		nil,
+		nil,
+	)
 
-	test_config_template := m.testProperties.Test_config_template
+	unitTest := m.testProperties.Test_options.Unit_test
 
-	auto_gen_config := m.testProperties.Auto_gen_config
+	runs_on := bazel.MakeStringListAttribute(android.RunsOn(
+		m.ModuleBase.HostSupported(),
+		m.ModuleBase.DeviceSupported(),
+		(unitTest != nil && *unitTest)))
 
 	attrs := &bazelShTestAttributes{
 		Srcs:                 srcs,
 		Data:                 data,
+		Data_bins:            dataBins,
 		Tags:                 tags,
-		Test_config:          test_config,
-		Test_config_template: test_config_template,
-		Auto_gen_config:      auto_gen_config,
+		Runs_on:              runs_on,
+		TestConfigAttributes: testConfigAttributes,
 	}
 
 	props := bazel.BazelTargetModuleProperties{
diff --git a/sysprop/Android.bp b/sysprop/Android.bp
index e5263fe..7f51000 100644
--- a/sysprop/Android.bp
+++ b/sysprop/Android.bp
@@ -12,6 +12,7 @@
         "soong-bp2build",
         "soong-cc",
         "soong-java",
+        "soong-sysprop-bp2build",
     ],
     srcs: [
         "sysprop_library.go",
diff --git a/sysprop/bp2build/Android.bp b/sysprop/bp2build/Android.bp
new file mode 100644
index 0000000..1b9eda8
--- /dev/null
+++ b/sysprop/bp2build/Android.bp
@@ -0,0 +1,16 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-sysprop-bp2build",
+    pkgPath: "android/soong/sysprop/bp2build",
+    deps: [
+        "soong-android",
+        "soong-bazel",
+    ],
+    srcs: [
+        "bp2build.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/sysprop/bp2build/bp2build.go b/sysprop/bp2build/bp2build.go
new file mode 100644
index 0000000..18991de
--- /dev/null
+++ b/sysprop/bp2build/bp2build.go
@@ -0,0 +1,106 @@
+// 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 bp2build
+
+import (
+	"android/soong/android"
+	"android/soong/bazel"
+)
+
+type SyspropLibraryLabels struct {
+	SyspropLibraryLabel  string
+	CcSharedLibraryLabel string
+	CcStaticLibraryLabel string
+	JavaLibraryLabel     string
+}
+
+// TODO(b/240463568): Additional properties will be added for API validation
+type bazelSyspropLibraryAttributes struct {
+	Srcs bazel.LabelListAttribute
+	Tags bazel.StringListAttribute
+}
+
+func Bp2buildBaseSyspropLibrary(ctx android.Bp2buildMutatorContext, name string, srcs bazel.LabelListAttribute) {
+	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.Bp2buildMutatorContext), ctx.Module())
+
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "sysprop_library",
+			Bzl_load_location: "//build/bazel/rules/sysprop:sysprop_library.bzl",
+		},
+		android.CommonAttributes{Name: name},
+		&bazelSyspropLibraryAttributes{
+			Srcs: srcs,
+			Tags: apexAvailableTags,
+		},
+	)
+}
+
+type bazelCcSyspropLibraryAttributes struct {
+	Dep             bazel.LabelAttribute
+	Min_sdk_version *string
+	Tags            bazel.StringListAttribute
+}
+
+func Bp2buildSyspropCc(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, minSdkVersion *string) {
+	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.Bp2buildMutatorContext), ctx.Module())
+
+	attrs := &bazelCcSyspropLibraryAttributes{
+		Dep:             *bazel.MakeLabelAttribute(":" + labels.SyspropLibraryLabel),
+		Min_sdk_version: minSdkVersion,
+		Tags:            apexAvailableTags,
+	}
+
+	if labels.CcSharedLibraryLabel != "" {
+		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.CcSharedLibraryLabel},
+			attrs)
+	}
+	if labels.CcStaticLibraryLabel != "" {
+		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.CcStaticLibraryLabel},
+			attrs)
+	}
+}
+
+type bazelJavaLibraryAttributes struct {
+	Dep             bazel.LabelAttribute
+	Min_sdk_version *string
+	Tags            bazel.StringListAttribute
+}
+
+func Bp2buildSyspropJava(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, minSdkVersion *string) {
+	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.Bp2buildMutatorContext), ctx.Module())
+
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "java_sysprop_library",
+			Bzl_load_location: "//build/bazel/rules/java:java_sysprop_library.bzl",
+		},
+		android.CommonAttributes{Name: labels.JavaLibraryLabel},
+		&bazelJavaLibraryAttributes{
+			Dep:             *bazel.MakeLabelAttribute(":" + labels.SyspropLibraryLabel),
+			Min_sdk_version: minSdkVersion,
+			Tags:            apexAvailableTags,
+		})
+}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index d16bf32..fe2cc9c 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -24,6 +24,8 @@
 	"sync"
 
 	"android/soong/bazel"
+	"android/soong/sysprop/bp2build"
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -170,6 +172,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 {
@@ -230,6 +238,10 @@
 	return m.BaseModuleName() + "_java_gen_public"
 }
 
+func (m *syspropLibrary) bp2buildJavaImplementationModuleName() string {
+	return m.BaseModuleName() + "_java_library"
+}
+
 func (m *syspropLibrary) BaseModuleName() string {
 	return m.ModuleBase.Name()
 }
@@ -410,6 +422,8 @@
 	Host_supported     *bool
 	Apex_available     []string
 	Min_sdk_version    *string
+	Cflags             []string
+	Ldflags            []string
 	Bazel_module       struct {
 		Label *string
 	}
@@ -431,6 +445,7 @@
 	Min_sdk_version   *string
 	Bazel_module      struct {
 		Bp2build_available *bool
+		Label              *string
 	}
 }
 
@@ -504,6 +519,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
+	ccProps.Cflags = m.properties.Cpp.Cflags
+	ccProps.Ldflags = m.properties.Cpp.Ldflags
 	ccProps.Bazel_module.Label = label
 	ctx.CreateModule(cc.LibraryFactory, &ccProps)
 
@@ -551,8 +568,10 @@
 		Min_sdk_version:   m.properties.Java.Min_sdk_version,
 		Bazel_module: struct {
 			Bp2build_available *bool
+			Label              *string
 		}{
-			Bp2build_available: proptools.BoolPtr(false),
+			Label: proptools.StringPtr(
+				fmt.Sprintf("//%s:%s", ctx.ModuleDir(), m.bp2buildJavaImplementationModuleName())),
 		},
 	})
 
@@ -573,6 +592,7 @@
 			Stem:        proptools.StringPtr(m.BaseModuleName()),
 			Bazel_module: struct {
 				Bp2build_available *bool
+				Label              *string
 			}{
 				Bp2build_available: proptools.BoolPtr(false),
 			},
@@ -592,13 +612,17 @@
 
 // TODO(b/240463568): Additional properties will be added for API validation
 func (m *syspropLibrary) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
-	labels := cc.SyspropLibraryLabels{
-		SyspropLibraryLabel: m.BaseModuleName(),
-		SharedLibraryLabel:  m.CcImplementationModuleName(),
-		StaticLibraryLabel:  cc.BazelLabelNameForStaticModule(m.CcImplementationModuleName()),
+	if m.Owner() != "Platform" {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "Only sysprop libraries owned by platform are supported at this time")
+		return
 	}
-	cc.Bp2buildSysprop(ctx,
-		labels,
-		bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Srcs)),
-		m.properties.Cpp.Min_sdk_version)
+	labels := bp2build.SyspropLibraryLabels{
+		SyspropLibraryLabel:  m.BaseModuleName(),
+		CcSharedLibraryLabel: m.CcImplementationModuleName(),
+		CcStaticLibraryLabel: cc.BazelLabelNameForStaticModule(m.CcImplementationModuleName()),
+		JavaLibraryLabel:     m.bp2buildJavaImplementationModuleName(),
+	}
+	bp2build.Bp2buildBaseSyspropLibrary(ctx, labels.SyspropLibraryLabel, bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Srcs)))
+	bp2build.Bp2buildSyspropCc(ctx, labels, m.properties.Cpp.Min_sdk_version)
+	bp2build.Bp2buildSyspropJava(ctx, labels, m.properties.Java.Min_sdk_version)
 }
diff --git a/sysprop/sysprop_library_conversion_test.go b/sysprop/sysprop_library_conversion_test.go
index 89adf7d..dabcc92 100644
--- a/sysprop/sysprop_library_conversion_test.go
+++ b/sysprop/sysprop_library_conversion_test.go
@@ -58,13 +58,18 @@
 				bp2build.AttrNameToString{
 					"dep": `":sysprop_foo"`,
 				}),
+			bp2build.MakeBazelTargetNoRestrictions("java_sysprop_library",
+				"sysprop_foo_java_library",
+				bp2build.AttrNameToString{
+					"dep": `":sysprop_foo"`,
+				}),
 		},
 	})
 }
 
 func TestSyspropLibraryCppMinSdkVersion(t *testing.T) {
 	bp2build.RunBp2BuildTestCaseSimple(t, bp2build.Bp2buildTestCase{
-		Description:                "sysprop_library with min_sdk_version",
+		Description:                "sysprop_library with cpp min_sdk_version",
 		ModuleTypeUnderTest:        "sysprop_library",
 		ModuleTypeUnderTestFactory: syspropLibraryFactory,
 		Filesystem: map[string]string{
@@ -105,6 +110,86 @@
 					"dep":             `":sysprop_foo"`,
 					"min_sdk_version": `"5"`,
 				}),
+			bp2build.MakeBazelTargetNoRestrictions("java_sysprop_library",
+				"sysprop_foo_java_library",
+				bp2build.AttrNameToString{
+					"dep": `":sysprop_foo"`,
+				}),
 		},
 	})
 }
+
+func TestSyspropLibraryJavaMinSdkVersion(t *testing.T) {
+	bp2build.RunBp2BuildTestCaseSimple(t, bp2build.Bp2buildTestCase{
+		Description:                "sysprop_library with java 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",
+	],
+	java: {
+		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"`,
+				}),
+			bp2build.MakeBazelTargetNoRestrictions("cc_sysprop_library_static",
+				"libsysprop_foo_bp2build_cc_library_static",
+				bp2build.AttrNameToString{
+					"dep": `":sysprop_foo"`,
+				}),
+			bp2build.MakeBazelTargetNoRestrictions("java_sysprop_library",
+				"sysprop_foo_java_library",
+				bp2build.AttrNameToString{
+					"dep":             `":sysprop_foo"`,
+					"min_sdk_version": `"5"`,
+				}),
+		},
+	})
+}
+
+func TestSyspropLibraryOwnerNotPlatformUnconvertible(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: "Vendor",
+	device_specific: true,
+}
+`,
+		ExpectedBazelTargets: []string{},
+	})
+}
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 80b86e0..e51fe39 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,
 		}
 
@@ -250,6 +251,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 +270,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 +280,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 +302,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/Android.bp b/testing/Android.bp
new file mode 100644
index 0000000..26a7d93
--- /dev/null
+++ b/testing/Android.bp
@@ -0,0 +1,19 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-testing",
+    pkgPath: "android/soong/testing",
+    deps: [
+        "blueprint",
+        "soong-android",
+        "soong-testing-test_spec_proto",
+
+    ],
+    srcs: [
+        "test_spec.go",
+        "init.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/testing/init.go b/testing/init.go
new file mode 100644
index 0000000..8820a60
--- /dev/null
+++ b/testing/init.go
@@ -0,0 +1,27 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package testing
+
+import (
+	"android/soong/android"
+)
+
+func init() {
+	RegisterBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("test_spec", TestSpecFactory)
+}
diff --git a/testing/test_spec.go b/testing/test_spec.go
new file mode 100644
index 0000000..1ad2768
--- /dev/null
+++ b/testing/test_spec.go
@@ -0,0 +1,127 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package testing
+
+import (
+	"path/filepath"
+	"strconv"
+
+	"android/soong/android"
+	"android/soong/testing/test_spec_proto"
+	"github.com/google/blueprint"
+	"google.golang.org/protobuf/proto"
+)
+
+// ErrTestModuleDataNotFound is the error message for missing test module provider data.
+const ErrTestModuleDataNotFound = "The module '%s' does not provide test specification data. Hint: This issue could arise if either the module is not a valid testing module or if it lacks the required 'TestModuleProviderKey' provider.\n"
+
+func TestSpecFactory() android.Module {
+	module := &TestSpecModule{}
+
+	android.InitAndroidModule(module)
+	android.InitDefaultableModule(module)
+	module.AddProperties(&module.properties)
+
+	return module
+}
+
+type TestSpecModule struct {
+	android.ModuleBase
+	android.DefaultableModuleBase
+	android.BazelModuleBase
+
+	// Properties for "test_spec"
+	properties struct {
+		// Specifies the name of the test config.
+		Name string
+		// Specifies the team ID.
+		TeamId string
+		// Specifies the list of tests covered under this module.
+		Tests []string
+	}
+}
+
+type testsDepTagType struct {
+	blueprint.BaseDependencyTag
+}
+
+var testsDepTag = testsDepTagType{}
+
+func (module *TestSpecModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// Validate Properties
+	if len(module.properties.TeamId) == 0 {
+		ctx.PropertyErrorf("TeamId", "Team Id not found in the test_spec module. Hint: Maybe the TeamId property hasn't been properly specified.")
+	}
+	if !isInt(module.properties.TeamId) {
+		ctx.PropertyErrorf("TeamId", "Invalid value for Team ID. The Team ID must be an integer.")
+	}
+	if len(module.properties.Tests) == 0 {
+		ctx.PropertyErrorf("Tests", "Expected to attribute some test but none found. Hint: Maybe the test property hasn't been properly specified.")
+	}
+	ctx.AddDependency(ctx.Module(), testsDepTag, module.properties.Tests...)
+}
+func isInt(s string) bool {
+	_, err := strconv.Atoi(s)
+	return err == nil
+}
+
+// Provider published by TestSpec
+type testSpecProviderData struct {
+	IntermediatePath android.WritablePath
+}
+
+var testSpecProviderKey = blueprint.NewProvider(testSpecProviderData{})
+
+type TestModuleProviderData struct {
+}
+
+var TestModuleProviderKey = blueprint.NewProvider(TestModuleProviderData{})
+
+func (module *TestSpecModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	for _, m := range ctx.GetDirectDepsWithTag(testsDepTag) {
+		if !ctx.OtherModuleHasProvider(m, TestModuleProviderKey) {
+			ctx.ModuleErrorf(ErrTestModuleDataNotFound, m.Name())
+		}
+	}
+	bpFilePath := filepath.Join(ctx.ModuleDir(), ctx.BlueprintsFile())
+	metadataList := make(
+		[]*test_spec_proto.TestSpec_OwnershipMetadata, 0,
+		len(module.properties.Tests),
+	)
+	for _, test := range module.properties.Tests {
+		targetName := test
+		metadata := test_spec_proto.TestSpec_OwnershipMetadata{
+			TrendyTeamId: &module.properties.TeamId,
+			TargetName:   &targetName,
+			Path:         &bpFilePath,
+		}
+		metadataList = append(metadataList, &metadata)
+	}
+	intermediatePath := android.PathForModuleOut(
+		ctx, "intermediateTestSpecMetadata.pb",
+	)
+	testSpecMetadata := test_spec_proto.TestSpec{OwnershipMetadataList: metadataList}
+	protoData, err := proto.Marshal(&testSpecMetadata)
+	if err != nil {
+		ctx.ModuleErrorf("Error: %s", err.Error())
+	}
+	android.WriteFileRule(ctx, intermediatePath, string(protoData))
+
+	ctx.SetProvider(
+		testSpecProviderKey, testSpecProviderData{
+			IntermediatePath: intermediatePath,
+		},
+	)
+}
diff --git a/testing/test_spec_proto/Android.bp b/testing/test_spec_proto/Android.bp
new file mode 100644
index 0000000..1cac492
--- /dev/null
+++ b/testing/test_spec_proto/Android.bp
@@ -0,0 +1,29 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+    name: "soong-testing-test_spec_proto",
+    pkgPath: "android/soong/testing/test_spec_proto",
+    deps: [
+            "golang-protobuf-reflect-protoreflect",
+            "golang-protobuf-runtime-protoimpl",
+        ],
+    srcs: [
+        "test_spec.pb.go",
+    ],
+}
diff --git a/testing/test_spec_proto/OWNERS b/testing/test_spec_proto/OWNERS
new file mode 100644
index 0000000..03bcdf1
--- /dev/null
+++ b/testing/test_spec_proto/OWNERS
@@ -0,0 +1,4 @@
+dariofreni@google.com
+joeo@google.com
+ronish@google.com
+caditya@google.com
diff --git a/testing/test_spec_proto/go.mod b/testing/test_spec_proto/go.mod
new file mode 100644
index 0000000..482cdbb
--- /dev/null
+++ b/testing/test_spec_proto/go.mod
@@ -0,0 +1,2 @@
+module test_spec_proto
+go 1.18
\ No newline at end of file
diff --git a/testing/test_spec_proto/regen.sh b/testing/test_spec_proto/regen.sh
new file mode 100644
index 0000000..2cf8203
--- /dev/null
+++ b/testing/test_spec_proto/regen.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+aprotoc --go_out=paths=source_relative:. test_spec.proto
diff --git a/testing/test_spec_proto/test_spec.pb.go b/testing/test_spec_proto/test_spec.pb.go
new file mode 100644
index 0000000..5cce600
--- /dev/null
+++ b/testing/test_spec_proto/test_spec.pb.go
@@ -0,0 +1,244 @@
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.30.0
+// 	protoc        v3.21.12
+// source: test_spec.proto
+
+package test_spec_proto
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type TestSpec struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// List of all test targets and their metadata.
+	OwnershipMetadataList []*TestSpec_OwnershipMetadata `protobuf:"bytes,1,rep,name=ownership_metadata_list,json=ownershipMetadataList" json:"ownership_metadata_list,omitempty"`
+}
+
+func (x *TestSpec) Reset() {
+	*x = TestSpec{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_test_spec_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TestSpec) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TestSpec) ProtoMessage() {}
+
+func (x *TestSpec) ProtoReflect() protoreflect.Message {
+	mi := &file_test_spec_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use TestSpec.ProtoReflect.Descriptor instead.
+func (*TestSpec) Descriptor() ([]byte, []int) {
+	return file_test_spec_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *TestSpec) GetOwnershipMetadataList() []*TestSpec_OwnershipMetadata {
+	if x != nil {
+		return x.OwnershipMetadataList
+	}
+	return nil
+}
+
+type TestSpec_OwnershipMetadata struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	TargetName   *string `protobuf:"bytes,1,opt,name=target_name,json=targetName" json:"target_name,omitempty"`
+	Path         *string `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"`
+	TrendyTeamId *string `protobuf:"bytes,3,opt,name=trendy_team_id,json=trendyTeamId" json:"trendy_team_id,omitempty"`
+}
+
+func (x *TestSpec_OwnershipMetadata) Reset() {
+	*x = TestSpec_OwnershipMetadata{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_test_spec_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *TestSpec_OwnershipMetadata) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TestSpec_OwnershipMetadata) ProtoMessage() {}
+
+func (x *TestSpec_OwnershipMetadata) ProtoReflect() protoreflect.Message {
+	mi := &file_test_spec_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use TestSpec_OwnershipMetadata.ProtoReflect.Descriptor instead.
+func (*TestSpec_OwnershipMetadata) Descriptor() ([]byte, []int) {
+	return file_test_spec_proto_rawDescGZIP(), []int{0, 0}
+}
+
+func (x *TestSpec_OwnershipMetadata) GetTargetName() string {
+	if x != nil && x.TargetName != nil {
+		return *x.TargetName
+	}
+	return ""
+}
+
+func (x *TestSpec_OwnershipMetadata) GetPath() string {
+	if x != nil && x.Path != nil {
+		return *x.Path
+	}
+	return ""
+}
+
+func (x *TestSpec_OwnershipMetadata) GetTrendyTeamId() string {
+	if x != nil && x.TrendyTeamId != nil {
+		return *x.TrendyTeamId
+	}
+	return ""
+}
+
+var File_test_spec_proto protoreflect.FileDescriptor
+
+var file_test_spec_proto_rawDesc = []byte{
+	0x0a, 0x0f, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x12, 0x0f, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x22, 0xdf, 0x01, 0x0a, 0x08, 0x54, 0x65, 0x73, 0x74, 0x53, 0x70, 0x65, 0x63, 0x12,
+	0x63, 0x0a, 0x17, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f, 0x6d, 0x65, 0x74,
+	0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x2b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x70, 0x72, 0x6f,
+	0x74, 0x6f, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x4f, 0x77, 0x6e, 0x65,
+	0x72, 0x73, 0x68, 0x69, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x15, 0x6f,
+	0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
+	0x4c, 0x69, 0x73, 0x74, 0x1a, 0x6e, 0x0a, 0x11, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69,
+	0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72,
+	0x67, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
+	0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61,
+	0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24,
+	0x0a, 0x0e, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x5f, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x54, 0x65,
+	0x61, 0x6d, 0x49, 0x64, 0x42, 0x27, 0x5a, 0x25, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
+	0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x74, 0x65,
+	0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+}
+
+var (
+	file_test_spec_proto_rawDescOnce sync.Once
+	file_test_spec_proto_rawDescData = file_test_spec_proto_rawDesc
+)
+
+func file_test_spec_proto_rawDescGZIP() []byte {
+	file_test_spec_proto_rawDescOnce.Do(func() {
+		file_test_spec_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_spec_proto_rawDescData)
+	})
+	return file_test_spec_proto_rawDescData
+}
+
+var file_test_spec_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_test_spec_proto_goTypes = []interface{}{
+	(*TestSpec)(nil),                   // 0: test_spec_proto.TestSpec
+	(*TestSpec_OwnershipMetadata)(nil), // 1: test_spec_proto.TestSpec.OwnershipMetadata
+}
+var file_test_spec_proto_depIdxs = []int32{
+	1, // 0: test_spec_proto.TestSpec.ownership_metadata_list:type_name -> test_spec_proto.TestSpec.OwnershipMetadata
+	1, // [1:1] is the sub-list for method output_type
+	1, // [1:1] is the sub-list for method input_type
+	1, // [1:1] is the sub-list for extension type_name
+	1, // [1:1] is the sub-list for extension extendee
+	0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_test_spec_proto_init() }
+func file_test_spec_proto_init() {
+	if File_test_spec_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_test_spec_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TestSpec); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_test_spec_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*TestSpec_OwnershipMetadata); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_test_spec_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   2,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_test_spec_proto_goTypes,
+		DependencyIndexes: file_test_spec_proto_depIdxs,
+		MessageInfos:      file_test_spec_proto_msgTypes,
+	}.Build()
+	File_test_spec_proto = out.File
+	file_test_spec_proto_rawDesc = nil
+	file_test_spec_proto_goTypes = nil
+	file_test_spec_proto_depIdxs = nil
+}
diff --git a/testing/test_spec_proto/test_spec.proto b/testing/test_spec_proto/test_spec.proto
new file mode 100644
index 0000000..86bc789
--- /dev/null
+++ b/testing/test_spec_proto/test_spec.proto
@@ -0,0 +1,33 @@
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+package test_spec_proto;
+option go_package = "android/soong/testing/test_spec_proto";
+
+message TestSpec {
+
+  message OwnershipMetadata {
+    // REQUIRED: Name of the build target
+    optional string target_name = 1;
+
+    // REQUIRED: Code location of the target.
+    // To be used to support legacy/backup systems that use OWNERS file and is
+    // also required for our dashboard to support per code location basis UI
+    optional string path = 2;
+
+    // REQUIRED: Team ID of the team that owns this target.
+    optional string trendy_team_id = 3;
+  }
+
+  // List of all test targets and their metadata.
+  repeated OwnershipMetadata ownership_metadata_list = 1;
+}
diff --git a/tests/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/genrule_sandbox_test.py b/tests/genrule_sandbox_test.py
index 0cebc2a..3799e92 100755
--- a/tests/genrule_sandbox_test.py
+++ b/tests/genrule_sandbox_test.py
@@ -15,12 +15,14 @@
 # limitations under the License.
 
 import argparse
+import asyncio
 import collections
 import json
 import os
+import socket
 import subprocess
 import sys
-import tempfile
+import textwrap
 
 def get_top() -> str:
   path = '.'
@@ -30,38 +32,65 @@
     path = os.path.join(path, '..')
   return os.path.abspath(path)
 
-def _build_with_soong(targets, target_product, *, keep_going = False, extra_env={}):
-  env = {
-      **os.environ,
-      "TARGET_PRODUCT": target_product,
-      "TARGET_BUILD_VARIANT": "userdebug",
-  }
-  env.update(extra_env)
+async def _build_with_soong(out_dir, targets, *, extra_env={}):
+  env = os.environ | extra_env
+
+  # Use nsjail to remap the out_dir to out/, because some genrules write the path to the out
+  # dir into their artifacts, so if the out directories were different it would cause a diff
+  # that doesn't really matter.
   args = [
+      'prebuilts/build-tools/linux-x86/bin/nsjail',
+      '-q',
+      '--cwd',
+      os.getcwd(),
+      '-e',
+      '-B',
+      '/',
+      '-B',
+      f'{os.path.abspath(out_dir)}:{os.path.abspath("out")}',
+      '--time_limit',
+      '0',
+      '--skip_setsid',
+      '--keep_caps',
+      '--disable_clone_newcgroup',
+      '--disable_clone_newnet',
+      '--rlimit_as',
+      'soft',
+      '--rlimit_core',
+      'soft',
+      '--rlimit_cpu',
+      'soft',
+      '--rlimit_fsize',
+      'soft',
+      '--rlimit_nofile',
+      'soft',
+      '--proc_rw',
+      '--hostname',
+      socket.gethostname(),
+      '--',
       "build/soong/soong_ui.bash",
       "--make-mode",
       "--skip-soong-tests",
   ]
-  if keep_going:
-    args.append("-k")
   args.extend(targets)
-  try:
-    subprocess.check_output(
-        args,
-        env=env,
-    )
-  except subprocess.CalledProcessError as e:
-    print(e)
-    print(e.stdout)
-    print(e.stderr)
-    exit(1)
+  process = await asyncio.create_subprocess_exec(
+      *args,
+      stdout=asyncio.subprocess.PIPE,
+      stderr=asyncio.subprocess.PIPE,
+      env=env,
+  )
+  stdout, stderr = await process.communicate()
+  if process.returncode != 0:
+    print(stdout)
+    print(stderr)
+    sys.exit(process.returncode)
 
 
-def _find_outputs_for_modules(modules, out_dir, target_product):
-  module_path = os.path.join(out_dir, "soong", "module-actions.json")
+async def _find_outputs_for_modules(modules):
+  module_path = "out/soong/module-actions.json"
 
   if not os.path.exists(module_path):
-    _build_with_soong(["json-module-graph"], target_product)
+    await _build_with_soong('out', ["json-module-graph"])
 
   with open(module_path) as f:
     action_graph = json.load(f)
@@ -70,7 +99,7 @@
   for mod in action_graph:
     name = mod["Name"]
     if name in modules:
-      for act in mod["Module"]["Actions"]:
+      for act in (mod["Module"]["Actions"] or []):
         if "}generate" in act["Desc"]:
           module_to_outs[name].update(act["Outputs"])
   return module_to_outs
@@ -88,20 +117,19 @@
   return different_modules
 
 
-def main():
+async def main():
   parser = argparse.ArgumentParser()
   parser.add_argument(
-      "--target_product",
-      "-t",
-      default="aosp_cf_arm64_phone",
-      help="optional, target product, always runs as eng",
-  )
-  parser.add_argument(
       "modules",
       nargs="+",
       help="modules to compare builds with genrule sandboxing enabled/not",
   )
   parser.add_argument(
+      "--check-determinism",
+      action="store_true",
+      help="Don't check for working sandboxing. Instead, run two default builds, and compare their outputs. This is used to check for nondeterminsim, which would also affect the sandboxed test.",
+  )
+  parser.add_argument(
       "--show-diff",
       "-d",
       action="store_true",
@@ -116,10 +144,13 @@
   args = parser.parse_args()
   os.chdir(get_top())
 
-  out_dir = os.environ.get("OUT_DIR", "out")
+  if "TARGET_PRODUCT" not in os.environ:
+    sys.exit("Please run lunch first")
+  if os.environ.get("OUT_DIR", "out") != "out":
+    sys.exit(f"This script expects OUT_DIR to be 'out', got: '{os.environ.get('OUT_DIR')}'")
 
   print("finding output files for the modules...")
-  module_to_outs = _find_outputs_for_modules(set(args.modules), out_dir, args.target_product)
+  module_to_outs = await _find_outputs_for_modules(set(args.modules))
   if not module_to_outs:
     sys.exit("No outputs found")
 
@@ -129,33 +160,48 @@
     sys.exit(0)
 
   all_outs = list(set.union(*module_to_outs.values()))
+  for i, out in enumerate(all_outs):
+    if not out.startswith("out/"):
+      sys.exit("Expected output file to start with out/, found: " + out)
 
-  print("building without sandboxing...")
-  _build_with_soong(all_outs, args.target_product)
-  with tempfile.TemporaryDirectory() as tempdir:
-    for f in all_outs:
-      subprocess.check_call(["cp", "--parents", f, tempdir])
+  other_out_dir = "out_check_determinism" if args.check_determinism else "out_not_sandboxed"
+  other_env = {"GENRULE_SANDBOXING": "false"}
+  if args.check_determinism:
+    other_env = {}
 
-    print("building with sandboxing...")
-    _build_with_soong(
-        all_outs,
-        args.target_product,
-        # We've verified these build without sandboxing already, so do the sandboxing build
-        # with keep_going = True so that we can find all the genrules that fail to build with
-        # sandboxing.
-        keep_going = True,
-        extra_env={"GENRULE_SANDBOXING": "true"},
-    )
+  # nsjail will complain if the out dir doesn't exist
+  os.makedirs("out", exist_ok=True)
+  os.makedirs(other_out_dir, exist_ok=True)
 
-    diffs = _compare_outputs(module_to_outs, tempdir)
-    if len(diffs) == 0:
-      print("All modules are correct")
-    elif args.show_diff:
-      for m, d in diffs.items():
-        print(f"Module {m} has diffs {d}")
-    else:
-      print(f"Modules {list(diffs.keys())} have diffs")
+  print("building...")
+  await asyncio.gather(
+    _build_with_soong("out", all_outs),
+    _build_with_soong(other_out_dir, all_outs, extra_env=other_env)
+  )
+
+  diffs = collections.defaultdict(dict)
+  for module, outs in module_to_outs.items():
+    for out in outs:
+      try:
+        subprocess.check_output(["diff", os.path.join(other_out_dir, out.removeprefix("out/")), out])
+      except subprocess.CalledProcessError as e:
+        diffs[module][out] = e.stdout
+
+  if len(diffs) == 0:
+    print("All modules are correct")
+  elif args.show_diff:
+    for m, files in diffs.items():
+      print(f"Module {m} has diffs:")
+      for f, d in files.items():
+        print("  "+f+":")
+        print(textwrap.indent(d, "    "))
+  else:
+    print(f"Modules {list(diffs.keys())} have diffs in these files:")
+    all_diff_files = [f for m in diffs.values() for f in m]
+    for f in all_diff_files:
+      print(f)
+
 
 
 if __name__ == "__main__":
-  main()
+  asyncio.run(main())
diff --git a/tests/lib.sh b/tests/lib.sh
index 0766d85..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
 
@@ -158,6 +163,7 @@
   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
@@ -197,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/run_integration_tests.sh b/tests/run_integration_tests.sh
index 6b9ff8b..231e18b 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -4,12 +4,14 @@
 
 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/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
@@ -23,4 +25,4 @@
 "$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53"
 
 "$TOP/build/bazel/ci/b_test.sh"
-
+"$TOP/build/soong/tests/symlinks_path_test.sh"
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index 73fbeab..8dc1630 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -35,14 +35,15 @@
 }
 
 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
 }
 
@@ -67,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
@@ -75,7 +76,7 @@
   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
@@ -217,7 +218,7 @@
   out_dir="$(setup)"
 
   # run_soong to build com.android.adbd.apex
-  run_soong "module_arm64" "${out_dir}" "sbom deapexer" "com.android.adbd"
+  run_soong "${out_dir}" "sbom deapexer" "com.android.adbd"
 
   deapexer=${out_dir}/host/linux-x86/bin/deapexer
   debugfs=${out_dir}/host/linux-x86/bin/debugfs_static
@@ -249,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"
@@ -271,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/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/ui/build/build.go b/ui/build/build.go
index 14d23a7..9d5c330 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(`
@@ -246,8 +274,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)
diff --git a/ui/build/config.go b/ui/build/config.go
index 084d28d..d345415 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -22,6 +22,7 @@
 	"math/rand"
 	"os"
 	"os/exec"
+	"os/user"
 	"path/filepath"
 	"runtime"
 	"strconv"
@@ -30,6 +31,7 @@
 	"time"
 
 	"android/soong/shared"
+	"android/soong/ui/metrics"
 
 	"google.golang.org/protobuf/proto"
 
@@ -84,7 +86,7 @@
 	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
+	buildFromSourceStub      bool
 	ensureAllowlistIntegrity bool   // For CI builds - make sure modules are mixed-built
 	bazelExitCode            int32  // For b runs - necessary for updating NonZeroExit
 	besId                    string // For b runs, to identify the BuildEventService logs
@@ -204,34 +206,6 @@
 	return nil
 }
 
-func defaultBazelProdMode(cfg *configImpl) bool {
-	// Environment flag to disable Bazel for users which experience
-	// broken bazel-handled builds, or significant performance regressions.
-	if cfg.IsBazelMixedBuildForceDisabled() {
-		return false
-	}
-	// Darwin-host builds are currently untested with Bazel.
-	if runtime.GOOS == "darwin" {
-		return false
-	}
-	return true
-}
-
-func UploadOnlyConfig(ctx Context, args ...string) Config {
-	ret := &configImpl{
-		environ:       OsEnvironment(),
-		sandboxConfig: &SandboxConfig{},
-	}
-	ret.parseArgs(ctx, args)
-	srcDir := absPath(ctx, ".")
-	bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
-	if err := loadEnvConfig(ctx, ret, bc); err != nil {
-		ctx.Fatalln("Failed to parse env config files: %v", err)
-	}
-	ret.metricsUploader = GetMetricsUploader(srcDir, ret.environ)
-	return Config{ret}
-}
-
 func NewConfig(ctx Context, args ...string) Config {
 	ret := &configImpl{
 		environ:               OsEnvironment(),
@@ -239,6 +213,11 @@
 		ninjaWeightListSource: DEFAULT,
 	}
 
+	// Skip soong tests by default on Linux
+	if runtime.GOOS == "linux" {
+		ret.skipSoongTests = true
+	}
+
 	// Default matching ninja
 	ret.parallel = runtime.NumCPU() + 2
 	ret.keepGoing = 1
@@ -404,8 +383,6 @@
 
 	// 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())
 	javaHome := func() string {
 		if override, ok := ret.environ.Get("OVERRIDE_ANDROID_JAVA_HOME"); ok {
@@ -432,8 +409,6 @@
 	ret.environ.Set("JAVA_HOME", absJavaHome)
 	ret.environ.Set("ANDROID_JAVA_HOME", javaHome)
 	ret.environ.Set("ANDROID_JAVA8_HOME", java8Home)
-	ret.environ.Set("ANDROID_JAVA9_HOME", java9Home)
-	ret.environ.Set("ANDROID_JAVA11_HOME", java11Home)
 	ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
 
 	// b/286885495, https://bugzilla.redhat.com/show_bug.cgi?id=2227130: some versions of Fedora include patches
@@ -455,17 +430,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)
@@ -482,6 +462,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) {
@@ -766,6 +782,8 @@
 			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" {
@@ -802,8 +820,8 @@
 			} 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
@@ -822,16 +840,6 @@
 			}
 		} else if arg == "--ensure-allowlist-integrity" {
 			c.ensureAllowlistIntegrity = true
-		} else if strings.HasPrefix(arg, "--bazel-exit-code=") {
-			bazelExitCodeStr := strings.TrimPrefix(arg, "--bazel-exit-code=")
-			val, err := strconv.Atoi(bazelExitCodeStr)
-			if err == nil {
-				c.bazelExitCode = int32(val)
-			} else {
-				ctx.Fatalf("Error parsing bazel-exit-code", err)
-			}
-		} else if strings.HasPrefix(arg, "--bes-id=") {
-			c.besId = strings.TrimPrefix(arg, "--bes-id=")
 		} else if len(arg) > 0 && arg[0] == '-' {
 			parseArgNum := func(def int) int {
 				if len(arg) > 2 {
@@ -879,9 +887,6 @@
 			c.arguments = append(c.arguments, arg)
 		}
 	}
-	if (!c.bazelProdMode) && (!c.bazelStagingMode) {
-		c.bazelProdMode = defaultBazelProdMode(c)
-	}
 }
 
 func validateNinjaWeightList(weightListFilePath string) (err error) {
@@ -1151,7 +1156,7 @@
 }
 
 func (c *configImpl) BuildFromTextStub() bool {
-	return c.buildFromTextStub
+	return !c.buildFromSourceStub
 }
 
 func (c *configImpl) TargetProduct() string {
@@ -1338,6 +1343,19 @@
 			return v
 		}
 	}
+	return c.rbeTmpDir()
+}
+
+func (c *configImpl) rbeDownloadTmpDir() string {
+	for _, f := range []string{"RBE_download_tmp_dir", "FLAG_download_tmp_dir"} {
+		if v, ok := c.environ.Get(f); ok {
+			return v
+		}
+	}
+	return c.rbeTmpDir()
+}
+
+func (c *configImpl) rbeTmpDir() string {
 	buildTmpDir := shared.TempDirForOutDir(c.SoongOutDir())
 	return filepath.Join(buildTmpDir, "rbe")
 }
@@ -1544,6 +1562,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())
 }
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/kati.go b/ui/build/kati.go
index aea56d3..31e7440 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -15,6 +15,8 @@
 package build
 
 import (
+	"android/soong/ui/metrics"
+	"android/soong/ui/status"
 	"crypto/md5"
 	"fmt"
 	"io/ioutil"
@@ -22,10 +24,6 @@
 	"os/user"
 	"path/filepath"
 	"strings"
-	"time"
-
-	"android/soong/ui/metrics"
-	"android/soong/ui/status"
 )
 
 var spaceSlashReplacer = strings.NewReplacer("/", "_", " ", "_")
@@ -198,32 +196,14 @@
 		}
 	}
 	writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_hostname.txt", hostname)
-
-	// BUILD_NUMBER should be set to the source control value that
-	// represents the current state of the source code.  E.g., a
-	// perforce changelist number or a git hash.  Can be an arbitrary string
-	// (to allow for source control that uses something other than numbers),
-	// but must be a single word and a valid file name.
-	//
-	// If no BUILD_NUMBER is set, create a useful "I am an engineering build
-	// from this date/time" value.  Make it start with a non-digit so that
-	// anyone trying to parse it as an integer will probably get "0".
-	cmd.Environment.Unset("HAS_BUILD_NUMBER")
-	buildNumber, ok := cmd.Environment.Get("BUILD_NUMBER")
+	_, ok = cmd.Environment.Get("BUILD_NUMBER")
 	// Unset BUILD_NUMBER during kati run to avoid kati rerun, kati will use BUILD_NUMBER from a file.
 	cmd.Environment.Unset("BUILD_NUMBER")
 	if ok {
 		cmd.Environment.Set("HAS_BUILD_NUMBER", "true")
-		writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", buildNumber)
 	} else {
-		buildNumber = fmt.Sprintf("eng.%.6s.%s", username, time.Now().Format("20060102.150405" /* YYYYMMDD.HHMMSS */))
 		cmd.Environment.Set("HAS_BUILD_NUMBER", "false")
-		writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", username)
 	}
-	// Write the build number to a file so it can be read back in
-	// without changing the command line every time.  Avoids rebuilds
-	// when using ninja.
-	writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_number.txt", buildNumber)
 
 	// Apply the caller's function closure to mutate the environment variables.
 	envFunc(cmd.Environment)
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index eba823a..65e2c8e 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -92,6 +92,7 @@
 	"expr":           Allowed,
 	"fuser":          Allowed,
 	"gcert":          Allowed,
+	"gcertstatus":    Allowed,
 	"getopt":         Allowed,
 	"git":            Allowed,
 	"hexdump":        Allowed,
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 3b9d301..19a54df 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -55,13 +55,14 @@
 
 func getRBEVars(ctx Context, config Config) map[string]string {
 	vars := map[string]string{
-		"RBE_log_dir":       config.rbeProxyLogsDir(),
-		"RBE_re_proxy":      config.rbeReproxy(),
-		"RBE_exec_root":     config.rbeExecRoot(),
-		"RBE_output_dir":    config.rbeProxyLogsDir(),
-		"RBE_proxy_log_dir": config.rbeProxyLogsDir(),
-		"RBE_cache_dir":     config.rbeCacheDir(),
-		"RBE_platform":      "container-image=" + remoteexec.DefaultImage,
+		"RBE_log_dir":          config.rbeProxyLogsDir(),
+		"RBE_re_proxy":         config.rbeReproxy(),
+		"RBE_exec_root":        config.rbeExecRoot(),
+		"RBE_output_dir":       config.rbeProxyLogsDir(),
+		"RBE_proxy_log_dir":    config.rbeProxyLogsDir(),
+		"RBE_cache_dir":        config.rbeCacheDir(),
+		"RBE_download_tmp_dir": config.rbeDownloadTmpDir(),
+		"RBE_platform":         "container-image=" + remoteexec.DefaultImage,
 	}
 	if config.StartRBE() {
 		name, err := config.rbeSockAddr(absPath(ctx, config.TempDir()))
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 44c20a0..667f0c9 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,6 +36,8 @@
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/microfactory"
+
+	"google.golang.org/protobuf/proto"
 )
 
 const (
@@ -50,6 +58,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 {
@@ -178,8 +193,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"))
@@ -295,8 +310,8 @@
 	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")
@@ -465,10 +480,118 @@
 	}
 }
 
+func updateSymlinks(ctx Context, dir, prevCWD, cwd string) error {
+	defer symlinkWg.Done()
+
+	visit := func(path string, d fs.DirEntry, err error) error {
+		if d.IsDir() && path != dir {
+			symlinkWg.Add(1)
+			go updateSymlinks(ctx, path, prevCWD, cwd)
+			return filepath.SkipDir
+		}
+		f, err := d.Info()
+		if err != nil {
+			return err
+		}
+		// If the file is not a symlink, we don't have to update it.
+		if f.Mode()&os.ModeSymlink != os.ModeSymlink {
+			return nil
+		}
+
+		atomic.AddUint32(&numFound, 1)
+		target, err := os.Readlink(path)
+		if err != nil {
+			return err
+		}
+		if strings.HasPrefix(target, prevCWD) &&
+			(len(target) == len(prevCWD) || target[len(prevCWD)] == '/') {
+			target = filepath.Join(cwd, target[len(prevCWD):])
+			if err := os.Remove(path); err != nil {
+				return err
+			}
+			if err := os.Symlink(target, path); err != nil {
+				return err
+			}
+			atomic.AddUint32(&numUpdated, 1)
+		}
+		return nil
+	}
+
+	if err := filepath.WalkDir(dir, visit); err != nil {
+		return err
+	}
+	return nil
+}
+
+func fixOutDirSymlinks(ctx Context, config Config, outDir string) error {
+	cwd, err := os.Getwd()
+	if err != nil {
+		return err
+	}
+
+	// Record the .top as the very last thing in the function.
+	tf := filepath.Join(outDir, ".top")
+	defer func() {
+		if err := os.WriteFile(tf, []byte(cwd), 0644); err != nil {
+			fmt.Fprintf(os.Stderr, fmt.Sprintf("Unable to log CWD: %v", err))
+		}
+	}()
+
+	// Find the previous working directory if it was recorded.
+	var prevCWD string
+	pcwd, err := os.ReadFile(tf)
+	if err != nil {
+		if os.IsNotExist(err) {
+			// No previous working directory recorded, nothing to do.
+			return nil
+		}
+		return err
+	}
+	prevCWD = strings.Trim(string(pcwd), "\n")
+
+	if prevCWD == cwd {
+		// We are in the same source dir, nothing to update.
+		return nil
+	}
+
+	symlinkWg.Add(1)
+	if err := updateSymlinks(ctx, outDir, prevCWD, cwd); err != nil {
+		return err
+	}
+	symlinkWg.Wait()
+	ctx.Println(fmt.Sprintf("Updated %d/%d symlinks in dir %v", numUpdated, numFound, outDir))
+	return nil
+}
+
+func migrateOutputSymlinks(ctx Context, config Config) error {
+	// Figure out the real out directory ("out" could be a symlink).
+	outDir := config.OutDir()
+	s, err := os.Lstat(outDir)
+	if err != nil {
+		if os.IsNotExist(err) {
+			// No out dir exists, no symlinks to migrate.
+			return nil
+		}
+		return err
+	}
+	if s.Mode()&os.ModeSymlink == os.ModeSymlink {
+		target, err := filepath.EvalSymlinks(outDir)
+		if err != nil {
+			return err
+		}
+		outDir = target
+	}
+	return fixOutDirSymlinks(ctx, config, outDir)
+}
+
 func runSoong(ctx Context, config Config) {
 	ctx.BeginTrace(metrics.RunSoong, "soong")
 	defer ctx.EndTrace()
 
+	if err := migrateOutputSymlinks(ctx, config); err != nil {
+		ctx.Fatalf("failed to migrate output directory to current TOP dir: %v", err)
+	}
+
 	// We have two environment files: .available is the one with every variable,
 	// .used with the ones that were actually used. The latter is used to
 	// determine whether Soong needs to be re-run since why re-run it if only
@@ -509,6 +632,10 @@
 
 		if config.BazelBuildEnabled() || config.Bp2Build() {
 			checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(bp2buildFilesTag))
+		} else {
+			// 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() {
@@ -599,8 +726,12 @@
 		targets = append(targets, config.SoongNinjaFile())
 	}
 
+	beforeSoongTimestamp := time.Now()
+
 	ninja(targets...)
 
+	loadSoongBuildMetrics(ctx, config, beforeSoongTimestamp)
+
 	distGzipFile(ctx, config, config.SoongNinjaFile(), "soong")
 	distFile(ctx, config, config.SoongVarsFile(), "soong")
 
@@ -614,6 +745,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/metrics/metrics.go b/ui/metrics/metrics.go
index d68ced8..4a275a8 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -32,7 +32,6 @@
 // of what an event is and how the metrics system is a stack based system.
 
 import (
-	"fmt"
 	"os"
 	"runtime"
 	"strings"
@@ -228,20 +227,6 @@
 	m.metrics.BuildDateTimestamp = proto.Int64(buildTimestamp.UnixNano() / int64(time.Second))
 }
 
-func (m *Metrics) UpdateTotalRealTimeAndNonZeroExit(data []byte, bazelExitCode int32) error {
-	if err := proto.Unmarshal(data, &m.metrics); err != nil {
-		return fmt.Errorf("Failed to unmarshal proto: %w", err)
-	}
-	startTime := *m.metrics.Total.StartTime
-	endTime := uint64(time.Now().UnixNano())
-
-	*m.metrics.Total.RealTime = *proto.Uint64(endTime - startTime)
-
-	bazelError := bazelExitCode != 0
-	m.metrics.NonZeroExit = proto.Bool(bazelError)
-	return nil
-}
-
 // SetBuildCommand adds the build command specified by the user to the
 // list of collected metrics.
 func (m *Metrics) SetBuildCommand(cmd []string) {
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index f3e677a..b75f572 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -279,7 +279,7 @@
 
 // Deprecated: Use ModuleTypeInfo_BuildSystem.Descriptor instead.
 func (ModuleTypeInfo_BuildSystem) EnumDescriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{5, 0}
+	return file_metrics_proto_rawDescGZIP(), []int{8, 0}
 }
 
 type ExpConfigFetcher_ConfigStatus int32
@@ -341,7 +341,7 @@
 
 // Deprecated: Use ExpConfigFetcher_ConfigStatus.Descriptor instead.
 func (ExpConfigFetcher_ConfigStatus) EnumDescriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{9, 0}
+	return file_metrics_proto_rawDescGZIP(), []int{12, 0}
 }
 
 type MetricsBase struct {
@@ -999,6 +999,177 @@
 	return ""
 }
 
+type PerfCounters struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The timestamp of these counters in nanoseconds.
+	Time *uint64 `protobuf:"varint,1,opt,name=time" json:"time,omitempty"`
+	// A list of counter names and values.
+	Groups []*PerfCounterGroup `protobuf:"bytes,2,rep,name=groups" json:"groups,omitempty"`
+}
+
+func (x *PerfCounters) Reset() {
+	*x = PerfCounters{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metrics_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PerfCounters) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PerfCounters) ProtoMessage() {}
+
+func (x *PerfCounters) ProtoReflect() protoreflect.Message {
+	mi := &file_metrics_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PerfCounters.ProtoReflect.Descriptor instead.
+func (*PerfCounters) Descriptor() ([]byte, []int) {
+	return file_metrics_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *PerfCounters) GetTime() uint64 {
+	if x != nil && x.Time != nil {
+		return *x.Time
+	}
+	return 0
+}
+
+func (x *PerfCounters) GetGroups() []*PerfCounterGroup {
+	if x != nil {
+		return x.Groups
+	}
+	return nil
+}
+
+type PerfCounterGroup struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The name of this counter group (e.g. "cpu" or "memory")
+	Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+	// The counters in this group
+	Counters []*PerfCounter `protobuf:"bytes,2,rep,name=counters" json:"counters,omitempty"`
+}
+
+func (x *PerfCounterGroup) Reset() {
+	*x = PerfCounterGroup{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metrics_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PerfCounterGroup) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PerfCounterGroup) ProtoMessage() {}
+
+func (x *PerfCounterGroup) ProtoReflect() protoreflect.Message {
+	mi := &file_metrics_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PerfCounterGroup.ProtoReflect.Descriptor instead.
+func (*PerfCounterGroup) Descriptor() ([]byte, []int) {
+	return file_metrics_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *PerfCounterGroup) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (x *PerfCounterGroup) GetCounters() []*PerfCounter {
+	if x != nil {
+		return x.Counters
+	}
+	return nil
+}
+
+type PerfCounter struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	// The name of this counter.
+	Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+	// The value of this counter.
+	Value *int64 `protobuf:"varint,2,opt,name=value" json:"value,omitempty"`
+}
+
+func (x *PerfCounter) Reset() {
+	*x = PerfCounter{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_metrics_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *PerfCounter) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*PerfCounter) ProtoMessage() {}
+
+func (x *PerfCounter) ProtoReflect() protoreflect.Message {
+	mi := &file_metrics_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use PerfCounter.ProtoReflect.Descriptor instead.
+func (*PerfCounter) Descriptor() ([]byte, []int) {
+	return file_metrics_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *PerfCounter) GetName() string {
+	if x != nil && x.Name != nil {
+		return *x.Name
+	}
+	return ""
+}
+
+func (x *PerfCounter) GetValue() int64 {
+	if x != nil && x.Value != nil {
+		return *x.Value
+	}
+	return 0
+}
+
 type ProcessResourceInfo struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -1029,7 +1200,7 @@
 func (x *ProcessResourceInfo) Reset() {
 	*x = ProcessResourceInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[4]
+		mi := &file_metrics_proto_msgTypes[7]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1042,7 +1213,7 @@
 func (*ProcessResourceInfo) ProtoMessage() {}
 
 func (x *ProcessResourceInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[4]
+	mi := &file_metrics_proto_msgTypes[7]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1055,7 +1226,7 @@
 
 // Deprecated: Use ProcessResourceInfo.ProtoReflect.Descriptor instead.
 func (*ProcessResourceInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{4}
+	return file_metrics_proto_rawDescGZIP(), []int{7}
 }
 
 func (x *ProcessResourceInfo) GetName() string {
@@ -1149,7 +1320,7 @@
 func (x *ModuleTypeInfo) Reset() {
 	*x = ModuleTypeInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[5]
+		mi := &file_metrics_proto_msgTypes[8]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1162,7 +1333,7 @@
 func (*ModuleTypeInfo) ProtoMessage() {}
 
 func (x *ModuleTypeInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[5]
+	mi := &file_metrics_proto_msgTypes[8]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1175,7 +1346,7 @@
 
 // Deprecated: Use ModuleTypeInfo.ProtoReflect.Descriptor instead.
 func (*ModuleTypeInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{5}
+	return file_metrics_proto_rawDescGZIP(), []int{8}
 }
 
 func (x *ModuleTypeInfo) GetBuildSystem() ModuleTypeInfo_BuildSystem {
@@ -1213,7 +1384,7 @@
 func (x *CriticalUserJourneyMetrics) Reset() {
 	*x = CriticalUserJourneyMetrics{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[6]
+		mi := &file_metrics_proto_msgTypes[9]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1226,7 +1397,7 @@
 func (*CriticalUserJourneyMetrics) ProtoMessage() {}
 
 func (x *CriticalUserJourneyMetrics) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[6]
+	mi := &file_metrics_proto_msgTypes[9]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1239,7 +1410,7 @@
 
 // Deprecated: Use CriticalUserJourneyMetrics.ProtoReflect.Descriptor instead.
 func (*CriticalUserJourneyMetrics) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{6}
+	return file_metrics_proto_rawDescGZIP(), []int{9}
 }
 
 func (x *CriticalUserJourneyMetrics) GetName() string {
@@ -1268,7 +1439,7 @@
 func (x *CriticalUserJourneysMetrics) Reset() {
 	*x = CriticalUserJourneysMetrics{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[7]
+		mi := &file_metrics_proto_msgTypes[10]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1281,7 +1452,7 @@
 func (*CriticalUserJourneysMetrics) ProtoMessage() {}
 
 func (x *CriticalUserJourneysMetrics) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[7]
+	mi := &file_metrics_proto_msgTypes[10]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1294,7 +1465,7 @@
 
 // Deprecated: Use CriticalUserJourneysMetrics.ProtoReflect.Descriptor instead.
 func (*CriticalUserJourneysMetrics) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{7}
+	return file_metrics_proto_rawDescGZIP(), []int{10}
 }
 
 func (x *CriticalUserJourneysMetrics) GetCujs() []*CriticalUserJourneyMetrics {
@@ -1323,12 +1494,14 @@
 	Events []*PerfInfo `protobuf:"bytes,6,rep,name=events" json:"events,omitempty"`
 	// Mixed Builds information
 	MixedBuildsInfo *MixedBuildsInfo `protobuf:"bytes,7,opt,name=mixed_builds_info,json=mixedBuildsInfo" json:"mixed_builds_info,omitempty"`
+	// Performance during for soong_build execution.
+	PerfCounters []*PerfCounters `protobuf:"bytes,8,rep,name=perf_counters,json=perfCounters" json:"perf_counters,omitempty"`
 }
 
 func (x *SoongBuildMetrics) Reset() {
 	*x = SoongBuildMetrics{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[8]
+		mi := &file_metrics_proto_msgTypes[11]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1341,7 +1514,7 @@
 func (*SoongBuildMetrics) ProtoMessage() {}
 
 func (x *SoongBuildMetrics) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[8]
+	mi := &file_metrics_proto_msgTypes[11]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1354,7 +1527,7 @@
 
 // Deprecated: Use SoongBuildMetrics.ProtoReflect.Descriptor instead.
 func (*SoongBuildMetrics) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{8}
+	return file_metrics_proto_rawDescGZIP(), []int{11}
 }
 
 func (x *SoongBuildMetrics) GetModules() uint32 {
@@ -1406,6 +1579,13 @@
 	return nil
 }
 
+func (x *SoongBuildMetrics) GetPerfCounters() []*PerfCounters {
+	if x != nil {
+		return x.PerfCounters
+	}
+	return nil
+}
+
 type ExpConfigFetcher struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
@@ -1425,7 +1605,7 @@
 func (x *ExpConfigFetcher) Reset() {
 	*x = ExpConfigFetcher{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[9]
+		mi := &file_metrics_proto_msgTypes[12]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1438,7 +1618,7 @@
 func (*ExpConfigFetcher) ProtoMessage() {}
 
 func (x *ExpConfigFetcher) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[9]
+	mi := &file_metrics_proto_msgTypes[12]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1451,7 +1631,7 @@
 
 // Deprecated: Use ExpConfigFetcher.ProtoReflect.Descriptor instead.
 func (*ExpConfigFetcher) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{9}
+	return file_metrics_proto_rawDescGZIP(), []int{12}
 }
 
 func (x *ExpConfigFetcher) GetStatus() ExpConfigFetcher_ConfigStatus {
@@ -1489,7 +1669,7 @@
 func (x *MixedBuildsInfo) Reset() {
 	*x = MixedBuildsInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[10]
+		mi := &file_metrics_proto_msgTypes[13]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1502,7 +1682,7 @@
 func (*MixedBuildsInfo) ProtoMessage() {}
 
 func (x *MixedBuildsInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[10]
+	mi := &file_metrics_proto_msgTypes[13]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1515,7 +1695,7 @@
 
 // Deprecated: Use MixedBuildsInfo.ProtoReflect.Descriptor instead.
 func (*MixedBuildsInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{10}
+	return file_metrics_proto_rawDescGZIP(), []int{13}
 }
 
 func (x *MixedBuildsInfo) GetMixedBuildEnabledModules() []string {
@@ -1552,7 +1732,7 @@
 func (x *CriticalPathInfo) Reset() {
 	*x = CriticalPathInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[11]
+		mi := &file_metrics_proto_msgTypes[14]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1565,7 +1745,7 @@
 func (*CriticalPathInfo) ProtoMessage() {}
 
 func (x *CriticalPathInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[11]
+	mi := &file_metrics_proto_msgTypes[14]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1578,7 +1758,7 @@
 
 // Deprecated: Use CriticalPathInfo.ProtoReflect.Descriptor instead.
 func (*CriticalPathInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{11}
+	return file_metrics_proto_rawDescGZIP(), []int{14}
 }
 
 func (x *CriticalPathInfo) GetElapsedTimeMicros() uint64 {
@@ -1623,7 +1803,7 @@
 func (x *JobInfo) Reset() {
 	*x = JobInfo{}
 	if protoimpl.UnsafeEnabled {
-		mi := &file_metrics_proto_msgTypes[12]
+		mi := &file_metrics_proto_msgTypes[15]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		ms.StoreMessageInfo(mi)
 	}
@@ -1636,7 +1816,7 @@
 func (*JobInfo) ProtoMessage() {}
 
 func (x *JobInfo) ProtoReflect() protoreflect.Message {
-	mi := &file_metrics_proto_msgTypes[12]
+	mi := &file_metrics_proto_msgTypes[15]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
 		if ms.LoadMessageInfo() == nil {
@@ -1649,7 +1829,7 @@
 
 // Deprecated: Use JobInfo.ProtoReflect.Descriptor instead.
 func (*JobInfo) Descriptor() ([]byte, []int) {
-	return file_metrics_proto_rawDescGZIP(), []int{12}
+	return file_metrics_proto_rawDescGZIP(), []int{15}
 }
 
 func (x *JobInfo) GetElapsedTimeMicros() uint64 {
@@ -1856,132 +2036,153 @@
 	0x6f, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f,
 	0x6e, 0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72,
 	0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb9,
-	0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
-	0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x75, 0x73,
-	0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02,
-	0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69,
-	0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74,
-	0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04,
-	0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72,
-	0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73, 0x4b, 0x62,
-	0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66,
-	0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x69, 0x6e,
-	0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11,
-	0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74,
-	0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x50, 0x61,
-	0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f, 0x5f, 0x69,
-	0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x69,
-	0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f, 0x5f, 0x6f,
-	0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a,
-	0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a, 0x76, 0x6f,
-	0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f,
-	0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18,
-	0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
-	0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e, 0x76, 0x6f,
-	0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f,
-	0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a,
-	0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65,
-	0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x0e, 0x4d,
-	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x5b, 0x0a,
-	0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c,
-	0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
-	0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79,
-	0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52, 0x0b, 0x62,
-	0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6e,
-	0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20,
-	0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
-	0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d,
-	0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a,
-	0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41, 0x4b, 0x45,
-	0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73,
+	0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x61,
+	0x0a, 0x0c, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x12, 0x12,
+	0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x69,
+	0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
+	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75,
+	0x6e, 0x74, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70,
+	0x73, 0x22, 0x64, 0x0a, 0x10, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72,
+	0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x08, 0x63, 0x6f, 0x75,
+	0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f,
+	0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x08, 0x63,
+	0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0x37, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x66, 0x43,
+	0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
+	0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x22, 0xb9, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f,
+	0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10,
+	0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65,
+	0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d,
+	0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69,
+	0x63, 0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f,
+	0x6b, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73,
+	0x4b, 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65,
+	0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d,
+	0x69, 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a,
+	0x0a, 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75,
+	0x6c, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72,
+	0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f,
+	0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x09, 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f,
+	0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a,
+	0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
+	0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65,
+	0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e,
+	0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78,
+	0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e,
+	0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a,
+	0x0e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12,
+	0x5b, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
+	0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75,
+	0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64,
+	0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52,
+	0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b,
+	0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a,
+	0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75,
+	0x6c, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74,
+	0x65, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12,
+	0x09, 0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41,
+	0x4b, 0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c,
+	0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f,
+	0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65,
+	0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73,
+	0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
+	0x73, 0x12, 0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65,
+	0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73,
 	0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
-	0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75,
-	0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72,
-	0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72,
-	0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12,
-	0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e,
+	0x52, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x22, 0x94, 0x03, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67,
+	0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07,
+	0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d,
+	0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e,
+	0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e,
+	0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f,
+	0x63, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74,
+	0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28,
+	0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69,
+	0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41,
+	0x6c, 0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f,
+	0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52,
+	0x0b, 0x6d, 0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06,
+	0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73,
+	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65,
+	0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69,
+	0x6c, 0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24,
+	0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74,
+	0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73,
+	0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
+	0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x46, 0x0a, 0x0d, 0x70, 0x65, 0x72, 0x66, 0x5f, 0x63, 0x6f,
+	0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73,
+	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
+	0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x52,
+	0x0c, 0x70, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0xdb, 0x01,
+	0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68,
+	0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
+	0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66,
+	0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+	0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a,
+	0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69,
+	0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72,
+	0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74,
+	0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10,
+	0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a,
+	0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53,
+	0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, 0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f,
+	0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12,
+	0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65,
+	0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
+	0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f,
+	0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69,
+	0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02,
+	0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
+	0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22,
+	0x8a, 0x02, 0x0a, 0x10, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68,
+	0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f,
+	0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69,
+	0x63, 0x72, 0x6f, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c,
+	0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f,
+	0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61,
+	0x6c, 0x50, 0x61, 0x74, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12,
+	0x41, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68,
+	0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62,
+	0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62,
+	0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61,
+	0x74, 0x68, 0x12, 0x48, 0x0a, 0x11, 0x6c, 0x6f, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69,
+	0x6e, 0x67, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e,
 	0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72,
-	0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72,
-	0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x04,
-	0x63, 0x75, 0x6a, 0x73, 0x22, 0xcc, 0x02, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x42, 0x75,
-	0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d, 0x6f, 0x64,
-	0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73,
-	0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f,
-	0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74, 0x6f, 0x74,
-	0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10,
-	0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69, 0x7a, 0x65,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c,
-	0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x65,
-	0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d,
-	0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x65, 0x76,
-	0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f,
-	0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73,
-	0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74,
-	0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64,
-	0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73,
-	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
-	0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e,
-	0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49,
-	0x6e, 0x66, 0x6f, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69,
-	0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74,
-	0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
-	0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45,
-	0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e,
-	0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74,
-	0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65,
-	0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04,
-	0x52, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66,
-	0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43,
-	0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49,
-	0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11,
-	0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, 0x10,
-	0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64,
-	0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62,
-	0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64,
-	0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65,
-	0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64,
-	0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75,
-	0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64,
-	0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65,
-	0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f,
-	0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x8a, 0x02, 0x0a, 0x10, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63,
-	0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c,
-	0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f,
-	0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64,
-	0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x63, 0x72,
-	0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65,
-	0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x63,
-	0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x4d,
-	0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x41, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61,
-	0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73,
-	0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69,
-	0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x63, 0x72, 0x69, 0x74,
-	0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x11, 0x6c, 0x6f, 0x6e, 0x67,
-	0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x05, 0x20,
-	0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c,
-	0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66,
-	0x6f, 0x52, 0x0f, 0x6c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x4a, 0x6f,
-	0x62, 0x73, 0x22, 0x62, 0x0a, 0x07, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a,
-	0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69,
-	0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70,
-	0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x27, 0x0a,
-	0x0f, 0x6a, 0x6f, 0x62, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6a, 0x6f, 0x62, 0x44, 0x65, 0x73, 0x63, 0x72,
-	0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69,
-	0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69,
-	0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+	0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6c, 0x6f, 0x6e,
+	0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x62, 0x0a, 0x07,
+	0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73,
+	0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d,
+	0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6a, 0x6f, 0x62, 0x5f, 0x64,
+	0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x0e, 0x6a, 0x6f, 0x62, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e,
+	0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e,
+	0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74,
+	0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
 }
 
 var (
@@ -1997,7 +2198,7 @@
 }
 
 var file_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 5)
-var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
+var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 16)
 var file_metrics_proto_goTypes = []interface{}{
 	(MetricsBase_BuildVariant)(0),          // 0: soong_build_metrics.MetricsBase.BuildVariant
 	(MetricsBase_Arch)(0),                  // 1: soong_build_metrics.MetricsBase.Arch
@@ -2008,15 +2209,18 @@
 	(*BuildConfig)(nil),                    // 6: soong_build_metrics.BuildConfig
 	(*SystemResourceInfo)(nil),             // 7: soong_build_metrics.SystemResourceInfo
 	(*PerfInfo)(nil),                       // 8: soong_build_metrics.PerfInfo
-	(*ProcessResourceInfo)(nil),            // 9: soong_build_metrics.ProcessResourceInfo
-	(*ModuleTypeInfo)(nil),                 // 10: soong_build_metrics.ModuleTypeInfo
-	(*CriticalUserJourneyMetrics)(nil),     // 11: soong_build_metrics.CriticalUserJourneyMetrics
-	(*CriticalUserJourneysMetrics)(nil),    // 12: soong_build_metrics.CriticalUserJourneysMetrics
-	(*SoongBuildMetrics)(nil),              // 13: soong_build_metrics.SoongBuildMetrics
-	(*ExpConfigFetcher)(nil),               // 14: soong_build_metrics.ExpConfigFetcher
-	(*MixedBuildsInfo)(nil),                // 15: soong_build_metrics.MixedBuildsInfo
-	(*CriticalPathInfo)(nil),               // 16: soong_build_metrics.CriticalPathInfo
-	(*JobInfo)(nil),                        // 17: soong_build_metrics.JobInfo
+	(*PerfCounters)(nil),                   // 9: soong_build_metrics.PerfCounters
+	(*PerfCounterGroup)(nil),               // 10: soong_build_metrics.PerfCounterGroup
+	(*PerfCounter)(nil),                    // 11: soong_build_metrics.PerfCounter
+	(*ProcessResourceInfo)(nil),            // 12: soong_build_metrics.ProcessResourceInfo
+	(*ModuleTypeInfo)(nil),                 // 13: soong_build_metrics.ModuleTypeInfo
+	(*CriticalUserJourneyMetrics)(nil),     // 14: soong_build_metrics.CriticalUserJourneyMetrics
+	(*CriticalUserJourneysMetrics)(nil),    // 15: soong_build_metrics.CriticalUserJourneysMetrics
+	(*SoongBuildMetrics)(nil),              // 16: soong_build_metrics.SoongBuildMetrics
+	(*ExpConfigFetcher)(nil),               // 17: soong_build_metrics.ExpConfigFetcher
+	(*MixedBuildsInfo)(nil),                // 18: soong_build_metrics.MixedBuildsInfo
+	(*CriticalPathInfo)(nil),               // 19: soong_build_metrics.CriticalPathInfo
+	(*JobInfo)(nil),                        // 20: soong_build_metrics.JobInfo
 }
 var file_metrics_proto_depIdxs = []int32{
 	0,  // 0: soong_build_metrics.MetricsBase.target_build_variant:type_name -> soong_build_metrics.MetricsBase.BuildVariant
@@ -2028,27 +2232,30 @@
 	8,  // 6: soong_build_metrics.MetricsBase.soong_runs:type_name -> soong_build_metrics.PerfInfo
 	8,  // 7: soong_build_metrics.MetricsBase.ninja_runs:type_name -> soong_build_metrics.PerfInfo
 	8,  // 8: soong_build_metrics.MetricsBase.total:type_name -> soong_build_metrics.PerfInfo
-	13, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics
+	16, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics
 	6,  // 10: soong_build_metrics.MetricsBase.build_config:type_name -> soong_build_metrics.BuildConfig
 	7,  // 11: soong_build_metrics.MetricsBase.system_resource_info:type_name -> soong_build_metrics.SystemResourceInfo
 	8,  // 12: soong_build_metrics.MetricsBase.bazel_runs:type_name -> soong_build_metrics.PerfInfo
-	14, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher
-	16, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo
+	17, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher
+	19, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo
 	2,  // 15: soong_build_metrics.BuildConfig.ninja_weight_list_source:type_name -> soong_build_metrics.BuildConfig.NinjaWeightListSource
-	9,  // 16: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo
-	3,  // 17: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem
-	5,  // 18: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase
-	11, // 19: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics
-	8,  // 20: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo
-	15, // 21: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo
-	4,  // 22: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus
-	17, // 23: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo
-	17, // 24: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo
-	25, // [25:25] is the sub-list for method output_type
-	25, // [25:25] is the sub-list for method input_type
-	25, // [25:25] is the sub-list for extension type_name
-	25, // [25:25] is the sub-list for extension extendee
-	0,  // [0:25] is the sub-list for field type_name
+	12, // 16: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo
+	10, // 17: soong_build_metrics.PerfCounters.groups:type_name -> soong_build_metrics.PerfCounterGroup
+	11, // 18: soong_build_metrics.PerfCounterGroup.counters:type_name -> soong_build_metrics.PerfCounter
+	3,  // 19: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem
+	5,  // 20: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase
+	14, // 21: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics
+	8,  // 22: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo
+	18, // 23: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo
+	9,  // 24: soong_build_metrics.SoongBuildMetrics.perf_counters:type_name -> soong_build_metrics.PerfCounters
+	4,  // 25: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus
+	20, // 26: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo
+	20, // 27: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo
+	28, // [28:28] is the sub-list for method output_type
+	28, // [28:28] is the sub-list for method input_type
+	28, // [28:28] is the sub-list for extension type_name
+	28, // [28:28] is the sub-list for extension extendee
+	0,  // [0:28] is the sub-list for field type_name
 }
 
 func init() { file_metrics_proto_init() }
@@ -2106,7 +2313,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ProcessResourceInfo); i {
+			switch v := v.(*PerfCounters); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2118,7 +2325,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ModuleTypeInfo); i {
+			switch v := v.(*PerfCounterGroup); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2130,7 +2337,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*CriticalUserJourneyMetrics); i {
+			switch v := v.(*PerfCounter); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2142,7 +2349,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*CriticalUserJourneysMetrics); i {
+			switch v := v.(*ProcessResourceInfo); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2154,7 +2361,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*SoongBuildMetrics); i {
+			switch v := v.(*ModuleTypeInfo); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2166,7 +2373,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*ExpConfigFetcher); i {
+			switch v := v.(*CriticalUserJourneyMetrics); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2178,7 +2385,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*MixedBuildsInfo); i {
+			switch v := v.(*CriticalUserJourneysMetrics); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2190,7 +2397,7 @@
 			}
 		}
 		file_metrics_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*CriticalPathInfo); i {
+			switch v := v.(*SoongBuildMetrics); i {
 			case 0:
 				return &v.state
 			case 1:
@@ -2202,6 +2409,42 @@
 			}
 		}
 		file_metrics_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ExpConfigFetcher); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metrics_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*MixedBuildsInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metrics_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*CriticalPathInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_metrics_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
 			switch v := v.(*JobInfo); i {
 			case 0:
 				return &v.state
@@ -2220,7 +2463,7 @@
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_metrics_proto_rawDesc,
 			NumEnums:      5,
-			NumMessages:   13,
+			NumMessages:   16,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index b437da7..11fcba7 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -213,6 +213,30 @@
   optional string error_message = 8;
 }
 
+message PerfCounters {
+  // The timestamp of these counters in nanoseconds.
+  optional uint64 time = 1;
+
+  // A list of counter names and values.
+  repeated PerfCounterGroup groups = 2;
+}
+
+message PerfCounterGroup {
+  // The name of this counter group (e.g. "cpu" or "memory")
+  optional string name = 1;
+
+  // The counters in this group
+  repeated PerfCounter counters = 2;
+}
+
+message PerfCounter {
+  // The name of this counter.
+  optional string name = 1;
+
+  // The value of this counter.
+  optional int64 value = 2;
+}
+
 message ProcessResourceInfo {
   // The name of the process for identification.
   optional string name = 1;
@@ -295,6 +319,9 @@
 
   // Mixed Builds information
   optional MixedBuildsInfo mixed_builds_info = 7;
+
+  // Performance during for soong_build execution.
+  repeated PerfCounters perf_counters = 8;
 }
 
 message ExpConfigFetcher {
diff --git a/ui/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/xml_conversion_test.go b/xml/xml_conversion_test.go
index 6606ddc..c052b44 100644
--- a/xml/xml_conversion_test.go
+++ b/xml/xml_conversion_test.go
@@ -121,8 +121,8 @@
 				"filename_from_src": `True`,
 				"dir":               `"etc"`,
 				"src": `select({
-        "//build/bazel/platforms/arch:arm": "barSrc",
-        "//build/bazel/platforms/arch:arm64": "bazSrc",
+        "//build/bazel_common_rules/platforms/arch:arm": "barSrc",
+        "//build/bazel_common_rules/platforms/arch:arm64": "bazSrc",
         "//conditions:default": None,
     })`,
 			})}})